70int Resample::gcd(
int a,
int b)
82RowVectorXd Resample::buildKernel(
int p,
int q,
int iNZeros)
84 int M = std::max(p, q);
85 int halfLen = iNZeros * M;
86 int L = 2 * halfLen + 1;
94 const double fc =
static_cast<double>(std::min(p, q)) / (2.0 *
static_cast<double>(M));
97 for (
int k = 0; k < L; ++k) {
98 double n = k - halfLen;
99 double win = 0.54 - 0.46 * std::cos(2.0 *
M_PI * k / (L - 1));
101 if (std::abs(n) < 1e-10) {
102 h(k) = 2.0 * fc * win;
105 h(k) = std::sin(2.0 *
M_PI * fc * n) / (
M_PI * n) * win;
110 h *=
static_cast<double>(p);
116RowVectorXd Resample::polyphaseConv(
const RowVectorXd& vecX,
117 const RowVectorXd& vecH,
122 const long long nIn =
static_cast<long long>(vecX.size());
123 const long long L =
static_cast<long long>(vecH.size());
126 const long long nOut = (nIn * p + q - 1) / q;
130 for (
long long m = 0; m < nOut; ++m) {
133 long long center = m *
static_cast<long long>(q) + halfLen;
139 long long j_min = (center - L + 1 + p - 1) / p;
140 if (j_min < 0) j_min = 0;
141 long long j_max = center / p;
142 if (j_max >= nIn) j_max = nIn - 1;
145 for (
long long j = j_min; j <= j_max; ++j) {
146 long long tap = center - j *
static_cast<long long>(p);
147 if (tap >= 0 && tap < L) {
148 val += vecH(
static_cast<int>(tap)) * vecX(
static_cast<int>(j));
151 y(
static_cast<int>(m)) = val;
166 if (vecData.size() == 0) {
167 qWarning() <<
"Resample::resample: empty input.";
170 if (dNewSFreq <= 0.0 || dOldSFreq <= 0.0) {
171 qWarning() <<
"Resample::resample: sampling frequencies must be positive.";
177 const int scale = 1000;
178 int p_raw =
static_cast<int>(std::round(dNewSFreq * scale));
179 int q_raw =
static_cast<int>(std::round(dOldSFreq * scale));
180 int g = gcd(p_raw, q_raw);
188 const int halfLen = iNZeros * std::max(p, q);
189 RowVectorXd h = buildKernel(p, q, iNZeros);
191 return polyphaseConv(vecData, h, p, q, halfLen);
199 const RowVectorXi& vecPicks,
202 if (matData.size() == 0)
return matData;
205 const int scale = 1000;
206 int p_raw =
static_cast<int>(std::round(dNewSFreq * scale));
207 int q_raw =
static_cast<int>(std::round(dOldSFreq * scale));
208 int g = gcd(p_raw, q_raw);
212 if (p == q)
return matData;
214 const int halfLen = iNZeros * std::max(p, q);
215 RowVectorXd h = buildKernel(p, q, iNZeros);
217 const int nIn =
static_cast<int>(matData.cols());
218 const int nOut =
static_cast<int>((
static_cast<long long>(nIn) * p + q - 1) / q);
219 const int nCh =
static_cast<int>(matData.rows());
221 MatrixXd result(nCh, nOut);
223 if (vecPicks.size() == 0) {
224 for (
int i = 0; i < nCh; ++i) {
225 result.row(i) = polyphaseConv(matData.row(i), h, p, q, halfLen);
232 for (
int k = 0; k < vecPicks.size(); ++k) {
234 if (i >= 0 && i < nCh) {
235 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)