• 【幅频均衡带通滤波器】基于FPGA的幅频均衡带通滤波器的设计


    1.软件版本

    matlab2013b,quartusii121.

    2.本算法理论知识

           带通滤波器在数字幅频均衡功率放大器中一个重要的组成部分,在介绍带通滤波器之前,我们首先来详细介绍一下数字幅频均衡功率放大器。

         本系统要求的指标为:

          本题要求在输入电压有效值为5mV的条件下,放大倍数达到400倍。而且20Hz到20kHz衰减不能超过1dB。-1 dB转化为信号幅值变化为11%,可以说指标要求很高。我们可以选择使用PGA或AD620实现这一指标。

         整个系统的基本结构如下所示:

    图1 系统总提结构框图

           根据以上分析,系统的整体框图如图1所示。输入信号首先通过前置放大电路放大到一定幅度,经过带阻网络后,信号的幅频特性发生变化。由于AD输入幅度限制,信号先经过衰减网络衰减两倍,再经过抗混叠滤波并使用AD对输入信号进行采样,将采样结果送入FPGA做幅频均衡。最后通过DA输出并滤波,经过D类功放后即可得到大功率信号。

    ·前置放大电路的设计

           输入信号电压放大倍数不小于400倍,单级运放的放大倍数难以做到这么高,所以采用两级运放的形式来做前级放大。由于系统频率为20Hz~20kHz,所以选用OP27运放完成电路。

    ·抗混叠滤波器电路设计

           根据采样定理,为了使采样信号不发生频域混叠,必须在A/D采样电路的前端加入抗混叠滤波器电路,滤波器截止频率为采样频率的一半。由于本系统主要处理20kHz以内的信号,所以选用开关电容滤波器LTC1068—25设计一个八阶椭圆滤波器,其截至频率为25kHz。

    ·A/D采样电路的设计

           根据题目的指标及系统频率的要求,我们需要一款采样率超过40KHz的采样芯片。AD9223是一款12bits、最高采样频率10MHz的性能优良的AD采样器件,由于以前使用过该芯片,为了更快的完成题目,所以选用AD9223作为采样芯片。

    ·数字幅频均衡模块设计

           数字幅频均衡模块的原理图如图4-3所示,如果要实现对带阻网络的完全补偿,那么FIR滤波器应与带阻网络互为逆系统.带阻网络的系统函数可以通过点频法测得,然后使用MATLAB求出加窗后FIR滤波器应该具有的单位脉冲响应。因为FIR系统具有线性相位特性,所以由其幅频响应就可以求得其系统函数。

    图2 数字幅频均衡模块的原理图

    ·D/A输出电路设计

          根据题目的指标及系统频率的要求,我们需要一款频率超过40KHz的模数输出芯片。DAC904是一款14bits、最高采样频率165MHz的的DA器件,由于以前使用过该芯片,所以仍选用DAC904作为数模输出芯片。

    ·功率放大电路设计

           D类功放第一部分为调制器,输入信号接比较器的正输入端,与三角波相比较。当正端上的电位高于负端三角波电位时,比较器输出为高电平,反之则输出低电平。这样,比较器输出的波形就是一个脉冲宽度被音频信号幅度调制后的波形,称为SPWM波。D类功放后级输出电路是一个脉冲控制的大电流开关放大器,正半周期比较器输出高电平,MOSFET晶体管Q1导通,且Q2截止,负半周期比较器输出高电平Q2导通,且Q1截止,这样它就把比较器输出的PWM信号变成高电压、大电流的大功率PWM信号,最后只需要通过一个二阶低通滤波器就可以把声音信息还原出来。

     

     

    3.部分源码

    1. library ieee;
    2. use ieee.std_logic_1164.all;
    3. use ieee.numeric_std.all;
    4. use std.textio.all;
    5. entity tb_firs is
    6. --START MEGAWIZARD INSERT CONSTANTS
    7. constant FIR_INPUT_FILE_c : string := "firs_input.txt";
    8. constant FIR_OUTPUT_FILE_c : string := "firs_output.txt";
    9. constant NUM_OF_CHANNELS_c : natural := 1;
    10. constant DATA_WIDTH_c : natural := 16;
    11. constant CHANNEL_OUT_WIDTH_c : natural := 0;
    12. constant OUT_WIDTH_c : natural := 35;
    13. constant COEF_SET_ADDRESS_WIDTH_c : natural := 0;
    14. constant COEF_RELOAD_BIT_WIDTH_c : natural := 35;
    15. --END MEGAWIZARD INSERT CONSTANTS
    16. end entity tb_firs;
    17. --library work;
    18. --library auk_dspip_lib;
    19. -------------------------------------------------------------------------------
    20. architecture rtl of tb_firs is
    21. signal ast_sink_data : std_logic_vector (DATA_WIDTH_c-1 downto 0) := (others => '0');
    22. signal ast_source_data : std_logic_vector (OUT_WIDTH_c-1 downto 0);
    23. signal ast_sink_error : std_logic_vector (1 downto 0) := (others => '0');
    24. signal ast_source_error : std_logic_vector (1 downto 0);
    25. signal ast_sink_valid : std_logic := '0';
    26. signal ast_source_valid : std_logic;
    27. signal ast_source_ready : std_logic := '0';
    28. signal clk : std_logic := '0';
    29. signal reset_testbench : std_logic := '0';
    30. signal reset_design : std_logic;
    31. signal eof : std_logic;
    32. signal ast_sink_ready : std_logic;
    33. signal start : std_logic;
    34. signal cnt : natural range 0 to NUM_OF_CHANNELS_c;
    35. constant tclk : time := 10 ns;
    36. constant time_lapse_max : time := 60 us;
    37. signal time_lapse : time;
    38. function div_ceil(a : natural; b : natural) return natural is
    39. variable res : natural := a/b;
    40. begin
    41. if res*b /= a then
    42. res := res +1;
    43. end if;
    44. return res;
    45. end div_ceil;
    46. function to_hex (value : in signed) return string is
    47. constant ne : integer := (value'length+3)/4;
    48. constant NUS : string(2 to 1) := (others => ' ');
    49. variable pad : std_logic_vector(0 to (ne*4 - value'length) - 1);
    50. variable ivalue : std_logic_vector(0 to ne*4 - 1);
    51. variable result : string(1 to ne);
    52. variable quad : std_logic_vector(0 to 3);
    53. begin
    54. if value'length < 1 then
    55. return NUS;
    56. else
    57. if value (value'left) = 'Z' then
    58. pad := (others => 'Z');
    59. else
    60. pad := (others => value(value'high));
    61. end if;
    62. ivalue := pad & std_logic_vector (value);
    63. for i in 0 to ne-1 loop
    64. quad := To_X01Z(ivalue(4*i to 4*i+3));
    65. case quad is
    66. when x"0" => result(i+1) := '0';
    67. when x"1" => result(i+1) := '1';
    68. when x"2" => result(i+1) := '2';
    69. when x"3" => result(i+1) := '3';
    70. when x"4" => result(i+1) := '4';
    71. when x"5" => result(i+1) := '5';
    72. when x"6" => result(i+1) := '6';
    73. when x"7" => result(i+1) := '7';
    74. when x"8" => result(i+1) := '8';
    75. when x"9" => result(i+1) := '9';
    76. when x"A" => result(i+1) := 'A';
    77. when x"B" => result(i+1) := 'B';
    78. when x"C" => result(i+1) := 'C';
    79. when x"D" => result(i+1) := 'D';
    80. when x"E" => result(i+1) := 'E';
    81. when x"F" => result(i+1) := 'F';
    82. when "ZZZZ" => result(i+1) := 'Z';
    83. when others => result(i+1) := 'X';
    84. end case;
    85. end loop;
    86. return result;
    87. end if;
    88. end function to_hex;
    89. begin
    90. DUT : entity work.firs
    91. port map (
    92. clk => clk,
    93. reset_n => reset_design,
    94. ast_sink_ready => ast_sink_ready,
    95. ast_sink_data => ast_sink_data,
    96. ast_source_data => ast_source_data,
    97. ast_sink_valid => ast_sink_valid,
    98. ast_source_valid => ast_source_valid,
    99. ast_source_ready => ast_source_ready,
    100. ast_sink_error => ast_sink_error,
    101. ast_source_error => ast_source_error);
    102. -- for example purposes, the ready signal is always asserted.
    103. ast_source_ready <= '1';
    104. -- no input error
    105. ast_sink_error <= (others => '0');
    106. -- start valid for first cycle to indicate that the file reading should start.
    107. start_p : process (clk, reset_testbench)
    108. begin
    109. if reset_testbench = '0' then
    110. start <= '1';
    111. elsif rising_edge(clk) then
    112. if ast_sink_valid = '1' and ast_sink_ready = '1' then
    113. start <= '0';
    114. end if;
    115. end if;
    116. end process start_p;
    117. -----------------------------------------------------------------------------------------------
    118. -- Read input data from file
    119. -----------------------------------------------------------------------------------------------
    120. source_model : process(clk) is
    121. file in_file : text open read_mode is FIR_INPUT_FILE_c;
    122. variable data_in : integer;
    123. variable indata : line;
    124. begin
    125. if rising_edge(clk) then
    126. if(reset_testbench = '0') then
    127. ast_sink_data <= std_logic_vector(to_signed(0, DATA_WIDTH_c)) after tclk/4;
    128. ast_sink_valid <= '0' after tclk/4;
    129. eof <= '0';
    130. else
    131. if not endfile(in_file) and (eof = '0') then
    132. eof <= '0';
    133. if((ast_sink_valid = '1' and ast_sink_ready = '1') or
    134. (start = '1'and not (ast_sink_valid = '1' and ast_sink_ready = '0'))) then
    135. readline(in_file, indata);
    136. read(indata, data_in);
    137. ast_sink_valid <= '1' after tclk/4;
    138. ast_sink_data <= std_logic_vector(to_signed(data_in, DATA_WIDTH_c)) after tclk/4;
    139. else
    140. ast_sink_valid <= '1' after tclk/4;
    141. ast_sink_data <= ast_sink_data after tclk/4;
    142. end if;
    143. else
    144. eof <= '1';
    145. ast_sink_valid <= '0' after tclk/4;
    146. ast_sink_data <= std_logic_vector(to_signed(0, DATA_WIDTH_c)) after tclk/4;
    147. end if;
    148. end if;
    149. end if;
    150. end process source_model;
    151. ---------------------------------------------------------------------------------------------
    152. -- Write FIR output to file
    153. ---------------------------------------------------------------------------------------------
    154. sink_model : process(clk) is
    155. file ro_file : text open write_mode is FIR_OUTPUT_FILE_c;
    156. variable rdata : line;
    157. variable data_r : string(div_ceil(OUT_WIDTH_c,4) downto 1);
    158. begin
    159. if rising_edge(clk) then
    160. if(ast_source_valid = '1' and ast_source_ready = '1') then
    161. -- report as hex representation of integer.
    162. data_r := to_hex(signed(ast_source_data));
    163. write(rdata, data_r);
    164. writeline(ro_file, rdata);
    165. end if;
    166. end if;
    167. end process sink_model;
    168. -------------------------------------------------------------------------------
    169. -- clock generator
    170. -------------------------------------------------------------------------------
    171. clkgen : process
    172. begin -- process clkgen
    173. if eof = '1' then
    174. clk <= '0';
    175. assert FALSE
    176. report "NOTE: Stimuli ended" severity note;
    177. wait;
    178. elsif time_lapse >= time_lapse_max then
    179. clk <= '0';
    180. assert FALSE
    181. report "ERROR: Reached time_lapse_max without activity, probably simulation is stuck!" severity Error;
    182. wait;
    183. else
    184. clk <= '0';
    185. wait for tclk/2;
    186. clk <= '1';
    187. wait for tclk/2;
    188. end if;
    189. end process clkgen;
    190. monitor_toggling_activity : process(clk, reset_testbench,
    191. ast_source_data, ast_source_valid)
    192. begin
    193. if reset_testbench = '0' then
    194. time_lapse <= 0 ns;
    195. elsif ast_source_data'event or ast_source_valid'event then
    196. time_lapse <= 0 ns;
    197. elsif rising_edge(clk) then
    198. if time_lapse < time_lapse_max then
    199. time_lapse <= time_lapse + tclk;
    200. end if;
    201. end if;
    202. end process monitor_toggling_activity;
    203. -------------------------------------------------------------------------------
    204. -- reset generator
    205. -------------------------------------------------------------------------------
    206. reset_testbench_gen : process
    207. begin -- process resetgen
    208. reset_testbench <= '1';
    209. wait for tclk/4;
    210. reset_testbench <= '0';
    211. wait for tclk*2;
    212. reset_testbench <= '1';
    213. wait;
    214. end process reset_testbench_gen;
    215. reset_design_gen : process
    216. begin -- process resetgen
    217. reset_design <= '1';
    218. wait for tclk/4;
    219. reset_design <= '0';
    220. wait for tclk*2;
    221. reset_design <= '1';
    222. wait for tclk*80;
    223. reset_design <= '1';
    224. wait for tclk*128*2;
    225. reset_design <= '1';
    226. wait;
    227. end process reset_design_gen;
    228. -------------------------------------------------------------------------------
    229. -- control signals
    230. -------------------------------------------------------------------------------
    231. end architecture rtl;

    4.仿真结论

    我们在MATLAB中对该IIR滤波器进行验证。代码如下所示:

    b=[1 -1.8986 08991];

    a=[2 -3.192 1.193];

    [h1,f1]=freqz(b,a,100,1000000);

    plot(f1,20*log10(abs(h1)));

    其仿真波形如下所示:

    图3 IIR滤波器的特性曲线

    从上图可以看到,其通带是从0开始的,虽然在整个通带范围20~20k中20hz误差很小,但是IIR由于本身的缺陷,并不能满足要求。

     

    ·基于FIR的方案验证

        其代码如下所示:

    fs=200000;

    wn1=[0.02 0.2];

    b = fir1(1024,wn1,'DC-0');

    freqz(b,1,1024,fs);axis([0,30000,-100,30]);grid;

    title('设计的FIR带通滤波器');

    其仿真结果如下所示:

    图4 带通FIR滤波器仿真图

    这里由于20hz的起始带通频率非常低,为了能使仿真效果能够明显点,这里通带频率为2K~20K。在实际使用的时候:

    图5 带通FIR滤波器仿真图

    由此可见,采用FIR滤波器可以达到设计要求。

    其仿真结果如下所示:

    5.参考文献

    [01]Mark Zwolinski.VHDL数字系统设计[M].电子工业出版社.2004

    [02]褚振勇,翁木云.FPGA设计及应用.西安电子科技大学出版社[M].2002

    [03]李玉山,来新泉.电子系统集成设计技术[M].电子工业出版社.2002.A25-15

  • 相关阅读:
    【软考】9.4 图的概念/存储/遍历/最小生成树/拓扑/查找
    Java面经整理
    C++ IO流
    redis 队列
    谷粒商城 高级篇 (四) --------- Elasticsearch-Rest-Client
    微信小程序 获取当前屏幕的可见高宽度
    Jmeter性能测试
    Geotools实现shape文件的写入
    php学习笔记
    【Spring】初阶二
  • 原文地址:https://blog.csdn.net/ccsss22/article/details/124834338