关注回复【fskmod】可看
在用matlab仿真生成fsk信号时,发现matlab库提供fskmod函数可以直接生成fsk信号,但生成的信号为复信号,于是查看其源码,结果对其原理看了好久都没明白,在网上查询资料也少得可怜,唯一有一篇也是对其中部分代码进行解释,且觉得该原函数提供的方法无法理解,然后文章作者最后进行了改动,得到了他想要的结果(笔者没仔细看,而是主要研究matlab库源码),且只是对参数和部分英文帮助进行了说明,并没有解释核心源码的含义。经过查阅相关资料后,笔者终于明白了其调制原理,现分享如下。
函数原型中重要代码如下:
function y = fskmod(x,M,freq_sep,nSamp,varargin)
- x:输入信号01比特
- M:调制进制数,比如2fsk调制M=2,4fsk调制M=4
- freq_sep:Δf=|f1-f2|,即相邻频率间隔
- nSamp:nSamp=Fs/RB,即每符号的采样点数
- varargin:可变参数,第一个为Fs,第二个为phase_cont
核心源码解释:
if (nargin >= 6)phase_type = varargin{2};%check the phase_type stringif ~( strcmpi(phase_type,'cont') || strcmpi(phase_type,'discont') )error(message('comm:fskmod:phaseCont'));end
elsephase_type = 'cont';
endif (strcmpi(phase_type, 'cont'))phase_cont = 1;
elsephase_cont = 0;
end
FSK调制分为相位不连续和相位连续2种方式,不指定默认的话是相位连续调制。这几句主要使判断Fs后是否还有参数,如果有(也就是>=6),那么判断字符串是’cont’还是’discont’,从而给变量phase_cont赋值为1(连续)或0(不连续)。
[nRows, nChan] = size(x);
获取输入数据的总数,即行数和列数,因此可以是2路或多路信号比特输入。
phaseIncr = (0:nSamp-1)' * (-(M-1):2:(M-1)) * 2*pi * freq_sep/2 * samptime;
在刚看到这一句时,完全想不明白这句是如何来的,更不清楚这句代码的目的是什么。通过查资料,先来看看FSK信号调制的原理。
以2FSK调制为例,信号表达式为
S(t)=m1(t)Acos(2πf1t+φ1)+m2(t)Acos(2πf2t+φ2)S(t)={{m}_{1}}(t)A\cos (2\pi {{f}_{1}}t+{{\varphi }_{1}})+{{m}_{2}}(t)A\cos (2\pi {{f}_{2}}t+{{\varphi }_{2}})S(t)=m1(t)Acos(2πf1t+φ1)+m2(t)Acos(2πf2t+φ2)
式中,m1(t)=∑n=−∞∞bng(t−nTb){{m}_{1}}(t)=\sum\limits_{n=-\infty }^{\infty }{{{b}_{n}}g(t-n{{T}_{b}})}m1(t)=n=−∞∑∞bng(t−nTb)
m2(t)=∑n=−∞∞bn‾g(t−nTb){{m}_{2}}(t)=\sum\limits_{n=-\infty }^{\infty }{\overline{{{b}_{n}}}g(t-n{{T}_{b}})}m2(t)=n=−∞∑∞bng(t−nTb)
实际上,在理想情况下,载波振荡的频率是随基带信号线性变化的,此时,调频信号可表示为
s(t)=Acos[2πfct+πΔf∫∞tm′(t)dt′+θc]s(t)=A\cos [2\pi {{f}_{c}}t+\pi \Delta f\int_{\infty }^{t}{{m}'(t)}d{t}'+{{\theta }_{c}}]s(t)=Acos[2πfct+πΔf∫∞tm′(t)dt′+θc]
其中, fcf_cfc是未调载波频率,θcθ_cθc是载波的初始相位,Δf\Delta fΔf是相邻频率间隔。
频率调制是用调制信息去控制载波的频率,由于瞬时相位是瞬时频率的积分,在上式中具体体现就是生成一个瞬时相偏πΔf∫∞tm′(t)dt′\pi \Delta f\int_{\infty }^{t}{{m}'(t)}d{t}'πΔf∫∞tm′(t)dt′,对其数字化即可变为
pi∗(0:nSamp−1)′∗(−1,+1)∗Δf/Fspi*(0:nSamp-1)'*(-1, +1)* Δf/Fspi∗(0:nSamp−1)′∗(−1,+1)∗Δf/Fs
因此这一句就是初始化一个码元符号内每个采样点信号相位的变化量(正1增加,负1减少)。
phIncrSym = phaseIncr(end,:);
phIncrSym就表示在一个码元结束时相位的总变化量
phIncrSamp = phaseIncr(2,:);
phIncrSamp表示相邻采样点之间的相位变化量
Phase = zeros(nSamp*nRows, nChan);
其中nChan表示输入信号路数,一般情况都是1路。输入信号总码元数为nRowsnChan,所以最后生成的相位总数为每符号的采样点码元总数,即nSampnRowsnChan,该句就是初始化一个变量用来存储最后的相位。主要分为2种情况:
一、相位不连续,此时又可分为2种情况。
(1) 当一个码元持续时间相偏总量πΔf∫∞tm′(t)dt′\pi \Delta f\int_{\infty }^{t}{{m}'(t)}d{t}'πΔf∫∞tm′(t)dt′为2π的整数倍即
if ( (~phase_cont) &&( floor(nSamp*freq_sep/2 * samptime) == nSamp*freq_sep/2 * samptime ) )
此时由于相位变化是周期性的,可以直接用以下2句代码生成调制信号的相位y。
exp_phaseIncr = exp(1i*phaseIncr);
y = reshape(exp_phaseIncr(:,x+1),nRows*nSamp,nChan);
(2) 当一个码元持续时间相偏总量πΔf∫∞tm′(t)dt′\pi \Delta f\int_{\infty }^{t}{{m}'(t)}d{t}'πΔf∫∞tm′(t)dt′不是2π的整数倍时,当前符号的初始相位是:(前一符号最后采样点相位+每采样点相位变化量)mod 2π,即
OscPhase = zeros(nChan, M);
OscPhase是针对这种情况设置的变量,存放下一符号开始时(第1个采样点)的相位,初始化为0。
OscPhase(iChan,:) = rem(OscPhase(iChan,:) + phIncrSym + phIncrSamp, 2*pi);
ph1 = OscPhase(iChan, x(iSym,iChan)+1);
其中ph1中存放的就是当前符号开始时的相位。
二、相位连续
相位连续时,当前符号开始时(第1个采样点)的相位时:前一符号最后采样点相位+每采样点相位变化量,与相位不连续相比,此处少了模2π运算,即
prevPhase = Phase(nSamp*iSym,iChan) + phIncrSamp(x(iSym,iChan)+1);
ph1 = prevPhase;
综上所述,最后再用统一的方法计算每个采样点的相位
Phase(nSamp*(iSym-1)+1:nSamp*iSym,iChan) = ph1*ones(nSamp,1)+ phaseIncr(:,x(iSym,iChan)+1);
最后,再生成FSK调制信号的正交基带数据
y = exp(1i*Phase);
以上就是整个fskmod函数的关键核心代码解读,得到调制的基带数据之后,再将基带信号数据正交上变频至中频,即乘以 即可。