WinFilter я использовал лишь для "рыбы" Си. Его целочисленные коэффициенты практически не работают, чаще всего вызывают переполнение аккумулятора. WinFiltr'у спасибо за код и возможность поиграться. Больше с него не взять. А рабочая лошадка - ELLF.EXE. Вот фильтр из этой программы. Подгонял неравномерность в полосе пропускания до тех пор, пока подавление на 1250Гц не приблизилось к 40дБ. Чем ровнее полоса пропускания, тем меньше точности коэффициентов требуется. Заложил в коэффициенты числителя усиление, чтобы фильтру напрямую подавать отсчёты АЦП без потери динамического диапазона на выходе. Фильтр устойчив к скачку входного сигнала с -2048 до 2048 за один интервал выборки. Используется до 31 разрядов аккумулятора, в 32-бит знаковое вмещаемся.
#include <stdint.h>
/* Author: Nikolay Pokhilchenko, AKA Nikolay_Po, 2018
* Filter parameters:
* Type: low pass, infinite response
* Design type: elliptic
* Coefficients by: ELLF.EXE, Copyright 2014 by Stephen L. Moshier, http://www.moshier.net/ellf.zip
* Computing code idea: WinFilter v0.8
* Order: 2
* Samplerate 10000Hz
* Passband 55Hz
* Stopband 1250Hz
* Passband ripple: 0.01dB
* Stopband min attenuation: 40.8dB
* Input sample width: 12bit signed (+/- 2048)
* Output sample width: 16bit signed
*/
int16_t LPF1250Hz(int16_t NewSample) {
static int32_t y[3]; //output samples
static int16_t x[3]; //input samples
x[2] = x[1];
x[1] = x[0];
x[0] = NewSample;
y[2] = y[1];
y[1] = y[0];
y[0] = (int32_t) 5348 * x[0];
y[0] += (int32_t) - 5232 * x[1] + 15127 * y[1];
y[0] += (int32_t) 5348 * x[2] - 7029 * y[2];
y[0] /= 8192;
return (y[0] / 2);
}
Дальше, пожалуй, ещё раз фильтровать ФНЧ и децимировать. Иначе низким порядком шестнадцати бит точности может не получиться.
Фильтр выше можете использовать в любых целях, на своё усмотрение.
P.S. Шум квантования можно ещё на бит снизить. У аккумулятора запас в два разряда, у деноминатора в один разряд был. С такими коэффициентами аккумулятор используется на 30 бит: Уже поправил код выше. Делением результата на два, увеличил значения коэффициентов номинатора (как по-русски?) и максимальное значение аккумулятора. Коэффициенты используют аккумулятор по-полной. Тест показал, что до 30.88 бит.
P.P.S.
Вот фильтр для второго прореживания:
#include <stdint.h>
/* Author: Nikolay Pokhilchenko, AKA Nikolay_Po, 2018
* Filter parameters:
* Type: low pass, infinite response
* Design type: elliptic
* Coefficients by: ELLF.EXE, Copyright 2014 by Stephen L. Moshier, http://www.moshier.net/ellf.zip
* Computing code idea: WinFilter v0.8
* Order: 4
* Samplerate 2500Hz
* Passband 55Hz
* Stopband 312.5Hz
* Passband ripple: <0.01dB
* Stopband min attenuation: 40.1dB
* Input sample width: 16bit signed (+/-32768)
* Output sample width: 16bit signed
*/
int16_t LPF312Hz(int16_t NewSample) {
static int32_t y[5]; //output samples
static int16_t x[5]; //input samples
x[4] = x[3];
x[3] = x[2];
x[2] = x[1];
x[1] = x[0];
x[0] = NewSample;
y[4] = y[3];
y[3] = y[2];
y[2] = y[1];
y[1] = y[0];
y[0] = (int32_t) 191 * x[0];
y[0] += (int32_t) - 227 * x[1] + 23928 * y[1];
y[0] += (int32_t) 346 * x[2] - 27211 * y[2];
y[0] += (int32_t) -227 * x[3] + 14100 * y[3];
y[0] += (int32_t) 191 * x[4] - 2799 * y[4];
y[0] /= 8192;
return (y[0]/2);
}
Си-код не проверял, но коэффициенты "гонял" в модели "R", контролируя возможные переполнения и учитывая округления целочисленных делений. У последнего фильтра усиление меньше единицы - чтобы избежать переполнения на выбросе переходного процесса, см. вторую картинку.
Итого, после двух прореживаний на 1:4, с 10кГц остаётся 625 отсчётов в секунду.
Попробовал посчитать полосовой фильтр для 625Гц выборки. Если укладываться в 5% неравномерности полосы пропускания, то для 4-го порядка фильтра, при полосе пропускания 45..55Гц и заграждении сверху с 90Гц можно ожидать затухания в 34.6дБ. Если не устраивает, то можно, сохранив порядок фильтра и пожертвовав неравномерностью в полосе пропускания, увеличить затухание. Или делать ещё одно звено ФНЧ с прореживанием.