117. Data from the sensor: windows, features, CMSIS-DSP
The model from section 116 received ready-made numbers — the RMS vibration and the peak frequency. On a device you have to compute them yourself from the stream of accelerometer samples: cut the stream into windows, remove the offset, take the spectrum, find the peak. How this is done matters more than the choice of model: a poor feature spoils any classifier. This section computes the features with the CMSIS-DSP library — the same one that runs on the F407 — only on a PC, where it can be checked against a calculation by the formulas, and shows how one well-chosen feature raises bearing recognition from 80 to 100 cases out of 100.
Models are section 116, the ADC is section 14, DMA is section 9, the accelerometer is section 99.
Terms used in the documentation
Term Meaning sampling rate how many samples are taken per second Nyquist frequency half the sampling rate aliasing high frequencies showing up as false low ones anti-aliasing filter a filter in front of the ADC that removes aliasing frame, window a piece of the signal of N samples fast Fourier transform (FFT) a fast way to compute the spectrum frequency bin the frequency band of one spectrum point spectral leakage the energy of a tone spreading into neighbouring bins window function (Hann) a weighting that tapers the edges of the window parabolic interpolation refining the peak with a parabola DC offset the constant component, the zero offset crest factor the largest value / RMS band energy the energy within a frequency band
117.1 From the sensor to the features
The chain on the device: accelerometer → ADC triggered by a timer, DMA stores the samples → a window of 256 samples → features → the model's decision. At a sampling rate of 1024 Hz a window lasts 250 ms, and a decision is ready four times a second; windows with half overlap give a decision every 125 ms. Everything below is about how to get from these 256 numbers two or three features you can trust.
117.2 Sampling rate and aliasing
Sampling tells frequencies apart only up to half its own rate: at 1024 Hz, up to 512 Hz. Everything above does not disappear but pretends to be a low frequency. Experiment: a 160 Hz tone sampled at 256 Hz landed in the spectrum at 96 Hz — 256 − 160. Such a false peak cannot be told from a real one by the spectrum, so the sampling rate is chosen with a margin above the highest frequency of interest, and a filter is placed in front of the ADC that suppresses everything above half the sampling rate.
117.3 The window: time against resolution
The spectrum of a window of N samples is divided into bins of width FS / N: at 1024 Hz and 256 samples, 4 Hz. A longer window gives narrower bins, but you wait longer for a decision and fast changes are harder to see. A 24 Hz tone falls exactly on bin 6, and the peak comes out at 24.0000 Hz, and the RMS at 0.3536 for an amplitude of 0.5: exactly 0.5 / √2, because a whole number of periods fit into the window.
117.4 Leakage and the Hann window
A 25 Hz tone does not fall on a bin, and its energy spreads into the neighbouring bins — leakage. Without a window, five bins away from the peak there is still −24.89 dB: this is enough to hide a weak bearing tone next to a strong one. The Hann window smoothly tapers the edges of the segment, and at the same place there is −52.81 dB. The window is applied before the transform, with one multiplication:
if (hann)
arm_mult_f32(buf, win, buf, N_WIN);
117.5 A peak between bins
The bin number gives the frequency in steps of 4 Hz. More precisely — the vertex of a parabola through the magnitudes of three neighbouring bins:
static float refine(uint32_t k)
{
if (k == 0 || k >= N_WIN / 2 - 1)
return (float)k;
float a = mag[k - 1], b = mag[k], c = mag[k + 1];
float den = a - 2.0f * b + c;
return den != 0.0f ? (float)k + 0.5f * (a - c) / den : (float)k;
}
For a 25 Hz tone without a window the parabola gives 24.19 Hz, with the Hann window 24.80 Hz. The window is needed here too: its peak is closer to a parabola in shape.
117.6 Offset, RMS and crest factor
An accelerometer powered from a single supply outputs vibration around the middle of the scale — for example, 1.65 V. This constant component is subtracted before anything else, otherwise it gets into the RMS and occupies the zero bin. Experiment: a 160 Hz tone with an amplitude of 0.5 on top of an offset of 1.65 — RMS 0.3536, the same as without the offset, and the peak exactly at 160.00 Hz. The crest factor is the largest value divided by the RMS: for a pure sine it is 1.4142, that is √2, while the impacts of a spalled bearing raise it noticeably higher — one more feature, almost for free.
117.7 A feature that fits the physics of the defect
Three motor states — 100 windows each, with amplitude spread of ±30 %, frequency spread and noise — and the threshold from section 116 on features computed from the signal:
| Normal | Imbalance | Bearing | |
|---|---|---|---|
| By peak frequency: correct | 100 | 82 | 80 |
| By energy in the 100–248 Hz band: correct | 100 | 82 | 100 |
By the frequency of the highest peak the bearing is recognized in only 80 windows out of 100: when the 25 Hz rotation tone turns out stronger than the defect tone, the peak moves to 25 Hz, and in 17 windows the bearing is taken for normal. The mean peak frequency for the bearing is 131.7 Hz instead of 160. The feature "share of energy in the 100–248 Hz band is greater than 0.1" asks not "where is the main peak" but "is there energy where the bearing sounds" — and recognizes it in all 100 windows. Imbalance is still confused with normal in 18 windows: they have the same frequency and a similar RMS, and that is already a question of data and model — sections 118–120.
arm_power_f32(mag + 1, N_WIN / 2 - 1, &e_all);
arm_power_f32(mag + BAND_LO, BAND_HI - BAND_LO + 1, &e_band);
f->band = e_all > 0.0f ? e_band / e_all : 0.0f;
117.8 CMSIS-DSP on the F407
The whole feature calculation is CMSIS-DSP calls:
arm_mean_f32(x, N_WIN, &mean); /* смещение нуля датчика и АЦП */
arm_offset_f32(x, -mean, buf, N_WIN);
arm_rms_f32(buf, N_WIN, &f->rms);
arm_absmax_f32(buf, N_WIN, &peak, &k);
The image for the F407 with the Keil startup file took 8964 bytes of code and 2920 bytes
of FFT tables in flash, and 6272 bytes of RAM — the window, spectrum
and sample buffers plus the stack and heap of the startup file. One line decides how much
the tables take: the generic arm_rfft_fast_init_f32 accepts any size
and therefore pulls tables for all sizes into the image — 79504 bytes, 27 times
more. Initialization for one size keeps only the ones needed:
return arm_rfft_fast_init_256_f32(&fft) == ARM_MATH_SUCCESS;
On a PC the same library is built by gcc in __GNUC_PYTHON__ mode,
and all the experiments of the section are computed with it; the check compared them with a calculation by
the formulas.
117.9 Pitfalls
There is a peak in the spectrum that the mechanism does not have. Aliasing: the sampling rate is too low or there is no filter in front of the ADC. 160 Hz at 256 Hz looks like 96 Hz.
The peak "wanders" between neighbouring frequencies. The tone does not fall on a bin. The Hann window and parabolic refinement.
The RMS does not drop to zero on a stopped motor. The constant component of the sensor is not subtracted.
The firmware grew by 75 KB from a single FFT. The generic initialization pulls in
tables for all sizes; use arm_rfft_fast_init_256_f32.
The bearing is visible one moment and not the next. The feature is "frequency of the main peak": with a strong rotation tone the peak moves to it. Use the energy in the defect band.
117.10 Summary
- 1024 Hz and 256 samples: a 250 ms window, a 4 Hz bin, frequencies resolved up to 512 Hz.
- Aliasing cannot be cured after the ADC: 160 Hz at 256 Hz is 96 Hz.
- Hann window: leakage of −52.81 dB instead of −24.89; the 25 Hz peak is refined to 24.80 Hz.
- The feature is chosen to fit the physics: energy in the bearing band gives 100 out of 100 against 80 for the peak frequency.
- CMSIS-DSP on the F407: 2920 bytes of tables with initialization for one size against 79504 for the generic one.
Full sources
feat117.c — vibration features from a window of samples with CMSIS-DSP.
/* Раздел 117: признаки вибрации из окна отсчётов — на CMSIS-DSP.
* Окно N_WIN отсчётов при FS: постоянная составляющая долой, СКЗ и пик-
* фактор, окно Ханна, быстрое преобразование Фурье, модуль спектра, пик
* и его уточнение параболой между бинами. Тот же файл собирается armclang
* для F407 и gcc на компьютере (CMSIS-DSP в режиме __GNUC_PYTHON__) —
* там feat117_host.c ставит опыты. Проверка — _verify/ml117_check.py. */
#include "arm_math.h"
#define FS 1024.0f /* Гц: частота выборки */
#define N_WIN 256u /* отсчётов в окне: 250 мс, 4 Гц на бин */
#define BAND_LO 25u /* бин 25 — 100 Гц: полоса дефекта подшипника */
#define BAND_HI 62u /* бин 62 — 248 Гц */
typedef struct {
float rms; /* СКЗ без постоянной составляющей */
float peak_hz; /* частота пика, уточнённая параболой */
float crest; /* пик-фактор: наибольший модуль / СКЗ */
float band; /* доля энергии спектра в полосе 100–248 Гц */
uint32_t bin; /* номер бина пика до уточнения */
} features_t;
static float win[N_WIN], buf[N_WIN], spec[N_WIN], mag[N_WIN / 2];
static arm_rfft_fast_instance_f32 fft;
/* инициализация под один размер: общая arm_rfft_fast_init_f32 тянет в образ таблицы всех размеров */
_Static_assert(N_WIN == 256u, "размер окна совпадает с arm_rfft_fast_init_256_f32");
int features_init(void)
{
arm_hanning_f32(win, N_WIN);
#ifdef FFT_ALL_SIZES /* для сравнения размеров образа */
return arm_rfft_fast_init_f32(&fft, N_WIN) == ARM_MATH_SUCCESS;
#else
return arm_rfft_fast_init_256_f32(&fft) == ARM_MATH_SUCCESS;
#endif
}
/* пик между бинами: вершина параболы через три соседних модуля */
static float refine(uint32_t k)
{
if (k == 0 || k >= N_WIN / 2 - 1)
return (float)k;
float a = mag[k - 1], b = mag[k], c = mag[k + 1];
float den = a - 2.0f * b + c;
return den != 0.0f ? (float)k + 0.5f * (a - c) / den : (float)k;
}
void features(const float *x, int hann, features_t *f)
{
float mean, peak, m;
uint32_t k;
arm_mean_f32(x, N_WIN, &mean); /* смещение нуля датчика и АЦП */
arm_offset_f32(x, -mean, buf, N_WIN);
arm_rms_f32(buf, N_WIN, &f->rms);
arm_absmax_f32(buf, N_WIN, &peak, &k);
f->crest = f->rms > 0.0f ? peak / f->rms : 0.0f;
if (hann)
arm_mult_f32(buf, win, buf, N_WIN);
arm_rfft_fast_f32(&fft, buf, spec, 0); /* buf служит рабочим — он больше не нужен */
arm_cmplx_mag_f32(spec, mag, N_WIN / 2);
mag[0] = 0.0f; /* в первой паре — ноль и Найквист вместе: отбросить */
arm_max_f32(mag, N_WIN / 2, &m, &f->bin);
f->peak_hz = refine(f->bin) * FS / N_WIN;
float e_all, e_band; /* энергия — сумма квадратов модулей */
arm_power_f32(mag + 1, N_WIN / 2 - 1, &e_all);
arm_power_f32(mag + BAND_LO, BAND_HI - BAND_LO + 1, &e_band);
f->band = e_all > 0.0f ? e_band / e_all : 0.0f;
}
/* модуль спектра последнего окна — для опытов и рисунка */
const float *features_spectrum(void)
{
return mag;
}
Next: section 118 "Training a small model in a container" — from windows with features to weights in the firmware.