79 const int nCh =
static_cast<int>(matData.rows());
80 const int nSamples =
static_cast<int>(matData.cols());
82 if (nComponents <= 0 || nComponents > nCh) {
89 VectorXd vecMean = matData.rowwise().mean();
90 MatrixXd matCentered = matData.colwise() - vecMean;
95 MatrixXd matWhitening, matDewhitening;
96 MatrixXd matWhite = whiten(matCentered, nComponents, matWhitening, matDewhitening);
109 std::mt19937 rng(
static_cast<unsigned>(randomSeed));
110 std::normal_distribution<double> dist(0.0, 1.0);
112 MatrixXd W_ica(nComponents, nComponents);
113 bool bConverged =
true;
115 for (
int i = 0; i < nComponents; ++i) {
117 VectorXd w(nComponents);
118 for (
int k = 0; k < nComponents; ++k) {
123 bool compConverged =
false;
124 for (
int iter = 0; iter < maxIter; ++iter) {
126 RowVectorXd u = w.transpose() * matWhite;
127 RowVectorXd g = u.array().tanh();
128 RowVectorXd gPrime = 1.0 - g.array().square();
131 VectorXd wNew = (matWhite * g.transpose()) / nSamples - gPrime.mean() * w;
134 gramSchmidt(wNew, W_ica, i);
137 double norm = wNew.norm();
140 for (
int k = 0; k < nComponents; ++k) {
149 double delta = std::abs(wNew.dot(w)) - 1.0;
152 if (std::abs(delta) < tol) {
153 compConverged =
true;
158 if (!compConverged) {
160 qWarning() <<
"ICA::run: component" << i <<
"did not converge within" << maxIter <<
"iterations.";
163 W_ica.row(i) = w.transpose();
173 MatrixXd matUnmixing = W_ica * matWhitening;
174 MatrixXd matMixing = matDewhitening * W_ica.transpose();
179 MatrixXd matSources = matUnmixing * matCentered;
185 result.
vecMean = std::move(vecMean);
204 const QVector<int>& excludedComponents)
206 if (excludedComponents.isEmpty()) {
217 MatrixXd matCentered = matData.colwise() - result.
vecMean;
220 const int nExcl = excludedComponents.size();
221 const int nCh =
static_cast<int>(result.
matMixing.rows());
222 const int nSamps =
static_cast<int>(matCentered.cols());
224 MatrixXd partialMixing(nCh, nExcl);
225 MatrixXd partialSources(nExcl, nSamps);
227 for (
int i = 0; i < nExcl; ++i) {
228 int idx = excludedComponents[i];
229 if (idx >= 0 && idx <
static_cast<int>(result.
matUnmixing.rows())) {
230 partialMixing.col(i) = result.
matMixing.col(idx);
231 partialSources.row(i) = result.
matUnmixing.row(idx) * matCentered;
233 partialMixing.col(i).setZero();
234 partialSources.row(i).setZero();
238 return matData - partialMixing * partialSources;
static IcaResult run(const Eigen::MatrixXd &matData, int nComponents=-1, int maxIter=200, double tol=1e-4, int randomSeed=42)