当前位置:   article > 正文

基于FPGA的数字插值滤波器仿真_滤波 插值 fpga

滤波 插值 fpga

一、插值原理

       由数字信号处理方面的知识我们了解到,对于数字信号的插值,在时域上看,就是将信号的采样率 Fs 变成原来的 L 倍,其中 L 便是插值倍率。最简单的插值就是在信号中间补零,如图所示

       下面的信号就是由上面的信号补零而来的,可以看见原来相邻的数字信号之间补了一个零,这就是最简单的信号插值。

       但是问题又出现了,我们想的是插值以后可以让波形更细腻,但是单纯补零好像并没有达到这个要求,那我们为什么还要这么做呢?

补零前后时域表达式如下,

 v(n)是补完零后的信号,这时再将其傅里叶变换,得到频域表达式如下

 可以见得插值前后信号的频域关系如下

由此可见,在时域 补零,实际上是将原来的频谱压缩,原来频率分量为\pi的经过插值后变到了\frac{\pi }{L}的位置上,如下图

       因此如果想实现真正的插值,就需要将镜像频率剔除,就是上图蓝色的部分,这也是时域补零带来的失真。

       这时就需要将补零后的信号通过滤波器滤除,由分析可知,插值滤波器仅需一个低通滤波器就可以实现。

PS:实际上在时域波形来看,补零后的零点和下一个实际信号点的突变就是一个高频分量,因此通过滤除高频分量就可以实现真正的插值。

二、高效滤波器结构

        由上述分析,仅需要低通滤波器就可以实现,卷积公式如下图:

       如果按照卷积公式直接进行运算,将会有很多0值参与乘法运算,这样会浪费资源与时间,为解决这个问题,将上式改写为

       由上式可以看到,这种高效结构将原来带零点的v(n)直接改写成补零前的x(n),这样就节省了无用的计算时间。

       利用此结构对信号进行25倍插值,设置100个滤波器系数,结构如下图

 

三、软硬件仿真

MATLAB仿真

       利用MATLAB对插值滤波器进行仿真,设置输入信号长度为256,进行25倍插值,滤波器阶数为99。

  1. % 采样序列为input_seq,长度为256
  2. input_seq = xn; % 输入的采样序列
  3. % 25倍插值后的序列长度
  4. interp_length = 256 * 25;
  5. % 进行插零值
  6. zero_padded_seq = zeros(1, interp_length);
  7. zero_padded_seq(1:25:end) = input_seq;
  8. % 设计低通滤波器
  9. filter_order = 99; % 滤波器阶数
  10. cutoff_freq = 0.04; % 截止频率
  11. filter_coeff = fir1(filter_order, cutoff_freq);
  12. % 应用低通滤波器
  13. filtered_seq = conv(zero_padded_seq, filter_coeff, 'same');
  14. %filtered_seq = conv(zero_padded_seq, fix_x, 'same');
  15. % 输出插值后的序列
  16. output_seq = 25*filtered_seq;

        结果如图

       可以看到滤波器实现了想要的结果,对正弦波数据进行了插值。

FPGA仿真

       通过MATLAB验证,实现了信号的插值,接下来将滤波器系数转入coe文件。

  1. % 放大2的16次幂
  2. x = filter_coeff * 20;
  3. qpath = quantizer('fixed','round','saturate',[20,0]);
  4. fix_x = quantize(qpath,x);
  5. % 转换为16进制有符号数
  6. % x_hex = dec2hex(typecast(int16(x), 'uint16')); % 转换为无符号整型,并转换为16进制字符串
  7. % x_hex = reshape(x_hex, [], 4); % 将16进制字符串按4个字符一组划分
  8. % fix_x = flipud(fix_x); % 翻转顺序,以满足coe文件的顺序要求
  9. % fix_x = cellstr(fix_x); % 转换为cell数组
  10. % fix_x = strcat(fix_x, {';'}); % 添加分号
  11. % 存储coe文件
  12. % 2. 将输入数组转换为16进制字符串
  13. hex_string = dec2hex(fix_x)
  14. % 3. 将16进制字符串写入coe文件
  15. filename = ' G:\BaiduNetdiskWorkspace\English_path\Interpolation\Interpolation_fir_99order.coe'; % 文件名
  16. fileID = fopen(filename, 'w');
  17. fprintf(fileID, 'memory_initialization_radix=16;\nmemory_initialization_vector=\n');
  18. for i = 1:size(hex_string, 1)
  19. fprintf(fileID, '%s,\n', hex_string(i,:));
  20. end
  21. fclose(fileID);

再将正弦波序列也存为coe文件,再存入FPGA中ROM IP核中(实际上应该用RAM,因为可以随时可以改,要不然滤波器只有一种截止频率,或者不使用低通滤波器进行插值滤波,本设计仅针对低通滤波器)

       顶层结构由三个单元组成,分别为正弦波ROM IP核,地址控制模块,以及运算模块组成,其中运算模块是依照高效滤波结构进行设计,调用四个乘法IP核,并且通过控制滤波器系数的地址,来获取参与运算的滤波器系数,并将其输入至乘法器,最终将四路乘法器输出相加,得到插值滤波结果。

四、仿真结果

       首先是寄存器地址,以上四路代表了四组滤波器系数寄存器的地址,可见是由上面分析的每组的系数是分别从h[0]、h[25]、h[50]、h[75]开始,到h[24]、h[49]、h[74]、h[99]结束一轮卷积。

       可以看到红色的信号是输入信号,是每隔25个时钟输入,意味着信号的采样率是2MSPS,而25倍插值后就是50MSPS。四路信号经过延时,依次落后一拍,与理论相符。(至于滤波后数变大,有一个原因是在MATLAB导出滤波器系数的时候,对滤波器系数进行了放大后再定点化,这样做的原因是滤波器系数都是小数,如果不放大直接定点化,则会出现全零或全一的结果,因此放大再定点是可以解决这个问题的)

       红色的为插值前的信号,绿色的为插值后的信号,可以看到实现了25倍插值。上图为数字,下图为模拟波形

        最终在硬件中实现了25倍插值滤波器。

完整代码可见github:

https://github.com/ZFXS55/Interpolation-filter-based-on-the-FPGA

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/462474
推荐阅读
相关标签
  

闽ICP备14008679号