简介

通过上篇文章【STM32学习笔记】简易音乐播放器+FFT频谱显示,以及一些wav文件data数据块、C语言、声学知识总结
的方法得到频域信号后,相位保持不变,赋值做一定的修改后做IFFT回时域再发送给DAC芯片播放

特点与不足

特点
1、能自由对频域的幅值和频段做处理,处理的精度取决于FFT的点数
2、借助stm32H7的硬件乘法器能保证处理的实时性
不足
1、有比较明显的失真
2、硬件资源消耗很大

分块介绍

在这里插入图片描述
1、计算原始相位
在这里插入图片描述

for (uint16_t i = 0; i < num_samples; i++)
{
    a = complex_input[2 * i];
    b = complex_input[2 * i + 1];
    phase_output[i] = atan2f(b, a);
}

2、根据原始相位和新的幅值重构频域数据
修改幅值时需要注意,因为频谱的对称性,修改赋值时要同时修改正负半轴

for(uint16_t i = 5; i < 22; i++)  new_magnitude[i] = 0.01f;
for(uint16_t i = 1024-5; i > 1024-22; i--)  new_magnitude[i] = 0.01f;
/** 
 * @brief       根据相位和新的幅值重构频域数据
 * @param       phase         : 相位数据
 * @param       new_magnitude : 新的幅值
 * @param       complex_output: 复数输出数据
 * @param       num_samples   : 采样点数
 * @retval      无
*/
static void reconstruct_complex_data(const float32_t *phase, const float32_t *new_magnitude, 
    float32_t *complex_output, uint32_t num_samples)
{
    for (uint16_t i = 0; i < num_samples; i++) 
    {
        complex_output[2 * i] = new_magnitude[i] * cosf(phase[i]);
        complex_output[2 * i + 1] = new_magnitude[i] * sinf(phase[i]);
    }
}

3、IFFT得到时域信号
同样输入数据以实部、虚部、实部、虚部的格式存储,该函数处理完后数据依然存储在complex_output中,我们需要的时域数据则只取实部数据即可

arm_cfft_f32(&arm_cfft_sR_f32_len1024, complex_output, 1, 1);

4、异常处理
调试时发现在FFT一组数据的首尾会出现这种现象
在这里插入图片描述
下图为matlab用同样方法得到的数据
在这里插入图片描述
既然matlab也有相似的现象,那可能是这种方法的数学性质导致的了,因此我仅在信号在头尾约1/3的位置加了个余弦窗

for(uint32_t i = 0; i < blockSize*0.1666f; i++){
    w = 0.6f - 0.4f * cosf (PI * i * k);
    pbuf[i] *= w;
}
for(uint32_t i = blockSize*0.8333f; i < blockSize; i++){
    w = 0.6f - 0.4f * cosf (PI * i * k);
    pbuf[i] *= w;
}

资源共享

代码
https://gitee.com/creator-len/study_music
效果展示

[STM32学习]频域滤波EQ方案验证

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐