65 const double sigma_t = dNCycles / (2.0 * MORLET_PI * dFreq);
68 const double step = 1.0 / dSFreq;
69 halfLen =
static_cast<int>(std::ceil(5.0 * sigma_t / step)) - 1;
71 const int nWav = 2 * halfLen + 1;
72 VectorXcd wavelet(nWav);
73 const double realOffset = bZeroMean ? std::exp(-2.0 * std::pow(MORLET_PI * dFreq * sigma_t, 2)) : 0.0;
75 for (
int i = 0; i < nWav; ++i) {
76 const double t = (i - halfLen) * step;
77 const double gauss = std::exp(-t * t / (2.0 * sigma_t * sigma_t));
78 const double phase = 2.0 * MORLET_PI * dFreq * t;
79 wavelet[i] = gauss * std::complex<double>(std::cos(phase) - realOffset, std::sin(phase));
82 wavelet /= std::sqrt(0.5) * wavelet.norm();
90 const RowVectorXd& vecFreqs,
93 const int nTimes =
static_cast<int>(vecData.cols());
94 const int nFreqs =
static_cast<int>(vecFreqs.cols());
97 result.
matPower.resize(nFreqs, nTimes);
102 Eigen::FFT<double> fft;
104 for (
int fi = 0; fi < nFreqs; ++fi) {
106 const VectorXcd wavelet =
buildWavelet(vecFreqs[fi], dSFreq, dNCycles, halfLen,
true);
108 const int nWav =
static_cast<int>(wavelet.size());
109 const int nConv = nextPow2(nTimes + nWav - 1);
112 VectorXd sigPad = VectorXd::Zero(nConv);
113 sigPad.head(nTimes) = vecData.transpose();
115 fft.fwd(sigSpec, sigPad);
118 VectorXd wavReal = VectorXd::Zero(nConv);
119 VectorXd wavImag = VectorXd::Zero(nConv);
120 for (
int k = 0; k < nWav; ++k) {
121 wavReal[k] = wavelet[k].real();
122 wavImag[k] = wavelet[k].imag();
124 VectorXcd wavSpecR, wavSpecI;
125 fft.fwd(wavSpecR, wavReal);
126 fft.fwd(wavSpecI, wavImag);
128 VectorXcd wavSpec = wavSpecR + std::complex<double>(0.0, 1.0) * wavSpecI;
131 VectorXcd product = sigSpec.array() * wavSpec.array();
133 fft.inv(conv, product);
136 for (
int t = 0; t < nTimes; ++t)
137 result.
matPower(fi, t) = std::norm(conv[t + halfLen]);
147 const RowVectorXd& vecFreqs,
149 const RowVectorXi& vecPicks)
151 std::vector<int> picks;
152 if (vecPicks.size() > 0) {
153 picks.reserve(
static_cast<std::size_t
>(vecPicks.size()));
154 for (
int i = 0; i < vecPicks.size(); ++i)
155 picks.push_back(vecPicks[i]);
157 picks.reserve(
static_cast<std::size_t
>(matData.rows()));
158 for (
int i = 0; i < static_cast<int>(matData.rows()); ++i)
162 QVector<MorletTfrResult> results;
163 results.reserve(
static_cast<int>(picks.size()));
165 results.append(
compute(matData.row(ch), dSFreq, vecFreqs, dNCycles));
static QVector< MorletTfrResult > computeMultiChannel(const Eigen::MatrixXd &matData, double dSFreq, const Eigen::RowVectorXd &vecFreqs, double dNCycles=7.0, const Eigen::RowVectorXi &vecPicks=Eigen::RowVectorXi())