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;
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>();
137 if (nOrient == 3 && nn.rows() == 3 * nSources) {
139 MatrixX3d perSource(nSources, 3);
140 for (
int s = 0; s < nSources; ++s)
141 perSource.row(s) = nn.row(3 * s + 2);
152 Gw, CmW, reg, nOrient,
153 weightNorm, pickOri, reduceRank, invMethod,
157 qWarning(
"InvLCMV::makeLCMV - Beamformer computation failed!");
166 result.
proj = projMat;
175 result.
rank =
static_cast<int>(CmW.rows());
182 verts.resize(forward.
src[0].vertno.
size() + forward.
src[1].vertno.
size());
183 verts << forward.
src[0].vertno, forward.
src[1].vertno;
188 }
else if (forward.
src.
size() == 1) {
189 verts = forward.
src[0].vertno;
193 qInfo(
"InvLCMV::makeLCMV - Done. Filter: %d x %d (sources=%d, orient=%d)",
194 static_cast<int>(W.rows()),
static_cast<int>(W.cols()), nSources, result.
nOrient());
201MatrixXd InvLCMV::applyFilter(
const MatrixXd& data,
const InvBeamformer& filters)
204 MatrixXd processed = data;
207 if (filters.
proj.size() > 0 && filters.
proj.rows() == data.rows()) {
208 processed = filters.
proj * processed;
212 if (filters.
whitener.size() > 0 && filters.
whitener.cols() == processed.rows()) {
213 processed = filters.
whitener * processed;
217 return filters.
weights[0] * processed;
224 if (!filters.
isValid() || filters.
kind !=
"LCMV") {
225 qWarning(
"InvLCMV::applyLCMV - Invalid or non-LCMV filters!");
231 if (filters.
chNames.size() > 0 &&
232 static_cast<int>(filters.
chNames.size()) != evoked.
data.rows()) {
234 const int nFilterCh =
static_cast<int>(filters.
chNames.size());
235 const int nTimes =
static_cast<int>(evoked.
data.cols());
236 data.resize(nFilterCh, nTimes);
237 for (
int i = 0; i < nFilterCh; ++i) {
240 qWarning(
"InvLCMV::applyLCMV - Channel %s not found in evoked!",
241 qPrintable(filters.
chNames[i]));
244 data.row(i) = evoked.
data.row(idx);
250 MatrixXd sol = applyFilter(data, filters);
253 const int nOrient = filters.
nOrient();
256 const int nSources =
static_cast<int>(sol.rows()) / 3;
257 const int nTimes =
static_cast<int>(sol.cols());
258 MatrixXd combined(nSources, nTimes);
259 for (
int s = 0; s < nSources; ++s) {
260 combined.row(s) = sol.middleRows(s * 3, 3).colwise().norm();
265 float tmin = evoked.
times.size() > 0 ? evoked.
times[0] : 0.0f;
284 if (!filters.
isValid() || filters.
kind !=
"LCMV") {
285 qWarning(
"InvLCMV::applyLCMVRaw - Invalid or non-LCMV filters!");
289 MatrixXd sol = applyFilter(data, filters);
291 const int nOrient = filters.
nOrient();
293 const int nSources =
static_cast<int>(sol.rows()) / 3;
294 const int nTimes =
static_cast<int>(sol.cols());
295 MatrixXd combined(nSources, nTimes);
296 for (
int s = 0; s < nSources; ++s) {
297 combined.row(s) = sol.middleRows(s * 3, 3).colwise().norm();
316 if (!filters.
isValid() || filters.
kind !=
"LCMV") {
317 qWarning(
"InvLCMV::applyLCMVCov - Invalid or non-LCMV filters!");
322 MatrixXd CmW = dataCov.
data;
327 const int nOrient = filters.
nOrient();
331 MatrixXd powerMat = power;
349 QList<InvSourceEstimate> results;
351 if (epochs.isEmpty()) {
352 qWarning(
"InvLCMV::applyLCMVEpochs - No epochs provided.");
355 if (!filters.
isValid() || filters.
kind !=
"LCMV") {
356 qWarning(
"InvLCMV::applyLCMVEpochs - Invalid or non-LCMV filters!");
360 for (
int i = 0; i < epochs.size(); ++i) {
363 qWarning(
"InvLCMV::applyLCMVEpochs - Epoch %d produced empty source estimate.", i);
384 qWarning(
"InvLCMV::makeLCMVResolutionMatrix - Could not compute LCMV filter.");
389 MatrixXd G = forward.
sol->data;
393 if (filters.
proj.size() > 0 && filters.
proj.rows() == G.rows()) {
394 Gw = filters.
proj * Gw;
401 MatrixXd
R = filters.
weights[0] * Gw;
403 qInfo(
"InvLCMV::makeLCMVResolutionMatrix - Resolution matrix: %d x %d",
404 static_cast<int>(
R.rows()),
static_cast<int>(
R.cols()));
#define FIFFV_MNE_FREE_ORI
Single averaged evoked response: time axis, samples, baseline, channel info and processing history.
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...
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.
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.
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