MNE-CPP  0.1.9
A Framework for Electrophysiology
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 
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("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 
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::Network::append
void append(QSharedPointer< NetworkEdge > newEdge)
CONNECTIVITYLIB::Network::getNodeAt
QSharedPointer< NetworkNode > getNodeAt(int i)
Definition: network.cpp:163
phaselagindex.h
PhaseLagIndex class declaration.
CONNECTIVITYLIB::PhaseLagIndex::compute
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)
Definition: phaselagindex.cpp:187
CONNECTIVITYLIB::Network::setSamplingFrequency
void setSamplingFrequency(float fSFreq)
Definition: network.cpp:492
CONNECTIVITYLIB::Network::setUsedFreqBins
void setUsedFreqBins(int iNumberFreqBins)
Definition: network.cpp:506
CONNECTIVITYLIB::PhaseLagIndex::calculate
static Network calculate(ConnectivitySettings &connectivitySettings)
Definition: phaselagindex.cpp:85
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::PhaseLagIndex::PhaseLagIndex
PhaseLagIndex()
Definition: phaselagindex.cpp:79
CONNECTIVITYLIB::ConnectivitySettings
This class is a container for connectivity settings.
Definition: connectivitysettings.h:91
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
CONNECTIVITYLIB::PhaseLagIndex::computePLI
static void computePLI(ConnectivitySettings &connectivitySettings, Network &finalNetwork)
Definition: phaselagindex.cpp:309