实验目的
1.使用EDA技术和硬件描述语言(Verilog)实现现代通信技术中的PCM编码技术。
2.加深对课程所学EDA技术以及PCM编码过程的理解。
实验原理
- PCM(Pulse Code Modulation)脉冲编码调制是数字通信的编码方式之一。主要过程是将话音、图像等模拟信号每隔一定时间进行取样,使其离散化,同时将抽样值按分层单位四舍五入取整量化,同时将抽样值按一组二进制码来表示抽样脉冲的幅值。
2.FPGA中的ROM是一种只读存储器,主要用来存储固化的初始化配置数据。在本实验中,使用ROM(Read-Only Memory)来存储模拟信号的样值。
3.ROM中的模拟信号样值数据用Matlab生成mif文件,再将此文件添加至ROM核中。
4.A律13折线近似法:
首先对信号幅值进行归一化处理,即信号的幅值在±1之间。
0~1范围 一分为二,中间点为1/2,取1/2~1之间为第八段
0~1/2范围 一分为二,中间点为1/4,取1/4~1/2为第七段
0~1/4范围 一分为二,中间点为1/8,取1/8~1/4为第六段
0~1/8范围 一分为二,中间点为1/16,取1/16~1/8为第五段
0~1/16范围 一分为二,中间点为1/32,取1/32~1/16为第四段
0~1/32范围 一分为二,中间点为1/64,取1/64~1/32为第三段
0~1/64范围 一分为二,中间点为1/128,取1/128~1/64为第二段
0~1/128范围 ,取0~1/128为第一段。
最后将每个(非均匀)线段再均匀分为16个量化间隔(0~15),这样共有16*16=256个量化级(话音)。
最小量化间隔△:第八段落长度最短,长度为1/128,段内再16等分,每一个小段就是1/2048,这就是最小量化间隔△。
5.八位折叠码:
C1为极性码, C2 C3 C4 为段落码, C5 C6 C7 C8为段内码;具体规则为:抽样值大于0,则极性码为1,小于0则极性码为0。
实验原理框图
实验步骤
1、由于PCM编码过程输入的是模拟信号,所以要用ModelSim输出一段模拟信号,这里使用Quartus软件的ROM核来存储模拟信号的样值。样值的输入采用Matlab生成mif文件,再将文件导入ROM核中。在设置ROM核时可以选择自动生成ROM.v文件,将其作为底层模块。
2、顶层模块的设计:使用状态机进行PCM的编码过程,采用8位码。
代码部分
rom.v
module rom (
address,
clock,
q);//自动生成的rom.v文件
input [11:0] address;
input clock;
output [11:0] q;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_off
`endif
tri1 clock;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_on
`endif
wire [11:0] sub_wire0;
wire [11:0] q = sub_wire0[11:0];
altsyncram altsyncram_component (
.address_a (address),
.clock0 (clock),
.q_a (sub_wire0),
.aclr0 (1'b0),
.aclr1 (1'b0),
.address_b (1'b1),
.addressstall_a (1'b0),
.addressstall_b (1'b0),
.byteena_a (1'b1),
.byteena_b (1'b1),
.clock1 (1'b1),
.clocken0 (1'b1),
.clocken1 (1'b1),
.clocken2 (1'b1),
.clocken3 (1'b1),
.data_a ({12{1'b1}}),
.data_b (1'b1),
.eccstatus (),
.q_b (),
.rden_a (1'b1),
.rden_b (1'b1),
.wren_a (1'b0),
.wren_b (1'b0));
defparam
altsyncram_component.address_aclr_a = "NONE",
altsyncram_component.clock_enable_input_a = "BYPASS",
altsyncram_component.clock_enable_output_a = "BYPASS",
altsyncram_component.init_file = "sin_code.mif",
altsyncram_component.intended_device_family = "Cyclone IV E",
altsyncram_component.lpm_hint = "ENABLE_RUNTIME_MOD=NO",
altsyncram_component.lpm_type = "altsyncram",
altsyncram_component.numwords_a = 4096,
altsyncram_component.operation_mode = "ROM",
altsyncram_component.outdata_aclr_a = "NONE",
altsyncram_component.outdata_reg_a = "CLOCK0",
altsyncram_component.widthad_a = 12,
altsyncram_component.width_a = 12,
altsyncram_component.width_byteena_a = 1;
endmodule
代码解释:这里rom模块中定义了两个输入变量clock(时钟)和address(地址),和一个输出变量q,当到达时钟上升沿时会输出当前地址下的值。这个模块在本实验中将作为子模块被顶层模块调用。
顶层模块:
module PCM(
input clk,
input rst_n,
input [11:0] address1,address2,
input [11:0] data,
output [11:0] readdata1,readdata2,
output reg [7:0] pcm );
rom rom_inst1 (
.address ( address1 ),
.clock ( clk ),
.q ( readdata1 )
);
rom rom_inst2 (
.address ( address2 ),
.clock ( clk ),
.q ( readdata2 )
);
reg [5:0] state;
integer mid1,mid2;
always@(clk)
begin
mid1=data;
mid2=mid1-2047;
if(!rst_n)
begin
state<='b000_000;
end
else
begin
//极性码部分
if(mid2>0)
begin mid1=mid2;pcm[7]=1;end
else
begin mid1=-mid2;pcm[7]=0;end
//段落码部分
case(state)
'b000_000:
begin
state='b000_001;
end
'b000_001:
begin
if(mid1>=128) //处于后4段
begin pcm[6]=1;state='b100_010;end
else
begin pcm[6]=0;state='b000_010;end//处于前4段
end
'b100_010:
begin
if(mid1>=512) //处于后四段中的后两段
begin pcm[5]=1;state='b100_011;end
else//处于后四段中的后两段
begin pcm[5]=0;state='b000_011;end
end
'b000_010:
begin
if(mid1>=32)//处于前四段中的后两段
begin pcm[5]=1;state='b100_100;end
else//处于前四段中的前两段
begin pcm[5]=0;state='b000_100;end
end
'b100_011:
begin
if(mid1>=1024) //处于第八段
begin pcm[4]=1;state='b111_000;end
else//处于第七段
begin pcm[4]=0;state='b110_000;end
end
'b000_011:
begin
if(mid1>=256) //处于第六段
begin pcm[4]=1;state='b101_000;end
else//处于处于第五段
begin pcm[4]=0;state='b100_000;end
end
'b100_100:
begin
if(mid1>=64) //处于第四段
begin pcm[4]=1;state='b011_000;end
else//处于第三段
begin pcm[4]=0;state='b010_000;end
end
'b000_100:
begin
if(mid1>=16) //处于第二段
begin pcm[4]=1;state='b001_000;end
else//处于第一段
begin pcm[4]=0;state='b000_111;end
end
//段内码部分
'b111_000: //第八段段内编码
begin
pcm[3:0]=(mid1-1024)/64;
state='b000_000;
end
'b110_000: //第七段段内编码
begin
pcm[3:0]=(mid1-512)/32;
state='b000_000;
end
'b101_000: //第六段段内编码
begin
pcm[3:0]=(mid1-256)/16;
state='b000_000;
end
'b100_000: //第五段段内编码
begin
pcm[3:0]=(mid1-128)/8;
state='b000_000;
end
'b011_000: //第四段段内编码
begin
pcm[3:0]=(mid1-64)/4;
state='b000_000;
end
'b010_000: //第三段段内编码
begin
pcm[3:0]=(mid1-32)/2;
state='b000_000;
end
'b001_000: //第二段段内编码
begin
pcm[3:0]=(mid1-16)/1;
state='b000_000;
end
'b000_111: //第一段段内编码
begin
pcm[3:0]=(mid1)/1;
state='b000_000;
end
endcase
end
end
endmodule
代码解释:在此模块中,共两次例化了rom模块,一次是输出模拟信号,另外一次是进行信号抽样。除了例化外,就是PCM编码函数。由于A律13折线法正值和负值部分各2048个量化电平,而输入的模拟信号的幅值是0-4096,所以在量化时,将大于2048的减去2048量化为正电平,小于2048的减去2048量化为负电平,正好可以对应PCM量化时的正负各2048个量化电平。
实验结果
1、输出模拟信号波形图
2、采样波形图
3、具体采样值
4、量化值
5、PCM编码输出
6、全部仿真波形图
实验所用软件
Quartus (Quartus Prime 18.1) Lite Edition
ModelSim - Intel FPGA Starter Edition 10.5b (Quartus Prime 18.1)
Matlab 2022