41 #define _USE_MATH_DEFINES
50 #include <Eigen/Eigen>
51 #include <Eigen/Geometry>
63 using namespace UTILSLIB;
64 using namespace Eigen;
76 return gcd(iB, iA % iB);
83 if (vec.size() % 3 != 0)
85 printf(
"Input must be a row or a column vector with 3N components\n");
89 MatrixXd tmp = MatrixXd(vec.transpose());
90 SparseMatrix<double>* s = make_block_diag(tmp,3);
92 SparseMatrix<double> sC = *s*s->transpose();
93 VectorXd* comb =
new VectorXd(sC.rows());
95 for(qint32 i = 0; i < sC.rows(); ++i)
96 (*comb)[i] = sC.coeff(i,i);
107 JacobiSVD<MatrixXd> svd(A);
108 s = svd.singularValues();
110 double c = s.maxCoeff()/s.minCoeff();
120 JacobiSVD<MatrixXd> svd(A);
121 s = svd.singularValues();
123 double c = s.maxCoeff()/s.mean();
137 SelfAdjointEigenSolver<MatrixXd> t_eigenSolver(A);
139 eig = t_eigenSolver.eigenvalues();
140 eigvec = t_eigenSolver.eigenvectors().transpose();
142 MNEMath::sort<double>(eig, eigvec,
false);
145 for(qint32 i = 0; i < eig.size()-rnk; ++i)
148 printf(
"Setting small %s eigenvalues to zero.\n", ch_type.toUtf8().constData());
150 printf(
"Not doing PCA for %s\n", ch_type.toUtf8().constData());
153 printf(
"Doing PCA for %s.",ch_type.toUtf8().constData());
156 eigvec = eigvec.block(eigvec.rows()-rnk, 0, rnk, eigvec.cols());
164 const std::string& ch_type,
169 SelfAdjointEigenSolver<MatrixXd> t_eigenSolver(A);
171 eig = t_eigenSolver.eigenvalues();
172 eigvec = t_eigenSolver.eigenvectors().transpose();
174 MNEMath::sort<double>(eig, eigvec,
false);
177 for(qint32 i = 0; i < eig.size()-rnk; ++i)
180 printf(
"Setting small %s eigenvalues to zero.\n", ch_type.c_str());
182 printf(
"Not doing PCA for %s\n", ch_type.c_str());
185 printf(
"Doing PCA for %s.",ch_type.c_str());
188 eigvec = eigvec.block(eigvec.rows()-rnk, 0, rnk, eigvec.cols());
198 std::vector<int> tmp;
200 std::vector< std::pair<int,int> > t_vecIntIdxValue;
203 for(qint32 i = 0; i < v1.size(); ++i)
204 tmp.push_back(v1[i]);
206 std::vector<int>::iterator it;
207 for(qint32 i = 0; i < v2.size(); ++i)
209 it = std::search(tmp.begin(), tmp.end(), &v2[i], &v2[i]+1);
211 t_vecIntIdxValue.push_back(std::pair<int,int>(v2[i], it-tmp.begin()));
214 std::sort(t_vecIntIdxValue.begin(), t_vecIntIdxValue.end(), MNEMath::compareIdxValuePairSmallerThan<int>);
216 VectorXi p_res(t_vecIntIdxValue.size());
217 idx_sel = VectorXi(t_vecIntIdxValue.size());
219 for(quint32 i = 0; i < t_vecIntIdxValue.size(); ++i)
221 p_res[i] = t_vecIntIdxValue[i].first;
222 idx_sel[i] = t_vecIntIdxValue[i].second;
296 for(qint32 i = 0; i < n; ++i)
330 std::string normalize)
351 qint32 ma = A.rows();
352 qint32 na = A.cols();
353 float bdn = ((float)na)/n;
359 printf(
"Width of matrix must be even multiple of n\n");
363 typedef Eigen::Triplet<double> T;
364 std::vector<T> tripletList;
365 tripletList.reserve(bdn*ma*n);
367 qint32 current_col, current_row, i, r, c;
368 for(i = 0; i < bdn; ++i)
371 current_row = i * ma;
373 for(r = 0; r < ma; ++r)
374 for(c = 0; c < n; ++c)
375 tripletList.push_back(T(r+current_row, c+current_col, A(r, c+current_col)));
378 SparseMatrix<double>* bd =
new SparseMatrix<double>((
int)floor((
float)ma*bdn+0.5),na);
380 bd->setFromTriplets(tripletList.begin(), tripletList.end());
392 int t_iNumOfCombination = (int)(n*(n-1)*0.5);
394 return t_iNumOfCombination;
402 JacobiSVD<MatrixXd> t_svdA(A);
403 VectorXd s = t_svdA.singularValues();
404 double t_dMax = s.maxCoeff();
407 for(qint32 i = 0; i < s.size(); ++i)
408 sum += s[i] > t_dMax ? 1 : 0;
415 const RowVectorXf ×,
416 const QPair<float,float>& baseline,
419 MatrixXd data_out = data;
420 QStringList valid_modes;
421 valid_modes <<
"logratio" <<
"ratio" <<
"zscore" <<
"mean" <<
"percent";
422 if(!valid_modes.contains(mode))
424 qWarning().noquote() <<
"[MNEMath::rescale] Mode" << mode <<
"is not supported. Supported modes are:" << valid_modes <<
"Returning input data.";
428 qInfo().noquote() << QString(
"[MNEMath::rescale] Applying baseline correction ... (mode: %1)").arg(mode);
431 qint32 imax = times.size();
433 if (baseline.second == baseline.first) {
436 float bmin = baseline.first;
437 for(qint32 i = 0; i < times.size(); ++i) {
438 if(times[i] >= bmin) {
445 float bmax = baseline.second;
447 if (baseline.second == baseline.first) {
451 for(qint32 i = times.size()-1; i >= 0; --i) {
452 if(times[i] <= bmax) {
459 qWarning() <<
"[MNEMath::rescale] imax < imin. Returning input data.";
463 VectorXd mean = data_out.block(0, imin,data_out.rows(),imax-imin).rowwise().mean();
464 if(mode.compare(
"mean") == 0) {
465 data_out -= mean.rowwise().replicate(data.cols());
466 }
else if(mode.compare(
"logratio") == 0) {
467 for(qint32 i = 0; i < data_out.rows(); ++i)
468 for(qint32 j = 0; j < data_out.cols(); ++j)
469 data_out(i,j) = log10(data_out(i,j)/mean[i]);
470 }
else if(mode.compare(
"ratio") == 0) {
471 data_out = data_out.cwiseQuotient(mean.rowwise().replicate(data_out.cols()));
472 }
else if(mode.compare(
"zscore") == 0) {
473 MatrixXd std_mat = data.block(0, imin, data.rows(), imax-imin) - mean.rowwise().replicate(imax-imin);
474 std_mat = std_mat.cwiseProduct(std_mat);
475 VectorXd std_v = std_mat.rowwise().mean();
476 for(qint32 i = 0; i < std_v.size(); ++i)
477 std_v[i] = sqrt(std_v[i] / (
float)(imax-imin));
479 data_out -= mean.rowwise().replicate(data_out.cols());
480 data_out = data_out.cwiseQuotient(std_v.rowwise().replicate(data_out.cols()));
481 }
else if(mode.compare(
"percent") == 0) {
482 data_out -= mean.rowwise().replicate(data_out.cols());
483 data_out = data_out.cwiseQuotient(mean.rowwise().replicate(data_out.cols()));
492 const RowVectorXf& times,
493 const std::pair<float,float>& baseline,
494 const std::string& mode)
496 MatrixXd data_out = data;
497 std::vector<std::string> valid_modes{
"logratio",
"ratio",
"zscore",
"mean",
"percent"};
498 if(std::find(valid_modes.begin(),valid_modes.end(), mode) == valid_modes.end())
500 qWarning().noquote() <<
"[MNEMath::rescale] Mode" << mode.c_str() <<
"is not supported. Supported modes are:";
501 for(
auto& mode : valid_modes){
502 std::cout << mode <<
" ";
504 std::cout <<
"\n" <<
"Returning input data.\n";
508 qInfo().noquote() << QString(
"[MNEMath::rescale] Applying baseline correction ... (mode: %1)").arg(mode.c_str());
511 qint32 imax = times.size();
513 if (baseline.second == baseline.first) {
516 float bmin = baseline.first;
517 for(qint32 i = 0; i < times.size(); ++i) {
518 if(times[i] >= bmin) {
525 float bmax = baseline.second;
527 if (baseline.second == baseline.first) {
531 for(qint32 i = times.size()-1; i >= 0; --i) {
532 if(times[i] <= bmax) {
539 qWarning() <<
"[MNEMath::rescale] imax < imin. Returning input data.";
543 VectorXd mean = data_out.block(0, imin,data_out.rows(),imax-imin).rowwise().mean();
544 if(mode.compare(
"mean") == 0) {
545 data_out -= mean.rowwise().replicate(data.cols());
546 }
else if(mode.compare(
"logratio") == 0) {
547 for(qint32 i = 0; i < data_out.rows(); ++i)
548 for(qint32 j = 0; j < data_out.cols(); ++j)
549 data_out(i,j) = log10(data_out(i,j)/mean[i]);
550 }
else if(mode.compare(
"ratio") == 0) {
551 data_out = data_out.cwiseQuotient(mean.rowwise().replicate(data_out.cols()));
552 }
else if(mode.compare(
"zscore") == 0) {
553 MatrixXd std_mat = data.block(0, imin, data.rows(), imax-imin) - mean.rowwise().replicate(imax-imin);
554 std_mat = std_mat.cwiseProduct(std_mat);
555 VectorXd std_v = std_mat.rowwise().mean();
556 for(qint32 i = 0; i < std_v.size(); ++i)
557 std_v[i] = sqrt(std_v[i] / (
float)(imax-imin));
559 data_out -= mean.rowwise().replicate(data_out.cols());
560 data_out = data_out.cwiseQuotient(std_v.rowwise().replicate(data_out.cols()));
561 }
else if(mode.compare(
"percent") == 0) {
562 data_out -= mean.rowwise().replicate(data_out.cols());
563 data_out = data_out.cwiseQuotient(mean.rowwise().replicate(data_out.cols()));
572 const MatrixX4f& mDevHeadDest,
573 const float& fThreshRot,
574 const float& fThreshTrans)
578 Matrix3f mRot = mDevHeadT.block(0,0,3,3);
579 Matrix3f mRotDest = mDevHeadDest.block(0,0,3,3);
581 VectorXf vTrans = mDevHeadT.block(0,3,3,1);
582 VectorXf vTransDest = mDevHeadDest.block(0,3,3,1);
584 Quaternionf quat(mRot);
585 Quaternionf quatNew(mRotDest);
588 Quaternionf quatCompare;
592 quatCompare = quat*quatNew.inverse();
593 fAngle = quat.angularDistance(quatNew);
594 fAngle = fAngle * 180 / M_PI;
597 float fMove = (vTrans-vTransDest).norm();
600 if(fMove > fThreshTrans) {
601 qInfo() <<
"Large movement: " << fMove*1000 <<
"mm";
604 }
else if (fAngle > fThreshRot) {
605 qInfo() <<
"Large rotation: " << fAngle <<
"degree";