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