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