A sensor product lives or dies on whether its numbers mean anything. Plenty of devices ship with a good sensor, a good microcontroller, and readings that jump around, drift, respond half a second late, or report a heartbeat that is actually a fluorescent light. The cause is almost never the hardware. It is that nobody made deliberate decisions about sampling, filtering, and arithmetic — cheap early, expensive after tooling.
Sampling: Nyquist and the filter you cannot skip
Nyquist says you must sample at more than twice the highest frequency present in the signal. The part that trips people up is present in the signal, not of interest to you. Sample a vibration sensor at 1 kHz for a 200 Hz feature, and energy at 1.4 kHz does not disappear — it folds back as a false 400 Hz component, indistinguishable from a real one, and no software filtering can remove it.
The fix is an analog anti-alias filter before the ADC, with its corner below half your sample rate. Even a simple RC network beats nothing; a second- or third-order active filter is standard where accuracy matters. Oversample by 4x to 10x rather than the theoretical 2x, then decimate in software — and put the filter on the schematic at the first review, because adding an op-amp stage later is a respin. Typical rates: 8–16 kHz for voice, 48 kHz for audio, 250–1000 Hz for ECG, 100–1600 Hz for IMU motion.
ADC resolution, and why 12 bits is not 12 bits
A datasheet says 12-bit or 16-bit. What you get is ENOB — effective number of bits — after noise, routinely two to four bits worse. A 12-bit ADC sharing ground with a switching regulator may deliver 9 usable bits, the difference between resolving 0.1 °C and 0.5 °C. What buys back real bits: a separately routed analog ground, a dedicated low-noise reference, source impedance low enough for the sample-and-hold, and oversampling with averaging, which gains about one bit per factor of four in extra samples. Whether your part's ADC suffices is one of the questions in how to choose a microcontroller, and a common reason projects add an external delta-sigma converter.
Fixed point or floating point
Modern Cortex-M4F, M7, and M33 parts have a single-precision FPU, and using floats is usually right. Most of these FPUs handle only single precision, so a stray double from a math.h call falls back to software emulation at 10x to 50x the cycles. Watch the literals — 0.5 instead of 0.5f drags an entire filter into double precision.
Fixed point still wins on M0+ and M3 parts with no FPU, on the tightest power budgets, and where you need bit-exact reproducibility with a desktop model. Q15 and Q31 with saturating arithmetic are conventional; get the headroom analysis wrong and a filter overflows into garbage on a loud input.
FIR versus IIR
| FIR | IIR | |
|---|---|---|
| Stability | Always stable | Can go unstable, especially in fixed point |
| Phase | Can be exactly linear | Nonlinear phase |
| Taps for a sharp cutoff | Many (50–200+) | Few (a handful of biquad stages) |
| CPU and memory | Higher | Much lower |
Use FIR when phase matters — comparing timing between channels, or where a waveform's shape is the measurement, as in ECG morphology. Use cascaded IIR biquads when you need a steep response cheaply, which covers most noise rejection. A practical default: a fourth-order Butterworth low-pass as two biquads, plus a notch at 60 Hz near mains wiring.
The moving average trap
The moving average is the filter everyone reaches for because it is four lines of code. It is a poor low-pass, and it adds latency equal to roughly half the window: a 64-sample average at 100 Hz adds about 320 ms of delay. On a temperature display nobody notices; on a button or a control loop, that is a broken product. For low-latency smoothing use an exponential moving average, a one-pole IIR with one tunable coefficient; to reject spikes use a median filter over 5 to 9 samples.
FFT sizing
Frequency resolution equals sample rate divided by FFT length; the time window equals FFT length divided by sample rate, and you cannot improve one without hurting the other. At 1 kHz sampling, a 256-point FFT gives about 3.9 Hz resolution over a 256 ms window; a 1,024-point FFT gives about 1 Hz over one second. Pick the length from the resolution you need, then check the window against your promised response time. Apply a window function — Hann is the safe default — or leakage smears every peak, and budget memory: a 1,024-point FFT in floats needs several kilobytes of buffers, real money on a part with 32 KB of RAM, part of how much flash and RAM your microcontroller really needs.
CMSIS-DSP and the compute budget
Do not hand-write filters. Arm's CMSIS-DSP library ships optimized FIR, biquad, FFT, and statistics functions in fixed and floating point, uses the SIMD and MAC instructions properly on M4/M7 parts, and typically beats naive C by two to five times. Then budget on paper: one FIR tap is about one cycle per sample on a Cortex-M4F, so a 100-tap FIR at 8 kHz is around 800,000 cycles per second — fine on an 80 MHz part, impossible alongside a radio stack on a 16 MHz one.
Power follows. On a battery product the question is whether the MCU can do the math in a burst and sleep again, the subject of low-power firmware and sleep modes: fill a DMA buffer while the core sleeps, wake once per block, process, sleep. Where classification rather than filtering is the goal, a small learned model may cost less than a hand-tuned pipeline — see machine learning on a microcontroller.
Getting it right the first time
Two habits prevent most DSP disasters. Capture raw, unfiltered data from real hardware in the real environment early, and design the chain against that recording offline before writing firmware. And keep a debug command in production firmware that streams raw samples off the device — when a customer reports bad readings, that is the difference between a diagnosis and a guess, and it makes the chain testable off-target, the answer to unit testing embedded code. The front end matters as much as the math, whether a MEMS microphone or an IMU in a wearable.
Projects House designs sensor front ends and the signal chain together, so the analog filtering, the converter, and the firmware math are chosen as one system. If your product depends on measuring something accurately, tell us what through the contact form.