57static constexpr double SSS_PI =
M_PI;
71MatrixXd regPinv(
const MatrixXd& A,
double reg = 1e-5)
73 JacobiSVD<MatrixXd>
svd(A, ComputeThinU | ComputeThinV);
74 const VectorXd& sv =
svd.singularValues();
75 double threshold = reg * sv(0);
77 for (
int i = 0; i < invSv.size(); ++i) {
78 invSv(i) = (sv(i) > threshold) ? 1.0 / sv(i) : 0.0;
80 return svd.matrixV() * invSv.asDiagonal() *
svd.matrixU().transpose();
89void SSS::computeNormALP(
int lmax,
double cosTheta,
double sinTheta,
90 MatrixXd& P, MatrixXd& dP)
93 if (sinTheta < 1e-12) {
97 const int sz = lmax + 2;
112 MatrixXd Praw(sz, sz);
116 Praw(1, 0) = cosTheta;
117 Praw(1, 1) = -sinTheta;
119 for (
int l = 2; l <= lmax + 1; ++l) {
120 Praw(l, l) = -(2 * l - 1) * sinTheta * Praw(l - 1, l - 1);
121 Praw(l, l - 1) = (2 * l - 1) * cosTheta * Praw(l - 1, l - 1);
122 for (
int m = 0; m <= l - 2; ++m) {
123 Praw(l, m) = ((2 * l - 1) * cosTheta * Praw(l - 1, m) - (l - 1 + m) * Praw(l - 2, m)) /
static_cast<double>(l - m);
128 for (
int l = 1; l <= lmax; ++l) {
129 for (
int m = 0; m <= l; ++m) {
133 for (
int k = l - m + 1; k <= l + m; ++k) {
134 fac /=
static_cast<double>(k);
136 double norm = (m == 0)
137 ? std::sqrt((2.0 * l + 1.0) / (4.0 * SSS_PI) * fac)
138 : std::sqrt(2.0 * (2.0 * l + 1.0) / (4.0 * SSS_PI) * fac);
140 P(l, m) = norm * Praw(l, m);
145 double sinThetaDeriv =
static_cast<double>(l) * cosTheta * Praw(l, m);
147 sinThetaDeriv -=
static_cast<double>(l + m) * Praw(l - 1, m);
149 dP(l, m) = norm * sinThetaDeriv / sinTheta;
156Vector3d SSS::basisGradCart(
int l,
int m,
bool bInternal,
157 const Vector3d& rPos,
158 const MatrixXd& P,
const MatrixXd& dP,
159 double cosTheta,
double sinTheta,
160 double cosPhi,
double sinPhi)
163 double r = rPos.norm();
165 return Vector3d::Zero();
168 const int absM = std::abs(m);
181 double Plm = P(l, absM);
182 double dPlm = dP(l, absM);
184 double angFactor, dAngFactor_phi;
187 dAngFactor_phi = 0.0;
189 double cosmPhi = std::cos(
static_cast<double>(m) * std::atan2(sinPhi, cosPhi));
190 double sinmPhi = std::sin(
static_cast<double>(m) * std::atan2(sinPhi, cosPhi));
192 dAngFactor_phi = -
static_cast<double>(m) * sinmPhi;
195 double cosmPhi = std::cos(
static_cast<double>(absM) * std::atan2(sinPhi, cosPhi));
196 double sinmPhi = std::sin(
static_cast<double>(absM) * std::atan2(sinPhi, cosPhi));
198 dAngFactor_phi =
static_cast<double>(absM) * cosmPhi;
202 double Ylm = Plm * angFactor;
205 double dYdTheta = dPlm * angFactor;
208 double dYdPhi = Plm * dAngFactor_phi;
216 double radPow, Gr_coeff, Gtu_coeff;
218 radPow = std::pow(r, -(l + 2));
219 Gr_coeff = -
static_cast<double>(l + 1) * radPow;
222 radPow = std::pow(r, l - 1);
223 Gr_coeff =
static_cast<double>(l) * radPow;
227 double Gr = Gr_coeff * Ylm;
228 double Gtheta = Gtu_coeff * dYdTheta;
229 double GphiTimesSin = Gtu_coeff * dYdPhi;
240 double Gphi = (sinTheta > 1e-12) ? GphiTimesSin / sinTheta : 0.0;
242 double gx = Gr * sinTheta * cosPhi + Gtheta * cosTheta * cosPhi - Gphi * sinPhi;
243 double gy = Gr * sinTheta * sinPhi + Gtheta * cosTheta * sinPhi + Gphi * cosPhi;
244 double gz = Gr * cosTheta - Gtheta * sinTheta;
246 return Vector3d(gx, gy, gz);
260 for (
int i = 0; i < fiffInfo.
nchan; ++i) {
261 int kind = fiffInfo.
chs[i].kind;
269 qWarning() <<
"SSS::computeBasis: no MEG channels found in FiffInfo.";
281 for (
int si = 0; si < nMeg; ++si) {
285 Vector3d rPos(
static_cast<double>(ch.
chpos.
r0(0)) - params.
origin(0),
290 Vector3d normal(
static_cast<double>(ch.
chpos.
ez(0)),
291 static_cast<double>(ch.
chpos.
ez(1)),
292 static_cast<double>(ch.
chpos.
ez(2)));
295 double nNorm = normal.norm();
302 double r = rPos.norm();
306 double cosTheta = rPos(2) / r;
307 double sinTheta = std::sqrt(rPos(0) * rPos(0) + rPos(1) * rPos(1)) / r;
308 if (sinTheta < 1e-12)
310 double phi = std::atan2(rPos(1), rPos(0));
311 double cosPhi = std::cos(phi);
312 double sinPhi = std::sin(phi);
316 computeNormALP(lmax, cosTheta, sinTheta, P, dP);
320 for (
int l = 1; l <= params.
iOrderIn; ++l) {
321 for (
int m = -l; m <= l; ++m) {
322 Vector3d grad = basisGradCart(l, m,
true,
324 cosTheta, sinTheta, cosPhi, sinPhi);
325 basis.
matSin(si, colIn) = normal.dot(grad);
332 for (
int l = 1; l <= params.
iOrderOut; ++l) {
333 for (
int m = -l; m <= l; ++m) {
334 Vector3d grad = basisGradCart(l, m,
false,
336 cosTheta, sinTheta, cosPhi, sinPhi);
337 basis.
matSout(si, colOut) = normal.dot(grad);
353 const VectorXd colNorms =
S.colwise().norm().cwiseMax(1e-300).transpose();
354 basis.
matPinvAll = colNorms.cwiseInverse().asDiagonal() * regPinv(
S * colNorms.cwiseInverse().asDiagonal(), params.
dRegIn);
369 MatrixXd matOut = matData;
372 MatrixXd megData(nMeg, matData.cols());
373 for (
int i = 0; i < nMeg; ++i) {
378 MatrixXd megSss = basis.
matProjIn * megData;
381 for (
int i = 0; i < nMeg; ++i) {
400 const int nSamp =
static_cast<int>(matData.cols());
401 const int bufLen = std::min(iBufferLength, nSamp);
403 MatrixXd matOut = matData;
406 MatrixXd megData(nMeg, nSamp);
407 for (
int i = 0; i < nMeg; ++i) {
419 while (offset < nSamp) {
420 int winLen = std::min(bufLen, nSamp - offset);
423 MatrixXd cInWin = cIn.middleCols(offset, winLen);
424 MatrixXd cOutWin = cOut.middleCols(offset, winLen);
430 JacobiSVD<MatrixXd>
svd(cOutWin, ComputeThinU | ComputeThinV);
431 const VectorXd& sv =
svd.singularValues();
432 const MatrixXd& V =
svd.matrixV();
435 double svMax = (sv.size() > 0) ? sv(0) : 0.0;
446 for (
int k = 0; k < sv.size(); ++k) {
447 if (sv(k) / svMax > dCorrLimit) {
455 Vr = V.leftCols(nRemove);
457 MatrixXd cInWinClean = cInWin - cInWin * (Vr * Vr.transpose());
458 cIn.middleCols(offset, winLen) = cInWinClean;
465 MatrixXd megTsss = basis.
matSin * cIn;
468 for (
int i = 0; i < nMeg; ++i) {
FIFF channel descriptor record (FIFF_CH_INFO): per-channel logical/scanner numbers,...
Symbolic FIFF tag, block, value, unit and channel-type constants shared across FIFFLIB.
Eigen::JacobiSVD< Eigen::Matrix3f > svd(S, Eigen::ComputeFullU|Eigen::ComputeFullV)
Signal-Space Separation (SSS) and temporal SSS (tSSS) for MEG data.
FIFF file I/O, in-memory data structures and high-level readers/writers.
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
static Basis computeBasis(const FIFFLIB::FiffInfo &fiffInfo, const Params ¶ms=Params())
static Eigen::MatrixXd apply(const Eigen::MatrixXd &matData, const Basis &basis)
static Eigen::MatrixXd applyTemporal(const Eigen::MatrixXd &matData, const Basis &basis, int iBufferLength=10000, double dCorrLimit=0.98)
Precomputed SSS basis and projectors for a given sensor array.
Eigen::MatrixXd matPinvAll
QVector< int > megChannelIdx
Eigen::MatrixXd matProjIn
Per-channel FIFF descriptor: identifiers, kind, calibration, coil type, channel-frame coil position a...
Full FIFF measurement info: per-channel descriptors, sampling and filter setup, projectors,...