简介:这份资源是面向通信工程、电子信息类专业学生的「通讯系统原理课程设计」完整文档,聚焦2FSK调制与解调系统的设计与MATLAB7.0仿真实现,适合正在做课设、需要参考完整方案与源码思路的学习者。文档围绕信源产生、发送滤波、加性高斯白噪声信道、相干解调与抽样判决等模块展开,给出参数设置、调制解调原理推导及SNR与误码率曲线分析,并附有可运行的源程序与仿真波形,便于对照理解开关法调制与相干解调的实现细节。资源包共1个doc文件,约579KB,内容涵盖设计任务与要求、方案论证、原理图与源程序仿真结果,结构完整,可直接作为课设报告撰写与仿真复现的参考。目前已有854人学习下载,适合需要快速搭建2FSK仿真链路、梳理通信系统模块关系并完成性能评价的读者。
1. 从一份课设源码说起:2FSK 调制解调到底能跑出什么
拿到这份《2FSK 调制与解调系统设计与仿真》的 MATLAB 源码时,我第一反应是:这不就是通信原理课设里最经典的那道题吗?但真把代码跑起来、把波形一张张看过去,才发现它比想象中完整——信源产生、2FSK 调制、加性高斯白噪声信道、相干解调、非相干解调、误码率统计、升余弦滤波、眼图,一条链路全串起来了。它适合两类人:一类是正在做通信原理课设、需要一份能跑通、能改参数、能出图的参考实现;另一类是已经工作、想快速用 MATLAB 验证 2FSK 在 AWGN 信道下误码率表现的开发者。整份代码基于 MATLAB7.0 时代的dmod/ddemod函数体系写成,虽然版本老,但调制解调的骨架清晰,拿来当教学模板或者二次开发的起点都够用。下面我按“这项目是什么 → 怎么跑 → 怎么改”的顺序,把这份源码拆开讲。
2. 系统架构与信号链路:一条 2FSK 链路是怎么搭起来的
2.1 模块划分:从信源到信宿的六个环节
这份设计的模块划分和通信原理教材上的框图基本一一对应,源码里也是按这个顺序往下写的。整条链路可以拆成六块:
| 模块 | 源码对应 | 关键函数/操作 | 作用 |
|---|---|---|---|
| 信源 | x=randsrc(numSymb,1,[0:M-1]) | randsrc | 产生二进制随机比特流 |
| 调制 | y=dmod(x,Fc,Fd,Fs,'fsk',M,df) | dmod | 键控法产生 2FSK 信号 |
| 信道 | y=awgn(y,SNR,...) | awgn | 叠加高斯白噪声 |
| 相干解调 | z1=ddemod(y,Fc,Fd,Fs,'fsk/eye',M,df) | ddemod | 相干方式恢复基带 |
| 非相干解调 | z2=ddemod(y,Fc,Fd,Fs,'fsk/eye/noncoh',M,df) | ddemod | 包络检波方式恢复 |
| 性能评估 | symerr(x,z1) | symerr | 统计误码率 |
这个划分的好处是每一块都能单独拿出来调。比如你只想看调制波形,把后面信道和解调注释掉就行;想对比相干和非相干,两条ddemod调用并排放着,改一个字符串参数就能切换。我一般会建议先把信源和调制跑通、确认波形对,再往下加信道,不然一出问题就不知道是调制错了还是解调错了。
2.2 调制端:开关法产生 2FSK 的参数含义
调制这一行是整个链路的核心,参数设错后面全白搭。源码里是这样写的:
Fc=10; % 载频 Fs=40; % 系统采样频率 Fd=1; % 码速率 N=Fs/Fd; % 每个码元的采样点数 df=10; % 两个载频的频率间隔 numSymb=25; % 仿真码元个数 M=2; % 进制数,2 表示 2FSK SNRpBit=60; % 每比特信噪比(dB) SNR=SNRpBit/log2(M); x=randsrc(numSymb,1,[0:M-1]); % 产生 25 个二进制随机码 y=dmod(x,Fc,Fd,Fs,'fsk',M,df); % 键控法数字带通调制逐项说清楚:Fc是标称载频,df是两个频率源 f1、f2 之间的间隔,实际调制时 f1 和 f2 分别落在Fc±df/2附近,所以df直接决定两个频率分得开不开。Fs/Fd得到每个码元的采样点数N,这个值太小波形会糊、太大仿真慢,40 是个折中。SNRpBit=60这个值高得离谱,本质上是让信道几乎不加噪声,方便先看纯净波形——真正做误码率曲线时这个值要往下调,后面会讲。dmod的'fsk'字符串告诉函数用频移键控,M=2是二进制,df传进去控制频偏。这里用的是开关法,两个独立频率源切换,所以相邻码元相位不连续,和教材里“调频法相位连续”的描述正好形成对照,源码注释里也点明了这一点。
2.3 信道与解调:相干和非相干并排对比
信道部分只有一行,但参数有讲究:
randn('state',seed(2)); y=awgn(y,SNR-10*log10(0.5)-10*log10(N),'measured',[],'dB');awgn的第二个参数是信噪比,这里做了两次换算:-10*log10(0.5)是因为 2FSK 一个码元周期内实际只用一个频率、能量减半;-10*log10(N)是把每比特信噪比折算到采样点级别。这两项不换算,加出来的噪声强度就对不上理论值,误码率曲线会整体偏移——这是很多人跑出来曲线“和教材对不上”的根因。'measured'表示按实际信号功率测量后再加噪声,比默认的假设功率更稳。
解调端两条路并排:
z1=ddemod(y,Fc,Fd,Fs,'fsk/eye',M,df); % 相干解调 z2=ddemod(y,Fc,Fd,Fs,'fsk/eye/noncoh',M,df); % 非相干解调'fsk/eye'里的eye是让函数顺带画眼图,noncoh后缀切换到非相干(包络检波)方式。相干解调需要本地载波与发送端同频同相,理论误码率更低;非相干不需要相位信息,实现简单但性能略差。源码把两者都跑一遍、各自symerr统计,正好用来验证“相干优于非相干”这个结论,而不是只背公式。
3. 把源码跑起来:环境、步骤与出图顺序
3.1 环境准备与版本兼容
这份代码写于 MATLAB7.0 时代,核心依赖是通信工具箱里的dmod、ddemod、awgn、symerr、rcosine、rcosflt、eyediagram。在新版 MATLAB 上跑,最大的坑是dmod/ddemod这套老函数在新版通信工具箱里已经被标记为不推荐甚至移除,直接运行会报 “Undefined function”。两条路:一是装回带这套函数的旧版工具箱环境;二是用fskmod/fskdemod替代,参数顺序不同,需要改调用。我一般建议先确认自己机器上which dmod有没有返回路径,没有就别硬跑,先决定走哪条替代路线。
运行前还要确认三件事:当前文件夹切到源码所在目录(否则simbasebandex这类自定义或示例函数找不到);randsrc属于通信工具箱,没装会报错;绘图窗口别开太多,源码一口气开了十个 figure,老机器容易卡。
3.2 分段运行:先波形后误码
整段代码一次跑完容易看花眼,我的习惯是分段执行。第一段只跑到调制:
Fc=10; Fs=40; Fd=1; N=Fs/Fd; df=10; numSymb=25; M=2; x=randsrc(numSymb,1,[0:M-1]); y=dmod(x,Fc,Fd,Fs,'fsk',M,df); t=[0:numPlot*Fs-1]./Fs; plot(t,y(1:length(t)),'b-'); axis([min(t) max(t) -1.5 1.5]);这段跑通后,figure(1) 是二进制随机序列杆图,figure(2) 是调制后的 2FSK 波形。看波形时重点确认两件事:码元“1”和“0”对应的频率是不是明显不同(疏密不同),幅度是不是稳定在 ±1 附近。如果波形挤成一团,多半是Fs相对Fc太小,采样点不够还原载波,把Fs提到Fc的 4 倍以上再试。
第二段加信道,figure(3) 看加噪后的波形,噪声肉眼可见但码元轮廓还在,说明信噪比设置合理。第三段跑解调,figure(5) 和 figure(7) 分别是相干、非相干解调结果与原序列的对比杆图,蓝叉是原序列、红圈是解调结果,两者重合度高说明解调正确。最后一段跑误码率统计和升余弦滤波,figure(8)(9) 是误码率曲线,figure(10) 是滤波前后波形对比。
3.3 误码率曲线怎么读
源码里simbasebandex([0:1:5])画的是理论误码率参考曲线,横轴是 Eb/N0(dB),纵轴是误码率(对数坐标)。自己仿真的点要和这条理论线贴得近才算对。如果仿真点整体偏高,先查 3.1 节说的awgn换算有没有漏;如果点很散,是numSymb=25太小、统计样本不够,把码元数加到几千再跑,曲线会平滑很多。这一步是整份课设的“验收标准”,波形再漂亮,误码率对不上理论值就说明链路某处参数错了。
4. 核心代码逐段拆解:调制、信道、解调三段关键实现
4.1 信源与调制:randsrc和dmod的配合
信源这一行看似简单,但randsrc(numSymb,1,[0:M-1])的第三个参数是取值集合,[0:M-1]在M=2时就是[0 1],等概率产生 0 和 1。如果想模拟有偏的信源(比如 0 出现概率更高),可以换成randsrc(numSymb,1,[0 1; 0.7 0.3])这种带概率矩阵的写法,这是二次开发时很容易加的一个点。
调制端dmod的完整签名是dmod(x,Fc,Fd,Fs,method,M,df),其中method='fsk'决定调制类型,M是进制数,df是频偏。这里有个容易忽略的细节:df和Fd的关系决定了两个频率是否正交。2FSK 相干解调要求两个载频在一个码元周期内正交,即频差是码速率的整数倍,源码里df=10、Fd=1,频差远大于码速率,正交性没问题,但占用带宽也大。如果做带宽受限的场景,要把df往Fd附近压,同时注意别压到两个频率重叠、解调分不开。
4.2 信道加噪:awgn那行换算的来龙去脉
前面提过awgn那行做了两次对数换算,这里展开说清楚,因为这是整份代码里最容易抄错的一行:
SNR=SNRpBit/log2(M); % 每符号信噪比 y=awgn(y,SNR-10*log10(0.5)-10*log10(N),'measured',[],'dB');SNRpBit是每比特信噪比,除以log2(M)得到每符号信噪比(M=2时两者相等)。-10*log10(0.5)修正 2FSK 每码元只用一半能量的因素;-10*log10(N)把符号级信噪比摊到N个采样点上,因为awgn是按采样点加噪声的。少了任何一项,加出来的噪声功率就和理论模型对不上,误码率曲线会整体平移几个 dB。我见过有人直接把SNRpBit丢给awgn,跑出来的曲线和教材差一大截,查了半天以为是解调写错了,其实就是这一行。
4.3 相干与非相干解调:一个字符串参数的差别
两条解调调用的差别只在方法字符串:
z1=ddemod(y,Fc,Fd,Fs,'fsk/eye',M,df); % 相干 z2=ddemod(y,Fc,Fd,Fs,'fsk/eye/noncoh',M,df); % 非相干ddemod内部对相干方式会重建本地载波、与接收信号相乘再低通滤波、抽样判决;非相干方式则走带通滤波加包络检波。对使用者来说,参数完全一样,只是方法串不同,这正是这套老函数方便的地方——切换解调方式不用改链路结构。但要注意,相干解调对载波相位敏感,如果信道里加了频偏或相偏,相干性能会明显下降,而非相干更鲁棒。做二次开发时如果想模拟载波恢复误差,可以在ddemod之前给y乘一个带相偏的复指数,对比两种解调的抗偏能力,这是个很有说服力的扩展实验。
4.4 升余弦滤波与眼图:rcosine和rcosflt的用法
滤波部分源码是这样写的:
Delay=3; R=0.5; PropD=0; [yf,tf]=rcosine(Fd,Fs,'fir',R,Delay); % 设计升余弦滤波器 [yo2,to2]=rcosflt(y,Fd,Fs,'filter',yf); % 对信号滤波 eyediagram(yo2,N); % 画眼图rcosine的R=0.5是滚降系数,取值 0 到 1,越小带宽越窄但拖尾越长、对定时误差越敏感;Delay=3是滤波器延迟(以码元为单位),影响滤波后波形的群延迟。rcosflt的'filter'模式表示用现成滤波器系数直接滤,不再重新设计。眼图eyediagram(yo2,N)的第二个参数N是每轨迹采样点数,眼图张开度直接反映码间干扰大小——滤波前眼图糊、滤波后张开,就说明升余弦把带外噪声压下去了。这一步在课设报告里是加分项,因为它把“滤波器到底有没有用”可视化了。
5. 避坑与排查:跑这份源码最容易翻车的五个地方
5.1 报 “Undefined function 'dmod'”
现象:一运行就停在调制那行,提示函数未定义。原因:新版 MATLAB 通信工具箱移除了dmod/ddemod这套老接口。解决:要么在旧版环境跑,要么改用fskmod/fskdemod,注意新函数参数顺序是fskmod(x,M,freq_sep,nsamp,Fs),和dmod不一样,得逐行改调用,别只换函数名。
5.2 误码率曲线和理论值差好几个 dB
现象:仿真点整体偏离simbasebandex理论线。原因:九成是awgn那行的信噪比换算漏了-10*log10(0.5)或-10*log10(N)。解决:按 4.2 节把两项补全,再确认'measured'参数在,然后加大numSymb重跑,曲线会贴回去。
5.3 调制波形挤成一团、看不出频率变化
现象:figure(2) 的波形像一团噪声,分不清 0 和 1。原因:Fs相对Fc太小,一个载波周期采样点不够。解决:把Fs提到Fc的 4 倍以上,或者把Fc降下来,保证每个码元内能看到多个完整载波周期。源码里Fc=10、Fs=40是 4 倍关系,刚好够,再降就糊。
5.4 十个 figure 一起弹、机器卡死
现象:运行后窗口疯狂弹出,老机器直接无响应。原因:源码从头到尾没关过 figure,一次全画。解决:在每段之间加pause或把不看的 figure 注释掉,分段运行;也可以在每个figure后加drawnow控制刷新节奏。我一般只留调制、加噪、解调对比、误码率四张图,其余按需开。
5.5 抽样判决那步“不知道怎么写”
现象:自己照着框图补抽样判决代码时卡住,不知道判决门限怎么定。原因:2FSK 相干解调的两路低通输出要比较大小,门限取两路之差过零即可,不是固定阈值。解决:如果直接用ddemod就不用自己写判决;如果要手写链路,判决就是比较 f1 支路和 f2 支路的抽样值,谁大判谁,源码里ddemod内部已经做了这件事,这也是为什么课设里“抽样判决模块始终报错、最后改用代码实现”的原因——模块化仿真里判决器配置比写一行比较逻辑麻烦得多。
6. 二次开发:把课设代码改成能验证结论的实验平台
这份源码最大的价值不在“能跑”,而在“能改”。我拿它做过一个小改造:把固定信噪比改成扫频式循环,一次跑出完整的误码率曲线,而不是靠simbasebandex画理论线、自己只放几个点。核心改动是把调制到统计误码率那段包进for循环:
SNR_vec = 0:2:12; % 扫描的信噪比范围(dB) ber_coh = zeros(size(SNR_vec)); ber_non = zeros(size(SNR_vec)); for k = 1:length(SNR_vec) y = dmod(x,Fc,Fd,Fs,'fsk',M,df); y = awgn(y,SNR_vec(k)-10*log10(0.5)-10*log10(N),'measured',[],'dB'); z1 = ddemod(y,Fc,Fd,Fs,'fsk',M,df); z2 = ddemod(y,Fc,Fd,Fs,'fsk/eye/noncoh',M,df); [~,ber_coh(k)] = symerr(x,z1); [~,ber_non(k)] = symerr(x,z2); end semilogy(SNR_vec,ber_coh,'b-o',SNR_vec,ber_non,'r-s');这段改动的关键点有三个:numSymb要加大到几千甚至上万,否则高信噪比下误码数为零、曲线断掉;awgn的换算两项一个都不能少,否则横轴对不上;semilogy用对数纵轴才能看清低误码率段的差异。跑出来两条线,相干那条应该整体在非相干下方,这就是“相干优于非相干”的直观证据,比报告里抄公式有说服力得多。
再往深改,可以加载波频偏和相偏,验证相干解调对同步误差的敏感度;也可以把信道从纯 AWGN 换成带多径的,看 2FSK 在衰落信道下的表现。改的时候有个血泪经验:每改一处就单独跑一次、存一张图,别一口气改五六处再跑,出了问题根本定位不到是哪一步引入的。我现在的习惯是每加一个实验变量,就先在SNRpBit固定、numSymb小的情况下跑通波形,确认链路没断,再放大样本跑统计。这份课设代码结构清晰、模块边界干净,正好适合这么一步步往上叠实验,希望帮到你。
本文还有配套的精品资源,点击获取