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))
106 whitener = invSqrtEig.asDiagonal() * noiseCov.
eigvec;
108 whitener = MatrixXd::Identity(nChannels, nChannels);
111 MatrixXd projMat = MatrixXd::Identity(nChannels, nChannels);
114 MatrixXd Gw = whitener * G;
117 MatrixX3d nn = forward.
source_nn.cast<
double>();
118 if (nOrient == 3 && nn.rows() == 3 * nSources) {
120 MatrixX3d perSource(nSources, 3);
121 for (
int s = 0; s < nSources; ++s)
122 perSource.row(s) = nn.row(3 * s + 2);
129 for (
int fi = 0; fi < nFreqs; ++fi) {
130 MatrixXd Cm = csdMatrices[fi];
132 if (Cm.rows() != nChannels || Cm.cols() != nChannels) {
133 qWarning(
"InvDICS::makeDICS - CSD[%d] dimension mismatch!", fi);
145 MatrixXd CmW = whitener * Cm * whitener.transpose();
146 CmW = (CmW + CmW.transpose()) * 0.5;
153 Gw, CmW, reg, nOrient,
154 weightNorm, pickOri, reduceRank, invMethod,
158 qWarning(
"InvDICS::makeDICS - Filter computation failed at frequency %d (%.1f Hz)!",
159 fi, frequencies(fi));
175 result.
proj = projMat;
184 result.
rank =
static_cast<int>(nChannels);
190 verts.resize(forward.
src[0].vertno.
size() + forward.
src[1].vertno.
size());
191 verts << forward.
src[0].vertno, forward.
src[1].vertno;
196 }
else if (forward.
src.
size() == 1) {
197 verts = forward.
src[0].vertno;
201 qInfo(
"InvDICS::makeDICS - Done. %d frequency filters computed.", nFreqs);
209 const VectorXd& frequencies,
212 if (!filters.
isValid() || filters.
kind !=
"DICS") {
213 qWarning(
"InvDICS::applyDICSCsd - Invalid or non-DICS filters!");
217 const int nFreqs =
static_cast<int>(csdMatrices.size());
218 const int nFilterFreqs = filters.
nFreqs();
220 if (nFreqs != nFilterFreqs) {
221 qWarning(
"InvDICS::applyDICSCsd - CSD count (%d) does not match filter count (%d)!",
222 nFreqs, nFilterFreqs);
226 const int nOrient = filters.
nOrient();
227 const int nSources = filters.
nSources();
231 MatrixXd powerMat(nSources, nFreqs);
233 for (
int fi = 0; fi < nFreqs; ++fi) {
234 MatrixXd Cm = csdMatrices[fi];
242 powerMat.col(fi) = power;
246 float fmin = (frequencies.size() > 0) ?
static_cast<float>(frequencies(0)) : 0.0f;
247 float fstep = (frequencies.size() > 1)
248 ?
static_cast<float>(frequencies(1) - frequencies(0))
268 if (!filters.
isValid() || filters.
kind !=
"DICS") {
269 qWarning(
"InvDICS::applyDICS - Invalid or non-DICS filters!");
272 if (freqIdx < 0 || freqIdx >= filters.
nFreqs()) {
273 qWarning(
"InvDICS::applyDICS - freqIdx %d out of range (0..%d)!",
274 freqIdx, filters.
nFreqs() - 1);
279 MatrixXd processed = data;
280 if (filters.
proj.size() > 0 && filters.
proj.rows() == data.rows()) {
281 processed = filters.
proj * processed;
283 if (filters.
whitener.size() > 0 && filters.
whitener.rows() == processed.rows()) {
284 processed = filters.
whitener * processed;
287 MatrixXd sol = filters.
weights[freqIdx] * processed;
290 const int nOrient = filters.
nOrient();
292 const int nSources =
static_cast<int>(sol.rows()) / 3;
293 const int nTimes =
static_cast<int>(sol.cols());
294 MatrixXd combined(nSources, nTimes);
295 for (
int s = 0; s < nSources; ++s) {
296 combined.row(s) = sol.middleRows(s * 3, 3).colwise().norm();
318 QList<InvSourceEstimate> results;
320 if (epochs.isEmpty()) {
321 qWarning(
"InvDICS::applyDICSEpochs - No epochs provided.");
324 if (!filters.
isValid() || filters.
kind !=
"DICS") {
325 qWarning(
"InvDICS::applyDICSEpochs - Invalid or non-DICS filters!");
329 for (
int i = 0; i < epochs.size(); ++i) {
332 qWarning(
"InvDICS::applyDICSEpochs - Epoch %d produced empty source estimate.", i);
#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...
Forward solution (gain matrix mapping source dipoles to sensor measurements).
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