v2.0.0
Loading...
Searching...
No Matches
rt_noise.cpp
Go to the documentation of this file.
1//=============================================================================================================
12
13//=============================================================================================================
14// INCLUDES
15//=============================================================================================================
16
17#include "rt_noise.h"
18
19//=============================================================================================================
20// QT INCLUDES
21//=============================================================================================================
22
23#include <QDebug>
24
25//=============================================================================================================
26// EIGEN INCLUDES
27//=============================================================================================================
28
29#include <unsupported/Eigen/FFT>
30
31//=============================================================================================================
32// STD INCLUDES
33//=============================================================================================================
34
35#include <cmath>
36
37//=============================================================================================================
38// USED NAMESPACES
39//=============================================================================================================
40
41using namespace RTPROCESSINGLIB;
42using namespace FIFFLIB;
43using namespace Eigen;
44
45//=============================================================================================================
46// DEFINE MEMBER METHODS — RtNoiseWorker
47//=============================================================================================================
48
50 FiffInfo::SPtr pFiffInfo,
51 qint32 iDataLength)
52: m_iFftLength(iFftLength)
53, m_dFs(pFiffInfo->sfreq)
54, m_iDataLength(iDataLength < 1 ? 10 : iDataLength)
55{
56 m_fWin = hanning(m_iFftLength, 0);
57}
58
59//=============================================================================================================
60
61void RtNoiseWorker::doWork(const MatrixXd& matData)
62{
63 if(m_bFirstBlock) {
64 m_iNumOfBlocks = m_iDataLength;
65 m_iBlockSize = static_cast<int>(matData.cols());
66 m_iSensors = static_cast<int>(matData.rows());
67 m_matCircBuf.resize(m_iSensors, static_cast<Eigen::Index>(m_iNumOfBlocks) * m_iBlockSize);
68 m_iBlockIndex = 0;
69 m_bFirstBlock = false;
70 }
71
72 // Accumulate block into circular buffer
73 m_matCircBuf.block(0, m_iBlockIndex * m_iBlockSize, m_iSensors, m_iBlockSize) = matData;
74
75 m_iBlockIndex++;
76 if(m_iBlockIndex < m_iNumOfBlocks) {
77 return;
78 }
79
80 // Enough blocks accumulated — compute spectrum
81 m_iBlockIndex = 0;
82
83 const int iTotalSamples = m_iNumOfBlocks * m_iBlockSize;
84 const int iHalfSpec = m_iFftLength / 2 + 1;
85 const int nb = iTotalSamples / m_iFftLength + 1;
86
87 MatrixXd sum_psdx = MatrixXd::Zero(m_iSensors, iHalfSpec);
88 RowVectorXd vecDataZeroPad = RowVectorXd::Zero(m_iFftLength);
89 RowVectorXcd vecFreqData(iHalfSpec);
90
91 for(int n = 0; n < nb; ++n) {
92 const int iOffset = n * m_iFftLength;
93
94 for(int i = 0; i < m_iSensors; ++i) {
95 // Extract and zero-pad segment
96 vecDataZeroPad.setZero();
97 const int iCopyLen = std::min(m_iFftLength, iTotalSamples - iOffset);
98 vecDataZeroPad.head(iCopyLen) = m_matCircBuf.block(i, iOffset, 1, iCopyLen);
99
100 // Apply Hanning window
101 for(int k = 0; k < m_iFftLength; ++k) {
102 vecDataZeroPad[k] *= m_fWin[k];
103 }
104
105 // FFT
106 Eigen::FFT<double> fft;
107 fft.SetFlag(fft.HalfSpectrum);
108 fft.fwd(vecFreqData, vecDataZeroPad);
109
110 // PSD from FFT
111 for(int j = 0; j < iHalfSpec; ++j) {
112 const double mag = std::abs(vecFreqData(j));
113 double spower = mag / (m_dFs * m_iFftLength);
114 if(j > 0 && j < m_iFftLength / 2) {
115 spower *= 2.0;
116 }
117 sum_psdx(i, j) += spower;
118 }
119 }
120 }
121
122 // Convert to dB
123 MatrixXd matResult(m_iSensors, iHalfSpec);
124 for(int i = 0; i < m_iSensors; ++i) {
125 for(int j = 0; j < iHalfSpec; ++j) {
126 matResult(i, j) = 10.0 * std::log10(sum_psdx(i, j) / nb);
127 }
128 }
129
130 emit resultReady(matResult);
131}
132
133//=============================================================================================================
134
135QVector<float> RtNoiseWorker::hanning(int N, short itype)
136{
137 QVector<float> w(N, 0.0f);
138
139 const int n = (itype == 1) ? N - 1 : N;
140
141 if(n % 2 == 0) {
142 const int half = n / 2;
143 for(int i = 0; i < half; ++i) {
144 w[i] = 0.5f * (1.0f - std::cos(2.0f * static_cast<float>(M_PI) * (i + 1) / (n + 1)));
145 }
146 int idx = half - 1;
147 for(int i = half; i < n; ++i) {
148 w[i] = w[idx--];
149 }
150 } else {
151 const int half = (n + 1) / 2;
152 for(int i = 0; i < half; ++i) {
153 w[i] = 0.5f * (1.0f - std::cos(2.0f * static_cast<float>(M_PI) * (i + 1) / (n + 1)));
154 }
155 int idx = half - 2;
156 for(int i = half; i < n; ++i) {
157 w[i] = w[idx--];
158 }
159 }
160
161 if(itype == 1) {
162 for(int i = N - 1; i >= 1; --i) {
163 w[i] = w[i - 1];
164 }
165 w[0] = 0.0f;
166 }
167
168 return w;
169}
170
171//=============================================================================================================
172// DEFINE MEMBER METHODS — RtNoise
173//=============================================================================================================
174
175RtNoise::RtNoise(qint32 iFftLength,
176 FiffInfo::SPtr pFiffInfo,
177 qint32 iDataLength,
178 QObject *parent)
179: QObject(parent)
180{
181 qRegisterMetaType<Eigen::MatrixXd>("Eigen::MatrixXd");
182
183 auto* worker = new RtNoiseWorker(iFftLength, pFiffInfo, iDataLength);
184 worker->moveToThread(&m_workerThread);
185
186 connect(&m_workerThread, &QThread::finished,
187 worker, &QObject::deleteLater);
188 connect(this, &RtNoise::operate,
189 worker, &RtNoiseWorker::doWork);
190 connect(worker, &RtNoiseWorker::resultReady,
192}
193
194//=============================================================================================================
195
197{
198 if(m_bIsRunning) {
199 stop();
200 }
201}
202
203//=============================================================================================================
204
205void RtNoise::append(const MatrixXd& matData)
206{
207 emit operate(matData);
208}
209
210//=============================================================================================================
211
213{
214 return m_bIsRunning;
215}
216
217//=============================================================================================================
218
220{
221 if(m_workerThread.isRunning()) {
222 m_workerThread.wait();
223 }
224
225 m_bIsRunning = true;
226 m_workerThread.start();
227 return true;
228}
229
230//=============================================================================================================
231
233{
234 m_bIsRunning = false;
235 m_workerThread.quit();
236 m_workerThread.wait();
237 return true;
238}
239
240//=============================================================================================================
241
242bool RtNoise::wait(unsigned long time)
243{
244 return m_workerThread.wait(time);
245}
246
#define M_PI
Real-time noise power-spectral-density estimation from streaming data blocks.
FIFF file I/O, in-memory data structures and high-level readers/writers.
Background worker that computes a noise power spectral density estimate from accumulated data blocks.
Definition rt_noise.h:64
void resultReady(const Eigen::MatrixXd &matSpecData)
RtNoiseWorker(qint32 iFftLength, FIFFLIB::FiffInfo::SPtr pFiffInfo, qint32 iDataLength)
Definition rt_noise.cpp:49
void doWork(const Eigen::MatrixXd &matData)
Definition rt_noise.cpp:61
bool wait(unsigned long time=ULONG_MAX)
Definition rt_noise.cpp:242
void operate(const Eigen::MatrixXd &matData)
void SpecCalculated(const Eigen::MatrixXd &matSpecData)
RtNoise(qint32 iFftLength, FIFFLIB::FiffInfo::SPtr pFiffInfo, qint32 iDataLength, QObject *parent=nullptr)
Definition rt_noise.cpp:175
void append(const Eigen::MatrixXd &matData)
Definition rt_noise.cpp:205
QSharedPointer< FiffInfo > SPtr
Definition fiff_info.h:90