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)
160 const int nChan =
static_cast<int>(evoked.
data.rows());
161 const int nTimes =
static_cast<int>(evoked.
data.cols());
164 if (noiseCov.
data.size() > 0 && noiseCov.
data.rows() == nChan) {
167 SelfAdjointEigenSolver<MatrixXd> solver(noiseCov.
data);
168 VectorXd eigvals = solver.eigenvalues();
169 MatrixXd eigvecs = solver.eigenvectors();
172 for (
int i = 0; i < eigvals.size(); ++i) {
177 MatrixXd sqrtCov = eigvecs * eigvals.cwiseSqrt().asDiagonal();
179 std::mt19937 gen(seed);
180 std::normal_distribution<double> dist(0.0, 1.0);
182 MatrixXd noise(nChan, nTimes);
183 for (
int i = 0; i < nChan; ++i) {
184 for (
int j = 0; j < nTimes; ++j) {
185 noise(i, j) = dist(gen);
189 double scaleFactor = 1.0 / std::sqrt(
static_cast<double>(nave));
190 evoked.
data += sqrtCov * noise * scaleFactor;
206 if (!fwd.
sol || fwd.
sol->data.size() == 0) {
207 qWarning() <<
"[simulateEvokedNoiseless] Forward solution has no gain matrix.";
212 qWarning() <<
"[simulateEvokedNoiseless] Source estimate is empty.";
216 MatrixXd G = fwd.
sol->data;
217 const int nDipoles =
static_cast<int>(G.cols());
218 const int nSrc =
static_cast<int>(stc.
data.rows());
219 const int nTimes =
static_cast<int>(stc.
data.cols());
221 if (nDipoles != nSrc) {
222 qWarning() <<
"[simulateEvokedNoiseless] Leadfield columns" << nDipoles
223 <<
"!= source estimate rows" << nSrc;
231 evoked.
times.resize(nTimes);
232 for (
int t = 0; t < nTimes; ++t) {
237 evoked.
last = nTimes - 1;
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,...
InvSourceEstimate value type — central source-space data container produced by every INVLIB inverse s...
Simulation utilities for source estimates and evoked data.
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).
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