快速傅立叶变换,用于将时间域的离散讯号转换至频率域表示,用户得以观察该讯号的频率组成成分与分布情形,是常见的讯号分析手段。此范例将示范如何透过 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));
}
}
}
}
|