FFT 是离散傅立叶变换的快速算法,可以将一个信号变换到频域。 N 个采样点,经过 FFT 之后,就可以得到 N 个复数结果。为了方便进行 FFT 运算,通常 N 取 2 的整数次方。这里我们设定最大为 1024,即 2 的 10 次方。
假设采样频率为 Fs,信号频率 F,采样点数为 N。那么 FFT 之后结果就是一个为 N 点的复数。每一个点就对应着一个频率点,即 Fn=(n-1)*Fs/N。这个点的模值,就是该频率值下的幅度特性。
假设 FFT 之后某点 n 用复数 a+bi 表示,那么这个复数的模就是 An= √a ∗ a + b ∗ b,相位就是 Pn=atan2(b,a)。根据以上的结果,就可以计算出 n 点(n≠1,且 n<=N/2)对应的信号的表达式为: An/(N/2)*cos(2*pi*Fn*t+Pn),即 2*An/N*cos(2*pi*Fn*t+Pn)。对于 n=1 点的信号,是直流分量,幅度即为 A1/N。由于 FFT 结果的对称性,通常我们只使用前半部分的结果,即小于采样频率一半的结果。
模块首先使用指定的内存数据 pSrc 初始化 xn 数组,接下来调用 fft 完成变换,结果存放在数组 xk 中,最后,我们计算模值并拷贝至 pDst。这里模值因为 scale 关系,需要乖 2048。
void getfft(int nfft, unsigned short *pSrc, unsigned short *pDst)
{
#pragma HLS INTERFACE s_axilite port=nfft
#pragma HLS INTERFACE m_axi port=pSrc offset=slave
#pragma HLS INTERFACE m_axi port=pDst offset=slave
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS dataflow
config_t fft_config;
status_t fft_status;
cmpxDataIn xn[FFT_LENGTH];
cmpxDataOut xk[FFT_LENGTH];
fft_config.setDir(0);
fft_config.setSch(0x2AB);
fft_config.setNfft(nfft);
access_src(pSrc, xn, 1<<nfft);
hls::fft<config1>(xn, xk, &fft_status, &fft_config);
access_dst(pDst, xk, 1<<nfft);
}
这里, setSch(0x2AB) 是设置 scale,即蝶形算法的每一级右移的位数 [2 2 2 2 3]。这样确保最后的结果也是 16 位的。这里 scale 对应的十进制值是 2^(2+2+2+2+3)=2048。
setNfft 用来设置采样数据长度,这里定义 10,即 2 的 10 次方,表示 1024 个采样点, setDir用来设置正逆变换。
虚框中为生成的三个波形叠加波形,虚框下面为 FFT 后结果,这里直流分量没有显示。