Jump to content
    

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

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

Edited by haker_fox
Переименовал тему. Переместил в раздел STM32.

Share this post


Link to post
Share on other sites

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

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

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

А можно пример какой-то? В части контроллера.

Share this post


Link to post
Share on other sites

CMSIS-DSP\Examples\ARM\arm_fir_example

не?

 

Share this post


Link to post
Share on other sites

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 (с нечетным количеством отводов) - формирует половинку от массива.
Для увеличения крутизны скатов еще "оконную" функцию к массиву применяют.

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

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

 

 

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

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

Edited by spirit_1

Share this post


Link to post
Share on other sites

3 hours ago, smk said:

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

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

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

Share this post


Link to post
Share on other sites

15 hours ago, Aleksandr Baranov said:

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

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

image.thumb.png.f4f02808181259d6c76b76470efcb8f4.png

 

Share this post


Link to post
Share on other sites

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

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;
}

 

Share this post


Link to post
Share on other sites

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

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

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

Share this post


Link to post
Share on other sites

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()

 

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

 

Edited by TU-104

Share this post


Link to post
Share on other sites

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); забираете амплитуду вашей частоты

Edited by spirit_1

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...