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 } else {
196 vecInputFFT = rowData.cwiseProduct(tapers.first.row(j));
197 }
198
199 // FFT for freq domain returning the half spectrum and multiply taper weights
200 fft.fwd(vecResultFreq, vecInputFFT, iNfft);
201 matTapSpectrum.row(j) = vecResultFreq * tapers.second(j);
202 }
203
204 inputData.vecTapSpectra.append(matTapSpectrum);
205 }
206 }
207
208// iTime = timer.elapsed();
209// qDebug() << QThread::currentThreadId() << "CrossCorrelation::compute timer - Tapered spectra:" << iTime;
210// timer.restart();
211
212 // Perform multiplication and transform back to time domain to find max XCOR coefficient
213 // Note that the result in time domain is mirrored around the center of the data (compared to Matlab)
214 MatrixXd matDistTrial = MatrixXd::Zero(iNRows, iNRows);
215 RowVectorXcd vecResultXCor;
216 int idx = 0;
217 double denom = tapers.second.sum();
218
219 for(i = 0; i < inputData.vecTapSpectra.size(); ++i) {
220 vecResultFreq = inputData.vecTapSpectra.at(i).colwise().sum() / denom;
221
222 for(j = i; j < inputData.vecTapSpectra.size(); ++j) {
223 vecResultXCor = vecResultFreq.cwiseProduct(inputData.vecTapSpectra.at(j).colwise().sum() / denom);
224
225 fft.inv(vecInputFFT, vecResultXCor, iNfft);
226
227 vecInputFFT.maxCoeff(&idx);
228
229 matDistTrial(i,j) = vecInputFFT(idx);
230 }
231 }
232
233// iTime = timer.elapsed();
234// qDebug() << QThread::currentThreadId() << "CrossCorrelation::compute timer - Multiplication and inv FFT:" << iTime;
235// timer.restart();
236
237 // Sum up weights
238 mutex.lock();
239
240 if(matDist.rows() != matDistTrial.rows() || matDist.cols() != matDistTrial.cols()) {
241 matDist.resize(matDistTrial.rows(), matDistTrial.cols());
242 matDist.setZero();
243 }
244
245 matDist += matDistTrial;
246
247 mutex.unlock();
248
249// iTime = timer.elapsed();
250// qDebug() << QThread::currentThreadId() << "CrossCorrelation::compute timer - Summing up matDist:" << iTime;
251// timer.restart();
252
254 inputData.vecTapSpectra.clear();
255 }
256}
Time-lagged cross-correlation between every channel pair, computed via the inverse FFT of the cross-s...
Weighted edge between two NetworkNode instances; stores the full per-frequency weight matrix and the ...
Node of a connectivity Network; carries a 3D position and the lists of incident (in / out,...
Graph container that stores the result of one functional-connectivity metric as nodes (sources/sensor...
Multi-taper spectral estimation: tapered FFT, power and cross-spectral density, DPSS weighting.
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:98
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:82
Graph node carrying a 3D position and its incident in/out, full/thresholded edge lists.
Definition networknode.h:80
QSharedPointer< NetworkNode > SPtr
Definition networknode.h:83
static QPair< Eigen::MatrixXd, Eigen::VectorXd > generateTapers(int iSignalLength, const QString &sWindowType="hanning")
Definition spectral.cpp:270