49int Resample::gcd(
int a,
int b)
61RowVectorXd Resample::buildKernel(
int p,
int q,
int iNZeros)
63 int M = std::max(p, q);
64 int halfLen = iNZeros * M;
65 int L = 2 * halfLen + 1;
73 const double fc =
static_cast<double>(std::min(p, q)) / (2.0 *
static_cast<double>(M));
76 for (
int k = 0; k < L; ++k) {
77 double n = k - halfLen;
78 double win = 0.54 - 0.46 * std::cos(2.0 *
M_PI * k / (L - 1));
80 if (std::abs(n) < 1e-10) {
81 h(k) = 2.0 * fc * win;
84 h(k) = std::sin(2.0 *
M_PI * fc * n) / (
M_PI * n) * win;
89 h *=
static_cast<double>(p);
95RowVectorXd Resample::polyphaseConv(
const RowVectorXd& vecX,
96 const RowVectorXd& vecH,
101 const long long nIn =
static_cast<long long>(vecX.size());
102 const long long L =
static_cast<long long>(vecH.size());
105 const long long nOut = (nIn * p + q - 1) / q;
109 for (
long long m = 0; m < nOut; ++m) {
112 long long center = m *
static_cast<long long>(q) + halfLen;
118 long long j_min = (center - L + 1 + p - 1) / p;
119 if (j_min < 0) j_min = 0;
120 long long j_max = center / p;
121 if (j_max >= nIn) j_max = nIn - 1;
124 for (
long long j = j_min; j <= j_max; ++j) {
125 long long tap = center - j *
static_cast<long long>(p);
126 if (tap >= 0 && tap < L) {
127 val += vecH(
static_cast<int>(tap)) * vecX(
static_cast<int>(j));
130 y(
static_cast<int>(m)) = val;
145 if (vecData.size() == 0) {
146 qWarning() <<
"Resample::resample: empty input.";
149 if (dNewSFreq <= 0.0 || dOldSFreq <= 0.0) {
150 qWarning() <<
"Resample::resample: sampling frequencies must be positive.";
156 const int scale = 1000;
157 int p_raw =
static_cast<int>(std::round(dNewSFreq * scale));
158 int q_raw =
static_cast<int>(std::round(dOldSFreq * scale));
159 int g = gcd(p_raw, q_raw);
167 const int halfLen = iNZeros * std::max(p, q);
168 RowVectorXd h = buildKernel(p, q, iNZeros);
170 return polyphaseConv(vecData, h, p, q, halfLen);
178 const RowVectorXi& vecPicks,
181 if (matData.size() == 0)
return matData;
184 const int scale = 1000;
185 int p_raw =
static_cast<int>(std::round(dNewSFreq * scale));
186 int q_raw =
static_cast<int>(std::round(dOldSFreq * scale));
187 int g = gcd(p_raw, q_raw);
191 if (p == q)
return matData;
193 const int halfLen = iNZeros * std::max(p, q);
194 RowVectorXd h = buildKernel(p, q, iNZeros);
196 const int nIn =
static_cast<int>(matData.cols());
197 const int nOut =
static_cast<int>((
static_cast<long long>(nIn) * p + q - 1) / q);
198 const int nCh =
static_cast<int>(matData.rows());
200 MatrixXd result(nCh, nOut);
202 if (vecPicks.size() == 0) {
203 for (
int i = 0; i < nCh; ++i) {
204 result.row(i) = polyphaseConv(matData.row(i), h, p, q, halfLen);
211 for (
int k = 0; k < vecPicks.size(); ++k) {
213 if (i >= 0 && i < nCh) {
214 result.row(i) = polyphaseConv(matData.row(i), h, p, q, halfLen);
Declaration of Resample — polyphase anti-aliased rational resampling for MEG/EEG data.
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
static Eigen::RowVectorXd resample(const Eigen::RowVectorXd &vecData, double dNewSFreq, double dOldSFreq, int iNZeros=10)
static Eigen::MatrixXd resampleMatrix(const Eigen::MatrixXd &matData, double dNewSFreq, double dOldSFreq, const Eigen::RowVectorXi &vecPicks=Eigen::RowVectorXi(), int iNZeros=10)