我是靠谱客的博主 大意可乐,这篇文章主要介绍2FSK调制解调实验,现在分享给大家,希望可以做个参考。

一,2FSK原理

频移键控是利用载波的频率变化来传递数字信息。数字频率调制是数据通信中使用较 早的一种通信方式,由于这种调制解调方式容易实现,抗噪声和抗衰减性能较强,因此在 中低速数字通信系统中得到了较为广泛的应用。在2FSK中,载波的频率随着二进制基带 信号在 f1 和 f2 两个频点间变化。故表达式

由图我们可以看出,一个 2FSK 信号可以看成是两个不同载频的 2ASK 信号的叠加。因 此 2FSK 的时域表达式又可以写成 :

2FSK 信号的产生主要利用键控法来实现,即在二进制基带矩形脉冲序列的控制下通 过开关电路对两个不同的独立频率进行选通,使其在每一个码元Ts 期间输出 f1或 f2 两个 载波之一,如下图所示。键控法产生的 2FSK 信号其相邻码元之间的相位不一定连续。

 在本实验中,我们可以直接发送不同频率的载波信号,也就是已经调制好的 2FSK 信 号,以两个频率来表示码元‘1’和‘0’即可。 2FSK 信号常用的解调方法是采用相干解调和非相干解调。其解调原理是将 2FSK 信号 分解为上下两路 2ASK 信号分别进行解调,然后进行判决。这里的抽样判决是直接比较两 路信号抽样值的大小,可以不专门设置门限。判决规则应与调制规则相呼应,调制时若规 定‘1’符号对应载波频率 f1 ,则接收时上支路的样值较大,应判为‘1’;反之,判为 码元‘0’。

除此之外,2FSK 信号还有其他解调方法,比如鉴频法、差分检测法、过零检测法等。 由于 2FSK 的信号比较简单,只有f1 和 f2 两个频率,且分别对应码元‘1’和‘0’。因此 在本实验中,我们选择的解调方法为滤波法,即设计一个滤波器,将频率成分为 f1 或 f2 的 信号滤除掉,只剩下 f1或 f2 的信号分量。然后设置一个阈值,将大于该值的判为码元‘1’, 则小于该值的即为码元‘0’。注意,这种判决必须和调制时所规定的码元一致。

二,matlab相关代码解析

1,发送端

发送端,我们直接发送调制好的 2FSK 信号。由上述原理可知,当基带信号为 0 时, 发送频率为 f0 的载波信号;当基带信号为 1 时,发送频率为  f1的载波信号。

 调制的映射规则即为‘1’—>1MHz,‘0’—>2MHz,参考代码如下:

复制代码
1
2
3
4
5
6
7
8
9
10
for i=1:length(bit_trans) if bit_trans(i)==1 m=carrier_1M; else m=carrier_2M; end m1=[m1 m]; end mod_data=m1;

mod_data 即为 2FSK 已调信号。我们可以画出它的频谱,由下图可以清晰的看出 2FSK 信 号有两根谱线,即两个频率值。

2,接收端

对于接收端,我们需要接收发送端的 2FSK 调制信号,因此 AD9361 的采样率和频点必 须与发送端一致,即samp_hex=dec2hex(20e6,8);  freq_hex=dec2hex(999e6,10);

帧到达检测完毕之后,接收到的信号应该是两路正交的 IQ 正弦波信号,他们的频率 为 1MHZ 和 2MHZ,分别对应码元‘0’和码元‘1‘(本实验中为 a1 和 a2)。 前面已经指出,2FSK 包含有两个频率成分(  f0和 f1),对于它的解调方式,本实验 采用滤波法,即设计一个滤波器,将频率成分为 f1的信号分量滤除掉,只剩下频率为  f1的信号(即是码元’1‘)。根升余弦滤波器是数字信号 处理过程中最常用的滤波器,在此我们利用 matlab 函数设计一个滤波器,将接收到的 信号中的 2MHz 的频率成分滤除掉,保留1MHz 频率。

复制代码
1
2
3
4
%-----解调,采用滤波法,滤除 2MHz 频率成分-----% flt1=rcosine(1,8,'fir/sqrt',0.05,1); st_flt = rcosflt(frame_data, 1, 1, 'filter', flt1); data_abs=abs(st_flt);

从图上可以看出,滤波效果比较好,只保留了 1MHz 频率分量,我们也可以从时域 观察一下滤波效果,可以更加直观的看出 2MHz 频率被滤除。此时,这就相当于一个 2ASK 信号了,对其取模判决即可解调。

复制代码
1
2
data_re=(data_abs>1e4); data_ex=data_re(4:20:end);

 判决阈值设为 1e4,然后进行 20 倍的抽取,即可还原出原始基带二进制码元信号。

 

 三,代码

运行发送端程序tx_2FSK.m,matlab命令行端显示“data transfer done”时,表明数据正常发送完毕

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
clc; clear all; close all; warning off; %****************ht7600*******************// %ref_hex 1=external ref;0=internal ref %vco_cal_hex 1=AUXDAC1;0=ADF4001 %fdd_tdd_hex 1=FDD 0=TDD %trx_sw_hex 1=TX 0=RX %****************ht7600*******************// rcount=dec2hex(10,4);%reference clock divide ncount=dec2hex(26,4);%internal vctcxo divide ref_hex=dec2hex(0,8);%1=external ref 0=internal ref vco_cal_hex=dec2hex(1,8);%1=auxdac 0=reference clock aux_dac1_hex=dec2hex(0,8); fdd_tdd_hex=dec2hex(1,8); trx_sw_hex=dec2hex(1,8); samp_hex=dec2hex(20e6,8); bw_hex=dec2hex(18e6,8); freq_hex=dec2hex(999e6,10); %%for ad9361 tx_att1=dec2hex(5000,8); tx_att2=dec2hex(30000,8); tx_chan=3;%1=tx1;2=tx2;3=tx1&tx2 %=====以下为数据调制部分=====% %-----数据源数量-----% bit_Num = 500; %-----产生随机数据帧,length=500-----% bit_trans = randint(1,bit_Num); %-----产生两个载频,分别为1MHz和2MHz carrier_I1=round(cos(2*pi/20*[0:19]).*30000); carrier_Q1=round(sin(2*pi/20*[0:19]).*30000); carrier_1M=carrier_I1+1i*carrier_Q1; carrier_I2=round(cos(2*pi/10*[0:9]).*30000); carrier_Q2=round(sin(2*pi/10*[0:9]).*30000); carrier_2M=carrier_I2+1i*carrier_Q2; %-----2MHz载波扩展为20bit,和1MHz载波等宽 carrier_2M=repmat(carrier_2M,1,2); %-----键控调频,1-->1MHz,0-->2MHz m1=[]; for i=1:length(bit_trans) if bit_trans(i)==1 m=carrier_1M; else m=carrier_2M; end m1=[m1 m]; end mod_data=m1; %-----创建帧同步训练序列-----% [training]=creat_training(); %-----数据组帧-----% txdata=[training mod_data]; %% copy to 2chanel if tx_chan==1 || tx_chan==2 txdata2=txdata; elseif tx_chan==3 txdata2=zeros(1,length(txdata)*2); txdata2(1:2:end)=txdata; txdata2(2:2:end)=txdata; end %% iq mux txdatas=zeros(1,length(txdata2)*2); txdatas(1:2:end)=real(txdata2); txdatas(2:2:end)=imag(txdata2); %% add pad rem=-1; i=0; while (rem<0) rem=1024*2^i-length(txdatas); i=i+1; end txdata1=[txdatas zeros(1,rem)]; txd1=(txdata1<0)*65536+txdata1; txd2=dec2hex(txd1,4); txd3=txd2(:,1:2); txd4=txd2(:,3:4); txd5=hex2dec(txd3); txd6=hex2dec(txd4); txd7=zeros(length(txd6)*2,1); txd7(1:2:end)=txd6; txd7(2:2:end)=txd5; %% open control port ctrl_link = udp('192.168.1.10', 5006); fopen(ctrl_link); %% open data port data_link = tcpip('192.168.1.10', 5005); set(data_link,'InputBufferSize',128*1024); set(data_link,'OutputBufferSize',128*1024); fopen(data_link); %% tx samp rate samp=[0 5 hex2dec('22') hex2dec('f0') hex2dec(samp_hex(7:8)) hex2dec(samp_hex(5:6)) hex2dec(samp_hex(3:4)) hex2dec(samp_hex(1:2))]; fwrite(ctrl_link,samp,'uint8'); %% tx bandwidth rate bw=[0 7 hex2dec('22') hex2dec('f0') hex2dec(bw_hex(7:8)) hex2dec(bw_hex(5:6)) hex2dec(bw_hex(3:4)) hex2dec(bw_hex(1:2))]; fwrite(ctrl_link,bw,'uint8'); %% send tx freq set cmd tx_freq=[hex2dec(freq_hex(1:2)) 3 hex2dec('22') hex2dec('f0') hex2dec(freq_hex(9:10)) hex2dec(freq_hex(7:8)) hex2dec(freq_hex(5:6)) hex2dec(freq_hex(3:4))]; fwrite(ctrl_link,tx_freq,'uint8'); %% send tx vga set cmd tx_vga=[0 9 hex2dec('22') hex2dec('f0') hex2dec(tx_att1(7:8)) hex2dec(tx_att1(5:6)) hex2dec(tx_att1(3:4)) hex2dec(tx_att1(1:2))]; %TX1 fwrite(ctrl_link,tx_vga,'uint8'); tx_vga=[0 11 hex2dec('22') hex2dec('f0') hex2dec(tx_att2(7:8)) hex2dec(tx_att2(5:6)) hex2dec(tx_att2(3:4)) hex2dec(tx_att2(1:2))]; %TX2 fwrite(ctrl_link,tx_vga,'uint8'); %% send tx channel set cmd channel=[tx_chan 0 hex2dec('20') hex2dec('f0') 0 0 0 0]; fwrite(ctrl_link,channel,'uint8'); %% custom rf control command % adf4001 config adf4001=[0 40 hex2dec('18') hex2dec('f0') hex2dec(ncount(3:4)) hex2dec(ncount(1:2)) hex2dec(rcount(3:4)) hex2dec(rcount(1:2))]; fwrite(ctrl_link,adf4001,'uint8'); % ref_select ref_select=[0 40 hex2dec('22') hex2dec('f0') hex2dec(ref_hex(7:8)) hex2dec(ref_hex(5:6)) hex2dec(ref_hex(3:4)) hex2dec(ref_hex(1:2))]; fwrite(ctrl_link,ref_select,'uint8'); % vco_cal_select vco_cal_select=[0 41 hex2dec('22') hex2dec('f0') hex2dec(vco_cal_hex(7:8)) hex2dec(vco_cal_hex(5:6)) hex2dec(vco_cal_hex(3:4)) hex2dec(vco_cal_hex(1:2))]; fwrite(ctrl_link,vco_cal_select,'uint8'); % fdd_tdd_select fdd_tdd_select=[0 42 hex2dec('22') hex2dec('f0') hex2dec(fdd_tdd_hex(7:8)) hex2dec(fdd_tdd_hex(5:6)) hex2dec(fdd_tdd_hex(3:4)) hex2dec(fdd_tdd_hex(1:2))]; fwrite(ctrl_link,fdd_tdd_select,'uint8'); % trx_sw trx_sw=[0 43 hex2dec('22') hex2dec('f0') hex2dec(trx_sw_hex(7:8)) hex2dec(trx_sw_hex(5:6)) hex2dec(trx_sw_hex(3:4)) hex2dec(trx_sw_hex(1:2))]; fwrite(ctrl_link,trx_sw,'uint8'); % aux_dac1 aux_dac1=[0 44 hex2dec('22') hex2dec('f0') hex2dec(aux_dac1_hex(7:8)) hex2dec(aux_dac1_hex(5:6)) hex2dec(aux_dac1_hex(3:4)) hex2dec(aux_dac1_hex(1:2))]; fwrite(ctrl_link,aux_dac1,'uint8'); %% send handshake cmd handshake=[2 0 hex2dec('16') hex2dec('f0') 0 0 0 0]; fwrite(ctrl_link ,handshake, 'uint8'); %% send handshake2 cmd data_length = dec2hex((2^(i-1)*2)*1024,8); handshake=[2 0 hex2dec('17') hex2dec('f0') hex2dec(data_length(7:8)) hex2dec(data_length(5:6)) hex2dec(data_length(3:4)) hex2dec(data_length(1:2))]; fwrite(ctrl_link ,handshake, 'uint8'); %% Write data to the zing and read from the host. fwrite(data_link,txd7,'uint8'); %% send handshake2 cmd to stop adc output %handshake=[hex2dec('ff') 0 hex2dec('17') hex2dec('f0') 0 0 0 0]; %fwrite(ctrl_link,handshake,'uint8'); %% close all link fclose(data_link); delete(data_link); clear data_link; fclose(ctrl_link); delete(ctrl_link); clear ctrl_link; disp('data tansfer done');

运行接收端程序rx_2FSK.m,程序会显示接受到的2FSK调制信号和经过解调之后恢复出的原始基带信号序列

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
clc; warning off; buff_size=256; samp_hex=dec2hex(20e6,8); bw_hex=dec2hex(18e6,8); freq_hex=dec2hex(999e6,10);%%for ad9361 rxgain1=25; rxgain2=5; rx_chan=3;%1=rx1;2=rx2;3=rx1&rx2 cyc=1; %% open control port ctrl_link = udp('192.168.1.10', 5006); fopen(ctrl_link); %% open data port data_link = tcpip('192.168.1.10', 5004); set(data_link,'InputBufferSize',256*1024); set(data_link,'OutputBufferSize',256*1024); fopen(data_link); %% rx samp rate samp=[0 17 hex2dec('22') hex2dec('f0') hex2dec(samp_hex(7:8)) hex2dec(samp_hex(5:6)) hex2dec(samp_hex(3:4)) hex2dec(samp_hex(1:2))]; fwrite(ctrl_link,samp,'uint8'); %% rx bandwidth rate bw=[0 19 hex2dec('22') hex2dec('f0') hex2dec(bw_hex(7:8)) hex2dec(bw_hex(5:6)) hex2dec(bw_hex(3:4)) hex2dec(bw_hex(1:2))]; fwrite(ctrl_link,bw,'uint8'); %% send rx freq rx_freq=[hex2dec(freq_hex(1:2)) 15 hex2dec('22') hex2dec('f0') hex2dec(freq_hex(9:10)) hex2dec(freq_hex(7:8)) hex2dec(freq_hex(5:6)) hex2dec(freq_hex(3:4))]; fwrite(ctrl_link,rx_freq,'uint8'); %% agc mode agc_mode=[0 21 hex2dec('22') hex2dec('f0') 0 0 0 0]; %定义RX1的增益控制模式 0-MGC 1-FGC 2-SGC fwrite(ctrl_link,agc_mode,'uint8'); agc_mode=[0 23 hex2dec('22') hex2dec('f0') 0 0 0 0]; fwrite(ctrl_link,agc_mode,'uint8'); %% send rx vga rx_vga=[0 25 hex2dec('22') hex2dec('f0') rxgain1 0 0 0]; fwrite(ctrl_link,rx_vga,'uint8'); rx_vga=[0 27 hex2dec('22') hex2dec('f0') rxgain2 0 0 0]; fwrite(ctrl_link,rx_vga,'uint8'); %% send rx channel set cmd channel=[rx_chan 0 hex2dec('21') hex2dec('f0') 0 0 0 0]; fwrite(ctrl_link,channel,'uint8'); %% send handshake cmd handshake=[2 1 hex2dec('16') hex2dec('f0') 0 0 0 0]; fwrite(ctrl_link,handshake,'uint8'); while(1) %% send handshake2 cmd to start adc thread size_hex=dec2hex(buff_size*1024,8); handshake=[2 1 hex2dec('17') hex2dec('f0') hex2dec(size_hex(7:8)) hex2dec(size_hex(5:6)) hex2dec(size_hex(3:4)) hex2dec(size_hex(1:2))]; fwrite(ctrl_link,handshake,'uint8'); %% read 256*1024 bytes data from zing data = fread(data_link,buff_size*1024,'uint8'); %% receive datah=data(2:2:end); datal=data(1:2:end); datah_hex=dec2hex(datah,2); datal_hex=dec2hex(datal,2); data_hex(:,1:2)=datah_hex; data_hex(:,3:4)=datal_hex; dataun=hex2dec(data_hex); datain=dataun-(dataun>32767)*65536; if rx_chan==1 a1=datain(1:2:end); a2=datain(2:2:end); a3=zeros(1,length(a1)); a4=zeros(1,length(a1)); elseif rx_chan==2 a3=datain(1:2:end); a4=datain(2:2:end); a1=zeros(1,length(a3)); a2=zeros(1,length(a3)); elseif rx_chan==3 a1=datain(1:4:end); a2=datain(2:4:end); a3=datain(3:4:end); a4=datain(4:4:end); end %=====以下为数据解调部分=====% %-----起始帧同步-----% [frame_data,syn_symbol] = rx_frame_sync(a1+a2,a1,a2,mod_data); %-----解调,采用滤波法,滤除2MHz频率成分-----% flt1=rcosine(1,8,'fir/sqrt',0.05,1); st_flt = rcosflt(frame_data, 1, 1, 'filter', flt1); data_abs=abs(st_flt); data_re=(data_abs>1e4); data_ex=data_re(4:20:end); demod_data=data_ex(2:end)'; %-----计算误码率-----% bit_err=biterr(demod_data,bit_trans); %-----画图显示-----% h=figure(1); clf; set(h,'name','2FSK调制解调系统'); subplot(221); plot(a1,'g'); hold on; plot(a2,'r'); ylim([-1e4 1e4]); axis square; title(['接收到的2FSK调制信号 cyc=',num2str(cyc)]); subplot(222); plot(bit_trans ,'b'); ylim([-0.2 1.2]); title(['原始基带信号序列 Total = ',num2str(length(bit_trans)),'bit']); subplot(223); plot(syn_symbol,'black'); ylim([0 1.2]); axis square; title('帧同步相关性曲线'); subplot(224); plot(demod_data ,'m'); ylim([-0.2 1.2]); title(['解调序列 Bit_err = ',num2str(bit_err),';Demod_times=',num2str(cyc)]); %-----接收次数变量值累加-----% cyc=cyc+1; %-----设置z键为停止键-----% if strcmpi(get(gcf,'CurrentCharacter'),'z') break; end pause(0.1); end %% send handshake2 cmd to stop adc thread handshake=[hex2dec('ff') 1 hex2dec('17') hex2dec('f0') 0 0 0 0]; fwrite(ctrl_link,handshake,'uint8'); %% close all link fclose(data_link); delete(data_link); clear data_link; fclose(ctrl_link); delete(ctrl_link); clear ctrl_link;

其中,cyc 显示接收数据次数,下方画出了帧同步曲线,原始基带信号和长度也示于上面, 解调序列显示误码率和解调次数,可以看到 bit_err 为 0,解调完全正确。 下图为2FSK调制解调图:

 creat_tream.m

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function [training]=creat_training() Ns=128; N1=320; Nx=512; x1=randn(1,Ns); x2=randn(1,Ns); x3=x1+x2.*i;%生成随机128点复数序列 y=x3(65:128);%x3的后64点用作循环前缀 y1=randn(1,N1); y2=randn(1,N1); y3=y1+y2.*i;%生成随机320点复数序列用作数据符号 train1=[y3 y x3 x3 y3];%帧结构,共三个符号 training=train1/sqrt(12); %数据量化为16bit index=30000./max([abs(real(training)),abs(imag(training))]); training=round(training.*index); end

rx_frame_sync.m

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function [ frame_data,syn_symbol] = rx_frame_sync(receive_data,data_I,data_Q,txdata_x) % receive_data=receive_data'; [xx,PS]=mapminmax(receive_data); frame_all=xx'; syn_symbol=syn_time(frame_all); [s1,s2]=max(syn_symbol(1:length(syn_symbol)/2)); frame_begin=s2+576; frame_end=frame_begin+length(txdata_x); %------------找到帧位置后组成一帧数据------------------------------ frame_data_I=data_I(frame_begin:frame_end); frame_data_Q=data_Q(frame_begin:frame_end); frame=frame_data_I+1i*frame_data_Q; frame_data=frame(2:end); end

sync_time.m

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function [C]=syn_time(data) Ns=128; N=length(data); N1=320; r=data; t1=zeros(1,N); t2=zeros(1,N); C=zeros(1,N);%原相关值对能量值归一化 C1=zeros(1,N+4);%用循环前缀进一步归一化 tt=0; for timing=1:N-700 for m=1:2*Ns t1(timing)=t1(timing)+0.5*((abs(r(m+timing)))^2);%整个序列能量值,除了1/2 end for m=1:Ns t2(timing)=t2(timing)+conj(r(m+timing))*r(m+Ns+timing);%前半序列和后半序列相关值 end C(1,timing)=(abs(t2(timing))^2)/(t1(timing)^2);%相关值对能量值归一化 end for timing=65:N-700 %利用训练序列的循环前缀设定一个滑动运算窗口对序列进行归一化 for i=-64:0 C1(1,timing)= C1(1,timing)+(1/65)*C(1,i+timing); end end [Y,I]=max(abs(C1)); timing_coarse=I-384; C=abs(C1); end

最后

以上就是大意可乐最近收集整理的关于2FSK调制解调实验的全部内容,更多相关2FSK调制解调实验内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(78)

评论列表共有 0 条评论

立即
投稿
返回
顶部