特权同学

基于FPGA/CPLD的MSK调制解调的工程应用

0
阅读(3554)

基于FPGA/CPLDMSK调制解调的工程应用

为了便于信号发射,提高信道利用率、发射功率效率以及改善通信质量,人们研制出各种通信信号的调制样式。尽管调制样式多种多样,但实质上调制不外乎用调制信号去控制载波的某一个(或几个)参数,使这个参数按照调制信号的规律而变化。调制信号可以分别“寄生”在已调信号的振幅、频率和相位中,相应的调制就是调幅、调频和调相这三大类熟知的调制方式。

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.正所谓用面积换速度吧。

Baidu
map