基于FPGA/CPLD的MSK调制解调的工程应用
0赞基于FPGA/CPLD的MSK调制解调的工程应用
为了便于信号发射,提高信道利用率、发射功率效率以及改善通信质量,人们研制出各种通信信号的调制样式。尽管调制样式多种多样,但实质上调制不外乎用调制信号去控制载波的某一个(或几个)参数,使这个参数按照调制信号的规律而变化。调制信号可以分别“寄生”在已调信号的振幅、频率和相位中,相应的调制就是调幅、调频和调相这三大类熟知的调制方式。
MSK信号就是调频这一大类中的一种相位连续的移频键控。其主要特点是包络恒定,带外辐射小,实现较简单,可用于移动通信中的数字传输。
MSK信号具有如下特点:
1)已调制信号的振幅是恒定的;
2)信号的频率偏移严格地等于正负1/4Ts,相应的调制指数h=(f2—f1)Ts=1/2;
3)以载波相位为基准的信号相位在一个码元期间内准确地线性变化正负Π/2;
4)在一个码元期间内,信号应包括四分之一载波周期的整数倍;
5)在码元转换时刻信号的相位是连续的,或者说,信号的波形没有突跳
MSK调制方式的突出优点是信号具有
恒定的振幅及信号的功率谱在主瓣以外衰减较快。然而,在一些通信场合,列如移动通信中,对信号带外辐射功率的限制是十分严格的,比如必须衰减70-80db以上。
GMSK是在MSK调制器之前加入一高斯低通滤波器。也就是说,用高斯低通滤波器作为MSK调制的前置滤波器。之前做过了高斯低通滤波器的FPGA设计。这一节做MSK调制的设计,下一节将把二者连接起来成为一个GMSK调制系统。
第三路信号source是基带码元,第五和第七路信号分别为IQ两路信号,其与分别与余弦和正弦相乘的波形如qsin和pcos所示。
产生两路正余弦高频调制信号分别为hsin和hcos,再将它们与原pq两路信号相乘结果如pmux和qmux。
将得到的pmux和qmux信号相加,得到的mskout信号即MSK调制的最后输出。
Verilog代码如下:
module msk_top(clk,rst,rfd,pcos,qsin,hcos,hsin,pmux,qmux,mskout);
input clk; //主时钟信号
input rst; //复位信号
input rfd;
// output[15:0] cos,sin;
output[15:0] pcos,qsin;
// output[15:0] p,q;
output[15:0] hcos,hsin;
output[31:0] pmux,qmux;
output[32:0] mskout;
wire clk_500; //50分频信号
wire clk_50; //500分频信号
wire nd; //差分编码输出标志位
wire rfd; //差分编码启动位
wire[15:0] source; //差分信号
wire[15:0] p,q; //pq两路信号
wire iqen; //pq两路信号输出标志位
wire[15:0] phase_in; //输入相位
wire ce; //cos和sin工作使能信号
wire csrdy; //cos和sin输出使能信号
wire pqsrdy; //pcos和qsin输出使能信号
wire[15:0] cos,sin; //正余弦发生信号
wire[15:0] pcos,qsin;//输出的I、Q两路信号
wire[15:0] phase_h; //高频相位
wire rdyhigh; //高频相位产生模块输出使能信号
wire[15:0] hcos,hsin;//高频正余弦输出
wire[31:0] pmux,qmux;//IQ两路信号的的最后输出
wire muxprdy,muxqrdy;//IQ两路信号的输出使能信号
wire[32:0] mskout; //MSK调制输出
wire mskrdy; //MSK调制使出使能信号
clkfen clkfen( .clk(clk), .rst(rst), .clk_500(clk_500), .clk_50(clk_50));
sent_source sent_source( .clk_50(clk_50), .rst(rst), .nd(nd), .rfd(rfd), .source(source) );
pqvalue pqvalue( .clk(clk_50), .rst(rst), .nd(nd), .signal_in(source), .preg(p), .qreg(q), .rdy(iqen));
phase_generate phase_generate( .clk(clk_500), .rst(rst), .en(nd), .phase(phase_in), .rdy(ce) );
cos_sin cos_sin( .phase_in(phase_in), .clk(clk_500), .ce(ce), .x_out(cos), .y_out(sin), .rdy(csrdy));
pcosqsin pcosqsin( .clk(clk), .rst(rst), .en(csrdy), .iqen(iqen), .p(p), .q(q),
.sin(sin), .cos(cos), .qsin(qsin), .pcos(pcos), .rdy(pqsrdy));
highfre highfre( .clk(clk_500), .rst(rst), .en(nd), .phase(phase_h), .rdy(rdyhigh));//高频相位产生模块
hcossin hcossin( .phase_in(phase_h), .clk(clk_500), .ce(rdyhigh), .x_out(hcos), .y_out(hsin), .rdy(hfrdy));
mux muxp( .clk(clk_500), .a(pcos), .b(hcos), .q(pmux), .nd(hfrdy), .rdy(muxprdy));
mux2 muxq( .clk(clk_500), .a(qsin), .b(hsin), .q(qmux), .nd(hfrdy), .rdy(muxqrdy));
add add( .clk(clk_500), .rst(rst), .en(muxprdy), .a(pmux), .b(qmux), .sum(mskout), .rdy(mskrdy));
endmodule
module clkfen(clk,rst,clk_500,clk_50);
input clk;
input rst;
output clk_50,clk_500;
reg clk_50,clk_500;
reg[8:0] num;
always @ (posedge clk or posedge rst) begin
if(rst) begin
num <= 9'd0;
clk_500 <= 0;
clk_50 <= 0;
end
else begin
num <= num+1;
// if(num == 9) begin
// num <= 0;
// clk_50 <= ~clk_50;
// end
case (num)
9'd49: clk_500 <= ~clk_500;
9'd99: clk_500 <= ~clk_500;
9'd149: clk_500 <= ~clk_500;
9'd199: clk_500 <= ~clk_500;
9'd249: clk_500 <= ~clk_500;
9'd299: clk_500 <= ~clk_500;
9'd349: clk_500 <= ~clk_500;
9'd399: clk_500 <= ~clk_500;
9'd449: clk_500 <= ~clk_500;
9'd499: begin num <= 0;
clk_500 <= ~clk_500;
clk_50 <= ~clk_50;
end
default: ;
endcase
end
end
endmodule
module sent_source(clk_50,rst,nd,rfd,source);
input clk_50; //50KHz时钟信号
input rst; //复位信号,高电平有效
input rfd;
output[15:0] source; //1bit基带信号,用16bit表示
output nd;
reg[15:0] source;
reg[15:0] scode;
reg[3:0] num;
reg nd;
always @ (posedge clk_50 or posedge rst) begin
if(rst) begin
nd <= 0;
source <= 16'd0;
num <= 4'b1111;
scode <= 16'b1010011010111111; //1011101001101001;
end
else if(rfd) begin
if(scode[num]) begin
source <= 16'h7fff;
end
else begin
source <= 16'h8000;
end
nd <= 1;
num <= num-1;
end
else nd <= 0;
end
endmodule
module pqvalue(clk,rst,nd,signal_in,preg,qreg,rdy);
input clk;
input rst;
input nd; //该模块工作启动信号
input[15:0] signal_in; //输入的十六位信号
output[15:0] preg;
output[15:0] qreg;
output rdy;
reg num;
reg[15:0] signal_reg;
reg[15:0] p,q;
reg[15:0] preg,qreg;
reg rdy; //输出标志位
reg rdy0;
always @ (posedge clk or posedge rst) begin
if(rst) begin
p <= 16'h7fff; //p的初始值为+1
q <= 16'h7fff; //q的初始值为+1
num <= 1;
signal_reg <= 0;
rdy0 <= 0;
end
else if(nd) begin
rdy0 <= 1;
num <= ~num;
signal_reg <= signal_in;
case( {signal_reg,signal_in} )
32'h7fff8000: if(num) q <= ~q;
else p <= ~p; //-1,+1
32'h80007fff: if(num) q <= ~q;
else p <= ~p; //+1,-1
default: ; //其它情况p和q值保持不变
endcase
end
else begin
p <= 16'h7fff; //p的初始值为+1
q <= 16'h7fff; //q的初始值为+1
num <= 1;
signal_reg <= 0;
rdy0 <= 0;
end
end
always @ (posedge clk) begin //将数据缓冲一个时钟周期后输出
if(rst) begin
preg <= 16'd0;
qreg <= 16'd0;
rdy <= 0;
end
else if(rdy0) begin
preg <= p;
qreg <= q;
rdy <= 1;
end
else begin
preg <= 16'd0;
qreg <= 16'd0;
rdy <= 0;
end
end
endmodule
module pqvalue(clk,rst,nd,signal_in,preg,qreg,rdy);
input clk;
input rst;
input nd; //该模块工作启动信号
input[15:0] signal_in; //输入的十六位信号
output[15:0] preg;
output[15:0] qreg;
output rdy;
reg num;
reg[15:0] signal_reg;
reg[15:0] p,q;
reg[15:0] preg,qreg;
reg rdy; //输出标志位
reg rdy0;
always @ (posedge clk or posedge rst) begin
if(rst) begin
p <= 16'h7fff; //p的初始值为+1
q <= 16'h7fff; //q的初始值为+1
num <= 1;
signal_reg <= 0;
rdy0 <= 0;
end
else if(nd) begin
rdy0 <= 1;
num <= ~num;
signal_reg <= signal_in;
case( {signal_reg,signal_in} )
32'h7fff8000: if(num) q <= ~q;
else p <= ~p; //-1,+1
32'h80007fff: if(num) q <= ~q;
else p <= ~p; //+1,-1
default: ; //其它情况p和q值保持不变
endcase
end
else begin
p <= 16'h7fff; //p的初始值为+1
q <= 16'h7fff; //q的初始值为+1
num <= 1;
signal_reg <= 0;
rdy0 <= 0;
end
end
always @ (posedge clk) begin //将数据缓冲一个时钟周期后输出
if(rst) begin
preg <= 16'd0;
qreg <= 16'd0;
rdy <= 0;
end
else if(rdy0) begin
preg <= p;
qreg <= q;
rdy <= 1;
end
else begin
preg <= 16'd0;
qreg <= 16'd0;
rdy <= 0;
end
end
endmodule
module phase_generate(clk,rst,en,phase,rdy);
input clk;
input rst;
input en;
output[15:0] phase;
output rdy;
reg[15:0] phase;
reg rdy;
always @ (posedge clk or posedge rst) begin
if(rst) begin
phase <= 16'h0000;
rdy <= 0;
end
else if(en) begin
rdy <= 1;
if( (phase < 16'h8000) && (phase > 16'h6087) ) begin
phase <= 16'h9b82; //-pi
end
else begin
phase <= phase + 16'h0527; //0527
end
end
else begin
phase <= 16'h0000;
rdy <= 0;
end
end
endmodule
module pcosqsin(clk,rst,en,iqen,p,q,sin,cos,qsin,pcos,rdy);
input clk;
input rst;
input en;
input iqen;
input[15:0] p,q;
input[15:0] sin,cos;
output[15:0] qsin,pcos;
output rdy;
reg[15:0] qsin,pcos;
reg rdy;
reg[15:0] preg,qreg;
always @ (posedge clk) begin
if(rst) begin
qsin <= 16'd0;
pcos <= 16'd0;
rdy <= 0;
end
else if(en) begin
rdy <= 1;
case(preg)
16'h7fff: pcos <= cos;
16'h8000: pcos <= ~cos + 1;
default: ;
endcase
case(qreg)
16'h7fff: qsin <= sin;
16'h8000: qsin <= ~sin + 1;
default: ;
endcase
end
else begin
qsin <= 16'd0;
pcos <= 16'd0;
rdy <= 0;
end
end
always @ (posedge clk) begin //pq两路信号缓冲一个时钟周期
if(rst) begin
preg <= 16'd0;
qreg <= 16'd0;
end
else if(iqen) begin
preg <= p;
qreg <= q;
end
else begin
preg <= 16'd0;
qreg <= 16'd0;
end
end
endmodule
module highfre(clk,rst,en,phase,rdy);
input clk;
input rst;
input en;
output[15:0] phase;
output rdy;
reg[15:0] phase;
reg rdy;
reg rdyreg;
always @ (posedge clk or posedge rst) begin
if(rst) begin
phase <= 16'h0000;
rdy <= 0;
end
else if(rdyreg) begin
rdy <= 1;
if( (phase < 16'h8000) && (phase > 16'h6087) ) begin
phase <= 16'h9b82; //-pi
end
else begin
phase <= phase + 16'h3243; //1657
end
end
else begin
phase <= 16'h0000;
rdy <= 0;
end
end
always @ (posedge clk or posedge rst) begin
if(rst) begin
rdyreg <= 0;
end
else if(en) begin
rdyreg <= 1;
end
else begin
rdyreg <= 0;
end
end
endmodule
module add(clk,rst,en,a,b,sum,rdy);
input clk;
input rst;
input en;
input[31:0] a,b;
output[32:0] sum;
output rdy;
reg[32:0] sum;
reg rdy;
always @ (posedge clk) begin
if(rst) begin
sum <= 33'd0;
rdy <= 0;
end
else if(en) begin
rdy <= 1;
sum <= {a[31],a} + {b[31],b};
end
else begin
sum <= 33'd0;
rdy <= 0;
end
end
endmodule
其中用到两个正余弦和两个乘法的IP Core.正所谓用面积换速度吧。