打印
[牛人杂谈]

FFT应用

[复制链接]
50|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
598330983|  楼主 | 2025-1-12 17:21 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
快速傅立叶变换,用于将时间域的离散讯号转换至频率域表示,用户得以观察该讯号的频率组成成分与分布情形,是常见的讯号分析手段。此范例将示范如何透过 ADC 与 TIMER 的搭配使用,取样出一段离散讯号,并进行快速傅立叶变换,最后观察频谱的数值分布是否符合原始输入讯号的特性。支持三种讯号长度范例,分别为 128 取样点,256取样点,以及512取样点。

原理

此范例采用 TIMER trigger ADC 的功能进行实作。首先利用波形产生器输出频率固定为 60 Hz的正弦波,模拟一般应用情境下欲分析的讯号来源,给予微控制器使用 ADC 进行取样。使用者可根据应用上的需求自行调整取样频率,注意其数值会直接影响频谱的带宽与分辨率。每次的 TIMER 逾时事件,硬件便会自动触发 ADC 进行一次取样动作,软件则须于 ADC 转换完毕后的中断服务内,将数据以位反转的排序写入缓冲区当中。
本范例程序提供必要参数的查表数值,可简化微处理机的运算量,包含傅立叶变换过程所需要的旋转因子常数,以及 Decimate-in-time 作法所需的位反转排序,开发者已经事前计算完毕并定义在头文件当中。由于寻找表的内容会根据讯号长度的不同而有异,不同长度设定的寻找表无法共享,使用者必须于头文件中选择范例提供的指定长度参数编译,流程主要可分为五个部分:
1. 指定讯号长度以及取样频率
2. 系统与周边硬件初始化
3. ADC 取样至指定数量为止
4. 执行傅立叶变换
5. 后置处理,显示频谱信息
EC_NUC121_FFT_Demo_V1.00.zip (1.36 MB)
void NuFFT(int *pi32RealBuffer, int *pi32ImageBuffer, uint32_t u32Len)
{
    const uint32_t N = u32Len;
    const uint32_t u32TotalStage = log(N) / log(2);

    uint32_t u32Stage, u32Span, u32Node, u32Twiddle, u32Angle;
    int32_t i32X1Real, i32X1Image, i32X2Real, i32X2Image;

    /* Iterations for log2(N) FFT butterfly stages */
    for (u32Stage = 0; u32Stage < u32TotalStage; u32Stage++)
    {
        /* Span indicates the buffer index for constituting a butterfly matrix */
        u32Span = pow(2, u32Stage);

        for (u32Twiddle = 0; u32Twiddle < u32Span; u32Twiddle++)
        {
            u32Angle = (N >> 1) / u32Span * u32Twiddle;

            for (u32Node = u32Twiddle; u32Node < N; u32Node += 2 * u32Span)
            {
                /* Get the real and image part of the input variable X1 */
                i32X1Real  = pi32RealBuffer [u32Node];
                i32X1Image = pi32ImageBuffer[u32Node];

                /* Get the real and image part of the input variable X2 */
                i32X2Real  = pi32RealBuffer [u32Node + u32Span];
                i32X2Image = pi32ImageBuffer[u32Node + u32Span];

                /* Y1 = X1 + X2 * twiddle factor
                 * The real part is   real * cos() + image * sin()
                 * The image part is -real * sin() + image * cos()
                 */
                pi32RealBuffer [u32Node] = i32X1Real  + RESCALE(i32X2Real * COS(u32Angle)) + RESCALE(i32X2Image * SIN(u32Angle));
                pi32ImageBuffer[u32Node] = i32X1Image - RESCALE(i32X2Real * SIN(u32Angle)) + RESCALE(i32X2Image * COS(u32Angle));

                /* Y2 = X1 - X2 * twiddle factor
                 * The real part is  -real * cos() - image * sin()
                 * The image part is  real * sin() - image * cos()
                 */
                pi32RealBuffer [u32Node + u32Span] = i32X1Real  - RESCALE(i32X2Real * COS(u32Angle)) - RESCALE(i32X2Image * SIN(u32Angle));
                pi32ImageBuffer[u32Node + u32Span] = i32X1Image + RESCALE(i32X2Real * SIN(u32Angle)) - RESCALE(i32X2Image * COS(u32Angle));
            }
        }
    }
}


使用特权

评论回复
沙发
598330983|  楼主 | 2025-1-12 17:24 | 只看该作者
这个函数你们看的懂吗

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

250

主题

5422

帖子

22

粉丝