1 | #include "signalanalyzer.h"
|
2 |
|
3 | #include <QDebug>
|
4 | #include <qfile.h>
|
5 | #include <QTime>
|
6 | #include <qtimer.h>
|
7 | #include <omp.h>
|
8 |
|
9 | #include "configuration.h"
|
10 |
|
11 | SignalAnalyzer::SignalAnalyzer()
|
12 | : QObject()
|
13 | {
|
14 | fftw_init_threads();
|
15 | updatePlan();
|
16 | }
|
17 |
|
18 | void SignalAnalyzer::updatePlan()
|
19 | {
|
20 | auto c = Configuration::instance();
|
21 | omp_set_num_threads(1); // TODO: ?
|
22 | fftw_plan_with_nthreads(1);
|
23 | auto tmp = fftw_alloc_real((c->channels+2)*c->average);
|
24 | m_plan = fftw_plan_dft_r2c_2d(c->average, c->channels,
|
25 | tmp, reinterpret_cast<fftw_complex*>(tmp),
|
26 | FFTW_ESTIMATE); // FFTW_MEASURE
|
27 | fftw_free(tmp);
|
28 | }
|
29 |
|
30 | SignalAnalyzer::~SignalAnalyzer()
|
31 | {
|
32 |
|
33 | }
|
34 |
|
35 | void SignalAnalyzer::processQueued()
|
36 | {
|
37 | if ( m_chunks.isEmpty() ) {
|
38 | return;
|
39 | }
|
40 | static uint32_t processed = 0;
|
41 |
|
42 | QTime t;
|
43 | t.start();
|
44 | auto chunk = m_chunks.takeFirst();
|
45 | auto s = processChunk(chunk);
|
46 | Q_EMIT processingFinished(s, chunk.identification);
|
47 | qDebug() << "processed chunk" << processed << "in" << t.elapsed() << "ms";
|
48 | processed++;
|
49 | QTimer::singleShot(3, this, &SignalAnalyzer::processQueued);
|
50 | }
|
51 |
|
52 | SignalAnalyzer::Spectrum SignalAnalyzer::processChunk(DataStream::DataBlock chunk)
|
53 | {
|
54 | auto c = Configuration::instance();
|
55 | static QVector<double> value_for_bits;
|
56 | if ( value_for_bits.isEmpty() ) {
|
57 | for ( int j = 0; j <= 256; j++ ) {
|
58 | // value_for_bits.append(bitswap_lut[j]);
|
59 | value_for_bits.append(j*0.004/sqrt(50));
|
60 | }
|
61 | }
|
62 |
|
63 | static QVector<double> window;
|
64 | if ( window.isEmpty() ) {
|
65 | for ( int j = 0; j < c->channels; j++ ) {
|
66 | window.append((0.54-0.46*cos(2*3.1415*j/(c->channels-1))));
|
67 | }
|
68 | }
|
69 |
|
70 | Q_ASSERT(chunk.data.size() == c->average * c->channels);
|
71 | static auto d = fftw_alloc_real((c->channels+2)*c->average);
|
72 | static auto dzero = d;
|
73 | d = dzero;
|
74 |
|
75 | auto src = chunk.data.data();
|
76 | for ( unsigned int i = 0; i < c->average; i++ ) {
|
77 | for ( unsigned int j = 0; j < c->channels; j++ ) {
|
78 | *d++ = value_for_bits.at(*reinterpret_cast<unsigned char*>(src++)) * window.at(j);
|
79 | }
|
80 | d += 2;
|
81 | }
|
82 |
|
83 | d = dzero;
|
84 | fftw_execute_dft_r2c(m_plan, d, reinterpret_cast<fftw_complex*>(d));
|
85 |
|
86 | d = dzero;
|
87 | Spectrum ret(c->channels/2);
|
88 | for ( unsigned int j = 0; j < c->average; j += 1 ) {
|
89 | for ( int i = 0; i < c->channels/2; i += 1 ) {
|
90 | const auto re = *d++;
|
91 | const auto im = *d++;
|
92 | ret[i] += re*re + im*im;
|
93 | }
|
94 | d += 2;
|
95 | }
|
96 |
|
97 | for ( int j = 0; j < ret.size(); j++ ) {
|
98 | // fftw normalization
|
99 | ret[j] /= c->average * c->channels;
|
100 | // averaging
|
101 | ret[j] /= c->average;
|
102 | // ret[j] = 10*log10(ret[j]);
|
103 | }
|
104 | return ret;
|
105 | }
|
106 |
|
107 | void SignalAnalyzer::addData(DataStream::DataBlock chunk)
|
108 | {
|
109 | // cpu_set_t cpuset;
|
110 | // CPU_ZERO(&cpuset);
|
111 | // CPU_SET(0, &cpuset);
|
112 | // pthread_setaffinity_np((pthread_t) pthread_self(), sizeof(cpu_set_t), &cpuset);
|
113 |
|
114 | // qDebug() << "adding chunk of size" << chunk.size() << "( queued:" << m_chunks.size() << ")";
|
115 | m_chunks.append(chunk);
|
116 | processQueued();
|
117 | // qDebug() << "processing finished";
|
118 | }
|