MNE-CPP 0.1.9
A Framework for Electrophysiology
Loading...
Searching...
No Matches
phaselagindex.cpp
Go to the documentation of this file.
1//=============================================================================================================
39//=============================================================================================================
40// INCLUDES
41//=============================================================================================================
42
43#include "phaselagindex.h"
44#include "../network/networknode.h"
45#include "../network/networkedge.h"
46#include "../network/network.h"
47
48#include <utils/spectral.h>
49
50//=============================================================================================================
51// QT INCLUDES
52//=============================================================================================================
53
54#include <QDebug>
55#include <QtConcurrent>
56
57//=============================================================================================================
58// EIGEN INCLUDES
59//=============================================================================================================
60
61#include <unsupported/Eigen/FFT>
62
63//=============================================================================================================
64// USED NAMESPACES
65//=============================================================================================================
66
67using namespace CONNECTIVITYLIB;
68using namespace Eigen;
69using namespace UTILSLIB;
70
71//=============================================================================================================
72// DEFINE GLOBAL METHODS
73//=============================================================================================================
74
75//=============================================================================================================
76// DEFINE MEMBER METHODS
77//=============================================================================================================
78
82
83//*******************************************************************************************************
84
86{
87// QElapsedTimer timer;
88// qint64 iTime = 0;
89// timer.start();
90
91 Network finalNetwork("PLI");
92
93 if(connectivitySettings.isEmpty()) {
94 qDebug() << "PhaseLagIndex::calculate - Input data is empty";
95 return finalNetwork;
96 }
97
98 if(AbstractMetric::m_bStorageModeIsActive == false) {
99 connectivitySettings.clearIntermediateData();
100 }
101
102 finalNetwork.setSamplingFrequency(connectivitySettings.getSamplingFrequency());
103
104 #ifdef EIGEN_FFTW_DEFAULT
105 fftw_make_planner_thread_safe();
106 #endif
107
108 //Create nodes
109 int iNRows = connectivitySettings.at(0).matData.rows();
110 RowVectorXf rowVert = RowVectorXf::Zero(3);
111
112 for(int i = 0; i < iNRows; ++i) {
113 rowVert = RowVectorXf::Zero(3);
114 if(connectivitySettings.getNodePositions().rows() != 0 && i < connectivitySettings.getNodePositions().rows()) {
115 rowVert(0) = connectivitySettings.getNodePositions().row(i)(0);
116 rowVert(1) = connectivitySettings.getNodePositions().row(i)(1);
117 rowVert(2) = connectivitySettings.getNodePositions().row(i)(2);
118 }
119
120 finalNetwork.append(NetworkNode::SPtr(new NetworkNode(i, rowVert)));
121 }
122
123 // Check that iNfft >= signal length
124 int iSignalLength = connectivitySettings.at(0).matData.cols();
125 int iNfft = connectivitySettings.getFFTSize();
126
127 // Generate tapers
128 QPair<MatrixXd, VectorXd> tapers = Spectral::generateTapers(iSignalLength, connectivitySettings.getWindowType());
129
130 // Initialize
131 int iNFreqs = int(floor(iNfft / 2.0)) + 1;
132
133 // Check if start and bin amount need to be reset to full spectrum
134 if(m_iNumberBinStart == -1 ||
135 m_iNumberBinAmount == -1 ||
136 m_iNumberBinStart > iNFreqs ||
137 m_iNumberBinAmount > iNFreqs ||
138 m_iNumberBinAmount + m_iNumberBinStart > iNFreqs) {
139 qDebug() << "PhaseLagIndex::calculate - Resetting to full spectrum";
140 AbstractMetric::m_iNumberBinStart = 0;
141 AbstractMetric::m_iNumberBinAmount = iNFreqs;
142 }
143
144 // Pass information about the FFT length. Use iNFreqs because we only use the half spectrum
145 finalNetwork.setFFTSize(iNFreqs);
146 finalNetwork.setUsedFreqBins(AbstractMetric::m_iNumberBinAmount);
147
148 QMutex mutex;
149
150 std::function<void(ConnectivitySettings::IntermediateTrialData&)> computeLambda = [&](ConnectivitySettings::IntermediateTrialData& inputData) {
151 compute(inputData,
152 connectivitySettings.getIntermediateSumData().vecPairCsdSum,
153 connectivitySettings.getIntermediateSumData().vecPairCsdImagSignSum,
154 mutex,
155 iNRows,
156 iNFreqs,
157 iNfft,
158 tapers);
159 };
160
161// iTime = timer.elapsed();
162// qWarning() << "Preparation" << iTime;
163// timer.restart();
164
165 // Compute DSWPLV in parallel for all trials
166 QFuture<void> result = QtConcurrent::map(connectivitySettings.getTrialData(),
167 computeLambda);
168 result.waitForFinished();
169
170// iTime = timer.elapsed();
171// qWarning() << "ComputeSpectraPSDCSD" << iTime;
172// timer.restart();
173
174 // Compute PLI
175 computePLI(connectivitySettings,
176 finalNetwork);
177
178// iTime = timer.elapsed();
179// qWarning() << "Compute" << iTime;
180// timer.restart();
181
182 return finalNetwork;
183}
184
185//=============================================================================================================
186
188 QVector<QPair<int,MatrixXcd> >& vecPairCsdSum,
189 QVector<QPair<int,MatrixXd> >& vecPairCsdImagSignSum,
190 QMutex& mutex,
191 int iNRows,
192 int iNFreqs,
193 int iNfft,
194 const QPair<MatrixXd, VectorXd>& tapers)
195{
196 if(inputData.vecPairCsdImagSign.size() == iNRows) {
197 //qDebug() << "PhaseLagIndex::compute - vecPairCsdImagSign was already computed for this trial.";
198 return;
199 }
200
201 int i,j;
202
203 // Calculate tapered spectra if not available already
204 // This code was copied and changed modified Utils/Spectra since we do not want to call the function due to time loss.
205 if(inputData.vecTapSpectra.isEmpty()) {
206 RowVectorXd vecInputFFT, rowData;
207 RowVectorXcd vecTmpFreq;
208
209 MatrixXcd matTapSpectrum(tapers.first.rows(), iNFreqs);
210
211 FFT<double> fft;
212 fft.SetFlag(fft.HalfSpectrum);
213
214 for (i = 0; i < iNRows; ++i) {
215 // Substract mean
216 rowData.array() = inputData.matData.row(i).array() - inputData.matData.row(i).mean();
217
218 // Calculate tapered spectra
219 for(j = 0; j < tapers.first.rows(); j++) {
220 // Zero padd if necessary. The zero padding in Eigen's FFT is only working for column vectors.
221 if (rowData.cols() < iNfft) {
222 vecInputFFT.setZero(iNfft);
223 vecInputFFT.block(0,0,1,rowData.cols()) = rowData.cwiseProduct(tapers.first.row(j));;
224 } else {
225 vecInputFFT = rowData.cwiseProduct(tapers.first.row(j));
226 }
227
228 // FFT for freq domain returning the half spectrum and multiply taper weights
229 fft.fwd(vecTmpFreq, vecInputFFT, iNfft);
230 matTapSpectrum.row(j) = vecTmpFreq * tapers.second(j);
231 }
232
233 inputData.vecTapSpectra.append(matTapSpectrum);
234 }
235 }
236
237 // Compute CSD
238 if(inputData.vecPairCsd.isEmpty()) {
239 MatrixXcd matCsd = MatrixXcd(iNRows, m_iNumberBinAmount);
240
241 double denomCSD = sqrt(tapers.second.cwiseAbs2().sum()) * sqrt(tapers.second.cwiseAbs2().sum()) / 2.0;
242
243 bool bNfftEven = false;
244 if (iNfft % 2 == 0){
245 bNfftEven = true;
246 }
247
248 for (i = 0; i < iNRows; ++i) {
249 for (j = i; j < iNRows; ++j) {
250 // Compute CSD (average over tapers if necessary)
251 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;
252
253 // Divide first and last element by 2 due to half spectrum
254 if(m_iNumberBinStart == 0) {
255 matCsd.row(j)(0) /= 2.0;
256 }
257
258 if(bNfftEven && m_iNumberBinStart + m_iNumberBinAmount >= iNFreqs) {
259 matCsd.row(j).tail(1) /= 2.0;
260 }
261 }
262
263 inputData.vecPairCsd.append(QPair<int,MatrixXcd>(i,matCsd));
264 inputData.vecPairCsdImagSign.append(QPair<int,MatrixXd>(i,matCsd.imag().cwiseSign()));
265 }
266
267 mutex.lock();
268
269 if(vecPairCsdSum.isEmpty()) {
270 vecPairCsdSum = inputData.vecPairCsd;
271 vecPairCsdImagSignSum = inputData.vecPairCsdImagSign;
272 } else {
273 for (int j = 0; j < vecPairCsdSum.size(); ++j) {
274 vecPairCsdSum[j].second += inputData.vecPairCsd.at(j).second;
275 vecPairCsdImagSignSum[j].second += inputData.vecPairCsdImagSign.at(j).second;
276 }
277 }
278
279 mutex.unlock();
280 } else {
281 if(inputData.vecPairCsdImagSign.isEmpty()) {
282 for (i = 0; i < inputData.vecPairCsd.size(); ++i) {
283 inputData.vecPairCsdImagSign.append(QPair<int,MatrixXd>(i,inputData.vecPairCsd.at(i).second.imag().cwiseSign()));
284 }
285
286 mutex.lock();
287
288 if(vecPairCsdImagSignSum.isEmpty()) {
289 vecPairCsdImagSignSum = inputData.vecPairCsdImagSign;
290 } else {
291 for (int j = 0; j < vecPairCsdImagSignSum.size(); ++j) {
292 vecPairCsdImagSignSum[j].second += inputData.vecPairCsdImagSign.at(j).second;
293 }
294 }
295
296 mutex.unlock();
297 }
298 }
299
300 if(!m_bStorageModeIsActive) {
301 inputData.vecPairCsd.clear();
302 inputData.vecTapSpectra.clear();
303 inputData.vecPairCsdImagSign.clear();
304 }
305}
306
307//=============================================================================================================
308
310 Network& finalNetwork)
311{
312 // Compute final PLI and create Network
313 MatrixXd matNom;
314 MatrixXd matWeight;
315 QSharedPointer<NetworkEdge> pEdge;
316 int j;
317
318 for (int i = 0; i < connectivitySettings.getIntermediateSumData().vecPairCsdImagSignSum.size(); ++i) {
319 matNom = connectivitySettings.getIntermediateSumData().vecPairCsdImagSignSum.at(i).second.cwiseAbs() / connectivitySettings.size();
320
321 for(j = i; j < matNom.rows(); ++j) {
322 matWeight = matNom.row(j).transpose();
323
324 pEdge = QSharedPointer<NetworkEdge>(new NetworkEdge(i, j, matWeight));
325
326 finalNetwork.getNodeAt(i)->append(pEdge);
327 finalNetwork.getNodeAt(j)->append(pEdge);
328 finalNetwork.append(pEdge);
329 }
330 }
331}
332
PhaseLagIndex class declaration.
Declaration of Spectral class.
This class is a container for connectivity settings.
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)
static void computePLI(ConnectivitySettings &connectivitySettings, Network &finalNetwork)
This class holds information about a network, can compute a distance table and provide network metric...
Definition network.h:89
void setUsedFreqBins(int iNumberFreqBins)
Definition network.cpp:506
void append(QSharedPointer< NetworkEdge > newEdge)
void setFFTSize(int iFFTSize)
Definition network.cpp:513
void setSamplingFrequency(float fSFreq)
Definition network.cpp:492
QSharedPointer< NetworkNode > getNodeAt(int i)
Definition network.cpp:163
This class holds an object to describe the edge of a network.
Definition networkedge.h:80
This class holds an object to describe the node of a network.
Definition networknode.h:82
QSharedPointer< NetworkNode > SPtr
Definition networknode.h:85
static QPair< Eigen::MatrixXd, Eigen::VectorXd > generateTapers(int iSignalLength, const QString &sWindowType="hanning")
Definition spectral.cpp:292