71 if(!forward.
sol || forward.
sol->data.size() == 0) {
72 qWarning(
"InvLCMV::makeLCMV - Forward solution has no gain matrix!");
76 MatrixXd G = forward.
sol->data;
77 const int nChannels =
static_cast<int>(G.rows());
79 const int nSources =
static_cast<int>(G.cols()) / nOrient;
81 qInfo(
"InvLCMV::makeLCMV - Leadfield: %d channels x %d sources (n_orient=%d)",
82 nChannels, nSources, nOrient);
88 if(noiseCov.
data.size() > 0) {
91 if(noiseCov.
eig.size() > 0 && noiseCov.
eigvec.size() > 0) {
92 VectorXd invSqrtEig(noiseCov.
eig.size());
93 for(
int i = 0; i < noiseCov.
eig.size(); ++i) {
94 invSqrtEig(i) = (noiseCov.
eig(i) > 1e-30)
95 ? 1.0 / std::sqrt(noiseCov.
eig(i))
98 whitener = invSqrtEig.asDiagonal() * noiseCov.
eigvec.transpose();
101 whitener = MatrixXd::Identity(nChannels, nChannels);
104 whitener = MatrixXd::Identity(nChannels, nChannels);
110 MatrixXd projMat = MatrixXd::Identity(nChannels, nChannels);
119 MatrixXd Gw = whitener * G;
121 MatrixXd CmData = dataCov.
data;
122 if(CmData.rows() != nChannels || CmData.cols() != nChannels) {
123 qWarning(
"InvLCMV::makeLCMV - Data covariance dimension (%d x %d) "
124 "does not match leadfield channels (%d)!",
125 static_cast<int>(CmData.rows()),
static_cast<int>(CmData.cols()), nChannels);
129 MatrixXd CmW = whitener * CmData * whitener.transpose();
131 CmW = (CmW + CmW.transpose()) * 0.5;
136 MatrixX3d nn = forward.
source_nn.cast<
double>();
145 Gw, CmW, reg, nOrient,
146 weightNorm, pickOri, reduceRank, invMethod,
150 qWarning(
"InvLCMV::makeLCMV - Beamformer computation failed!");
159 result.
proj = projMat;
169 result.
rank =
static_cast<int>(CmW.rows());
176 verts.resize(forward.
src[0].vertno.
size() + forward.
src[1].vertno.
size());
177 verts << forward.
src[0].vertno, forward.
src[1].vertno;
178 }
else if(forward.
src.
size() == 1) {
179 verts = forward.
src[0].vertno;
183 qInfo(
"InvLCMV::makeLCMV - Done. Filter: %d x %d (sources=%d, orient=%d)",
184 static_cast<int>(W.rows()),
static_cast<int>(W.cols()), nSources, result.
nOrient());
191MatrixXd InvLCMV::applyFilter(
const MatrixXd &data,
const InvBeamformer &filters)
194 MatrixXd processed = data;
197 if(filters.
proj.size() > 0 && filters.
proj.rows() == data.rows()) {
198 processed = filters.
proj * processed;
202 if(filters.
whitener.size() > 0 && filters.
whitener.cols() == processed.rows()) {
203 processed = filters.
whitener * processed;
207 return filters.
weights[0] * processed;
215 qWarning(
"InvLCMV::applyLCMV - Invalid or non-LCMV filters!");
221 if(filters.
chNames.size() > 0 &&
222 static_cast<int>(filters.
chNames.size()) != evoked.
data.rows()) {
224 const int nFilterCh =
static_cast<int>(filters.
chNames.size());
225 const int nTimes =
static_cast<int>(evoked.
data.cols());
226 data.resize(nFilterCh, nTimes);
227 for(
int i = 0; i < nFilterCh; ++i) {
230 qWarning(
"InvLCMV::applyLCMV - Channel %s not found in evoked!",
231 qPrintable(filters.
chNames[i]));
234 data.row(i) = evoked.
data.row(idx);
240 MatrixXd sol = applyFilter(data, filters);
243 const int nOrient = filters.
nOrient();
246 const int nSources =
static_cast<int>(sol.rows()) / 3;
247 const int nTimes =
static_cast<int>(sol.cols());
248 MatrixXd combined(nSources, nTimes);
249 for(
int s = 0; s < nSources; ++s) {
250 combined.row(s) = sol.middleRows(s * 3, 3).colwise().norm();
255 float tmin = evoked.
times.size() > 0 ? evoked.
times[0] : 0.0f;
274 qWarning(
"InvLCMV::applyLCMVRaw - Invalid or non-LCMV filters!");
278 MatrixXd sol = applyFilter(data, filters);
280 const int nOrient = filters.
nOrient();
282 const int nSources =
static_cast<int>(sol.rows()) / 3;
283 const int nTimes =
static_cast<int>(sol.cols());
284 MatrixXd combined(nSources, nTimes);
285 for(
int s = 0; s < nSources; ++s) {
286 combined.row(s) = sol.middleRows(s * 3, 3).colwise().norm();
305 qWarning(
"InvLCMV::applyLCMVCov - Invalid or non-LCMV filters!");
310 MatrixXd CmW = dataCov.
data;
315 const int nOrient = filters.
nOrient();
319 MatrixXd powerMat = power;
336 QList<InvSourceEstimate> results;
338 if (epochs.isEmpty()) {
339 qWarning(
"InvLCMV::applyLCMVEpochs - No epochs provided.");
342 if (!filters.
isValid() || filters.
kind !=
"LCMV") {
343 qWarning(
"InvLCMV::applyLCMVEpochs - Invalid or non-LCMV filters!");
347 for (
int i = 0; i < epochs.size(); ++i) {
350 qWarning(
"InvLCMV::applyLCMVEpochs - Epoch %d produced empty source estimate.", i);
371 qWarning(
"InvLCMV::makeLCMVResolutionMatrix - Could not compute LCMV filter.");
376 MatrixXd G = forward.
sol->data;
380 if (filters.
proj.size() > 0 && filters.
proj.rows() == G.rows()) {
381 Gw = filters.
proj * Gw;
388 MatrixXd
R = filters.
weights[0] * Gw;
390 qInfo(
"InvLCMV::makeLCMVResolutionMatrix - Resolution matrix: %d x %d",
391 static_cast<int>(
R.rows()),
static_cast<int>(
R.cols()));
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,...
Single averaged evoked response: time axis, samples, baseline, channel info and processing history.
Shared math kernels (filter derivation, source power, regularised pseudo-inverse) used by both the LC...
Linearly Constrained Minimum Variance (LCMV) beamformer — time-domain source-power and source-time-co...
Static linear-algebra helpers: SVD-based conditioning, block-diagonal assembly, sorted index pairs.
Core MNE data structures (source spaces, source estimates, hemispheres).
FIFF file I/O, in-memory data structures and high-level readers/writers.
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
Inverse source estimation (MNE, dSPM, sLORETA, dipole fitting).
FIFF noise / data covariance: matrix, channel names, kind, applied projectors, bads,...
Single averaged evoked response: time axis, data, baseline, channel info and averaging metadata.
Full FIFF measurement info: per-channel descriptors, sampling and filter setup, projectors,...
Computed beamformer spatial filter container.
BeamformerPickOri pickOri
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 InvSourceEstimate applyLCMVCov(const FIFFLIB::FiffCov &dataCov, const InvBeamformer &filters)
static InvBeamformer makeLCMV(const FIFFLIB::FiffInfo &info, const MNELIB::MNEForwardSolution &forward, const FIFFLIB::FiffCov &dataCov, double reg=0.05, const FIFFLIB::FiffCov &noiseCov=FIFFLIB::FiffCov(), BeamformerPickOri pickOri=BeamformerPickOri::None, BeamformerWeightNorm weightNorm=BeamformerWeightNorm::UnitNoiseGain, bool reduceRank=false, BeamformerInversion invMethod=BeamformerInversion::Matrix)
static QList< InvSourceEstimate > applyLCMVEpochs(const QList< Eigen::MatrixXd > &epochs, float tmin, float tstep, const InvBeamformer &filters)
static InvSourceEstimate applyLCMV(const FIFFLIB::FiffEvoked &evoked, const InvBeamformer &filters)
static InvSourceEstimate applyLCMVRaw(const Eigen::MatrixXd &data, float tmin, float tstep, const InvBeamformer &filters)
static Eigen::MatrixXd makeLCMVResolutionMatrix(const MNELIB::MNEForwardSolution &forward, const FIFFLIB::FiffInfo &info, const FIFFLIB::FiffCov &dataCov, double reg=0.05, const FIFFLIB::FiffCov &noiseCov=FIFFLIB::FiffCov())
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