【幅频均衡带通滤波器】基于FPGA的幅频均衡带通滤波器的设计[通俗易懂]

【幅频均衡带通滤波器】基于FPGA的幅频均衡带通滤波器的设计[通俗易懂]1.软件版本matlab2013b,quartusii121.2.本算法理论知识带通滤波器在数字幅频均衡功率放大器中一个重要的组成部分,在介绍带通滤波器之前,我们首先来详细介绍一下数字幅频均衡功率放大器。本系统要求的指标为:本题要求在输入电压有效值为5mV的条件下,放大倍数达到400倍。而且20Hz到20kHz衰减不能超过1dB。-1dB转化为信号幅值变化为11%,可以说指标要求很高。我们可以选择使用PGA或AD620实现这一指标。整个…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

1.软件版本

matlab2013b,quartusii121.

2.本算法理论知识

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

     本系统要求的指标为:

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

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

【幅频均衡带通滤波器】基于FPGA的幅频均衡带通滤波器的设计[通俗易懂]

图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系统具有线性相位特性,所以由其幅频响应就可以求得其系统函数。

【幅频均衡带通滤波器】基于FPGA的幅频均衡带通滤波器的设计[通俗易懂]

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

·D/A输出电路设计

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

·功率放大电路设计

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

 【幅频均衡带通滤波器】基于FPGA的幅频均衡带通滤波器的设计[通俗易懂]

 【幅频均衡带通滤波器】基于FPGA的幅频均衡带通滤波器的设计[通俗易懂]

3.部分源码

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
entity tb_firs is
--START MEGAWIZARD INSERT CONSTANTS
  constant FIR_INPUT_FILE_c  : string := "firs_input.txt";
  constant FIR_OUTPUT_FILE_c : string := "firs_output.txt";
  constant NUM_OF_CHANNELS_c        : natural := 1;
  constant DATA_WIDTH_c             : natural := 16;
  constant CHANNEL_OUT_WIDTH_c      : natural := 0;
  constant OUT_WIDTH_c              : natural := 35;
  constant COEF_SET_ADDRESS_WIDTH_c : natural := 0;
  constant COEF_RELOAD_BIT_WIDTH_c  : natural := 35;

--END MEGAWIZARD INSERT CONSTANTS
end entity tb_firs;


--library work;
--library auk_dspip_lib;

-------------------------------------------------------------------------------

architecture rtl of tb_firs is
  
  signal ast_sink_data    : std_logic_vector (DATA_WIDTH_c-1 downto 0) := (others => '0');
  signal ast_source_data  : std_logic_vector (OUT_WIDTH_c-1 downto 0);
  signal ast_sink_error   : std_logic_vector (1 downto 0)              := (others => '0');
  signal ast_source_error : std_logic_vector (1 downto 0);
  signal ast_sink_valid   : std_logic                                  := '0';
  signal ast_source_valid : std_logic;
  signal ast_source_ready : std_logic                                  := '0';
  signal clk            : std_logic := '0';
  signal reset_testbench        : std_logic := '0';
  signal reset_design   : std_logic;
  signal eof            : std_logic;
  signal ast_sink_ready : std_logic;
  signal start : std_logic;
  signal cnt   : natural range 0 to NUM_OF_CHANNELS_c;
  constant tclk           : time := 10 ns;
  constant time_lapse_max : time := 60 us;
  signal time_lapse       : time;
  function div_ceil(a : natural; b : natural) return natural is
    variable res : natural := a/b;
  begin
    if res*b /= a then
      res := res +1;
    end if;
    return res;
  end div_ceil;

  function to_hex (value : in signed) return string is
    constant ne     : integer        := (value'length+3)/4;
    constant NUS    : string(2 to 1) := (others => ' ');  
    variable pad    : std_logic_vector(0 to (ne*4 - value'length) - 1);
    variable ivalue : std_logic_vector(0 to ne*4 - 1);
    variable result : string(1 to ne);
    variable quad   : std_logic_vector(0 to 3);
  begin
    if value'length < 1 then
      return NUS;
    else
      if value (value'left) = 'Z' then
        pad := (others => 'Z');
      else
        pad := (others => value(value'high));             
      end if;
      ivalue := pad & std_logic_vector (value);
      for i in 0 to ne-1 loop
        quad := To_X01Z(ivalue(4*i to 4*i+3));
        case quad is
          when x"0"   => result(i+1) := '0';
          when x"1"   => result(i+1) := '1';
          when x"2"   => result(i+1) := '2';
          when x"3"   => result(i+1) := '3';
          when x"4"   => result(i+1) := '4';
          when x"5"   => result(i+1) := '5';
          when x"6"   => result(i+1) := '6';
          when x"7"   => result(i+1) := '7';
          when x"8"   => result(i+1) := '8';
          when x"9"   => result(i+1) := '9';
          when x"A"   => result(i+1) := 'A';
          when x"B"   => result(i+1) := 'B';
          when x"C"   => result(i+1) := 'C';
          when x"D"   => result(i+1) := 'D';
          when x"E"   => result(i+1) := 'E';
          when x"F"   => result(i+1) := 'F';
          when "ZZZZ" => result(i+1) := 'Z';
          when others => result(i+1) := 'X';
        end case;
      end loop;
      return result;
    end if;
  end function to_hex;  
begin
  
  DUT : entity work.firs
    port map (
      clk                => clk,
      reset_n            => reset_design,
      ast_sink_ready     => ast_sink_ready,
      ast_sink_data      => ast_sink_data,
      ast_source_data    => ast_source_data,
      ast_sink_valid     => ast_sink_valid,
      ast_source_valid   => ast_source_valid,
      ast_source_ready   => ast_source_ready,
      ast_sink_error   => ast_sink_error,
      ast_source_error => ast_source_error);
  -- for example purposes, the ready signal is always asserted.
  ast_source_ready <= '1';

  -- no input error
  ast_sink_error <= (others => '0');

  -- start valid for first cycle to indicate that the file reading should start.
  start_p : process (clk, reset_testbench)
  begin
    if reset_testbench = '0' then
      start <= '1';
    elsif rising_edge(clk) then
      if ast_sink_valid = '1' and ast_sink_ready = '1' then
        start <= '0';
      end if;
    end if;
  end process start_p;
  -----------------------------------------------------------------------------------------------
  -- Read input data from file                                                                 
  -----------------------------------------------------------------------------------------------
  source_model : process(clk) is
    file in_file     : text open read_mode is FIR_INPUT_FILE_c;
    variable data_in : integer;
    variable indata  : line;
  begin
    if rising_edge(clk) then
      if(reset_testbench = '0') then
        ast_sink_data  <= std_logic_vector(to_signed(0, DATA_WIDTH_c)) after tclk/4;
        ast_sink_valid <= '0' after tclk/4;
        eof            <= '0';
      else
        if not endfile(in_file) and (eof = '0') then
          eof <= '0';
          if((ast_sink_valid = '1' and ast_sink_ready = '1') or
             (start = '1'and not (ast_sink_valid = '1' and ast_sink_ready = '0'))) then
            readline(in_file, indata);
            read(indata, data_in);
            ast_sink_valid <= '1' after tclk/4;
            ast_sink_data  <= std_logic_vector(to_signed(data_in, DATA_WIDTH_c)) after tclk/4;
          else
            ast_sink_valid <= '1' after tclk/4;
            ast_sink_data  <= ast_sink_data after tclk/4;
          end if;
        else
          eof            <= '1';
          ast_sink_valid <= '0' after tclk/4;
          ast_sink_data  <= std_logic_vector(to_signed(0, DATA_WIDTH_c)) after tclk/4;
        end if;
      end if;
    end if;
  end process source_model;
  ---------------------------------------------------------------------------------------------
  -- Write FIR output to file                                               
  ---------------------------------------------------------------------------------------------

  sink_model : process(clk) is
    file ro_file   : text open write_mode is FIR_OUTPUT_FILE_c;
    variable rdata : line;
    variable data_r : string(div_ceil(OUT_WIDTH_c,4) downto 1);
  begin
    if rising_edge(clk) then
      if(ast_source_valid = '1' and ast_source_ready = '1') then
        -- report as hex representation of integer.
        data_r := to_hex(signed(ast_source_data));
        write(rdata, data_r);
        writeline(ro_file, rdata);
      end if;
    end if;
  end process sink_model;
-------------------------------------------------------------------------------
-- clock generator
-------------------------------------------------------------------------------      
  clkgen : process
  begin  -- process clkgen
    if eof = '1' then
      clk <= '0';
      assert FALSE
        report "NOTE: Stimuli ended" severity note;
      wait;
    elsif time_lapse >= time_lapse_max then
      clk <= '0';
      assert FALSE
        report "ERROR: Reached time_lapse_max without activity, probably simulation is stuck!" severity Error;
      wait;      
    else
      clk <= '0';
      wait for tclk/2;
      clk <= '1';
      wait for tclk/2;
    end if;
  end process clkgen;

  monitor_toggling_activity : process(clk, reset_testbench,
                                      ast_source_data, ast_source_valid)
  begin
    if reset_testbench = '0' then
      time_lapse <= 0 ns;
    elsif ast_source_data'event or ast_source_valid'event then
      time_lapse <= 0 ns;
    elsif rising_edge(clk) then
      if time_lapse < time_lapse_max then
        time_lapse <= time_lapse + tclk;
      end if;
    end if;
  end process monitor_toggling_activity;


-------------------------------------------------------------------------------
-- reset generator
-------------------------------------------------------------------------------
  reset_testbench_gen : process
  begin  -- process resetgen
    reset_testbench <= '1';
    wait for tclk/4;
    reset_testbench <= '0';
    wait for tclk*2;
    reset_testbench <= '1';
    wait;
  end process reset_testbench_gen;
  reset_design_gen : process
  begin  -- process resetgen
    reset_design <= '1';
    wait for tclk/4;
    reset_design <= '0'; 
    wait for tclk*2;
    reset_design <= '1';
    wait for tclk*80;
    reset_design <= '1';
    wait for tclk*128*2;
    reset_design <= '1';
    wait;
  end process reset_design_gen;

-------------------------------------------------------------------------------
-- control signals
-------------------------------------------------------------------------------

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)));

其仿真波形如下所示:

【幅频均衡带通滤波器】基于FPGA的幅频均衡带通滤波器的设计[通俗易懂]

图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带通滤波器’);

其仿真结果如下所示:

【幅频均衡带通滤波器】基于FPGA的幅频均衡带通滤波器的设计[通俗易懂]

图4 带通FIR滤波器仿真图

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

【幅频均衡带通滤波器】基于FPGA的幅频均衡带通滤波器的设计[通俗易懂]

图5 带通FIR滤波器仿真图

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

【幅频均衡带通滤波器】基于FPGA的幅频均衡带通滤波器的设计[通俗易懂]

【幅频均衡带通滤波器】基于FPGA的幅频均衡带通滤波器的设计[通俗易懂]

其仿真结果如下所示:

【幅频均衡带通滤波器】基于FPGA的幅频均衡带通滤波器的设计[通俗易懂]

5.参考文献

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

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/197858.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号