32#include <QtConcurrent>
38#include <unsupported/Eigen/FFT>
69 if (connectivitySettings.
isEmpty()) {
70 qDebug() <<
"Coherency::calculateReal - Input data is empty";
74#ifdef EIGEN_FFTW_DEFAULT
75 fftw_make_planner_thread_safe();
78 int iSignalLength = connectivitySettings.
at(0).
matData.cols();
85 int iNRows = connectivitySettings.
at(0).
matData.rows();
86 int iNFreqs = int(floor(iNfft / 2.0)) + 1;
106 QFuture<void> result = QtConcurrent::map(connectivitySettings.
getTrialData(),
108 result.waitForFinished();
115 std::function<void(QPair<int, MatrixXcd>&)> computePSDCSDLambda = [&](QPair<int, MatrixXcd>& pairInput) {
116 computePSDCSDAbs(mutex,
123 computePSDCSDLambda);
124 resultCSDPSD.waitForFinished();
140 if (connectivitySettings.
isEmpty()) {
141 qDebug() <<
"Coherency::calculateImag - Input data is empty";
145#ifdef EIGEN_FFTW_DEFAULT
146 fftw_make_planner_thread_safe();
149 int iSignalLength = connectivitySettings.
at(0).
matData.cols();
150 int iNfft = connectivitySettings.
getFFTSize();
156 int iNRows = connectivitySettings.
at(0).
matData.rows();
157 int iNFreqs = int(floor(iNfft / 2.0)) + 1;
177 QFuture<void> result = QtConcurrent::map(connectivitySettings.
getTrialData(),
179 result.waitForFinished();
186 std::function<void(QPair<int, MatrixXcd>&)> computePSDCSDLambda = [&](QPair<int, MatrixXcd>& pairInput) {
187 computePSDCSDImag(mutex,
194 computePSDCSDLambda);
195 resultCSDPSD.waitForFinished();
206 QVector<QPair<int, MatrixXcd>>& vecPairCsdSum,
211 const QPair<MatrixXd, VectorXd>& tapers)
226 bool bNfftEven =
false;
227 if (iNfft % 2 == 0) {
232 fft.SetFlag(fft.HalfSpectrum);
234 double denomPSD = tapers.second.cwiseAbs2().sum() / 2.0;
236 RowVectorXd vecInputFFT, rowData;
237 RowVectorXcd vecTmpFreq;
239 MatrixXcd matTapSpectrum(tapers.first.rows(), iNFreqs);
245 for (i = 0; i < iNRows; ++i) {
247 rowData.array() = inputData.
matData.row(i).array() - inputData.
matData.row(i).mean();
251 for (j = 0; j < tapers.first.rows(); j++) {
253 if (rowData.cols() < iNfft) {
254 vecInputFFT.setZero(iNfft);
255 vecInputFFT.block(0, 0, 1, rowData.cols()) = rowData.cwiseProduct(tapers.first.row(j));
258 vecInputFFT = rowData.cwiseProduct(tapers.first.row(j));
262 fft.fwd(vecTmpFreq, vecInputFFT, iNfft);
263 matTapSpectrum.row(j) = vecTmpFreq * tapers.second(j);
274 inputData.
matPsd.row(i)(0) /= 2.0;
278 inputData.
matPsd.row(i).tail(1) /= 2.0;
284 if (matPsdSum.rows() == 0 || matPsdSum.cols() == 0) {
285 matPsdSum = inputData.
matPsd;
287 matPsdSum += inputData.
matPsd;
303 double denomCSD = sqrt(tapers.second.cwiseAbs2().sum()) * sqrt(tapers.second.cwiseAbs2().sum()) / 2.0;
305 for (i = 0; i < iNRows; ++i) {
306 for (j = i; j < iNRows; ++j) {
312 matCsd.row(j)(0) /= 2.0;
316 matCsd.row(j).tail(1) /= 2.0;
320 inputData.
vecPairCsd.append(QPair<int, MatrixXcd>(i, matCsd));
325 if (vecPairCsdSum.isEmpty()) {
328 for (j = 0; j < vecPairCsdSum.size(); ++j) {
329 vecPairCsdSum[j].second += inputData.
vecPairCsd.at(j).second;
353void Coherency::computePSDCSDAbs(QMutex& mutex,
355 const QPair<int, MatrixXcd>& pairInput,
356 const MatrixXd& matPsdSum)
358 MatrixXd matPSDtmp(matPsdSum.rows(), matPsdSum.cols());
359 RowVectorXd rowPsdSum = matPsdSum.row(pairInput.first);
361 for (
int j = 0; j < matPSDtmp.rows(); ++j) {
362 matPSDtmp.row(j) = rowPsdSum.cwiseProduct(matPsdSum.row(j));
366 MatrixXcd matCohy = pairInput.second.cwiseQuotient(matPSDtmp.cwiseSqrt());
368 QSharedPointer<NetworkEdge> pEdge;
371 int i = pairInput.first;
373 for (j = i; j < matCohy.rows(); ++j) {
374 matWeight = matCohy.row(j).cwiseAbs().transpose();
375 pEdge = QSharedPointer<NetworkEdge>(
new NetworkEdge(i, j, matWeight));
378 finalNetwork.
getNodeAt(i)->append(pEdge);
379 finalNetwork.
getNodeAt(j)->append(pEdge);
380 finalNetwork.
append(pEdge);
387void Coherency::computePSDCSDImag(QMutex& mutex,
389 const QPair<int, MatrixXcd>& pairInput,
390 const MatrixXd& matPsdSum)
392 MatrixXd matPSDtmp(matPsdSum.rows(), matPsdSum.cols());
393 RowVectorXd rowPsdSum = matPsdSum.row(pairInput.first);
395 for (
int j = 0; j < matPSDtmp.rows(); ++j) {
396 matPSDtmp.row(j) = rowPsdSum.cwiseProduct(matPsdSum.row(j));
399 MatrixXcd matCohy = pairInput.second.cwiseQuotient(matPSDtmp.cwiseSqrt());
401 QSharedPointer<NetworkEdge> pEdge;
404 int i = pairInput.first;
406 for (j = i; j < matCohy.rows(); ++j) {
407 matWeight = matCohy.row(j).imag().transpose();
408 pEdge = QSharedPointer<NetworkEdge>(
new NetworkEdge(i, j, matWeight));
411 finalNetwork.
getNodeAt(i)->append(pEdge);
412 finalNetwork.
getNodeAt(j)->append(pEdge);
413 finalNetwork.
append(pEdge);
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...
Complex coherency between every channel pair and its two reductions: magnitude (coherence) and imagin...
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
IntermediateSumData & getIntermediateSumData()
const QString & getWindowType() const
Per-trial intermediate frequency-domain data used during connectivity computation.
QVector< QPair< int, Eigen::MatrixXcd > > vecPairCsd
QVector< Eigen::MatrixXcd > vecTapSpectra
Eigen::MatrixXd matPsdSum
QVector< QPair< int, Eigen::MatrixXcd > > vecPairCsdSum
static int m_iNumberBinAmount
static bool m_bStorageModeIsActive
static int m_iNumberBinStart
static void calculateImag(Network &finalNetwork, ConnectivitySettings &connectivitySettings)
static void calculateAbs(Network &finalNetwork, ConnectivitySettings &connectivitySettings)
Graph container for one connectivity metric; nodes + weighted edges + threshold/visualisation state.
void append(QSharedPointer< NetworkEdge > newEdge)
QSharedPointer< NetworkNode > getNodeAt(int i)
static QPair< Eigen::MatrixXd, Eigen::VectorXd > generateTapers(int iSignalLength, const QString &sWindowType="hanning")