MATLAB仿真:FSK/PSK调制解调与图像传输链路设计
简介一套适合电子信息类本科毕业设计的 MATLAB 工程压缩包将数字图像处理基础与通信原理中的 FSK、PSK 调制解调系统相结合。压缩包共 8 个文件包含可直接运行的 .m 源码、用于交互演示的 .fig 图形界面、运行效果截图以及一份 PDF 课题文档整体仅 514KB便于下载与二次开发。源码覆盖信号生成、调制映射、加噪传输、解调判决与误码率统计等环节配合界面和截图可快速验证算法流程其中 FSK 通过载波频率变化传递比特PSK 则以相位偏移承载数据两者在抗噪声和频谱效率上各有侧重。PDF 文档从课题背景、技术原理到案例赏析给出说明适合作为课程设计或毕业设计参考资料。目前已有 111 人学习下载对于想用 MATLAB 理解数字调制与图像传输的同学是一份轻量且完整的入门范例。1. 数字图像处理与FSK/PSK调制解调放进同一个MATLAB工程里要解决什么做过图像类毕业设计的人都有个共同体感滤波、边缘检测、直方图均衡这些代码跑得再漂亮一旦把图片当作信号源送进信道图像立即变成满屏雪花。这个标题把“数字图像处理”和“FSK/PSK调制与解调系统”放在一起本质是在要求你完成一条完整链路——源端是灰度图像信道端是频移键控或相移键控接收端要从噪声里把像素值一个个抠回来。适合两类人一类是通信方向但选题偏图像的毕业生另一类是手里已有MATLAB图像处理代码、想补上信道仿真模块的学生。一个反直觉的结论先放这儿在纯高斯白噪声信道下BPSK误码性能优于非相干2FSK大约3dB但加上频率偏移后结论会反转FSK反而更耐用——这正是你需要同时掌握两套调制方式的原因。2. FSK与PSK的原理边界与MATLAB最小波形实现2.1 符号如何变成波形2FSK的频差约束与BPSK/QPSK的相位映射FSK把信息放在频率上2FSK的两个符号对应两个不同载频。设码元速率Rb1/Tb两个频率为fc±Δf/2信号可写为s1(t) cos(2π(fcΔf/2)t) s2(t) cos(2π(fc-Δf/2)t)两路信号在单个码元区间内正交的条件是Δf·Tb为整数。工程上习惯取Δf(1~2)Rb频差太小频谱交叠严重解调时两路带通滤波器无法分离频差过大则占用带宽线性增加。这个约束直接对应MATLAB里fskmod/fskdemod的freq_sep参数后面会用到。PSK则把信息放在相位上。BPSK用0和π两个相位表示0/1QPSK用0、π/2、π、3π/2四个相位表示2bit组合格雷映射时相邻相位只差1个bit误判到相邻星座点时只错1位这是QPSK比4ASK实用的关键原因。MATLAB里pskmod的输入就是0到M-1的整数下标相位映射关系由phaseoffset参数决定。下面是不依赖通信工具箱也能跑通的最小2FSK波形生成代码Rb 100; % 符号速率 100 baud fs 1000; % 采样率 1 kHz delta_f 200; % 频差 200 Hz 2*Rb fc 500; % 载波 500 Hz sps fs / Rb; % 每符号采样点数 10 bits randi([0 1], 10, 1); t (0:length(bits)*sps-1) / fs; % 每个时刻的瞬时频率bit1 用 fcdelta_f/2bit0 用 fc-delta_f/2 f_inst fc (2*bits - 1) * delta_f / 2; f_inst repmat(f_inst, sps, 1); f_inst f_inst(:); % 相位累积生成连续相位FSK避免频率切换处的相位跳变 phase 2 * pi * cumsum(f_inst) / fs; s cos(phase);这里的关键是用cumsum做相位累积而不是对每个bit独立拼接cos片段。连续相位FSK的频谱旁瓣比相位跳变型低很多后续加带限滤波器时也更容易处理。f_inst的构造里2*bits-1把0/1映射成-1/1的频偏方向repmat把每个符号的瞬时频率扩展到sps个采样点。如果换成非连续相位FSK接收端用包络检波同样能解但发端频谱会宽出不少毕设答辩时容易被问住。QPSK的发端更简洁用通信工具箱一行搞定M 4; % QPSK data randi([0 M-1], 1000, 1); sps 8; tx pskmod(data, M, 0); % 第三个参数是相位偏移默认0 tx_up rectpulse(tx, sps); % 每符号复制sps次形成波形pskmod输出的tx_up是复基带信号实部虚部分别对应I/Q两路。phaseoffset取0时星座点位于0、π/2、π、3π/2取π/4时旋转45°实际系统常取π/4让星座点避开坐标轴便于用绝对值做非相干检测。2.2 非相干与相干解调的真实工程差异以及fskdemod/pskdemod的参数含义解调方式的选择直接决定接收机复杂度。FSK最常用的非相干解调是包络检波接收信号通过中心频率分别在fcΔf/2和fc-Δf/2的两个窄带带通滤波器比较两路包络大小包络大的一路对应发送符号。这个过程不需要恢复载波相位结构简单代价是误码率比相干FSK差约3dB。PSK则相反信息全在相位里必须做相干解调也就是说接收端需要先恢复载波的频率和相位这就是毕设里最容易卡壳的载波同步问题。在MATLAB里这两个解调器都有现成函数% 2FSK非相干解调 rx_fsk awgn(tx_fsk, 10, measured); % 加10dB噪声 data_hat_fsk fskdemod(rx_fsk, 2, delta_f/fs, sps, noncoherent); % QPSK相干解调 rx_psk awgn(tx_psk, 10, measured); data_hat_psk pskdemod(rx_psk, M, 0);fskdemod的第三个参数freq_sep是归一化频差单位是弧度/采样点还是赫兹看MATLAB帮助这里freq_sep必须以“相对采样率的比值”传入即delta_f/fs。这个细节很多人栽过直接填200会让解调器以为频差是200倍采样率输出全是错。第四个参数nsamp必须与发端rectpulse或上采样倍数严格一致。noncoherent选项让解调器使用包络检波代价是误码率差一些好处是不需要锁相环。pskdemod默认按相干方式解调把接收符号映射到欧氏距离最近的理想星座点。如果发端没有做差分编码这里必须保证星座绝对相位正确一旦频偏存在pskdemod结果就会一片混乱。顺带一提LoRa这类低功耗广域网里常出现FSK与其他调制混合的设计FSK段负责前导码检测和粗略同步后段再用更高阶调制传数据。这正是利用FSK对频偏不敏感、无需锁相环的特性和毕设里“先FSK找同步、再PSK传高速数据”的思路同源。2.3 用星座图把“调制对了没有”变成可读的结果调完制先别急着加噪声第一件事是看星座图。scatterplot是调试通信链路最常用的工具scatterplot(tx, sps, 0, rx); grid on; title(QPSK发射星座);如果代码正确图上应该看到四个点分别落在单位圆与坐标轴交点处。加噪声后再画一幅scatterplot(rx_psk, sps, 0, bx);这时四个点变成四团“云”云的弥散半径正比于噪声幅度。星座图能直观告诉你三件事一是调制映射有没有错二是噪声背景下判决余量还剩多少三是是否存在相位旋转——如果四个云团绕原点转了一个角度说明有频偏这个线索比看误码率数字更早暴露问题。3. 从调制到误码率一条可直接跑的FSK/PSK仿真链路3.1 复基带等效为什么仿真不用写射频MATLAB里所有pskmod、fskmod的输出都是复基带信号。带通信号与复基带的关系是s(t) Re{ s_bb(t) * exp(j*2π*fc*t) }通信系统仿真几乎全在复基带完成因为载波fc只起频谱搬移作用不改变符号判决结果。FSK在复基带里表现为两路不同频率的复指数PSK则是单位圆上的相位点。这样做的好处是不用按射频采样率跑仿真计算量小几个数量级。数字图像处理毕设里的图像数据量动辄几十万像素如果每个像素都按射频载波仿真一台普通电脑根本跑不动复基带等效是唯一现实选择。3.2 AWGN信道下Eb/N0与SNR的换算以及噪声怎么加误码率曲线的横轴通常用Eb/N0每比特能量与噪声功率谱密度之比而MATLAB的awgn函数接受的是SNR信号功率与噪声功率之比。两者换算关系为SNR(dB) Eb/N0(dB) 10*log10(bits_per_symbol)BPSK每个符号携带1bitSNR等于Eb/N0QPSK每符号2bit同样符号能量下SNR比Eb/N0高3dB。注意awgn的measured选项会先测量信号平均功率再按给定SNR生成噪声仿真中必须用它否则信号归一化方式不同会导致实际信噪比偏离设定值。换算表可以记成下面这样调制方式bits/symbolSNR换算dB占用带宽近似BPSK1SNREb/N0RbQPSK2SNREb/N03Rb/22FSK 非相干1SNREb/N02ΔfRb这张表直接决定awgn里的snr参数怎么填。经常有人拿Eb/N010dB直接塞进awgn的第二个参数结果仿真误码率比理论值差3~6dB查半天查不出原因多半是漏了bits_per_symbol这项。3.3 误码率主循环、置信区间与理论曲线对比完整跑一段误码率仿真并把结果与理论曲线叠在一起M 2; % BPSK n_symbols 100000; % 每信噪比点发送符号数 EbNo_db 0:2:10; ber_sim zeros(size(EbNo_db)); for k 1:length(EbNo_db) data randi([0 M-1], n_symbols, 1); tx pskmod(data, M, 0); % 能量归一化 SNR换算 snr EbNo_db(k) 10*log10(log2(M)); rx awgn(tx, snr, measured); data_hat pskdemod(rx, M, 0); ber_sim(k) sum(data ~ data_hat) / n_symbols; end ber_theory berawgn(EbNo_db, psk, M, nondiff); semilogy(EbNo_db, ber_sim, o-); hold on; semilogy(EbNo_db, ber_theory, s-); grid on; xlabel(Eb/N0 (dB)); ylabel(BER); legend(BPSK仿真, BPSK理论);逻辑说明pskmod的输出已经是单位能量符号awgn内部按照输入信号功率生成相应噪声功率。berawgn里的nondiff表示非差分相干解调的理论误码率对应pskdemod的判决方式。仿真点数100000时BER1e-3意味着约100个错误符号95%置信区间半宽约1.96sqrt(1e-3(1-1e-3)/100000)≈1.96e-4误差在一个量级内还能接受。想看到1e-5以下的误码率把n_symbols提到1e6以上跑起来也就几十秒。4. 把图像作为信源像素到符号、RS纠错、PSNR验收4.1 灰度图到调制符号的映射与逆映射图像不能直接送进pskmod需要先把灰度值拆成比特流再按星座阶数分组映射。这里常见误区是把灰度值直接当调制电平输入导致一个噪声毛刺就让像素值跳变几十级。正确做法是位平面分解img imread(cameraman.tif); img_gray im2gray(img); [nr, nc] size(img_gray); % 每个像素8bit按位平面展开成一维比特流 bits_img de2bi(img_gray(:), 8, left-msb); % 256x8 bits_flat bits_img(:); % 2048x1 % QPSK每符号2bit把比特流重新排列成符号索引 pairs reshape(bits_flat, 2, []); sym_idx bi2de(pairs, left-msb); % 0~3 % 映射到QPSK星座 tx pskmod(sym_idx, 4, 0); % 经过信道... rx awgn(tx, snr, measured); % 接收端逆过程 sym_hat pskdemod(rx, 4, 0); bits_hat de2bi(sym_hat, 2, left-msb); bits_flat_hat bits_hat(:); bits_img_hat reshape(bits_flat_hat, 8, nr*nc); img_recovered uint8(bi2de(bits_img_hat, left-msb)); img_recovered reshape(img_recovered, nr, nc);de2bi的left-msb参数保证第1列是最高位高位错误对像素值影响大低位错误影响小。错误比特出现在高位时单个bit错误会让像素值改变128肉眼表现为雪花点出现在低位则只改变1~2级灰度几乎看不出来。所以接收端图像质量的退化不是均匀的这也解释了为什么同样的误码率下图像的主观损伤程度与错误比特的位置分布强相关。4.2 RS(255,223)按字节纠错为图像传输加一道保险灰度图像一个像素正好8bit天然适合按字节做纠错。RS码工作在GF(256)上一个符号就是一个字节RS(255,223)把223字节信息编码成255字节码字能纠正t(255-223)/216个错误字节。MATLAB实现rs_enc comm.RSEncoder(CodewordLength, 255, MessageLength, 223); rs_dec comm.RSDecoder(CodewordLength, 255, MessageLength, 223); % 把像素字节流分块每块223字节 n_blocks ceil(length(img_bytes) / 223); img_bytes_pad [img_bytes; zeros(223*n_blocks - length(img_bytes), 1)]; img_bytes_mat reshape(img_bytes_pad, 223, n_blocks); enc_mat rs_enc(img_bytes_mat); % 每行一个码字255字节 enc_stream enc_mat(:); % 送调制前打平RS编码的开销是(255-223)/255≈12.5%。不加纠错时图像恢复的临界误码率大约在1e-2超过这个值图像就完全不可读加了RS编码且误码率在1e-2以内解码后通常能恢复出几乎无错图像这个增益对毕设演示来说非常可观。但要提醒一点RS(255,223)的纠错上限是16个错误字节如果信道质量极差、单码字错误超过16字节解码器会越纠越错。实际使用时可以在译码输出上再做一次校验RS编码自带的就是这种检错能力。4.3 恢复质量的判定BER到PSNR的换算经验图像恢复质量用峰值信噪比PSNR衡量。MATLAB里自带psnr函数但自己写会更清楚mse mean((double(img_gray(:)) - double(img_recovered(:))).^2); psnr_val 10 * log10(255^2 / (mse eps));double转换必须做uint8相减会回绕产生错误结果加eps是防止无噪声时mse恰好为零导致log10(inf)。经验数值PSNR大于30dB时肉眼很难区分原图和恢复图PSNR在25~30dB之间图像有轻微可感知退化PSNR低于20dB图像已经严重损伤。对应关系上BPSK/QPSK在AWGN信道下BER达到1e-3量级时恢复图像PSNR大约在30dB上下这个交叉点通常就是毕设里选工作信噪比门限的依据。5. 验收技巧星座图、眼图与频偏定位三个必测项5.1 眼图判读采样点该取在哪里发送端如果加了升余弦脉冲成形接收端解调前要画眼图确认最佳采样时刻。命令是eyediagram(rx, sps*2, 2, sps/2);四个参数分别是每行采样点数、每行码元数、起始偏移。眼图张开最大的位置就是最佳采样点横坐标落在(sps的整数倍偏移)处。眼睛高度对应噪声容限眼睛宽度对应定时误差容忍度。如果眼图中间横着一条线说明存在直流偏差或频偏导致星座旋转。数字图像处理里的图像恢复效果再好眼图这关过不了链路就是不合格的。5.2 频偏定位帧头相关法给出偏移量和相位旋转PSK系统最隐蔽的问题是频偏。接收信号与本地已知前导序列做互相关可以同时估计符号定时起点和残余频偏preamble ones(64, 1); % 已知前导符号 [corr_val, lag] xcorr(rx, preamble); [~, idx] max(abs(corr_val)); % 相关峰对应的符号起点 start_offset length(rx) - lag(idx) 1; % 取前导段估计相位旋转 r_preamble rx(start_offset:start_offset63) .* conj(preamble); phase_est angle(mean(r_preamble)); % 换算归一化频偏 delta_f_est phase_est / (2 * pi * sps);xcorr的lag向量以零延迟为中心相关峰位置给出定时偏移相位估计用的是前导符号共轭相乘后取平均把单个符号的噪声影响平滑掉。delta_f_est是相对采样率的频偏乘以fs才是赫兹值。这个方法的估计范围是±1/(264sps)超出后会相位模糊。频偏每增加一点点星座图旋转速度就加快判决边界形同虚设。5.3 把SNR从0扫到20看PSNR一条完整验收曲线答辩时最有说服力的一张图是把上述链路串起来扫描不同SNR下图像恢复的PSNRsnr_range 0:2:20; psnr_arr zeros(size(snr_range)); for k 1:length(snr_range) rx awgn(tx, snr_range(k), measured); % 解调、RS译码、图像重建... psnr_arr(k) psnr_val; end plot(snr_range, psnr_arr, o-); grid on; xlabel(SNR (dB)); ylabel(恢复图像PSNR (dB));这条曲线呈现明显的“悬崖”特性低信噪比区PSNR缓慢爬升到某一门限后急剧上升并趋于饱和。FSK和PSK两条曲线画在一起时交点左侧FSK恢复质量更好交点右侧PSK占优这正好可以作为调制方式选型的量化依据。本文还有配套的精品资源点击获取