ФНЧ Баттерворта

Все что касается фильтрации
Rem
Сообщения: 34
Зарегистрирован: 13 май 2014, 20:20

ФНЧ Баттерворта

Сообщение Rem »

Здравствуйте. Я пытаюсь создавать программы для музыкальных инструментов (в основном для гитары). Демонстрацию рабочей версии можете посмотреть тут - https://www.youtube.com/watch?v=D-F2KHjamFg
Пришел попросить помощи для выбора фильтра. Частота стандартная 44100 Гц. Размер захватываемого буфера 1024 семпла. Частота высокой ноты на 1 струне 12 ладу примерно 660 Гц. (На самом деле бывает и выше, но для обучения достаточно такого диапазона). Сейчас после захвата (на скрине верхний график) применяется скользящее среднее (нижний график), но это плохой вариант.
Как я понял, фильтр Баттерворта оставляет низкие частоты практически не тронутыми и заглушает высокие частоты. Я бы хотел с вашей помощью применить его к своим программам. Пока изучаю теорию, потом приду с кодом на проверку.
Вложения
2015-01-28 00 52 50.png
2015-01-28 00 52 50.png (6.49 КБ) 9389 просмотров

Rem
Сообщения: 34
Зарегистрирован: 13 май 2014, 20:20

Re: ФНЧ Баттерворта

Сообщение Rem »

Для изучения фильтра решил накидать генератор синусоиды. Потом можно будет генерировать разные частоты, длительности, и отправлять массив на фильтрацию с разными параметрами.
RND сделал чтоб смещение фазы было. M_PI может быть вам придется писать по другому, или число вставить.

Код: Выделить всё

#include <stdio.h>
#include <math.h>

#define FREQ 44100
#define BUFER_SIZE 512
#define RAND 346

int main(void) {
	int i;
	float freq=440;
	float sin_array [BUFER_SIZE];
	
	for(i=0; i<=BUFER_SIZE; i++){
		sin_array[i]= sin ((i+RAND) * 2 *  M_PI *freq / FREQ);
		printf ("%i %f\n", i, sin_array[i]);
	}
	return 0;
}

Аватара пользователя
Santik
Сообщения: 609
Зарегистрирован: 28 дек 2010, 08:04
Откуда: Мирный (Якутия)
Контактная информация:

Re: ФНЧ Баттерворта

Сообщение Santik »

Какая-то совсем неправильная программа :shock:
Если я Вас правильно понял, Вы хотели написать:

Теперь посмотрим, что у Вас:
t=(i+RAND)/FREQ - это вообще непонятно.

1. начальную фазу надо вычислять вне цикла
2. 2 * M_PI *freq / FREQ- надо вычислять вне цикла
и вообще что это freq / FREQ???

Код: Выделить всё

int main(void) {
   int i;
   float freq=440;
   float freq_d=44100;
   float Pi=3.14159265358;
   float sin_array [BUFER_SIZE];
   float faza,z;
   
   faza=2*Pi*RAND;// подразумевается что функция RAND возвращает случайное число от 0.0 до 1.0
   z=2*Pi*freq/freq_d;
   for(i=0; i<=BUFER_SIZE; i++){
      sin_array[i]= sin (i*z+faza);
      printf ("%i %f\n", i, sin_array[i]);
   }
   return 0;
}
Советую написать генератор сигнала, который бы автоматически генерировал гармоники.

Rem
Сообщения: 34
Зарегистрирован: 13 май 2014, 20:20

Re: ФНЧ Баттерворта

Сообщение Rem »

Можно изменить для понятности

Код: Выделить всё

#define SAMPLE_RATE 44100
#define BUFER_SIZE 512
#define RAND 0
Я амплитуду рассчитываю от номера семпла, а не от значения времени. И RAND смещается на произвольный семпл. В том месте начальная амплитуда не равна нулю.
Для объективности приведу несколько значений. Начало синусоиды:
0 0.000000
1 0.062648
2 0.125051
3 0.186961
Конец первой волны и начало второй происходит около сотого семпла.
99 -0.076861
100 -0.014247
101 0.048423
102 0.110903
Давайте сравним с вашими расчётами и убедимся, что всё верно.
Пожалуй надо будет генерацию в отдельную функцию вынести, чтоб можно было в один массив примешивать произвольное количество синусин с произвольными частотой и амплитудой. Но сначала надо разобраться с одной.

Rem
Сообщения: 34
Зарегистрирован: 13 май 2014, 20:20

Re: ФНЧ Баттерворта

Сообщение Rem »

Ещё я с частотой не могу определиться :)
Гарантировано должно передаваться без искажений до ноты МИ второй октавы = 659.26 Гц
Диапазон гитары примерно до 20 лада, до ноты ДО третьей октавы = 1046.5 Гц
Если тренажер переделать под стандартные инструменты (клавишные) то он может задавать ноты до ноты МИ третьей октавы (1318.5 Гц)
Как рассчитать коэффициенты для этих частот? Можно округлить, например 700, 1000, 1300.

Статьи для себя, чтоб не потерять.
Расчет аналогового нормированного фильтра нижних частот Баттерворта
Пример расчета цифрового фильтра нижних частот Баттерворта

Аватара пользователя
Santik
Сообщения: 609
Зарегистрирован: 28 дек 2010, 08:04
Откуда: Мирный (Якутия)
Контактная информация:

Re: ФНЧ Баттерворта

Сообщение Santik »

Rem писал(а): Пожалуй надо будет генерацию в отдельную функцию вынести, чтоб можно было в один массив примешивать произвольное количество синусин с произвольными частотой и амплитудой. Но сначала надо разобраться с одной.
Можно проще сделать. Взять одну синусоиду и ограничить ее по амплитуде. Наличие гармоник будет гарантировано! Если ограничить симметрично то будут отсутствовать чётные гармоники.
Sin_ogr.JPG
О частотах (может я не совсем правильно понял вопрос?):
https://ru.wikipedia.org/ :
Можно математически вычислить частоты для всего звукоряда, пользуясь формулой:

где f0 — частота камертона (например Ля 440 Hz), а i — количество полутонов в интервале от искомого звука к эталону f0.
Последовательность вычисленных таким образом частот образует геометрическую прогрессию:
например, можно вычислить частоту звука на тон (2 полутона) ниже от камертона Ля — ноты соль:
i=-2

если нам надо вычислить ноту Соль, но на октаву (12 полутонов) выше:
i=12-2=10

Частоты двух полученных нот Соль отличаются в два раза, что дает чистую октаву. Преимущества равномерной темперации также в том, что можно произвольно транспонировать пьесу на произвольный интервал вверх или вниз.
Последний раз редактировалось Santik 15 фев 2015, 08:14, всего редактировалось 1 раз.

Аватара пользователя
Santik
Сообщения: 609
Зарегистрирован: 28 дек 2010, 08:04
Откуда: Мирный (Якутия)
Контактная информация:

Re: ФНЧ Баттерворта

Сообщение Santik »

Rem писал(а): Я амплитуду рассчитываю от номера семпла, а не от значения времени. И RAND смещается на произвольный семпл. В том месте начальная амплитуда не равна нулю.
Дело в том что RAND вычисляется внутри цикла! И это неправильно! Получилась синусоида с частотной модуляцией!

Код: Выделить всё

Dt=RAND;
 for(i=0; i<=BUFER_SIZE; i++){
      sin_array[i]= sin ((i+Dt) * 2 *  M_PI *freq / FREQ);
      printf ("%i %f\n", i, sin_array[i]);
   }
   return 0;
}
И ещё:
#define SAMPLE_RATE 44100 ????
SAMPLE_RATE по определению = 1/Fd=1/44100!

Rem
Сообщения: 34
Зарегистрирован: 13 май 2014, 20:20

Re: ФНЧ Баттерворта

Сообщение Rem »

Если фильтр второго порядка, и частота среза 1300Гц - такие условия достаточны для расчёта?

Аватара пользователя
Santik
Сообщения: 609
Зарегистрирован: 28 дек 2010, 08:04
Откуда: Мирный (Якутия)
Контактная информация:

Re: ФНЧ Баттерворта

Сообщение Santik »

Да, достаточно.
Баттерворд1300.JPG

Rem
Сообщения: 34
Зарегистрирован: 13 май 2014, 20:20

Re: ФНЧ Баттерворта

Сообщение Rem »

Ух как хорошо получилось :)
В данном примере я генерирую несколько синусоид. Измеряю максимальную амплитуду. Потом отправляю на фильтрацию. Измеряю новую амплитуду. На скрине видно, как уменьшаются итоговые значения от увеличения частоты.
Единственный вопрос. В итоговом массиве Y первые два значения присвоил нулю. Правильно сделал?
Весь код на си:

Код: Выделить всё

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define SAMPLE_RATE 44100
#define BUFER_SIZE 10000

void SinGen( float freq, int bufersize, int samplrate, float * sampleblock);
float FindMaxAmpl( float * sampleblock , int bufersize);
void Butterworth (float * sampleblock , int bufersize);

int main()
{
    printf("Butterworth filter\n");
    float FreqArr[]={250, 500, 1000, 2000, 4000, 8000, 16000, 22000};
    float sin_array [BUFER_SIZE];
    int i;
    float MaxAmpl=0, MaxAmplFilter=0;

    for (i=0; i<8; i++){
        //генерируем разные синусоиды
        SinGen(FreqArr[i], BUFER_SIZE, SAMPLE_RATE, sin_array);

        //находим макисмальную амплитуду
        MaxAmpl = FindMaxAmpl (sin_array, BUFER_SIZE);

        //отправляем на фильтрацию по Баттерворту
        Butterworth (sin_array, BUFER_SIZE);

        //находим макс амплитуту после фильтрации
        MaxAmplFilter = FindMaxAmpl (sin_array, BUFER_SIZE);

        //выводим результаты
        printf ("f=%f max=%f max_filter=%f\n", FreqArr[i], MaxAmpl, MaxAmplFilter);
    }
    return 0;
}

void SinGen( float freq, int bufersize, int samplrate, float * sin_array)
{
    // генерируем массив семплов для синусоиды
    int i;
    int random = rand()%10000;
    for ( i=0; i<bufersize ; i++){
    	sin_array[i]= sin ((i+random) * 2 * M_PI *freq / samplrate); // вместо 0 можно поставить rand();
    }
    return;
}

float FindMaxAmpl( float * sampleblock , int bufersize)
{
    int i;
    float Max=0;

    for ( i=0; i<bufersize ; i++){
          //  printf("buf[i]=%f \n", sampleblock[i] );
        if ( fabs(sampleblock[i]) > Max) Max = fabs (sampleblock[i]);
    }
    return Max;
}

void Butterworth(float * X , int bufersize)
{
    //коэффициенты фильтра Баттерворта второго порядка
    float b1 = 0.01413248273498;
    float b2 = 0.02826496546996;
    float b3 = 0.01413248273498;

    float a1 = 1.0;
    float a2 = -1.636681376728;
    float a3 = 0.693211307667;

    float Y[bufersize]; // для фильтрованного сигнала
    Y[0] = 0;
    Y[1] = 0;
    int k;
    for ( k=2; k<bufersize; k++){
        Y[k] = b1*X[k] + b2*X[k-1] + b3*X[k-2] - a2*Y[k-1] - a3*Y[k-2];
    }
    // переносим в исходный массив
    for ( k=0; k<bufersize; k++) X[k] = Y[k];
    return;
}
Вложения
2015-02-26 05 22 52.png

Ответить