目的:使用stm32f407zgt6制作一个iir低通滤波器,混频信号200hz加50hz,输出50hz;
使用:
定时器2触发ADC实时采集,定时器6触发DAC输出,采样频率为10k,数据传输都是DMA。
滤波使用dsp库中的 arm_biquad_cascade_df1_f32(&S, inputF32,outputF32,1);
因为想要实时输出,每次只处理一个点。
结果:
输入波形与输出波形一样。没有实现滤波。
环境:cubemx与keilarm
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "dac.h"
#include "dma.h"
#include "tim.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "arm_math.h"
#include "stdio.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
//static void arm_iir_f32_lp(void);
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
#define numStages 2 /* 2阶IIR滤波的个数 */
#define TEST_LENGTH_SAMPLES 400 /* 采样点数 */
#define BLOCK_SIZE 1 /* 调用一次arm_biquad_cascade_df1_f32处理的采样点个数 */
uint32_t blockSize = BLOCK_SIZE;
uint32_t numBlocks = TEST_LENGTH_SAMPLES/BLOCK_SIZE; /* 需要调用arm_biquad_cascade_df1_f32的次数 */
static float32_t testInput_f32_50Hz_200Hz[TEST_LENGTH_SAMPLES]; /* 采样点 */
static float32_t testOutput[TEST_LENGTH_SAMPLES]; /* 滤波后的输出 */
static float32_t IIRStateF32[4*numStages]; /* 状态缓存 */
int a=0;
/* 巴特沃斯低通滤波器系数 80Hz*/
const float32_t IIRCoeffs32LP[5*numStages] = {
1.0f, 2.0f, 1.0f, 1.479798894397216679763573665695730596781f, -0.688676953053861784503908438637154176831f,
1.0f, 2.0f, 1.0f, 1.212812092620218384908525877108331769705f, -0.384004162286553540894828984164632856846f
};
uint16_t Sine12bit[32] = {
2048 , 2460 , 2856 , 3218 , 3532 , 3786 , 3969 , 4072 ,
4093 , 4031 , 3887 , 3668 , 3382 , 3042 ,2661 , 2255 ,
1841 , 1435 , 1054 , 714 , 428 , 209 , 65 , 3 ,
24 , 127 , 310 , 564 , 878 , 1240 , 1636 , 2048
};
uint32_t i;
arm_biquad_casd_df1_inst_f32 S;
float32_t ScaleValue;
float32_t *inputF32, *outputF32;
float32_t dac_value[1];
float32_t ScaleValue = 0.052219514664161220673932461977528873831f * 0.042798017416583809813257488485760404728f ;
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_DAC_Init();
MX_TIM6_Init();
MX_ADC1_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
inputF32 = &testInput_f32_50Hz_200Hz[0];
outputF32 = &testOutput[0];
arm_biquad_cascade_df1_init_f32(&S, numStages, (float32_t *)&IIRCoeffs32LP[0], (float32_t *)&IIRStateF32[0]);
HAL_TIM_Base_Start(&htim2);
HAL_ADC_Start_DMA(&hadc1,(uint32_t *)testInput_f32_50Hz_200Hz,1);
HAL_TIM_Base_Start(&htim6);
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)dac_value,1, DAC_ALIGN_12B_R);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 168;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
a=~a;
inputF32[0] = (float32_t)testInput_f32_50Hz_200Hz[0];
arm_biquad_cascade_df1_f32(&S, inputF32,outputF32,1);
testOutput[0]=outputF32[0];
dac_value[0]=testOutput[0]*ScaleValue;
HAL_GPIO_WritePin(GPIOF,GPIO_PIN_9,a);
}
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
滤除200hz的信号
要实现滤波的功能,首先需要设计滤波器,方法大概为:在MATLAB命令窗口输入fdatool,然后调出滤波器设计窗口,然后填入参数,点击Design Filter,点击Edit->Convert Structure,选择I型,转化好后,点击File-Export,第一项选择Coefficient File(ASCII):第一项选择好以后,第二项选择Decimal:点击Export。
设计滤波器系数之后,就可以使用IIR滤波器函数:arm_biquad_cascade_df1_f32
参考 https://blog.csdn.net/weixin_50932441/article/details/128064922
如果你的输入波形与输出波形一样,没有实现滤波的效果,可能有以下几个问题需要检查和解决:
滤波器的系数配置:
确保你正确配置了低通滤波器的系数。滤波器的系数决定了滤波器的特性,包括截止频率等。你可以通过DSPLib库中的函数来计算合适的滤波器系数,以满足你的滤波需求。
数据类型选择:
确保你选择了合适的数据类型来进行滤波计算。arm_biquad_cascade_df1_f32函数使用的是float32类型的数据。如果你的输入数据是int类型,你需要将其转换为float32类型进行滤波计算。
缓冲区设置:
确保你为输入和输出数据分配了足够的缓冲区。arm_biquad_cascade_df1_f32函数需要一个输入缓冲区和一个输出缓冲区。
DMA配置:
确保你正确配置了DMA通道和相关的寄存器。确保DMA从ADC读取数据并将其传输到处理滤波的函数,然后再将滤波后的数据传输到DAC进行输出。
DMA传输触发:
确保你正确配置DMA的传输触发源。定时器2触发ADC实时采集,定时器6触发DAC输出,需要配置DMA的传输触发源为对应的定时器触发。
中断优先级:
确保你正确配置了中断的优先级。如果你在使用中断来触发ADC和DAC的采样和输出,确保中断优先级设置正确,以便确保采样和输出的时间同步。
请检查以上步骤,并确保正确配置了每个模块的设置和参数。如果仍然无法实现滤波效果,请提供更多的代码和相关设置,以便更详细地分析问题并提供进一步的帮助。
在代码中,200Hz的信号被滤除,可以通过修改TEST_LENGTH_SAMPLES和numStages的值来调整滤波器的性能和输出结果。
#include "main.h"
#include "adc.h"
#include "dac.h"
#include "dma.h"
#include "tim.h"
#include "gpio.h"
#include "arm_math.h"
#include "stdio.h"
#define numStages 2 // 2阶IIR滤波器的个数
#define TEST_LENGTH_SAMPLES 400 // 采样点数
#define BLOCK_SIZE 1 // 调用一次arm_biquad_cascade_df1_f32处理的采样点个数
static float32_t testInput_f32_50Hz_200Hz[TEST_LENGTH_SAMPLES]; // 采样点
static float32_t testOutput[TEST_LENGTH_SAMPLES]; // 滤波后的输出
static float32_t IIRStateF32[4 * numStages]; // 状态缓存
const float32_t IIRCoeffs32LP[5 * numStages] = { // 巴特沃斯低通滤波器系数 80Hz
1.0f, 2.0f, 1.0f, 1.479798894397216679763573665695730596781f, -0.688676953053861784503908438637154176831f,
1.0f, 2.0f, 1.0f, 1.212812092620218384908525877108331769705f, -0.384004162286553540894828984164632856846f
};
arm_biquad_cascade_df1_inst_f32 S;
float32_t ScaleValue;
float32_t *inputF32, *outputF32;
float32_t dac_value[1];
void SystemClock_Config(void);
void Error_Handler(void);
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
inputF32[0] = (float32_t)testInput_f32_50Hz_200Hz[0];
arm_biquad_cascade_df1_f32(&S, inputF32, outputF32, 1);
testOutput[0] = outputF32[0];
dac_value[0] = testOutput[0] * ScaleValue;
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_DAC_Init();
MX_TIM6_Init();
MX_ADC1_Init();
MX_TIM2_Init();
inputF32 = &testInput_f32_50Hz_200Hz[0];
outputF32 = &testOutput[0];
arm_biquad_cascade_df1_init_f32(&S, numStages, (float32_t *)&IIRCoeffs32LP[0], (float32_t *)&IIRStateF32[0]);
HAL_TIM_Base_Start(&htim2);
HAL_TIM_Base_Start(&htim6);
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)testInput_f32_50Hz_200Hz, 1);
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)dac_value, 1, DAC_ALIGN_12B_R);
ScaleValue = 0.052219514664161220673932461977528873831f * 0.042798017416583809813257488485760404728f;
while (1)
{
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 16;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK |
RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000);
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
void Error_Handler(void)
{
__disable_irq();
while (1)
{
}
}
基于new bing部分指引作答:
1、首先,请确保您已正确设置IIR滤波器的系数和状态。在您的代码中,您定义了巴特沃斯低通滤波器的系数IIRCoeffs32LP和状态缓存IIRStateF32,并在初始化后将其传递给arm_biquad_cascade_df1_init_f32函数。请确保这些系数和状态是正确的。
2、其次,请确保您正确获取输入样本,并将其传递给滤波器函数。在您的代码中,您在HAL_ADC_ConvCpltCallback回调函数中获取了输入样本,并将其存储在inputF32数组中。然后,您调用arm_biquad_cascade_df1_f32函数并将输入样本传递给它。但是,请注意,您将inputF32和outputF32指针分别定义为&testInput_f32_50Hz_200Hz[0]和&testOutput[0],这可能导致错误的内存访问。您应该直接使用这些数组而不是定义指针。
3、此外,您在arm_biquad_cascade_df1_f32函数之后立即将输出值outputF32[0]存储在testOutput[0]数组中,并将其乘以ScaleValue后传递给DAC。然而,滤波器的输出值可能不是立即可用的,因此在获取输出值之前,您应该等待滤波器完成处理。您可以使用arm_biquad_cascade_df1_f32函数的返回值来判断滤波器是否已完成处理。
下面是对您的代码进行了一些修改的示例:
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_DAC_Init();
MX_TIM6_Init();
MX_ADC1_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
// 移除下面两行定义
// inputF32 = &testInput_f32_50Hz_200Hz[0];
// outputF32 = &testOutput[0];
arm_biquad_cascade_df1_init_f32(&S, numStages, (float32_t *)&IIRCoeffs32LP[0], (float32_t *)&IIRStateF32[0]);
HAL_TIM_Base_Start(&htim2);
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)testInput_f32_50Hz_200Hz, 1);
HAL_TIM_Base_Start(&htim6);
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)dac_value, 1, DAC_ALIGN_12B_R);
while (1)
{
// 空闲循环
}
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
a = ~a;
// 直接使用数组而不是定义指针
testInput_f32_50Hz_200Hz[0] = (float32_t)testInput_f32_50Hz_200Hz[0];
// 等待滤波器完成处理
if (arm_biquad_cascade_df1_f32(&S, testInput_f32_50Hz_200Hz, testOutput, 1) == ARM_MATH_SUCCESS)
{
dac_value[0] = testOutput[0] * ScaleValue;
}
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_9, a);
}
/* USER CODE END 3 */
这只是一个示例修改,可能还需要其他更改才能完全解决问题。您可能还需要检查其他代码部分,例如时钟配置和外设初始化,以确保它们正确无误。
要修改您的代码以实现对200Hz信号的滤波,您需要更新滤波器系数和相应的变量。根据您提供的代码,以下是修改的部分:
更新滤波器系数:将巴特沃斯低通滤波器的系数更改为适用于200Hz截止频率的系数。您可以使用MATLAB或其他滤波器设计工具来计算这些系数,然后将其更新到代码中的IIRCoeffs32LP数组。
/* 巴特沃斯低通滤波器系数 200Hz */
const float32_t IIRCoeffs32LP[5*numStages] = {
1.0f, 2.0f, 1.0f, 0.8850222227396416f, -0.4300648228049617f,
1.0f, 2.0f, 1.0f, 0.783011244625315f, -0.3370114227395669f
};
这只是一个示例系数,您可能需要根据具体的滤波器设计需求进行调整。
更新采样频率和截止频率:根据您的要求,采样频率为10kHz,截止频率为200Hz。确保在代码中正确设置这些参数。
#define SAMPLING_FREQUENCY 10000 /* 采样频率 */
#define CUTOFF_FREQUENCY 200 /* 截止频率 */
更新ScaleValue的计算:ScaleValue用于将滤波器输出缩放为DAC的输出值。确保根据新的滤波器系数进行适当的计算。
float32_t ScaleValue = <根据新的滤波器系数进行计算>;
这些是您需要修改的主要部分。请注意,这只是一个示例,您可能还需要根据您的具体硬件和应用程序需求进行其他修改。
在进行修改后,重新编译和运行代码,您应该能够看到对200Hz信号的滤波效果。
希望这些信息对您有所帮助!
答案参考ChatGPT Plus版,整理汇总。希望能帮助你解决问题
代码中的一些问题可能导致滤波器无法正常工作。以下是可能的问题和建议的解决方法:
HAL_ADC_ConvCpltCallback
中,你将输入值和输出值分别存储在inputF32
和outputF32
数组中。然而,在处理函数中,你只处理了第一个采样点(inputF32[0]
和outputF32[0]
)。这意味着你只处理了输入和输出缓冲区中的一个采样点。你需要在循环中处理所有的采样点。你可以使用循环来遍历输入和输出缓冲区,如下所示:for (uint32_t i = 0; i < numBlocks; i++) {
inputF32[0] = testInput_f32_50Hz_200Hz[i]; // 设置当前采样点的输入值
arm_biquad_cascade_df1_f32(&S, inputF32, outputF32, blockSize); // 处理当前采样点
// 更新输出缓冲区的当前采样点
testOutput[i] = outputF32[0];
// 更新DAC的输出值
dac_value[0] = testOutput[i] * ScaleValue;
// 设置GPIO引脚状态
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_9, a);
// 增加数组索引
inputF32++;
outputF32++;
}
DMA传输配置:确保DMA配置正确,以实现从ADC到内存和从内存到DAC的数据传输。检查DMA的配置参数,包括数据宽度、数据方向和缓冲区地址等。
ADC和DAC的初始化:确保ADC和DAC的初始化正确,并使用正确的采样率和数据对齐方式。
系数和状态数组大小:根据你的滤波器配置,确保IIRCoeffs32LP
和IIRStateF32
数组的大小足够存储所有的滤波器系数和状态。根据你的代码,每个滤波器阶段需要4个状态变量,因此状态数组的大小应为4 * numStages
。
系数的设置:根据你的要求,你使用了巴特沃斯低通滤波器的系数。确保这些系数是正确的,以实现所需的滤波效果。
请仔细检查以上问题,并对代码进行相应的修改。如果问题仍然存在,请提供更多关于硬件配置和问题描述的信息,以便更详细地分析问题的原因。