55 const std::vector<MatrixXd> &csdMatrices,
56 const VectorXd &frequencies,
68 const int nFreqs =
static_cast<int>(csdMatrices.size());
70 qWarning(
"InvDICS::makeDICS - No CSD matrices provided!");
73 if(frequencies.size() != nFreqs) {
74 qWarning(
"InvDICS::makeDICS - Frequency vector size mismatch with CSD count!");
81 if(!forward.
sol || forward.
sol->data.size() == 0) {
82 qWarning(
"InvDICS::makeDICS - Forward solution has no gain matrix!");
86 MatrixXd G = forward.
sol->data;
87 const int nChannels =
static_cast<int>(G.rows());
89 const int nSources =
static_cast<int>(G.cols()) / nOrient;
91 qInfo(
"InvDICS::makeDICS - Leadfield: %d channels x %d sources (n_orient=%d), %d frequencies",
92 nChannels, nSources, nOrient, nFreqs);
98 if(noiseCov.
data.size() > 0 && noiseCov.
eig.size() > 0 && noiseCov.
eigvec.size() > 0) {
99 VectorXd invSqrtEig(noiseCov.
eig.size());
100 for(
int i = 0; i < noiseCov.
eig.size(); ++i) {
101 invSqrtEig(i) = (noiseCov.
eig(i) > 1e-30)
102 ? 1.0 / std::sqrt(noiseCov.
eig(i))
105 whitener = invSqrtEig.asDiagonal() * noiseCov.
eigvec.transpose();
107 whitener = MatrixXd::Identity(nChannels, nChannels);
110 MatrixXd projMat = MatrixXd::Identity(nChannels, nChannels);
113 MatrixXd Gw = whitener * G;
116 MatrixX3d nn = forward.
source_nn.cast<
double>();
121 for(
int fi = 0; fi < nFreqs; ++fi) {
122 MatrixXd Cm = csdMatrices[fi];
124 if(Cm.rows() != nChannels || Cm.cols() != nChannels) {
125 qWarning(
"InvDICS::makeDICS - CSD[%d] dimension mismatch!", fi);
137 MatrixXd CmW = whitener * Cm * whitener.transpose();
138 CmW = (CmW + CmW.transpose()) * 0.5;
145 Gw, CmW, reg, nOrient,
146 weightNorm, pickOri, reduceRank, invMethod,
150 qWarning(
"InvDICS::makeDICS - Filter computation failed at frequency %d (%.1f Hz)!",
151 fi, frequencies(fi));
167 result.
proj = projMat;
177 result.
rank =
static_cast<int>(nChannels);
183 verts.resize(forward.
src[0].vertno.
size() + forward.
src[1].vertno.
size());
184 verts << forward.
src[0].vertno, forward.
src[1].vertno;
185 }
else if(forward.
src.
size() == 1) {
186 verts = forward.
src[0].vertno;
190 qInfo(
"InvDICS::makeDICS - Done. %d frequency filters computed.", nFreqs);
198 const VectorXd &frequencies,
202 qWarning(
"InvDICS::applyDICSCsd - Invalid or non-DICS filters!");
206 const int nFreqs =
static_cast<int>(csdMatrices.size());
207 const int nFilterFreqs = filters.
nFreqs();
209 if(nFreqs != nFilterFreqs) {
210 qWarning(
"InvDICS::applyDICSCsd - CSD count (%d) does not match filter count (%d)!",
211 nFreqs, nFilterFreqs);
215 const int nOrient = filters.
nOrient();
216 const int nSources = filters.
nSources();
217 const int nChannels = filters.
nChannels();
220 MatrixXd powerMat(nSources, nFreqs);
222 for(
int fi = 0; fi < nFreqs; ++fi) {
223 MatrixXd Cm = csdMatrices[fi];
231 powerMat.col(fi) = power;
235 float fmin = (frequencies.size() > 0) ?
static_cast<float>(frequencies(0)) : 0.0f;
236 float fstep = (frequencies.size() > 1)
237 ?
static_cast<float>(frequencies(1) - frequencies(0))
257 qWarning(
"InvDICS::applyDICS - Invalid or non-DICS filters!");
260 if(freqIdx < 0 || freqIdx >= filters.
nFreqs()) {
261 qWarning(
"InvDICS::applyDICS - freqIdx %d out of range (0..%d)!",
262 freqIdx, filters.
nFreqs() - 1);
267 MatrixXd processed = data;
268 if(filters.
proj.size() > 0 && filters.
proj.rows() == data.rows()) {
269 processed = filters.
proj * processed;
271 if(filters.
whitener.size() > 0 && filters.
whitener.rows() == processed.rows()) {
272 processed = filters.
whitener * processed;
275 MatrixXd sol = filters.
weights[freqIdx] * processed;
278 const int nOrient = filters.
nOrient();
280 const int nSources =
static_cast<int>(sol.rows()) / 3;
281 const int nTimes =
static_cast<int>(sol.cols());
282 MatrixXd combined(nSources, nTimes);
283 for(
int s = 0; s < nSources; ++s) {
284 combined.row(s) = sol.middleRows(s * 3, 3).colwise().norm();
305 QList<InvSourceEstimate> results;
307 if (epochs.isEmpty()) {
308 qWarning(
"InvDICS::applyDICSEpochs - No epochs provided.");
311 if (!filters.
isValid() || filters.
kind !=
"DICS") {
312 qWarning(
"InvDICS::applyDICSEpochs - Invalid or non-DICS filters!");
316 for (
int i = 0; i < epochs.size(); ++i) {
319 qWarning(
"InvDICS::applyDICSEpochs - Epoch %d produced empty source estimate.", i);
Forward solution (gain matrix mapping source dipoles to sensor measurements).
#define FIFFV_MNE_FREE_ORI
Full FIFF measurement metadata: everything from FIFFB_MEAS / FIFFB_MEAS_INFO needed to interpret a re...
Noise / data covariance matrix as stored under FIFFB_MNE_COV, with channel names, kind,...
Shared math kernels (filter derivation, source power, regularised pseudo-inverse) used by both the LC...
Dynamic Imaging of Coherent Sources (DICS) beamformer — frequency-domain source-power and source-time...
Core MNE data structures (source spaces, source estimates, hemispheres).
FIFF file I/O, in-memory data structures and high-level readers/writers.
Inverse source estimation (MNE, dSPM, sLORETA, dipole fitting).
FIFF noise / data covariance: matrix, channel names, kind, applied projectors, bads,...
Full FIFF measurement info: per-channel descriptors, sampling and filter setup, projectors,...
Computed beamformer spatial filter container.
BeamformerPickOri pickOri
Eigen::VectorXd frequencies
BeamformerWeightNorm weightNorm
Eigen::MatrixX3f sourceNn
BeamformerInversion inversion
Eigen::MatrixX3d maxPowerOri
std::vector< Eigen::MatrixXd > weights
static Eigen::VectorXd computePower(const Eigen::MatrixXd &Cm, const Eigen::MatrixXd &W, int nOrient)
static bool computeBeamformer(const Eigen::MatrixXd &G, const Eigen::MatrixXd &Cm, double reg, int nOrient, BeamformerWeightNorm weightNorm, BeamformerPickOri pickOri, bool reduceRank, BeamformerInversion invMethod, const Eigen::MatrixX3d &nn, Eigen::MatrixXd &W, Eigen::MatrixX3d &maxPowerOri)
static InvBeamformer makeDICS(const FIFFLIB::FiffInfo &info, const MNELIB::MNEForwardSolution &forward, const std::vector< Eigen::MatrixXd > &csdMatrices, const Eigen::VectorXd &frequencies, double reg=0.05, bool realFilter=true, const FIFFLIB::FiffCov &noiseCov=FIFFLIB::FiffCov(), BeamformerPickOri pickOri=BeamformerPickOri::None, BeamformerWeightNorm weightNorm=BeamformerWeightNorm::UnitNoiseGain, bool reduceRank=false, BeamformerInversion invMethod=BeamformerInversion::Matrix)
static InvSourceEstimate applyDICS(const Eigen::MatrixXd &data, float tmin, float tstep, const InvBeamformer &filters, int freqIdx=0)
static QList< InvSourceEstimate > applyDICSEpochs(const QList< Eigen::MatrixXd > &epochs, float tmin, float tstep, const InvBeamformer &filters, int freqIdx=0)
static InvSourceEstimate applyDICSCsd(const std::vector< Eigen::MatrixXd > &csdMatrices, const Eigen::VectorXd &frequencies, const InvBeamformer &filters)
Source-space inverse-solution container with dense grid plus optional focal-dipole,...
InvSourceSpaceType sourceSpaceType
InvOrientationType orientationType
In-memory representation of an -fwd.fif forward solution.
MNELIB::MNESourceSpaces src
FIFFLIB::fiff_int_t source_ori
Eigen::MatrixX3f source_nn
FIFFLIB::FiffNamedMatrix::SDPtr sol