v2.0.0
Loading...
Searching...
No Matches
crosscorrelation.cpp
Go to the documentation of this file.
1//=============================================================================================================
14
15//=============================================================================================================
16// INCLUDES
17//=============================================================================================================
18
19#include "crosscorrelation.h"
22#include "../network/network.h"
23
24#include <math/spectral.h>
25
26//=============================================================================================================
27// QT INCLUDES
28//=============================================================================================================
29
30#include <QDebug>
31#include <QtConcurrent>
32
33//=============================================================================================================
34// EIGEN INCLUDES
35//=============================================================================================================
36
37#include <unsupported/Eigen/FFT>
38
39//=============================================================================================================
40// USED NAMESPACES
41//=============================================================================================================
42
43using namespace CONNECTIVITYLIB;
44using namespace Eigen;
45using namespace UTILSLIB;
46
47//=============================================================================================================
48// DEFINE GLOBAL METHODS
49//=============================================================================================================
50
51//=============================================================================================================
52// DEFINE MEMBER METHODS
53//=============================================================================================================
54
58
59//=============================================================================================================
60
62{
63 // QElapsedTimer timer;
64 // qint64 iTime = 0;
65 // timer.start();
66
67#ifdef EIGEN_FFTW_DEFAULT
68 fftw_make_planner_thread_safe();
69#endif
70
71 Network finalNetwork("XCOR");
72
73 if (connectivitySettings.isEmpty()) {
74 qDebug() << "CrossCorrelation::calculate - Input data is empty";
75 return finalNetwork;
76 }
77
79 connectivitySettings.clearIntermediateData();
80 }
81
82 finalNetwork.setSamplingFrequency(connectivitySettings.getSamplingFrequency());
83
84 //Create nodes
85 int rows = connectivitySettings.at(0).matData.rows();
86 RowVectorXf rowVert = RowVectorXf::Zero(3);
87
88 for (int i = 0; i < rows; ++i) {
89 rowVert = RowVectorXf::Zero(3);
90
91 if (connectivitySettings.getNodePositions().rows() != 0 && i < connectivitySettings.getNodePositions().rows()) {
92 rowVert(0) = connectivitySettings.getNodePositions().row(i)(0);
93 rowVert(1) = connectivitySettings.getNodePositions().row(i)(1);
94 rowVert(2) = connectivitySettings.getNodePositions().row(i)(2);
95 }
96
97 finalNetwork.append(NetworkNode::SPtr(new NetworkNode(i, rowVert)));
98 }
99
100 // Generate tapers
101 int iSignalLength = connectivitySettings.at(0).matData.cols();
102 int iNfft = connectivitySettings.getFFTSize();
103
104 QPair<MatrixXd, VectorXd> tapers = Spectral::generateTapers(iSignalLength, connectivitySettings.getWindowType());
105
106 // Compute the cross correlation in parallel
107 QMutex mutex;
108 MatrixXd matDist;
109
110 std::function<void(ConnectivitySettings::IntermediateTrialData&)> computeLambda = [&](ConnectivitySettings::IntermediateTrialData& inputData) {
111 compute(inputData,
112 matDist,
113 mutex,
114 iNfft,
115 tapers);
116 };
117
118 // iTime = timer.elapsed();
119 // qWarning() << "Preparation" << iTime;
120 // timer.restart();
121
122 // Calculate connectivity matrix over epochs and average afterwards
123 QFuture<void> resultMat = QtConcurrent::map(connectivitySettings.getTrialData(),
124 computeLambda);
125 resultMat.waitForFinished();
126
127 matDist /= connectivitySettings.size();
128
129 // iTime = timer.elapsed();
130 // qWarning() << "ComputeSpectraPSDCSD" << iTime;
131 // timer.restart();
132
133 //Add edges to network
134 MatrixXd matWeight(1, 1);
135 QSharedPointer<NetworkEdge> pEdge;
136 int j;
137
138 for (int i = 0; i < matDist.rows(); ++i) {
139 for (j = i; j < matDist.cols(); ++j) {
140 matWeight << matDist(i, j);
141
142 pEdge = QSharedPointer<NetworkEdge>(new NetworkEdge(i, j, matWeight));
143
144 finalNetwork.getNodeAt(i)->append(pEdge);
145 finalNetwork.getNodeAt(j)->append(pEdge);
146 finalNetwork.append(pEdge);
147 }
148 }
149
150 // iTime = timer.elapsed();
151 // qWarning() << "Compute" << iTime;
152 // timer.restart();
153
154 return finalNetwork;
155}
156
157//=============================================================================================================
158
160 MatrixXd& matDist,
161 QMutex& mutex,
162 int iNfft,
163 const QPair<MatrixXd, VectorXd>& tapers)
164{
165 // QElapsedTimer timer;
166 // qint64 iTime = 0;
167 // timer.start();
168
169 // Calculate tapered spectra if not available already
170 RowVectorXd vecInputFFT, rowData;
171 RowVectorXcd vecResultFreq;
172
173 FFT<double> fft;
174 fft.SetFlag(fft.HalfSpectrum);
175
176 int i, j;
177 int iNRows = inputData.matData.rows();
178
179 // Calculate tapered spectra if not available already
180 // This code was copied and changed modified Utils/Spectra since we do not want to call the function due to time loss.
181 if (inputData.vecTapSpectra.isEmpty()) {
182 int iNFreqs = int(floor(iNfft / 2.0)) + 1;
183 MatrixXcd matTapSpectrum(tapers.first.rows(), iNFreqs);
184
185 for (i = 0; i < iNRows; ++i) {
186 // Substract mean
187 rowData.array() = inputData.matData.row(i).array() - inputData.matData.row(i).mean();
188
189 // Calculate tapered spectra
190 for (j = 0; j < tapers.first.rows(); j++) {
191 // Zero padd if necessary. The zero padding in Eigen's FFT is only working for column vectors.
192 if (rowData.cols() < iNfft) {
193 vecInputFFT.setZero(iNfft);
194 vecInputFFT.block(0, 0, 1, rowData.cols()) = rowData.cwiseProduct(tapers.first.row(j));
195 ;
196 } else {
197 vecInputFFT = rowData.cwiseProduct(tapers.first.row(j));
198 }
199
200 // FFT for freq domain returning the half spectrum and multiply taper weights
201 fft.fwd(vecResultFreq, vecInputFFT, iNfft);
202 matTapSpectrum.row(j) = vecResultFreq * tapers.second(j);
203 }
204
205 inputData.vecTapSpectra.append(matTapSpectrum);
206 }
207 }
208
209 // iTime = timer.elapsed();
210 // qDebug() << QThread::currentThreadId() << "CrossCorrelation::compute timer - Tapered spectra:" << iTime;
211 // timer.restart();
212
213 // Perform multiplication and transform back to time domain to find max XCOR coefficient
214 // Note that the result in time domain is mirrored around the center of the data (compared to Matlab)
215 MatrixXd matDistTrial = MatrixXd::Zero(iNRows, iNRows);
216 RowVectorXcd vecResultXCor;
217 int idx = 0;
218 double denom = tapers.second.sum();
219
220 for (i = 0; i < inputData.vecTapSpectra.size(); ++i) {
221 vecResultFreq = inputData.vecTapSpectra.at(i).colwise().sum() / denom;
222
223 for (j = i; j < inputData.vecTapSpectra.size(); ++j) {
224 vecResultXCor = vecResultFreq.cwiseProduct(inputData.vecTapSpectra.at(j).colwise().sum() / denom);
225
226 fft.inv(vecInputFFT, vecResultXCor, iNfft);
227
228 vecInputFFT.maxCoeff(&idx);
229
230 matDistTrial(i, j) = vecInputFFT(idx);
231 }
232 }
233
234 // iTime = timer.elapsed();
235 // qDebug() << QThread::currentThreadId() << "CrossCorrelation::compute timer - Multiplication and inv FFT:" << iTime;
236 // timer.restart();
237
238 // Sum up weights
239 mutex.lock();
240
241 if (matDist.rows() != matDistTrial.rows() || matDist.cols() != matDistTrial.cols()) {
242 matDist.resize(matDistTrial.rows(), matDistTrial.cols());
243 matDist.setZero();
244 }
245
246 matDist += matDistTrial;
247
248 mutex.unlock();
249
250 // iTime = timer.elapsed();
251 // qDebug() << QThread::currentThreadId() << "CrossCorrelation::compute timer - Summing up matDist:" << iTime;
252 // timer.restart();
253
255 inputData.vecTapSpectra.clear();
256 }
257}
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...
Time-lagged cross-correlation between every channel pair, computed via the inverse FFT of the cross-s...
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.
static Network calculate(ConnectivitySettings &connectivitySettings)
static void compute(ConnectivitySettings::IntermediateTrialData &inputData, Eigen::MatrixXd &matDist, QMutex &mutex, 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 append(QSharedPointer< NetworkEdge > newEdge)
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