v2.0.0
Loading...
Searching...
No Matches
unbiasedsquaredphaselagindex.cpp
Go to the documentation of this file.
1//=============================================================================================================
15
16//=============================================================================================================
17// INCLUDES
18//=============================================================================================================
19
23#include "../network/network.h"
24
25#include <math/spectral.h>
26
27//=============================================================================================================
28// QT INCLUDES
29//=============================================================================================================
30
31#include <QDebug>
32#include <QtConcurrent>
33
34//=============================================================================================================
35// EIGEN INCLUDES
36//=============================================================================================================
37
38#include <unsupported/Eigen/FFT>
39
40//=============================================================================================================
41// USED NAMESPACES
42//=============================================================================================================
43
44using namespace CONNECTIVITYLIB;
45using namespace Eigen;
46using namespace UTILSLIB;
47
48//=============================================================================================================
49// DEFINE GLOBAL METHODS
50//=============================================================================================================
51
52//=============================================================================================================
53// DEFINE MEMBER METHODS
54//=============================================================================================================
55
59
60//*******************************************************************************************************
61
63{
64 // QElapsedTimer timer;
65 // qint64 iTime = 0;
66 // timer.start();
67
68 Network finalNetwork("USPLI");
69
70 if (connectivitySettings.isEmpty()) {
71 qDebug() << "UnbiasedSquaredPhaseLagIndex::calculate - Input data is empty";
72 return finalNetwork;
73 }
74
76 connectivitySettings.clearIntermediateData();
77 }
78
79 finalNetwork.setSamplingFrequency(connectivitySettings.getSamplingFrequency());
80
81#ifdef EIGEN_FFTW_DEFAULT
82 fftw_make_planner_thread_safe();
83#endif
84
85 //Create nodes
86 int rows = connectivitySettings.at(0).matData.rows();
87 RowVectorXf rowVert = RowVectorXf::Zero(3);
88
89 for (int i = 0; i < rows; ++i) {
90 rowVert = RowVectorXf::Zero(3);
91
92 if (connectivitySettings.getNodePositions().rows() != 0 && i < connectivitySettings.getNodePositions().rows()) {
93 rowVert(0) = connectivitySettings.getNodePositions().row(i)(0);
94 rowVert(1) = connectivitySettings.getNodePositions().row(i)(1);
95 rowVert(2) = connectivitySettings.getNodePositions().row(i)(2);
96 }
97
98 finalNetwork.append(NetworkNode::SPtr(new NetworkNode(i, rowVert)));
99 }
100
101 // Check that iNfft >= signal length
102 int iSignalLength = connectivitySettings.at(0).matData.cols();
103 int iNfft = connectivitySettings.getFFTSize();
104
105 // Generate tapers
106 QPair<MatrixXd, VectorXd> tapers = Spectral::generateTapers(iSignalLength, connectivitySettings.getWindowType());
107
108 // Initialize
109 int iNRows = connectivitySettings.at(0).matData.rows();
110 int iNFreqs = int(floor(iNfft / 2.0)) + 1;
111
112 // Check if start and bin amount need to be reset to full spectrum
113 if (m_iNumberBinStart == -1 ||
114 m_iNumberBinAmount == -1 ||
115 m_iNumberBinStart > iNFreqs ||
116 m_iNumberBinAmount > iNFreqs ||
118 qDebug() << "UnbiasedSquaredPhaseLagIndex::calculate - Resetting to full spectrum";
121 }
122
123 // Pass information about the FFT length. Use iNFreqs because we only use the half spectrum
124 finalNetwork.setFFTSize(iNFreqs);
126
127 QMutex mutex;
128
129 std::function<void(ConnectivitySettings::IntermediateTrialData&)> computeLambda = [&](ConnectivitySettings::IntermediateTrialData& inputData) {
130 compute(inputData,
131 connectivitySettings.getIntermediateSumData().vecPairCsdSum,
132 connectivitySettings.getIntermediateSumData().vecPairCsdImagSignSum,
133 mutex,
134 iNRows,
135 iNFreqs,
136 iNfft,
137 tapers);
138 };
139
140 // iTime = timer.elapsed();
141 // qWarning() << "Preparation" << iTime;
142 // timer.restart();
143
144 // Compute DSWPLV in parallel for all trials
145 QFuture<void> result = QtConcurrent::map(connectivitySettings.getTrialData(),
146 computeLambda);
147 result.waitForFinished();
148
149 // iTime = timer.elapsed();
150 // qWarning() << "ComputeSpectraPSDCSD" << iTime;
151 // timer.restart();
152
153 // Compute USPLI
154 computeUSPLI(connectivitySettings,
155 finalNetwork);
156
157 // iTime = timer.elapsed();
158 // qWarning() << "Compute" << iTime;
159 // timer.restart();
160
161 return finalNetwork;
162}
163
164//=============================================================================================================
165
167 QVector<QPair<int, MatrixXcd>>& vecPairCsdSum,
168 QVector<QPair<int, MatrixXd>>& vecPairCsdImagSignSum,
169 QMutex& mutex,
170 int iNRows,
171 int iNFreqs,
172 int iNfft,
173 const QPair<MatrixXd, VectorXd>& tapers)
174{
175 if (inputData.vecPairCsdImagSign.size() == iNRows) {
176 //qDebug() << "UnbiasedSquaredPhaseLagIndex::compute - vecPairCsdImagSign was already computed for this trial.";
177 return;
178 }
179
180 int i;
181
182 // Calculate tapered spectra if not available already
183 // This code was copied and changed modified Utils/Spectra since we do not want to call the function due to time loss.
184 if (inputData.vecTapSpectra.size() != iNRows) {
185 inputData.vecTapSpectra.clear();
186
187 RowVectorXd vecInputFFT, rowData;
188 RowVectorXcd vecTmpFreq;
189
190 MatrixXcd matTapSpectrum(tapers.first.rows(), iNFreqs);
191
192 FFT<double> fft;
193 fft.SetFlag(fft.HalfSpectrum);
194
195 for (i = 0; i < iNRows; ++i) {
196 // Substract mean
197 rowData.array() = inputData.matData.row(i).array() - inputData.matData.row(i).mean();
198
199 // Calculate tapered spectra if not available already
200 for (int j = 0; j < tapers.first.rows(); j++) {
201 // Zero padd if necessary. The zero padding in Eigen's FFT is only working for column vectors.
202 if (rowData.cols() < iNfft) {
203 vecInputFFT.setZero(iNfft);
204 vecInputFFT.block(0, 0, 1, rowData.cols()) = rowData.cwiseProduct(tapers.first.row(j));
205 ;
206 } else {
207 vecInputFFT = rowData.cwiseProduct(tapers.first.row(j));
208 }
209
210 // FFT for freq domain returning the half spectrum and multiply taper weights
211 fft.fwd(vecTmpFreq, vecInputFFT, iNfft);
212 matTapSpectrum.row(j) = vecTmpFreq * tapers.second(j);
213 }
214
215 inputData.vecTapSpectra.append(matTapSpectrum);
216 }
217 }
218
219 // Compute CSD
220 if (inputData.vecPairCsd.isEmpty()) {
221 double denomCSD = sqrt(tapers.second.cwiseAbs2().sum()) * sqrt(tapers.second.cwiseAbs2().sum()) / 2.0;
222
223 bool bNfftEven = false;
224 if (iNfft % 2 == 0) {
225 bNfftEven = true;
226 }
227
228 MatrixXcd matCsd = MatrixXcd(iNRows, m_iNumberBinAmount);
229
230 for (i = 0; i < iNRows; ++i) {
231 for (int j = i; j < iNRows; ++j) {
232 // Compute CSD (average over tapers if necessary)
233 matCsd.row(j) = inputData.vecTapSpectra.at(i).block(0, m_iNumberBinStart, inputData.vecTapSpectra.at(i).rows(), m_iNumberBinAmount).cwiseProduct(inputData.vecTapSpectra.at(j).block(0, m_iNumberBinStart, inputData.vecTapSpectra.at(j).rows(), m_iNumberBinAmount).conjugate()).colwise().sum() / denomCSD;
234
235 // Divide first and last element by 2 due to half spectrum
236 if (m_iNumberBinStart == 0) {
237 matCsd.row(j)(0) /= 2.0;
238 }
239
240 if (bNfftEven && m_iNumberBinStart + m_iNumberBinAmount >= iNFreqs) {
241 matCsd.row(j).tail(1) /= 2.0;
242 }
243 }
244
245 inputData.vecPairCsd.append(QPair<int, MatrixXcd>(i, matCsd));
246 inputData.vecPairCsdImagSign.append(QPair<int, MatrixXd>(i, matCsd.imag().cwiseSign()));
247 }
248
249 mutex.lock();
250
251 if (vecPairCsdSum.isEmpty()) {
252 vecPairCsdSum = inputData.vecPairCsd;
253 vecPairCsdImagSignSum = inputData.vecPairCsdImagSign;
254 } else {
255 for (int j = 0; j < vecPairCsdSum.size(); ++j) {
256 vecPairCsdSum[j].second += inputData.vecPairCsd.at(j).second;
257 vecPairCsdImagSignSum[j].second += inputData.vecPairCsdImagSign.at(j).second;
258 }
259 }
260
261 mutex.unlock();
262 } else {
263 if (inputData.vecPairCsdImagSign.isEmpty()) {
264 for (i = 0; i < inputData.vecPairCsd.size(); ++i) {
265 inputData.vecPairCsdImagSign.append(QPair<int, MatrixXd>(i, inputData.vecPairCsd.at(i).second.imag().cwiseSign()));
266 }
267
268 mutex.lock();
269
270 if (vecPairCsdImagSignSum.isEmpty()) {
271 vecPairCsdImagSignSum = inputData.vecPairCsdImagSign;
272 } else {
273 for (int j = 0; j < vecPairCsdImagSignSum.size(); ++j) {
274 vecPairCsdImagSignSum[j].second += inputData.vecPairCsdImagSign.at(j).second;
275 }
276 }
277
278 mutex.unlock();
279 }
280 }
281
283 inputData.vecPairCsd.clear();
284 inputData.vecTapSpectra.clear();
285 inputData.vecPairCsdImagSign.clear();
286 }
287}
288
289//=============================================================================================================
290
292 Network& finalNetwork)
293{
294 // Compute final DSWPLV and create Network
295 MatrixXd matNom;
296 MatrixXd matWeight;
297 QSharedPointer<NetworkEdge> pEdge;
298 int j;
299 double dNTrials = double(connectivitySettings.size() - 1.0);
300
301 for (int i = 0; i < connectivitySettings.getIntermediateSumData().vecPairCsdImagSignSum.size(); ++i) {
302 matNom = connectivitySettings.getIntermediateSumData().vecPairCsdImagSignSum.at(i).second.cwiseAbs() / connectivitySettings.size();
303 matNom = (connectivitySettings.size() * matNom.array().square() - 1.0) / dNTrials;
304
305 for (j = i; j < matNom.rows(); ++j) {
306 matWeight = matNom.row(j).transpose();
307
308 pEdge = QSharedPointer<NetworkEdge>(new NetworkEdge(i, j, matWeight));
309
310 finalNetwork.getNodeAt(i)->append(pEdge);
311 finalNetwork.getNodeAt(j)->append(pEdge);
312 finalNetwork.append(pEdge);
313 }
314 }
315}
Multi-taper spectral estimation: tapered FFT, power and cross-spectral density, DPSS weighting.
Node of a connectivity CONNECTIVITYLIB::Network; carries a 3D position and the lists of incident (in ...
Weighted edge between two CONNECTIVITYLIB::NetworkNode instances; stores the full per-frequency weigh...
Graph container that stores the result of one functional-connectivity metric as nodes (sources/sensor...
Unbiased estimator of squared Phase Lag Index between every channel pair.
Functional connectivity metrics (coherence, PLV, cross-correlation, etc.).
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
Aggregates trial data, spectral cache and node geometry shared by all CONNECTIVITYLIB metrics.
QList< IntermediateTrialData > & getTrialData()
const IntermediateTrialData & at(int i) const
const Eigen::MatrixX3f & getNodePositions() const
Per-trial intermediate frequency-domain data used during connectivity computation.
QVector< QPair< int, Eigen::MatrixXcd > > vecPairCsdSum
QVector< QPair< int, Eigen::MatrixXd > > vecPairCsdImagSignSum
static void computeUSPLI(ConnectivitySettings &connectivitySettings, Network &finalNetwork)
static Network calculate(ConnectivitySettings &connectivitySettings)
static void compute(ConnectivitySettings::IntermediateTrialData &inputData, QVector< QPair< int, Eigen::MatrixXcd > > &vecPairCsdSum, QVector< QPair< int, Eigen::MatrixXd > > &vecPairCsdImagSignSum, QMutex &mutex, int iNRows, int iNFreqs, int iNfft, const QPair< Eigen::MatrixXd, Eigen::VectorXd > &tapers)
Graph container for one connectivity metric; nodes + weighted edges + threshold/visualisation state.
Definition network.h:106
void setUsedFreqBins(int iNumberFreqBins)
Definition network.cpp:493
void append(QSharedPointer< NetworkEdge > newEdge)
void setFFTSize(int iFFTSize)
Definition network.cpp:500
void setSamplingFrequency(float fSFreq)
Definition network.cpp:479
QSharedPointer< NetworkNode > getNodeAt(int i)
Definition network.cpp:143
Weighted, directional edge in a Network; carries per-frequency weights plus a band-averaged scalar.
Definition networkedge.h:85
Graph node carrying a 3D position and its incident in/out, full/thresholded edge lists.
Definition networknode.h:83
QSharedPointer< NetworkNode > SPtr
Definition networknode.h:85
static QPair< Eigen::MatrixXd, Eigen::VectorXd > generateTapers(int iSignalLength, const QString &sWindowType="hanning")
Definition spectral.cpp:270