我是靠谱客的博主 大意可乐,最近开发中收集的这篇文章主要介绍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,参考代码如下:

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 频率。

%-----解调,采用滤波法,滤除 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 信号了,对其取模判决即可解调。

data_re=(data_abs>1e4);
data_ex=data_re(4:20:end);

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

 

 三,代码

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

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调制信号和经过解调之后恢复出的原始基带信号序列

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

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

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

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调制解调实验所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部