Перейти к содержанию
    

Полосовой фильтр с помощью CMSIS DSP

Научите как сделать на STM32 полосовой фильтр на 1 кГц.  Нужно знать есть ли сигнал с чакстотой 1 кГц. Спасибо.

Изменено пользователем haker_fox
Переименовал тему. Переместил в раздел STM32.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, smk сказал:

Научите как сделать на STM32 полосовой фильтр на 1 кГц.  Нужно знать есть ли сигнал с чакстотой 1 кГц. Спасибо.

Так же как и не на STM32: Поставить Matlab, запустить его компонент FDAtool и смоделировать фильтр в нём. Затем - перенести полученную таблицу коэффициентов в программу в МК.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Есть довольно старый бесплатный пакет Winfilter. Можно попробовать его, если нет Матлаба.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Spoiler
// Расчёт фильтра нижних частот
// Расчёт фильтра без наложения оконной функции
static void fir_design_lowpass(FLOAT_t *dCoeff, int iCoefNum, FLOAT_t m_fCutHigh)
{
	const int iHalfLen = (iCoefNum - 1) / 2;
	int iCnt;

	/*------------------*/
	/*  Lowpass filter  */
	/*------------------*/

	dCoeff [iHalfLen] = m_fCutHigh;
	for (iCnt = 1; iCnt <= iHalfLen; iCnt ++)
	{
		const FLOAT_t a = (FLOAT_t) M_PI * iCnt;
		const FLOAT_t k = SINF(m_fCutHigh * a) / a;
		dCoeff [iHalfLen - iCnt] = k;
	}
}

// Расчёт фильтра - пробки
// ((CutLow > 0.0) && (CutHigh < 1.0) && (CutLow < CutHigh))
// Расчёт фильтра без наложения оконной функции
static void fir_design_bandstop(FLOAT_t * dCoeff, int iCoefNum, FLOAT_t fCutLow, FLOAT_t fCutHigh)
{
	const int iHalfLen = (iCoefNum - 1) / 2;
	int iCnt;

	/*------------------*/
	/* Bandstop filter  */
	/*------------------*/
	//if ((CutLow > 0.0) && (CutHigh < 1.0) && (CutLow>CutHigh)) {

	dCoeff [iHalfLen] = fCutLow - fCutHigh;   
	for (iCnt = 1; iCnt <= iHalfLen; iCnt ++) 
	{ 
		const FLOAT_t a = (FLOAT_t) M_PI_2 * iCnt;	// M_PI_2 - constant pi/2
		const FLOAT_t k = SINF((fCutLow - fCutHigh) * a) * COSF((fCutHigh + fCutLow) * a) / a;  
		dCoeff [iHalfLen - iCnt] = k;
	}   

	dCoeff [iHalfLen] += 1;   
}

// Расчёт фильтра без наложения оконной функции
static void fir_design_passtrough(FLOAT_t * dCoeff, int iCoefNum, FLOAT_t dGain)
{
	const int iHalfLen = (iCoefNum - 1) / 2;
	int iCnt;

	for (iCnt = 1; iCnt <= iHalfLen; iCnt ++)
	{
		dCoeff [iHalfLen - iCnt] = 0;
	}
	dCoeff [iHalfLen] = dGain;
}

// Без наложения оконной функции
static void fir_design_bandpass(FLOAT_t * dCoeff, int iCoefNum, FLOAT_t fCutLow, FLOAT_t fCutHigh)
{
	const int iHalfLen = (iCoefNum - 1) / 2;
	int iCnt;

	dCoeff [iHalfLen] = fCutHigh - fCutLow;
	for (iCnt = 1; iCnt <= iHalfLen; iCnt ++)
	{
		const FLOAT_t a = (FLOAT_t) M_PI_2 * iCnt;	// M_PI_2 - constant pi/2
		const FLOAT_t k = SINF((fCutHigh - fCutLow) * a) *
										 COSF((fCutHigh + fCutLow) * a) / a;
		dCoeff [iHalfLen - iCnt] = k;
	}
}

 

Это расчеты для симметричных FIR (с нечетным количеством отводов) - формирует половинку от массива.
Для увеличения крутизны скатов еще "оконную" функцию к массиву применяют.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Мне бы пример полосового фильтра на какую-то частоту и что пересчитывать нужно если частота другая нужна. Спасибо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 1/16/2023 at 5:06 PM, smk said:

Мне бы пример полосового фильтра на какую-то частоту и что пересчитывать нужно если частота другая нужна. Спасибо.

Наьираете в гуле чтото типа FIR Filter C

Смотрите ссылки где то что вас интересует

Например

https://sestevenson.wordpress.com/implementation-of-fir-filtering-in-c-part-1/

https://stackoverflow.com/questions/14997850/fir-filter-implementation-in-c-programming

https://lloydrochester.com/post/c/fir-filter/

https://dspguru.com/dsp/tricks/fir-filtering-in-c/

https://dspguru.com/dsp/tricks/fir-filtering-in-c/

https://github.com/topics/fir-filter

итд. 

Для СТМ32

https://embeddedexpert.io/?p=763

Кстати у стм есть ДСП библиотека с примерами  и готовыми функциями
тоже можете вполне использовать 

 

 

Посмотрите на структурные схемы ФИРа , поймите что есть что и реализация абсолютно проста, математика программирования не сложная 

Тогда сможете использовать различные визарды фильтров. Но если на раз и забыть то чтото найдете в примерах выше

Изменено пользователем spirit_1

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 hours ago, smk said:

Мне бы пример полосового фильтра на какую-то частоту и что пересчитывать нужно если частота другая нужна. Спасибо.

Упомянутый Winfilter генерирует С-код.

Пересчитвать коэффициенты в микроконтроллере "налету", так, чтобы получить любую полосу и частоту проблематично. Разве что, если это простой фильтр. Если требуется обнаружить 1 кГц или какую-то другую одну частоту - может быть подумать о преобразовании Герцеля?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

15 hours ago, Aleksandr Baranov said:

Есть довольно старый бесплатный пакет Winfilter. Можно попробовать его, если нет Матлаба.

Ещё онлайн есть такая штука http://t-filter.engineerjs.com , FIR мне понравился

image.thumb.png.f4f02808181259d6c76b76470efcb8f4.png

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как это использовать?
 

void SampleFilter_init(SampleFilter* f) {
  int i;
  for(i = 0; i < SAMPLEFILTER_TAP_NUM; ++i)
    f->history[i] = 0;
  f->last_index = 0;
}

void SampleFilter_put(SampleFilter* f, double input) {
  f->history[f->last_index++] = input;
  if(f->last_index == SAMPLEFILTER_TAP_NUM)
    f->last_index = 0;
}

double SampleFilter_get(SampleFilter* f) {
  double acc = 0;
  int index = f->last_index, i;
  for(i = 0; i < SAMPLEFILTER_TAP_NUM; ++i) {
    index = index != 0 ? index-1 : SAMPLEFILTER_TAP_NUM-1;
    acc += f->history[index] * filter_taps[i];
  };
  return acc;
}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

15 часов назад, smk сказал:

Мне бы пример полосового фильтра на какую-то частоту и что пересчитывать нужно если частота другая нужна. Спасибо.

Если вам нужно обнаруживать сигналы с разными частотами, то советую БПФ он же FFT . Ничего не надо будет пересчитывать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

27 minutes ago, smk said:

Как это использовать?
 

void SampleFilter_init(SampleFilter* f) {
  int i;
  for(i = 0; i < SAMPLEFILTER_TAP_NUM; ++i)
    f->history[i] = 0;
  f->last_index = 0;
}

void SampleFilter_put(SampleFilter* f, double input) {
  f->history[f->last_index++] = input;
  if(f->last_index == SAMPLEFILTER_TAP_NUM)
    f->last_index = 0;
}

double SampleFilter_get(SampleFilter* f) {
  double acc = 0;
  int index = f->last_index, i;
  for(i = 0; i < SAMPLEFILTER_TAP_NUM; ++i) {
    index = index != 0 ? index-1 : SAMPLEFILTER_TAP_NUM-1;
    acc += f->history[index] * filter_taps[i];
  };
  return acc;
}

 

Так всё же понятно:

- Завести переменную - структуру SampleFiler, передать её в начале в инит (там просто нулями заполняется массив сэмплов).

- Очередной сэмпл положить в массив функцией ..._put()

- Забрать c выхода фильтра тоже очередное значение .._get()

 

Но вам тут выше посоветовали для вашей задачи (обнаружение частоты) - быстрее Гертцелем

 

Изменено пользователем TU-104

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 1/17/2023 at 8:16 AM, Lmx2315 said:

Если вам нужно обнаруживать сигналы с разными частотами, то советую БПФ он же FFT . Ничего не надо будет пересчитывать.

Герцель в самый раз для такого, 

#define PI 3.14159265358979323846 
#define buffer_size 44100 
double samples[buffer_size]; 
double FS = 44100.0; //fréquence d'échantillonnage 
double FDETECT = 1000.0; // fréquence à détecter 

int K; 
double coefficient; 
double W; 
double sine; 
double cosine; 
double Q0, Q1, Q2; 
double real; 
double imag; 
double magnitude; 
double scalingFactor; 
int i; 

K = (int) (0.5 + ((buffer_size * FDETECT) / FS));
W = (2.0 * PI * K) / buffer_size; 
cosine = cos(W); 
sine = sin(W); 
coefficient = 2 * cos(W); 
scalingFactor = buffer_size / 2.0; 

Q0 = 0; 
Q1 = 0; 
Q2 = 0; 
	
for (i=0 ; i<buffer_size ; i++) 
 {
  Q0 = samples[i] + (coefficient * Q1) - Q2;
  Q2 = Q1;
  Q1 = Q0;
 }
real = (Q0 - (Q1 * cosine)) / scalingFactor; 
imag = (- Q1 * sine) / scalingFactor;	
magnitude = sqrt(real * real + imag * imag);

Пример из Википедии

Думаю все понятно

double FS- часота вашего АЦП

double FDETECT- частота детекции

double samples[buffer_size]; буфер  с отсчетами

magnitude = sqrt(real * real + imag * imag); - амлитуда сигнала

Если надо постоянно отслеживать амплитуду то постоянно суете samples как переменную 

и в magnitude = sqrt(real * real + imag * imag); забираете амплитуду вашей частоты

Изменено пользователем spirit_1

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Полезная тема, надо положить её в закладки.

А вот еще тогда такой вопрос. В некоторых ЫЕЬ32-микроконтроллерах есть DFDSM - цифровой фильтр для сигма-дельта модуляции. Я немного поискал по этой теме и понял, что такое и как выглядит сигма-дельта модуляция. Теперь вопрос - этот модуль DFDSM в микроконтроллере, на нем можно ли построить цифровой фильтр частот? Как я понял, источник сигма-дельта сигнала нужен внешний, то есть внешний АЦП с таким выходом. Окей. А модуль DFSDM в микроконтроллере, он только преобразует входной сигма-дельта сигнал в числовые значения или же еще каким-то образом является цифровым фильтром частот?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...