2FSK的介绍可以参考:https://blog.csdn.net/qq_39148922/article/details/84337730
下面介绍verilog HDL的源代码
module FSK(
input clk,//时钟信号
output reg [7:0]sigOut,//输出已调信号
output reg [7:0]carryWave1,//1对应的载波幅度
output reg [7:0]carryWave0,//0对应的载波幅度
output wire codeSource,//数字基带信号
output reg codeClk=0,//用来控制数字基带信号的时钟
output reg stClk=0//用来控制载波的时钟,数字基带时钟周期应为载波时钟的n倍
);
//分频器部分
reg [7:0]codeClkCount=0;//时钟计数器
reg [3:0]carryClkCount=0;//载波时钟计数器
always @(posedge clk)
begin
//codeClk
if(codeClkCount==127)
begin
codeClk=~codeClk;
codeClkCount=0;
end
else
begin
codeClkCount=codeClkCount+1;
end
//carryClk
if(carryClkCount==1)
begin
stClk=~stClk;
carryClkCount=0;
end
else
begin
carryClkCount=carryClkCount+1;
end
end
//数字基带信号,m序列发生器
reg [5:0]outReg=6'b010101;//序列寄存器初始化
reg mAdded;//m序列移位的辅助变量
assign codeSource=outReg[5];//输出变量为寄存器序列的最高位
always @(negedge codeClk)
begin
//手动异或
if(outReg[0]==outReg[5])
begin
mAdded=0;
end
else
begin
mAdded=1;
end
outReg=outReg<<1;//对寄存器左移
outReg=outReg+mAdded;
end
//载波的产生
reg [7:0]waveCount=0;//载波幅度查询变量
always @(posedge stClk)
begin
if(waveCount==63)
begin
waveCount=0;
end
else
begin
waveCount=waveCount+1;
end
//根据查询变量进行载波幅度查询
case(waveCount)
0:begin carryWave0<=0;carryWave1<=0; end
1:begin carryWave0<=12;carryWave1<=25; end
2:begin carryWave0<=25;carryWave1<=49; end
3:begin carryWave0<=37;carryWave1<=71; end
4:begin carryWave0<=49;carryWave1<=90; end
5:begin carryWave0<=60;carryWave1<=106; end
6:begin carryWave0<=71;carryWave1<=117; end
7:begin carryWave0<=81;carryWave1<=125; end
8:begin carryWave0<=90;carryWave1<=127; end
9:begin carryWave0<=98;carryWave1<=125; end
10:begin carryWave0<=106;carryWave1<=117; end
11:begin carryWave0<=112;carryWave1<=106; end
12:begin carryWave0<=117;carryWave1<=90; end
13:begin carryWave0<=122;carryWave1<=71; end
14:begin carryWave0<=125;carryWave1<=49; end
15:begin carryWave0<=126;carryWave1<=25; end
16:begin carryWave0<=127;carryWave1<=0; end
17:begin carryWave0<=126;carryWave1<=-25; end
18:begin carryWave0<=125;carryWave1<=-49; end
19:begin carryWave0<=122;carryWave1<=-71; end
20:begin carryWave0<=117;carryWave1<=-90; end
21:begin carryWave0<=112;carryWave1<=-106; end
22:begin carryWave0<=106;carryWave1<=-117; end
23:begin carryWave0<=98;carryWave1<=-125; end
24:begin carryWave0<=90;carryWave1<=-127; end
25:begin carryWave0<=81;carryWave1<=-125; end
26:begin carryWave0<=71;carryWave1<=-117; end
27:begin carryWave0<=60;carryWave1<=-106; end
28:begin carryWave0<=49;carryWave1<=-90; end
29:begin carryWave0<=37;carryWave1<=-71; end
30:begin carryWave0<=25;carryWave1<=-49; end
31:begin carryWave0<=12;carryWave1<=-25; end
32:begin carryWave0<=0;carryWave1<=0; end
33:begin carryWave0<=-12;carryWave1<=25; end
34:begin carryWave0<=-25;carryWave1<=49; end
35:begin carryWave0<=-37;carryWave1<=71; end
36:begin carryWave0<=-49;carryWave1<=90; end
37:begin carryWave0<=-60;carryWave1<=106; end
38:begin carryWave0<=-71;carryWave1<=117; end
39:begin carryWave0<=-81;carryWave1<=125; end
40:begin carryWave0<=-90;carryWave1<=127; end
41:begin carryWave0<=-98;carryWave1<=125; end
42:begin carryWave0<=-106;carryWave1<=117; end
43:begin carryWave0<=-112;carryWave1<=106; end
44:begin carryWave0<=-117;carryWave1<=90; end
45:begin carryWave0<=-122;carryWave1<=71; end
46:begin carryWave0<=-125;carryWave1<=49; end
47:begin carryWave0<=-126;carryWave1<=25; end
48:begin carryWave0<=-127;carryWave1<=0; end
49:begin carryWave0<=-126;carryWave1<=-25; end
50:begin carryWave0<=-125;carryWave1<=-49; end
51:begin carryWave0<=-122;carryWave1<=-71; end
52:begin carryWave0<=-117;carryWave1<=-90; end
53:begin carryWave0<=-112;carryWave1<=-106; end
54:begin carryWave0<=-106;carryWave1<=-117; end
55:begin carryWave0<=-98;carryWave1<=-125; end
56:begin carryWave0<=-90;carryWave1<=-127; end
57:begin carryWave0<=-81;carryWave1<=-125; end
58:begin carryWave0<=-71;carryWave1<=-117; end
59:begin carryWave0<=-60;carryWave1<=-106; end
60:begin carryWave0<=-49;carryWave1<=-90; end
61:begin carryWave0<=-37;carryWave1<=-71; end
62:begin carryWave0<=-25;carryWave1<=-49; end
63:begin carryWave0<=-12;carryWave1<=-25; end
endcase
end
//调制部分
always @(posedge stClk)
begin
if(codeSource)
begin
sigOut=carryWave1;
end
else
begin
sigOut=carryWave0;
end
end
endmodule
方法相对粗糙一些,毕竟是第一次用verilog实现调制的过程,就是按照调制的原理分步完成,考虑到的可优化的地方较少。
下面逐个对每个模块进行介绍。
分频器
//分频器部分
reg [7:0]codeClkCount=0;//时钟计数器
reg [3:0]carryClkCount=0;//载波时钟计数器
always @(posedge clk)
begin
//codeClk
if(codeClkCount==127)
begin
codeClk=~codeClk;
codeClkCount=0;
end
else
begin
codeClkCount=codeClkCount+1;
end
//carryClk
if(carryClkCount==1)
begin
stClk=~stClk;
carryClkCount=0;
end
else
begin
carryClkCount=carryClkCount+1;
end
end
对于分频器,写过verilog的同学应该都比较熟悉。就是让程序去数数嘛,看着时钟滴答滴答的走:1、2、3、4……127!然后将时钟取反一次,再次重新计数。这叫做256分频。计数置位的时刻应该是分频数的一半。
需要特别说明的是,在这里之所以需要两个时钟,主要还是为了下面的系统处理进行服务的。分频数应该适应于要处理的问题。我们希望看到数字信号的每个码元对应正弦波的一个周期,或者两个周期,总之要有一个容易判断的对应关系。不然如果一串数字信号是00001111,这样的信号调制过后,谁能知道一个正弦波中有几个0几个1呢。
至于分频后时钟比例的确定,到后面载波的部分再进一步确定。
数字基带信号的产生
//数字基带信号,m序列发生器
reg [5:0]outReg=6'b010101;//序列寄存器初始化
reg mAdded;//m序列移位的辅助变量
assign codeSource=outReg[5];//输出变量为寄存器序列的最高位
always @(negedge codeClk)
begin
//手动异或
if(outReg[0]==outReg[5])
begin
mAdded=0;
end
else
begin
mAdded=1;
end
outReg=outReg<<1;//对寄存器左移
outReg=outReg+mAdded;
end
数字基带信号通过m序列产生。m序列通过控制寄存器移位来产生“不太有规律”的信号,这样的信号通常用来当作一个系统的检测序列。不必太纠结于m序列的产生原理,只要是可以测试系统的二进制序列都可以。完全可以随心所欲地写一串二进制码让它循环输出,也可以达到测试系统的效果。
载波的产生
//载波的产生
reg [7:0]waveCount=0;//载波幅度查询变量
always @(posedge stClk)
begin
if(waveCount==63)
begin
waveCount=0;
end
else
begin
waveCount=waveCount+1;
end
//根据查询变量进行载波幅度查询
case(waveCount)
0:begin carryWave0<=0;carryWave1<=0; end
1:begin carryWave0<=12;carryWave1<=25; end
2:begin carryWave0<=25;carryWave1<=49; end
3:begin carryWave0<=37;carryWave1<=71; end
4:begin carryWave0<=49;carryWave1<=90; end
5:begin carryWave0<=60;carryWave1<=106; end
6:begin carryWave0<=71;carryWave1<=117; end
7:begin carryWave0<=81;carryWave1<=125; end
8:begin carryWave0<=90;carryWave1<=127; end
9:begin carryWave0<=98;carryWave1<=125; end
10:begin carryWave0<=106;carryWave1<=117; end
11:begin carryWave0<=112;carryWave1<=106; end
12:begin carryWave0<=117;carryWave1<=90; end
13:begin carryWave0<=122;carryWave1<=71; end
14:begin carryWave0<=125;carryWave1<=49; end
15:begin carryWave0<=126;carryWave1<=25; end
16:begin carryWave0<=127;carryWave1<=0; end
17:begin carryWave0<=126;carryWave1<=-25; end
18:begin carryWave0<=125;carryWave1<=-49; end
19:begin carryWave0<=122;carryWave1<=-71; end
20:begin carryWave0<=117;carryWave1<=-90; end
21:begin carryWave0<=112;carryWave1<=-106; end
22:begin carryWave0<=106;carryWave1<=-117; end
23:begin carryWave0<=98;carryWave1<=-125; end
24:begin carryWave0<=90;carryWave1<=-127; end
25:begin carryWave0<=81;carryWave1<=-125; end
26:begin carryWave0<=71;carryWave1<=-117; end
27:begin carryWave0<=60;carryWave1<=-106; end
28:begin carryWave0<=49;carryWave1<=-90; end
29:begin carryWave0<=37;carryWave1<=-71; end
30:begin carryWave0<=25;carryWave1<=-49; end
31:begin carryWave0<=12;carryWave1<=-25; end
32:begin carryWave0<=0;carryWave1<=0; end
33:begin carryWave0<=-12;carryWave1<=25; end
34:begin carryWave0<=-25;carryWave1<=49; end
35:begin carryWave0<=-37;carryWave1<=71; end
36:begin carryWave0<=-49;carryWave1<=90; end
37:begin carryWave0<=-60;carryWave1<=106; end
38:begin carryWave0<=-71;carryWave1<=117; end
39:begin carryWave0<=-81;carryWave1<=125; end
40:begin carryWave0<=-90;carryWave1<=127; end
41:begin carryWave0<=-98;carryWave1<=125; end
42:begin carryWave0<=-106;carryWave1<=117; end
43:begin carryWave0<=-112;carryWave1<=106; end
44:begin carryWave0<=-117;carryWave1<=90; end
45:begin carryWave0<=-122;carryWave1<=71; end
46:begin carryWave0<=-125;carryWave1<=49; end
47:begin carryWave0<=-126;carryWave1<=25; end
48:begin carryWave0<=-127;carryWave1<=0; end
49:begin carryWave0<=-126;carryWave1<=-25; end
50:begin carryWave0<=-125;carryWave1<=-49; end
51:begin carryWave0<=-122;carryWave1<=-71; end
52:begin carryWave0<=-117;carryWave1<=-90; end
53:begin carryWave0<=-112;carryWave1<=-106; end
54:begin carryWave0<=-106;carryWave1<=-117; end
55:begin carryWave0<=-98;carryWave1<=-125; end
56:begin carryWave0<=-90;carryWave1<=-127; end
57:begin carryWave0<=-81;carryWave1<=-125; end
58:begin carryWave0<=-71;carryWave1<=-117; end
59:begin carryWave0<=-60;carryWave1<=-106; end
60:begin carryWave0<=-49;carryWave1<=-90; end
61:begin carryWave0<=-37;carryWave1<=-71; end
62:begin carryWave0<=-25;carryWave1<=-49; end
63:begin carryWave0<=-12;carryWave1<=-25; end
endcase
end
用来进行频率调制的是两种正弦波,而正弦波是连续的模拟信号,在数字系统中只能通过采样对它进行近似化处理。预先设定好64个数值,并且对时钟滴答进行计数。计数到不同的时刻的时候,就按照时刻对应的数值查询预先存储好的正弦波的幅度值。比如现在时钟计数变量waveCount=48;那面就根据case语句找到对应的carryWave0=127,carryWave1=0。
如何获得这些正弦波的数值呢?用计算器么?你有耐心的话可以尝试一下。下面介绍一些如何用matlab生成这些代码,matlab真可谓大学生写作业的偷懒神器(不过有一套答案的话更是美滋滋)。
matlab偷懒代码
t=0:63;
y0=round(127*sin(2*pi*t/64));
y1=round(127*sin(4*pi*t/64));
fid=fopen('dataSave.txt','wt');
for i=0:63
fprintf(fid,'%d:begin carryWave0<=%d;carryWave1<=%d; end\n',i,y0(i+1),y1(i+1));
end
fclose(fid);
用matlab对正弦波取样,计算,存储到记事本中,而且,在生成的时候直接将语句中的begin end和一些必要的逻辑符号都包括了。毕竟只是个偷懒的手段,重在解决问题,脑补matlab大佬笑笑不说话的样子……
计算正弦波的时候,之所以将幅度取为127,是载波幅度寄存器的限制。8位的寄存器共可以表达256个数字,考虑到正负两边,因此绝对值最大127了。这个要根据调制的时候分配的寄存器大小来考虑。
调制部分
//调制部分
always @(posedge stClk)
begin
if(codeSource)
begin
sigOut=carryWave1;
end
else
begin
sigOut=carryWave0;
end
end
2FSK调制的核心思想就是0和1两种不同的状态对应两种不同的频率,到信号接收端的时候通过判断信号的频率从而确定数字信号原本的状态。因此通过一个if的判断语句即可完成。
testbench代码如下
`timescale 10ns/10ps
module test_sim;
reg clk;
wire [7:0]sigOut;
wire [7:0]carryWave0;
wire [7:0]carryWave1;
wire codeSource;
wire codeClk;
wire stClk;
FSK FSK(
.clk (clk),
.sigOut (sigOut),
.carryWave0 (carryWave0),
.carryWave1 (carryWave1),
.codeSource (codeSource),
.codeClk (codeClk),
.stClk (stClk)
);
parameter clkper=100;
initial
begin
clk = 1'b0;
end
always
begin
#(clkper / 2) clk=~clk;
end
endmodule
通过modelsim得到的仿真结果如下图
这里需要注意一个细节,我在最后仿真的时候才看到的一个问题
控制数字基带信号的时钟,codeClk,它的第一个上升沿并不是发生在codeClk的一个周期之后,而是半个周期。因此通过时钟上升沿来改变m序列的变化的话,就会产生调制后的信号发生相位突变。
所以在设置时钟的时候应该特别考虑时钟的起始位置,以及两个时钟的配合方式。这里通过把触发方式改为时钟下降沿来解决。