matlab2013b,quartusii121.
带通滤波器是数字振幅平衡功率放大器的重要组成部分。在介绍带通滤波器之前,我们将首先详细介绍数字振幅平衡功率放大器。
本系统要求的指标为:
本课题要求输入电压的有效值为5mV在这种情况下,放大倍数达到400倍。Hz到20kHz衰减不得超过1dB。-1 dB可以说指标要求很高,信号幅值变化为11%。我们可以选择使用它PGA或AD620实现这一指标。
整个系统的基本结构如下:

图1 系统总结结构框图
根据上述分析,系统的整体框图如图1所示。输入信号首先通过前置放大电路放大到一定范围,信号的振幅频率特性通过阻塞网络发生变化。由于AD输入范围限制,信号通过衰减网络衰减两倍,然后通过抗混叠滤波器使用AD采样输入信号,输入采样结果FPGA均衡幅频。最后通过DA输出并滤波,经过D类功放后即可得到大功率信号。
·设计前置放大电路
输入信号电压放大倍数不小于400倍,单级放大倍数难以达到如此高,因此采用两级放大的形式进行前级放大。因为系统频率为20Hz~20kHz,所以选用OP27运输完成电路。
·抗混叠滤波器电路设计
根据采样定理,为了防止采样信号频域混合,必须在A/D抗混叠滤波器电路添加到采样电路的前端,截止频率为采样频率的一半。因为这个系统主要处理200年kHz因此,选择开关电容滤波器LTC八阶椭圆滤波器设计于1068-25,截止频率为25kHz。
·A/D采样电路的设计
根据主题指标和系统频率的要求,我们需要一个采样率超过40KHz采样芯片。AD9223是一款12bits、最高采样频率为10MHz性能优异AD采样器件,由于以前使用过芯片,为了更快地完成主题,所以选择AD9223作为采样芯片。
·数字振幅平衡模块设计
数字幅频平衡模块的原理图如图4-3所示。如果要实现对带阻网络的完全补偿,那么FIR滤波器应与带阻网络相互反向.点频法可以测量带阻网络的系统函数,然后使用MATLAB求出加窗后FIR滤波器应具有单位脉冲响应。因为FIR系统具有线性相位特性,所以由其幅频响应就可以求得其系统函数。
图2 数字幅频平衡模块的原理图
·D/A输出电路设计
根据主题的指标和系统频率的要求,我们需要40多个频率KHz模数输出芯片。DAC904是一款14bits、最高采样频率为165MHz的的DA由于以前使用过芯片,设备仍然被选择DAC904作为数模输出芯片。
·电源放大电路设计
D与三角波相比,类功放的第一部分是调制器,输入信号接比器的正输入端。当正端电位高于负三角波电位时,比较器输出为高电平,反之亦然。这样,比较器输出的波形是由音频信号范围调制的脉冲宽度的波形,称为SPWM波。D类功放后输出电路是脉冲控制的大电流开关放大器,正半周期比较器输出高电平,MOSFET晶体管Q1导通,且Q2截止日期,负半周期比较器输出高电平Q2导通,且Q1截止日期,使其输出比较器PWM信号变成高电压、大电流的大功率PWM最后,声音信息只能通过二级低通滤波器恢复。
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;
我们在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