The problem comes before the model
A motor vibrates and a small device tries to detect an anomaly. The system records a peak at 300 hertz, meaning three hundred oscillations per second. Can we conclude that the motor really contains that vibration? Not necessarily: with unsuitable sampling, a 700-hertz component can leave exactly the same digital trace. A highly accurate AI model cannot distinguish two causes presented as identical numbers unless it has additional information.
This article asks how to preserve useful information when bringing a physical signal into an embedded system, a computer integrated into a device. We start with two simple waves, prove why they become indistinguishable and build a filter before reducing samples. We also examine the price: delay, memory and operations. All signals and numerical results are synthetic and reproducible; we have measured no motor, board or EL-AI product.
Sampling means looking at intervals
An accelerometer can produce a time-varying signal. The analogue-to-digital converter, often abbreviated ADC, represents it as numbers acquired at discrete instants. With sampling rate f_s of 1,000 samples per second, we observe it every millisecond. We do not directly retain what happens between observations. The issue is not just bits per number: even infinitely precise numbers can ambiguously describe dynamics observed too infrequently.
To isolate the effect we use a cosine: a regular oscillation with unit amplitude and zero initial phase. Frequency f counts cycles per second, t is time in seconds and n is the integer sample index. Substituting t = n/f_s evaluates the wave only at available instants. Round brackets here denote continuous time and square brackets the digital sequence; they do not alter the sensor’s physics, but make our observations explicit.
Two frequencies, one sequence
Set f_s = 1,000 Hz and compare f = 700 Hz with f = 300 Hz. In one millisecond the first wave completes 0.7 turns and the second 0.3. Cosine gives the same value for opposite angles, and adding a whole number of turns changes nothing. These two properties, not a software bug, make the samples identical. The derivation below holds for every integer n, not just points we might plot.
This is aliasing: different physical frequencies take on the same identity in a sampled sequence. Across 1,000 samples our numerical check finds a maximum difference of about 1.27 × 10⁻¹², due to finite computer arithmetic; mathematically it is zero. Changing phase can change an alias’s sign or phase, but does not remove the general ambiguity. An external assumption, such as prior knowledge that frequencies above 400 Hz are absent, can exclude explanations. That is additional information, not information recovered from the samples.
The frequency f_s/2 is called the Nyquist frequency. To represent an arbitrary band-limited signal without aliasing, its highest frequency must lie below that threshold; at the exact boundary some phases become problematic. Yet “the useful signal is at 300 Hz” does not mean “the entire signal lies below 500 Hz”. Interference and harmonics above the threshold still enter the converter. A real system must therefore characterize and limit even what we do not want to measure.
Why filtering afterward may be too late
Suppose acquisition has already occurred at 1 kHz and we apply a digital filter preserving 300 Hz. It also preserves the contribution from 700 Hz, now superimposed on the same samples. Removing 300 Hz removes both explanations. A filter cannot decide which component was real once their distinction has been lost. Protection must act before the operation that makes frequencies indistinguishable: before the ADC for initial sampling, and before each subsequent reduction in digital sampling rate.
Our experiment instead starts at 4,000 samples per second: 300 and 700 Hz both lie below 2,000 Hz and remain distinguishable. We then want to deliver only 1,000 samples per second to the model. Keeping every fourth sample is decimation by M = 4. Doing so without filtering recreates the original problem. The intermediate filter must attenuate components that would become ambiguous at the new sampling rate while preserving the band of interest.
A constructed, checkable filter
We use an FIR, finite impulse response, filter: each output is a weighted sum of finitely many recent samples. Weights h[k] describe each sample’s contribution. This is not a trained neural network: we explicitly choose a low-pass response, preserving slower oscillations and attenuating faster ones. The sum shows both the calculation and its cost. With L = 129 coefficients, direct evaluation requires 129 products and their sum.
The first line filters; the second takes every fourth output. m indexes the new sequence. To define coefficients, start with a sinc, the ideal low-pass shape, truncate it to 129 values and soften the edges with a Hann window. Windowing reduces some response ripples at the cost of a non-instantaneous transition. Finally divide all weights by their sum so a constant input retains its level after the initial transient.
The number 64 centres the response: it is half the 128 intervals between first and last coefficient. f_c is the design cutoff parameter, not a guarantee of unchanged transmission up to 400 Hz and immediate disappearance afterward. A finite filter has a transition region. We therefore inspect its actual response at the example frequencies and across the full plot. The code uses NumPy’s normalized sinc definition; changing conventions without adjusting the formula would produce a different filter.
The result: a false peak stops dominating
Build the input from a useful 300 Hz component of amplitude 0.2 and an unwanted 700 Hz component of amplitude 1. Amplitudes are normalized, without claiming physical acceleration units. Without filtering, decimation superimposes both components: the 300 Hz peak has amplitude 1.2. Software might mistake it for a useful vibration six times larger than expected. That conclusion depends on the chosen phases; other phases could partly cancel the components instead.
With filtering, gain at 300 Hz is 0.998531, so almost all the useful component passes. At 700 Hz it is about 0.0000131684. Expressed in decibels, the response at that specific frequency is −97.61 dB; here decibels use 20 log₁₀ of the amplitude ratio. This does not mean that the whole rejected band receives that attenuation: the graph shows different minima and maxima. After filtering and decimation, the synthetic signal’s measured 300 Hz amplitude is about 0.199693, close to the original 0.2.
| Quantity | Calculated value |
|---|---|
| f_s → f_out | 4000 → 1000 Hz |
| |H(300 Hz)| | 0.998531446 |
| |H(700 Hz)| | 0.0000131684 |
| A300: x[4m] | 1.200000000 |
| A300: y[4m] | 0.199693121 |
| (L−1)/(2f_s) | 16 ms |

For a checkable comparison, generate 5,000 samples at 4 kHz, apply causal convolution and select indices 256 through 4252 in steps of four: exactly 1,000 outputs. Starting at 256 avoids the filter’s startup transient, lasting at most 128 input samples for this sequence. Over that second of data we estimate amplitude by sinusoidal projection at 300 Hz, equivalent to the corresponding discrete Fourier transform coefficient. The window contains an integer number of cycles; we are not studying spectral leakage from unaligned frequencies.
The hidden cost: waiting and storing samples
The coefficients are symmetric: the filter has linear phase and introduces a group delay of (L−1)/2 samples in the useful band. With L = 129 and f_s = 4 kHz, that is 64 samples or 16 ms. A recognizer requiring quick reactions must include it in the overall budget. This does not mean 16 ms of CPU work: signal delay differs from the processor time needed to calculate the sums.
Processing blocks of 128 inputs requires 32 ms to collect a full block. A sample near its beginning waits longer than one near its end; that wait must not be confused with group delay. Transfers, model computation and possible queues add further time. We measured neither mean latency nor device percentiles: we identified two deterministic design contributions. Smaller blocks reduce collection waiting but may increase call and transfer overhead.
CMSIS-DSP’s FIR decimator documentation specifies L + B − 1 state values for B-input blocks. With four-byte float32 in our example, state would occupy 1,024 bytes, coefficients 516, input 512 and the 32-sample output 128. That totals 2,180 bytes if all four arrays reside in RAM; keeping coefficients in read-only memory leaves 1,664 bytes for the three explicit buffers. Stack, structures, alignment, DMA and the AI model are excluded: this is not a measurement of application peak RAM.
Computing only retained outputs with the direct sum requires about 129,000 multiply–accumulate operations per second per channel: 129 coefficients times 1,000 outputs. Computing all 4,000 outputs before discarding three quarters would require four times as many. Arithmetic describes work, not duration: vector instructions, symmetry, cache and implementation affect real cost. Our NumPy experiment computes full convolution for clarity; we did not run the CMSIS kernel on Cortex-M.
What would change on a real board
The first check would concern the analogue path. Sampling at 4 kHz does not protect against every frequency: components above 2 kHz can already fold into the digital input. Sensor, internal filter and any external filter must be considered together. We do not assume that an accelerometer automatically includes a suitable filter. ADC saturation and poor mechanical mounting introduce problems distinct from aliasing; our digital filter does not solve them.
Next would come a numerical check at the actual precision. Published results use float64; −97.61 dB attenuation at 700 Hz is not guaranteed after coefficient conversion to float32 or fixed-point integers. Recalculate the response, check overflow and saturation, and verify block boundaries while preserving filter state. Resetting it every block would introduce repeated transients, changing the signal precisely when we want to make it more reliable.
Finally, evaluate model decisions using the same acquisition chain in training and deployment. A filter change alters amplitudes, phase and delay; a model may have accidentally learned an artefact. Tests should record known input frequencies, sensor configuration, clock, versions and code, then measure platform latency and power. This is a proposed protocol: we report no unmeasured power, energy per inference or diagnostic accuracy.
The conclusion: protect information before interpreting it
The opening 300 Hz peak was insufficient to identify the real vibration. We now know why: observation timing can erase a physical distinction, and downstream AI cannot recreate it without further assumptions. In our constructed case, filtering at 4 kHz before reducing to 1 kHz preserves the useful component and suppresses its contaminant. The cost is quantifiable in delay, buffers and computation, while hardware performance remains to be tested. Designing embedded AI therefore includes designing how the world becomes data.
Sources, code and reproduction conditions
MIT 6.300 — Sampling and Aliasing, Spring 2026.
Arm CMSIS-DSP — Finite Impulse Response Decimator, main documentation.
Analog Devices — Filter Basics: Anti-Aliasing.
The sources document sampling, anti-aliasing protection and the decimator interface. CMSIS main is mutable documentation accessed on 25 September 2026, not a kernel version we benchmarked. The filter, signals and comparison are constructed in the attached experiment. The snippet calculates gain and delay; the archive adds convolution, amplitude estimation and the figure. We used Python 3.14.0, NumPy 2.5.3 and Matplotlib 3.11.2, with no random numbers. This editorial analysis does not imply that EL-AI already offers embedded products or installations.
import numpy as np
fs, fc, taps = 4000, 400, 129
k = np.arange(taps)
h = (2*fc/fs) * np.sinc((2*fc/fs)*(k-64)) * np.hanning(taps)
h /= h.sum()
for f in (300, 700):
gain = abs(np.sum(h*np.exp(-2j*np.pi*f*k/fs)))
print(f, round(float(gain), 9))
print("delay_ms", 1000*64/fs)
Code, data, and instructions · JSON. Educational calculations executed with Python 3.14.0; figures with Matplotlib 3.11.2. AI-assisted analysis, without claiming peer review or human review. Original illustrative ImageGen cover: it does not document EL-AI people, premises, or installations. Sources accessed 25 September 2026.

