Δ-∑A/D转换器以其高精度和易于用标准数字CMOS 工艺实现的特点而被广泛应用。数字抽取滤波器是它的重要组成部分,通常采用多级结构来实现。由于梳状滤波器是一种结构简单的线性相位FIR滤波器,所以通常被用作数字滤波器的第一级。文中设计了一种梳状滤波器,该滤波器用于Δ-∑模数转换器中数字滤波器的第一级,以级联结构实现,在每一级中采用多相分解结构,以此减小滤波器的功耗和面积。滤波器电路采用Verilog HDL设计,通过ModelSim进行调试与功能仿真,然后将仿真结果导入MATLAB进行频谱分析。分析结果表明该阻带衰减达到了100 dB,系统达到了功能要求。最后用综合工具Synplify Pro 7.3对代码进行综合与优化,生成了综合网表,证明该滤波器系统可以综合。
随着计算机、通信和多媒体技术的飞速发展,电子产业已经形成了以数字技术为主体的格局,特别是半导体产业显的尤为突出。半导体技术数字化和集成化的日益提高,在推动微控制器(MCU)、数字信号处理器(DSP)、微机械电子系统(MEMS)的发展中,也推动了“嵌入” 或“隐性”模数转换技术的发展[1]。在这些因素的影响下,人们已经开始利用一颗芯片来实现完整的系统,凭借数字信号处理技术可靠的精度、完美的再现性、更大的灵活性等优良特性,实现了介于模拟技术与数字系统之间的接口—模数转换器。虽然模拟部件与数字部件的集成具有诸多好处,但是在关键功能中使用纯模拟芯片将会使性能得以提升,这样就推动了模数转换技术朝着高精度、高速度的方向迈进[2];而且模数转换器(ADC)的性能常常决定了系统的性能。
如今,A/D转换器的发展趋势主要有以下特点[2]:结构不断简化;转换速度提高;高速下尽可能的提高分辨率。
采用过采样Δ-∑模数转换形式可以在提高速度的同时更有效地提高转换器的分辨率,而且其精度已经达到了24位以上。 在过采样Δ-∑A/ D变换器中, 抽取滤波器将经整形后的过采样信号的带外噪声滤除并将抽样频率降低到基带信号的奈奎斯特频率, 最终得到高精度的数字信号, 通常采用多级结构来实现抽取滤波器, 由于梳状滤波器的结构简单以及其频率响应特性,通常用于第一级;其后各级则为 FIR抽取器。
模/数转换器可分为两大类:传统意义上的多位转换器(又称Nyquist模/数转换器)和一位超速采样转换器(又称Δ-∑模/数转换器)。
采用传统技术的Nyquist ADC的分辨率取决于片内精准DAC的匹配;如:逐次逼近(SAR)型、积分型、并行转换、流水线转换和折叠差值转换ADC等[2],都受此局限性的限制,很难实现高于16位的ADC分辨率;如果要实现16位的分辨率,需要复杂的高阶模拟抗混迭滤波器、定时及幅度误差都极小的采样保持电路等,困难极大,成本很高。高分辨率的Nyquist ADC通常以奈奎斯特速率(采样频率大约是输入信号最大频率的2倍)作为采样频率。奈奎斯特采样器需要复杂的模拟低通滤波器(也叫抗混淆滤波器)来限制进入模数转换器和采样保持器电路信号的最大频率。
2.1 传统模数转换器
2.1.1 逐次逼近型转换
逐次逼近型转换方式在当今的模数转换领域有着广泛的应用,它是将需要进行转换的模拟信号与已知的不同的参考电压进行多次比较,使转换后的数字量在数值上逐次逼近输入模拟量的对应值。逐次逼近型转换方式的特点是:转换速度较高,可以达到100万次/秒(MPSP);在低于12位分辨率的情况下,电路实现上较其他转换方式成本低;转换时间确定。但这种转换方式需要数模转换电路,由于高精度的数模转换电路需要较高的电阻或电容匹配网络,故精度不会很高。
2.1.2 积分型转换
积分型模数转换技术在低速、高精度测量领域有着广泛的应用,特别是在数字仪表领域。积分型模数转换技术有单积分和双积分两种转换方式,单积分模数转换的工作原理是将被转换的电信号先变成一段时间间隔,然后再对时间间隔记数,从而间接把模拟量转换成数字量的一种模数转换方法,它的主要缺陷是转换精度不高,主要受到斜坡电压发生器、比较器精度以及时钟脉冲稳定型的影响。
为了提高积分型转换器在同样条件下的转换精度,可采用双积分型转换方式,双积分型转换器通过对模拟输入信号的两次积分,部分抵消了由于斜坡发生器所产生的误差,提高了转换精度。双积分型转换方式的特点表现在:精度较高,可以达到22位;抗干扰能力强,由于积分电容的作用,能够大幅抑止高频噪声。但是,它的转换速度太慢,转换精度随转换速率的增加而降低,每秒100~300次(SPS)对应的转换精度为12位。所以这种转换方式主要应用在低速高精度的转换领域。
2.1.3 并行转换
并行转换方式在所有的模数转换中,转换速度最快,并行转换是一种直接的模数转换方式。它大大减少了转换过程的中间步骤,每一位数字代码几乎在同一时刻得到,因此,并行转换又称为闪烁型转换方式。并行转换的主要特点是它的转换速度特别快,可达50MPSP,特别适合高速转换领域。缺点是分辨率不高,一般都在10位以下;精度较高时,功耗较大。这主要是受到了电路实现的影响,因为一个 N位的并行转换器,需要2N-1个比较器和分压电阻,所以精度越高,比较器的数目越多,制造越困难。
2.1.4 流水线转换
流水线型转换方式是并行转换方式的改进,它在一定程度上既具有并行转换高速的特点,又克服了制造困难的问题。以8位的两级流水线型为例,它的转换过程首先是进行第一级高4位的并行闪烁转换,得到高4位信号;然后把输入的模拟信号与第一级转换后数字信号所表示的模拟量相减,得到的差值送入第二级并行闪烁转换器,得到低4 位信号。流水线型转换方式的特点是:精度较高,可达16位左右;转换速度较快,16位该种类型的ADC速度可达5MPSP,较逐次比较型快;分辨率相同的情况下,电路规模及功耗大大降低。但流水线型转换方式是以牺牲速度来换取高精度的,还存在转换出错的可能。即第一级剩余信号的范围不满足第二级并行闪烁ADC量程的要求时,会产生线性失真或失码现象,需要额外的电路进行调整。
2.1.5 折叠差值转换
折叠插值型转换方式克服了流水线型分步转换所带来的速度下降,它通过预处理电路,同时得到高位和低位数据,元件的数目却大大减少。折叠插值型转换方式信号预处理的方法是折叠—就是把输入较大的信号映射到某一个较小的区域内,并将其转换成数字信号,这个数据为整个数字量的低位数据;然后再找出输入信号被映射的区间,该区间也以数字量表示,这个数据为整个数字量的高位数据。高位和低位数据经过处理,得到最后的数字信号。
折叠插值转换方式的特点是:数据的两次量化是同时进行的,具有并行转换的特点,速度较快;电路规模及功耗不大,如8位转换器只需40个比较器。折叠插值方式在信号频率过高时,需要额外的处理电路;且当位数超过8位时,如要保持较少的比较器数目,折叠插值变得很麻烦,所以一般只用于8位以下的转换器当中。
触发器的设计属于时序逻辑设计部分,触发器的边沿敏感的存储单元,数据存储的动作是由某一个信号(通常叫时钟信号)的上升沿或下降沿进行同步的。D触发器是一种最简单的触发器,它在时钟的第个有效沿存储D输入端的当前值,这个值与当前已存储的数据无关;同时它也可以作为一个时钟的延迟。1位D触发器模块的方框图及其真值表分别如图4-3和表4-1所示。
以下是所编写的Verilog HDL代码,列出了1位的D触发器、1位的抽取器和5位的加法器。
(1) 程序清单4-1 时钟代码
`timescale 1ns/1ps
module clk(clk,reset,clk_2,clk_4,clk_8,clk_16,clk_32, hold_2,hold_4,hold_8,
hold_16,hold_32, start_2,start_4,start_8,start_16,start_32);
input clk,reset;
output clk_2,clk_4,clk_8,clk_16,clk_32;
output start_2,start_4,start_8,start_16,start_32;
output hold_2,hold_4,hold_8,hold_16,hold_32;
reg hold_2,hold_4,hold_8,hold_16,hold_32;
reg[4:0] count;
reg start_2,start_4,start_8,start_16,start_32;
wire clk_32=~count[4],clk_16=~count[3],clk_8=~count[2],clk_4=~count[1], clk_2=~count[0];
always @(posedge clk or posedge reset)
if (reset)
begin
hold_2<=1; hold_4<=1; hold_8<=1; hold_16<=1; hold_32<=1;
count<=0;
start_2<=1; start_4<=1; start_8<=1; start_16<=1; start_32<=1;
end
else
begin
count<=count+1;
if(count==5'b11111)
begin
hold_2<=0; hold_4<=0; hold_8<=0; hold_16<=0; hold_32<=0; start_32<=0;
end
else if(count==15)
begin
hold_2<=0; hold_4<=0; hold_8<=0; hold_16<=0; start_16<=0;
end
else if(count==7)
begin
hold_2<=0; hold_4<=0; hold_8<=0; start_8<=0;
end
else if(count[1:0]==2'b11)
begin
hold_2<=0; hold_4<=0; start_4<=0;
end
else if(count[0]==1)
begin
hold_2<=0; start_2<=0;
end
else begin
hold_2<=1; hold_4<=1; hold_8<=1; hold_16<=1;
end
end
endmodule
(2) 程序清单4-2 1位D触发器代码
`timescale 1ns/1ps
module D_s(data_in,reset,clk,data_out);
parameter size=1;
input [size-1:0]data_in;
input reset;
input clk;
output[size-1:0] data_out=4'b0;
reg[size-1:0] data_out;
always @(posedge clk)
if(reset)
data_out<=0;
else
data_out<=data_in;
endmodule
(3) 程序清单4-3 1位抽取器代码
`timescale 1ns/1ps
module samp1(data_out,data_in,hold,clk,reset);
parameter size=1;
output[size-1:0]data_out;
input[size-1:0]data_in;
input clk,hold,reset;
reg[size-1:0]data_out=1'b0;
always @(posedge clk)
if(reset)
data_out<=0;
else
if (hold)
data_out<=data_out;
else
data_out<=data_in;
endmodule
(4) 程序清单4-4 5位加法器代码
`timescale 1ns/1ps
module sum5(in_a,in_b,cin,sum,c);
parameter size=5;
output c;
output [size-1:0]sum;
input [size-1:0]in_a,in_b;
input cin;
assign {c,sum}=in_a+in_b+cin;
endmodule
(5) 程序清单4-5 级联结构第1级代码
`timescale 1ns/1ps
module stage0(out,in,start_2,clk,clk_2,hold_2,reset);
parameter size=1;
input in;
input clk,reset;
input hold_2;
input clk_2;
input start_2;
output[size+3:0] out;
wire clk_2,clk_4,clk_8,clk_16,clk_32, start_2,start_4,start_8,start_16,start_32;
wire hold_2,hold_4,hold_8,hold_16,hold_32;
wire [size-1:0] ploy_0,ploy_1,ploy_2;
wire [size+3:0] ploy00,ploy11,ploy22;
wire[size+3:0] sum1,sum2,sum3;
wire[size+3:0] out;
wire c1,c2,c3,c4;
wire c1_D,c2_D,c3_D,c4_D;
wire[size-1:0] data_D;
wire[size-1:0] x0_1,x0_2;
wire[size+3:0] x0_11,x0_22;
wire[size+3:0] y1,y0;
wire[size+3:0] x1_D,x2_D,x3_D;
assign out=y0+y1;
samp1 S1(ploy_0,in,hold_2,clk,reset);
D_s DD(in,reset,clk,data_D);
samp1 S2(ploy_1,data_D,hold_2,clk,reset);
D_s DD1(ploy_1,start_2,clk_2,ploy_2);
D_s DD2(ploy_0,start_2,clk_2,x0_1);
D_s DD3(x0_1,start_2,clk_2,x0_2);
assign x0_11={4'b0,x0_1},x0_22={4'b0,x0_2},ploy00={4'b0,ploy_0},
ploy11={4'b0,ploy_1}, ploy22={4'b0,ploy_2}; // 位扩展
// H0(z)
D_s D4(c1,start_2,clk_2,c1_D);
sum5 F1(ploy00,x0_22,c1_D,sum1,c1);
D_s D5(c2,start_2,clk_2,c2_D);
D_s_5 D6(x0_22,start_2,clk_2,x2_D);
sum5 F2(x2_D,x0_22,c2_D,sum2,c2);
D_s D7(c3,start_2,clk_2,c3_D);
sum5 F3(sum1,sum2,c3_D,y0,c3);
// H1(z)
D_s D8(c4,start_2,clk_2,c4_D);
sum5 F4(ploy11,ploy22,c4_D,sum3,c4);
D_s_5 D9(sum3,start_2,clk_2,x3_D);
D_s_5 D10(x3_D,start_2,clk_2,y1);
endmodule
(6) 程序清单4-6 梳状滤波器的综合代码
`timescale 1ns/1ps
module cmb(in,reset,clk,clk_2,clk_4,clk_8,clk_16,clk_32, hold_2,hold_4,hold_8,
hold_16,hold_32,start_2,start_4,start_8,start_16,start_32,out);
input in;
input reset;
input clk,clk_2,clk_4,clk_8,clk_16,clk_32;
input hold_2,hold_4,hold_8,hold_16,hold_32;
input start_2,start_4,start_8,start_16,start_32;
output [20:0] out;
wire [4:0] out0;
wire [8:0] out1;
wire [12:0] out2;
wire [16:0] out3;
wire clk_2,clk_4,clk_8,clk_16,clk_32, hold_2,hold_4,hold_8,hold_16,hold_32;
wire start_2,start_4,start_8,start_16,start_32;
integer MFile;
stage0 v0(out0,in,start_2,clk,clk_2,hold_2,reset);
stage1 v1(out1,out0,start_4,clk_2,clk_4,hold_4,start_2);
stage2 v2(out2,out1,start_8,clk_4,clk_8,hold_8,start_4);
stage3 v3(out3,out2,start_16,clk_8,clk_16,hold_16,start_8);
stage4 v4(out,out3,start_32,clk_16,clk_32,hold_32,start_16);
initial
begin
MFile=$fopen("open_comb_20k.txt"); // 打开文档
if(!MFile)
begin
$display(" Could not open");
$finish;
end
end
always @(posedge clk_32)
begin
$fdisplay (MFile,"%d",out); // 以十进制显示输出
$fclose(MFile);
end
always @(posedge clk_32)
$display ("comb_out=%b",out); // 以二进制在命令框中显示输出
endmodule
(7) 程序清单4-7 综合测试代码
`timescale 1ns/1ps
`include "cmb.v"
module test_cmb( );
parameter length=65536*6;
reg in;
reg reset;
reg clk;
reg mem[length-1:0] ;
wire[20:0] out;
integer k;
initial begin
in=0;
reset=1;
clk=0;
# 30 reset=0;
end
always # 10 clk=~clk;
initial $readmemb("input_65536_6_20k.dat",mem); // 读入调制后的信号
initial for (k=0;k<length-1;k=k+1)
@(posedge clk)
begin
in=mem[k];
end
clk CLK(clk,reset,clk_2,clk_4,clk_8,clk_16,clk_32, hold_2,hold_4,hold_8,
hold_16,hold_32,start_2,start_4,start_8,start_16,start_32);
cmb T(in,reset,clk,clk_2,clk_4,clk_8,clk_16,clk_32, hold_2,hold_4,hold_8,
hold_16,hold_32,start_2,start_4,start_8,start_16,start_32,out);
endmodule