36#include <Eigen/Eigenvalues>
60 const VectorXi& activeVertices,
61 const VectorXi& allVertices,
64 const int nAll =
static_cast<int>(allVertices.size());
65 const int nActive =
static_cast<int>(activeVertices.size());
66 const float tstep = 1.0f / params.
sfreq;
67 const int nTimes =
static_cast<int>(params.
duration * params.
sfreq);
69 if (nTimes <= 0 || nAll <= 0) {
70 qWarning() <<
"[simulateStc] Invalid parameters.";
75 QList<int> activeRows;
76 for (
int a = 0; a < nActive; ++a) {
78 for (
int v = 0; v < nAll; ++v) {
79 if (allVertices(v) == activeVertices(a)) {
86 qWarning() <<
"[simulateStc] Active vertex" << activeVertices(a) <<
"not in allVertices.";
92 MatrixXd data = MatrixXd::Zero(nAll, nTimes);
94 std::mt19937 gen(params.
seed);
95 std::uniform_real_distribution<double> timeDist(0.2, 0.8);
97 for (
int a = 0; a < nActive; ++a) {
99 double centerFrac = timeDist(gen);
100 double centerSample = centerFrac * nTimes;
101 double sigma = nTimes * 0.1;
103 for (
int t = 0; t < nTimes; ++t) {
104 double exponent = -0.5 * std::pow((t - centerSample) / sigma, 2.0);
105 data(activeRows[a], t) = std::exp(exponent);
115 const MatrixXd& waveforms,
116 const VectorXi& activeVertices,
117 const VectorXi& allVertices,
121 const int nAll =
static_cast<int>(allVertices.size());
122 const int nActive =
static_cast<int>(activeVertices.size());
123 const int nTimes =
static_cast<int>(waveforms.cols());
125 if (waveforms.rows() != nActive) {
126 qWarning() <<
"[simulateStcFromWaveforms] waveforms.rows() != activeVertices.size()";
130 MatrixXd data = MatrixXd::Zero(nAll, nTimes);
132 for (
int a = 0; a < nActive; ++a) {
133 for (
int v = 0; v < nAll; ++v) {
134 if (allVertices(v) == activeVertices(a)) {
135 data.row(v) = waveforms.row(a);
157 if (evoked.
data.size() == 0)
return evoked;
159 const int nChan =
static_cast<int>(evoked.
data.rows());
160 const int nTimes =
static_cast<int>(evoked.
data.cols());
163 if (noiseCov.
data.size() > 0 && noiseCov.
data.rows() == nChan) {
166 SelfAdjointEigenSolver<MatrixXd> solver(noiseCov.
data);
167 VectorXd eigvals = solver.eigenvalues();
168 MatrixXd eigvecs = solver.eigenvectors();
171 for (
int i = 0; i < eigvals.size(); ++i) {
172 if (eigvals(i) < 0) eigvals(i) = 0;
175 MatrixXd sqrtCov = eigvecs * eigvals.cwiseSqrt().asDiagonal();
177 std::mt19937 gen(seed);
178 std::normal_distribution<double> dist(0.0, 1.0);
180 MatrixXd noise(nChan, nTimes);
181 for (
int i = 0; i < nChan; ++i) {
182 for (
int j = 0; j < nTimes; ++j) {
183 noise(i, j) = dist(gen);
187 double scaleFactor = 1.0 / std::sqrt(
static_cast<double>(nave));
188 evoked.
data += sqrtCov * noise * scaleFactor;
204 if (!fwd.
sol || fwd.
sol->data.size() == 0) {
205 qWarning() <<
"[simulateEvokedNoiseless] Forward solution has no gain matrix.";
210 qWarning() <<
"[simulateEvokedNoiseless] Source estimate is empty.";
214 MatrixXd G = fwd.
sol->data;
215 const int nChan =
static_cast<int>(G.rows());
216 const int nDipoles =
static_cast<int>(G.cols());
217 const int nSrc =
static_cast<int>(stc.
data.rows());
218 const int nTimes =
static_cast<int>(stc.
data.cols());
220 if (nDipoles != nSrc) {
221 qWarning() <<
"[simulateEvokedNoiseless] Leadfield columns" << nDipoles
222 <<
"!= source estimate rows" << nSrc;
230 evoked.
times.resize(nTimes);
231 for (
int t = 0; t < nTimes; ++t) {
236 evoked.
last = nTimes - 1;
Forward solution (gain matrix mapping source dipoles to sensor measurements).
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.
InvSourceEstimate value type — central source-space data container produced by every INVLIB inverse s...
Simulation utilities for source estimates and evoked data.
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).
DSPSHARED_EXPORT INVLIB::InvSourceEstimate simulateStc(const Eigen::VectorXi &activeVertices, const Eigen::VectorXi &allVertices, const SimulateStcParams ¶ms=SimulateStcParams())
Create a synthetic source time course.
DSPSHARED_EXPORT INVLIB::InvSourceEstimate simulateStcFromWaveforms(const Eigen::MatrixXd &waveforms, const Eigen::VectorXi &activeVertices, const Eigen::VectorXi &allVertices, float tmin=0.0f, float tstep=0.001f)
Create a synthetic source time course from custom waveforms.
DSPSHARED_EXPORT FIFFLIB::FiffEvoked simulateEvokedNoiseless(const MNELIB::MNEForwardSolution &fwd, const INVLIB::InvSourceEstimate &stc, const FIFFLIB::FiffInfo &info)
Simulate evoked data without noise.
DSPSHARED_EXPORT FIFFLIB::FiffEvoked simulateEvoked(const MNELIB::MNEForwardSolution &fwd, const INVLIB::InvSourceEstimate &stc, const FIFFLIB::FiffInfo &info, const FIFFLIB::FiffCov &noiseCov, int nave=1, int seed=42)
Simulate evoked data from a source estimate and forward model.
Inverse source estimation (MNE, dSPM, sLORETA, dipole fitting).
Parameters for source time course simulation.
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,...
Source-space inverse-solution container with dense grid plus optional focal-dipole,...
In-memory representation of an -fwd.fif forward solution.
FIFFLIB::FiffNamedMatrix::SDPtr sol