Skip to content

NOTES

Resampling — Three Rate Conversion Modes

Downsampling (keep/skip), upsampling (zero-insertion), arbitrary-factor linear interpolation.


Algorithm

Downsampling — tiny_downsample_skip_f32

\[ y[n] = x[n \cdot M + \text{offset}], \quad n = 0, \dots, \lfloor (L - \text{offset}) / M \rfloor \]

Keep one sample every \(M\). \(\text{offset}\) controls starting phase.

Aliasing risk

Signal bandwidth must be limited to \(f_s / (2M)\) before downsampling, or high frequencies fold into the baseband.

Upsampling — tiny_upsample_zero_f32

Insert \(L-1\) zeros between each original sample. Output length: \(L \cdot N\).

Spectral images

Zero-insertion introduces \(L-1\) spectral copies of the original → requires low-pass post-filtering.

Linear Interpolation — tiny_resample_f32

\[ y[m] = x[n] + (x[n+1] - x[n]) \cdot \alpha, \quad n = \lfloor m \cdot R \rfloor,\; \alpha = m \cdot R - n \]

\(R = \text{orig_len} / \text{new_len}\). Works for any rational factor.

High-frequency roll-off

Linear interpolation acts as a time-varying low-pass filter. High frequencies are attenuated, especially during upsampling.


API Reference

// Downsample: keep 1 sample every M
int tiny_downsample_skip_f32(const float *input, int len,
                             int M, int offset, float *output);

// Upsample: insert N-1 zeros between samples
int tiny_upsample_zero_f32(const float *input, int len,
                           int N, float *output);

// Arbitrary-factor linear interpolation resampling
int tiny_resample_f32(const float *input, int orig_len,
                      int new_len, float *output);