感觉有好久一段时间没有发博文了,看到忽然又多了几个人的关注,不发一篇文章过意不去,嘻嘻嘻。疫情在家,之前做过这个移频键控系统的实物实验,但还没有做理论分析,趁着这个机会,把实验仿真做了吧。
系统采用两个频率不同,起始相位一致的正弦波信号作为载波。对用户码元判断为正时,使用频率较高的载波;反之则使用频率较低的载波。调制后混合调制结果,然后发射出去。模拟经过高斯信道,人为加入高斯噪声,然后接收。
接收后,把信号分别进行带通数字滤波,两个滤波器的通带频率不一样。滤波后,对结果进行幅度比较,即可码元判决出用户发送的码元。
载波波形图如下图所示:
低频载波采用100Hz的正弦波,高频载波采用200Hz的正弦波,这两个载波起始相位与结束相位一致。
因为matlab只能处理数字信号,所以需要把以上载波离散化,代码中对这两个载波使用了【采样率:5000Hz,采样点数:50】的参数进行采样,从而把连续载波离散化。
图中可见疏密程度不一样的正弦波,每50个点表示一个用户码元,密集部分的高频正弦波表示正码元1,稀疏部分表示负码元-1。这是根据码元的极性,把各个部分的载波连接在一起的结果。
在实验中,模拟高斯信道,人为地给调制结果在解调前加入高斯噪声。以上图片就是调制结果加入高斯噪声的结果。
人为加入噪声使用的是matlab自带的“awgn”函数,该函数可以自动地为数据按照信噪比加上高斯白噪声。代码如下所示:
meanPower = powerCnt(modulat)/length(modulat);
send = awgn(modulat,snr,meanPower);
在加入高斯噪声后,使用双带通滤波器法对信号进行解调。
滤波器采用凯塞尔窗函数法设计,产生一个FIR滤波器。
下图是通带为80~120Hz的带通滤波器的分析图。
下图是通带为180~220Hz的带通滤波器的分析图。
可见这两个滤波器在通带处有线性相位特征,使得信号通过时,结果不会出现相位失真。
把接收信号分别与两个滤波器进行卷积,即可得到滤波结果。
滤波使用matlab自带的“conv”函数,把数字滤波器与信号进行卷积,从而得到滤波结果。
%滤波,接收到的信号与fir滤波器进行卷积
res_high = conv(send,highFilter);
res_low = conv(send,lowFilter);
滤波结果中,两边趋于平滑的部分对于判决是无意义的,所以要按照 码元数量*载波采样数 的结果居中截取有效部分,如下图所示。
把居中截取出来的信号,按照载波一个码元对应采样点的个数分组,对每一组取绝对值求和,高频滤波输出与低频滤波输出的每一个组分别对应比较求和结果,如果高频的求和结果大,则该组被判决成正极性码元;反之则被判决为负极性码元。
每个对应的信噪比,传输1万个码元作为测试。
信噪比从-30dB到10dB,以0.1dB为步进进行测试。
从实验结果可以看出,误码率曲线呈现S形下滑,在信噪比大于5时,系统基本可以无误码率传输。
对实验结果使用罗杰斯蒂(logistic)模型进行拟合。模型公式如下:
y ~ = a 1 + b e − c x \widetilde{y}=\frac{a}{1+be^{-cx}} y =1+be−cxa
公式中,a、b、c为拟合参数,e为自然常数。
使用MATLAB拟合结果如下:
根据结果可以得到仿真模型通过信噪比估计误码率的经验公式:
General model:
f(x) = a/(1+b*exp(-c*x))
Coefficients (with 95% confidence bounds):
a = 49.38 (49.31, 49.45)
b = 13.52 (13.34, 13.7)
c = -0.2842 (-0.2857, -0.2826)
Goodness of fit:
SSE: 38.88
R-square: 0.9998
Adjusted R-square: 0.9998
RMSE: 0.313
链接:https://pan.baidu.com/s/1rLzolqa6yBwMeebmn4YqRg
提取码:7oue
main.m
%{
本项目用于移频键控通信系统的仿真
解调使用双滤波器方案,即对输入的信号分别进行通带不同的两个FIR滤波器,
对输出进行块判决,实现码元复现。
2020/4/9 21:20
%}
clear all;
%是否原理展示
%0时表示做误码率随信噪比变化实验
%1时表示原理展示,绘制原理图与分析图
isPlot = 0;
%测试码元数
if isPlot
%如果绘制原理图,就减少码元数
codeSize = 5;
else
codeSize = 1e5;
end
%生成要发送的码元
sourceCode = bipolarGen(codeSize);
%生成两个不同频率的载波信号
%采样率取5000Hz,根据奈奎斯特定理,采样率至少为频率的两倍
sampleRate = 5000;
%采样点数,过大可能会产生寄生扩频,影响实验结果
sampleSize = 50;
%100Hz低频载波
carrierLow = carrierGen(100,sampleRate,sampleSize);
%200Hz高频载波
carrierHigh = carrierGen(200,sampleRate,sampleSize);
%绘制载波图形
if isPlot
figure(1)
plot(carrierLow)
hold on;
plot(carrierHigh)
title('载波信号');
legend('低频载波','高频载波');
end
%%调频调制%%
modulat = modulation(sourceCode,carrierLow,carrierHigh);
if isPlot
figure(2)
%绘制调频结果
plot(modulat)
title('频率调制结果');
end
%生成80~120Hz的带通滤波器
fcuts = [0 80 120 150]; %定义通带和阻带的频率
mags = [0 1 0]; %定义通带和阻带
devs = [0.1 0.01 0.1]; %定义通带或阻带的纹波系数
lowFilter = getFilter(fcuts,mags,devs,sampleRate);
%生成180~220Hz的带通滤波器
fcuts = [150 180 220 250]; %定义通带和阻带的频率
mags = [0 1 0]; %定义通带和阻带
devs = [0.1 0.01 0.1]; %定义通带或阻带的纹波系数
highFilter = getFilter(fcuts,mags,devs,sampleRate);
%滤波器分析
if isPlot
figure(4)
freqz(lowFilter)
title('低频带通滤波器分析图');
figure(5)
freqz(highFilter)
title('高频带通滤波器分析图');
end
if ~isPlot
%开始信噪比
startSnr = -30;
%结束信噪比
endSnr = 10;
%信噪比测试间隔
divSnr = 0.1;
%误码率记录器
errorRate = zeros(1,(endSnr-startSnr)/divSnr);
%研究误码率与信噪比的关系,开启多线程
parfor index = 1:(endSnr-startSnr)/divSnr
%%通过高斯信道,人为添加高斯噪声%%
%信噪比(db)
snr = startSnr + (index-1)*divSnr;
%平均功率(dbW)
meanPower = powerCnt(modulat)/length(modulat);
send = awgn(modulat,snr,meanPower);
%%解调,使用两个带通滤波器%%
%滤波,接收到的信号与fir滤波器进行卷积
res_high = conv(send,highFilter);
res_low = conv(send,lowFilter);
%%一个载波周期内比较绝对幅度%%
%截取滤波结果中间部分
low_input = arrayCut(res_low,codeSize*sampleSize);
high_input = arrayCut(res_high,codeSize*sampleSize);
%判决
result = compare(low_input,high_input,sampleSize);
%与发送前生成的码元进行比较,得到正确率
rightRate = rightRateCnt(result,sourceCode);
disp(['当前信噪比',num2str(snr),'dBW,','正确率',num2str(rightRate*100),'%']);
%记录错误率
errorRate(index) = (1 - rightRate)*100;
end
%绘制误码率曲线
figure(7)
plot(linspace(startSnr,endSnr,length(errorRate)),errorRate);
xlabel('信噪比(dB)');
ylabel('误码率(%)');
title('误码率随信噪比的变化曲线');
else
%%通过高斯信道,人为添加高斯噪声%%
%信噪比(db)
snr = 5;
%平均功率(dbW)
meanPower = powerCnt(modulat)/length(modulat);
send = awgn(modulat,snr,meanPower);
if isPlot
figure(3)
%绘制噪声结果
title('接收端接收到的波形');
plot(send);
end
%%解调,使用两个带通滤波器%%
%滤波,接收到的信号与fir滤波器进行卷积
res_high = conv(send,highFilter);
res_low = conv(send,lowFilter);
if isPlot
figure(6)
plot(res_low)
hold on;
plot(res_high)
title('滤波结果');
legend('低频带通滤波输出','高频带通滤波输出');
end
end
bipolarGen.m
function [code] = bipolarGen(size)
%bipolarGen 产生指定长度的二进制双极性码元数组
% 码元的产生采用随机函数
foo = rand(1,size);
for i = 1:length(foo)
if foo(i) > 0.5
foo(i) = 1;
else
foo(i) = -1;
end
end
code = foo;
end
carrierGen.m
function [res] = carrierGen(freq,sampleRate,size)
%carrierGen 产出载波
% 参数:freq:频率 sampleRate:采样率 size:载波长度
n=0:size-1;
t=n/sampleRate;%时间序列
res=sin(2*pi*freq*t);
end
modulation.m
function [res] = modulation(code,carrierLow,carrierHigh)
%modulation 调频调制函数
% 参数: code:码元 carrierLow:低频载波 carrierHigh:高频载波
res = zeros(1,length(code)*length(carrierLow));
for i = 1:length(code)
if code(i) > 0
res((i-1)*length(carrierLow)+1:i*length(carrierLow)) = carrierHigh;
else
res((i-1)*length(carrierLow)+1:i*length(carrierLow)) = carrierLow;
end
end
end
getFilter.m
function result = getFilter(fcuts,mags,devs,freq)
%getFilter 获取切尔雪夫等幅纹滤波器
% fcuts:定义通带和阻带的频率
% mags:定义通带和阻带
% devs:定义通带或阻带的纹波系数
% freq:采样率
%{
demo
fcuts = [200 900 1100 2000]; %定义通带和阻带的频率
mags = [1 0 1]; %定义通带和阻带
devs = [0.1 0.01 0.1]; %定义通带或阻带的纹波系数
%}
[n,Wn,beta,ftype] = kaiserord(fcuts,mags,devs,freq); %计算出凯塞窗N,beta的值
result = fir1(n,Wn,ftype,kaiser(n+1,beta),'noscale'); %生成滤波器
end
powerCnt.m
function res = powerCnt(input)
%powerCnt 功率计算函数
%参数 input:需要计算功率的数组
res = 10*log10(sum(input.*input));
end
arrayCut.m
function res = arrayCut(array,size)
%arrayCut 根据需要的长度,居中截取数组
% 因为在FIR滤波之后,结果会增长,对于解调来说,
% 滤波卷积结果两端的部分是多余的,应该去除。
start = floor((length(array)-size)/2+1);
res = array(start:start+size-1);
end
compare.m
function [res] = compare(inputLow,inputHigh,samplePoint)
%compare 比较一个周期内的低通与高通的输出,并通过判决还原出原波形
% inputLow:低通滤波器的输出
% inputHigh:高通滤波器的输出
% samplePoint:载波的采样点数
%初始化结果数组
res = zeros(1,length(inputLow)/samplePoint);
for i = 1:length(inputLow)/samplePoint
low_amp = sum(abs(inputLow((i-1)*samplePoint+1:i*samplePoint)));
high_amp = sum(abs(inputHigh((i-1)*samplePoint+1:i*samplePoint)));
if(low_amp > high_amp)
res(i) = -1;
else
res(i) = 1;
end
end
end
rightRateCnt.m
function res = rightRateCnt(arg0,arg1)
%rightRateCnt 统计两个数组的相识程度
rightCnt = 0;
for i = 1:length(arg0)
if(arg0(i) == arg1(i))
rightCnt = rightCnt + 1;
end
end
res = rightCnt / length(arg0);
end
经过仿真,算是补齐了当年实物实验所缺的东西。本来以为可以很快回到学校,没想到一场疫情,使得开学时间一拖再拖,我过了一个历史上最长的寒假!
之前在“枪战王者”游戏仿真的时候说过要考研,但结果参加了2019年“TI杯”国赛,国赛结束后还有北京的“农建杯”,比完赛后在北京玩了两个星期,那两个星期真的是我大学期间最开心的时间。其实参加国赛前就已经提前对考研失败这一结果做好了心里准备,与考研每天对着一大堆书做对比,国赛才是我内心真正喜欢的。
大四上学期开学了,这也可以说大学期间最失败的事,“保研”失败了!在舍友的动员下,我开始真正的买书,加入考研大军,但奈何课设多,培训多,真正准备考研的时间只有不足两个月!结果数学复习完,英语刷了一套题,政治把考前500题刷完,专业课基本没复习,就这样准备非常不充分的情况下上了考场!
到现在(2020/4/10)真的看到自己考研成绩,尽管国家线还没出来,但估计是没戏了。
考研初试结束后我开始了实习,过年前还可以到公司实地实习,过年后,因为疫情,只能在家远程实习上班,现在也还是一样,已经远程上班两个多月了。说实在的我有点喜欢上了远程上班,不用挤地铁,宅家有熟悉的办公环境。
看着舍友在为考研复试做准备,我在远程上班,心里有种奇怪的感觉,这可能就是马哲所说的:“同一性越强,斗争性就越强”吧。对于考研我已经不太想二战了,考研真的好累,关键是要准备的东西太偏向书面,那不是我感兴趣的。
我真正想要的,其实是该工作就工作,有自己的闲暇时间做一点自己感兴趣的研究,周末一家人去喝茶、闲谈。生活如此足矣!
看到这的都是朋友了吧,点个赞呗