99 const int nCh =
static_cast<int>(matData.rows());
100 const int nSamples =
static_cast<int>(matData.cols());
102 if (nComponents <= 0 || nComponents > nCh) {
109 VectorXd vecMean = matData.rowwise().mean();
110 MatrixXd matCentered = matData.colwise() - vecMean;
115 MatrixXd matWhitening, matDewhitening;
116 MatrixXd matWhite = whiten(matCentered, nComponents, matWhitening, matDewhitening);
129 std::mt19937 rng(
static_cast<unsigned>(randomSeed));
130 std::normal_distribution<double> dist(0.0, 1.0);
132 MatrixXd W_ica(nComponents, nComponents);
133 bool bConverged =
true;
135 for (
int i = 0; i < nComponents; ++i) {
137 VectorXd w(nComponents);
138 for (
int k = 0; k < nComponents; ++k) {
143 bool compConverged =
false;
144 for (
int iter = 0; iter < maxIter; ++iter) {
146 RowVectorXd u = w.transpose() * matWhite;
147 RowVectorXd g = u.array().tanh();
148 RowVectorXd gPrime = 1.0 - g.array().square();
151 VectorXd wNew = (matWhite * g.transpose()) / nSamples
155 gramSchmidt(wNew, W_ica, i);
158 double norm = wNew.norm();
161 for (
int k = 0; k < nComponents; ++k) {
170 double delta = std::abs(wNew.dot(w)) - 1.0;
173 if (std::abs(delta) < tol) {
174 compConverged =
true;
179 if (!compConverged) {
181 qWarning() <<
"ICA::run: component" << i <<
"did not converge within" << maxIter <<
"iterations.";
184 W_ica.row(i) = w.transpose();
194 MatrixXd matUnmixing = W_ica * matWhitening;
195 MatrixXd matMixing = matDewhitening * W_ica.transpose();
200 MatrixXd matSources = matUnmixing * matCentered;
206 result.
vecMean = std::move(vecMean);
225 const QVector<int>& excludedComponents)
227 if (excludedComponents.isEmpty()) {
235 for (
int idx : excludedComponents) {
236 if (idx >= 0 && idx <
static_cast<int>(matSources.rows())) {
237 matSources.row(idx).setZero();
242 MatrixXd matRecon = result.
matMixing * matSources;
243 return matRecon.colwise() + result.
vecMean;
static IcaResult run(const Eigen::MatrixXd &matData, int nComponents=-1, int maxIter=200, double tol=1e-4, int randomSeed=42)