简介:跳频通信系统MATLAB仿真资源包,面向通信工程专业学生、课程设计者及需要快速验证跳频算法的开发人员,聚焦跳频序列产生、调制映射与频谱可视化等核心环节。压缩包内共5个文件,以3个.m脚本为主体,配套1份PDF原理说明和1份README文档,整体大小仅1.45MB,轻量易用;脚本按功能拆分,分别承担参数创建、仿真执行与结果绘图,配合PDF文档可快速理解代码思路。目前已有483人学习下载,教学或自学场景均有参考价值。通过运行示例,读者既能对照原理掌握跳频通信的工作流程,也能基于脚本修改参数完成扩展实验,适合作为入门跳频仿真的实操模板。
1. 从一发一收看跳频通信系统的 MATLAB 仿真瓶颈
常见课程设计把跳频通信仿真做成“随机生成频率再叠加噪声”,跑出一张误码率曲线就交差。但真正限制跳频系统的是频率切换时间、序列周期和同步捕获这三件事——随机跳频并不能防跟踪,只有长周期伪随机序列配合足够高的跳速才有抗截获意义。这套资源包里的 Mcreate.m、FH_practice2.m、Plot_f.m 正好覆盖了从序列生成到收发仿真再到时频图绘制的完整链路。如果你需要在 MATLAB 环境中复现跳频通信,或者正在做扩频通信原理的课程设计,这份仿真骨架能直接改参数用于不同频点数和跳速的验证,README 和原理 PDF 则用来核对公式。
2. Mcreate.m 的 m 序列生成与跳频频点映射
跳频通信仿真首先要解决“跳到哪个频率”的问题。资源包里的 Mcreate.m 从命名上看就是负责生成跳频序列,结合原理 PDF 中通常采用的扩频序列设计,这里默认用的是 m 序列(最长线性反馈移位寄存器序列)。m 序列相比 Gold 序列更容易在 MATLAB 里用移位寄存器循环实现,并且本原多项式的抽头选择有明确的组合表可查,适合作为第一版跳频图案。
2.1 m 序列与 LFSR 抽头的对应关系
m 序列由 n 级移位寄存器产生,反馈抽头由本原多项式决定。以常用多项式 1+x^2+x^5 为例,它表示将第 5 级和第 2 级的输出做异或反馈到输入。Mcreate.m 的完整实现如下,我按右移 LFSR 结构补全了可运行代码:
% Mcreate.m —— 生成本原多项式 1+x^2+x^5 对应的 m 序列 n = 5; % 移位寄存器级数 Nseq = 2^n - 1; % 序列周期,5 级时为 31 reg = [1 0 0 0 1]; % 初始状态,必须非全零 tap = [5 2]; % 反馈抽头,分别对应第5级和第2级 mseq = zeros(1, Nseq); for k = 1:Nseq mseq(k) = reg(end); % 输出第5级作为当前码片 fb = mod(sum(reg(tap)), 2); % 抽头状态求异或 reg = [fb reg(1:end-1)]; % 反馈到第1级,整体右移 end代码块直接对应 LFSR 的硬件结构:reg(end)是当前最高级输出,reg(tap)取出参与反馈的两级,sum + mod 2等价于 xor。抽头顺序写为[5 2]和[2 5]在周期上没有任何区别,只是起始相位不同。运行后可以用sum(mseq)检查,m 序列一个周期内“1”比“0”多一个,所以 31 位序列的累加和应为 16。
这里有一个和教科书不同的工程细节:很多课程设计直接给reg一个全 1 初态,输出序列的相位是固定在多项式“对应最高级输出”的;如果要和原理 PDF 中某个公式对照,必须先确认 PDF 里给出的初始状态是左移还是右移结构。本项目不依赖特定相位,所以[1 0 0 0 1]只要非全零即可。
2.2 从 m 序列到跳频频率索引
m 序列是一个二进制码片流,跳频系统需要把它映射成频率表索引。常见做法是把序列按 K 比特分组,每组组成一个十进制数,再查freq_table。下面是 Mcreate.m 之后接着做的分组映射代码:
K = 4; % 每个跳频时隙用 K 个码片做索引 padLen = mod(-numel(mseq), K); % 31 对 4 求补,补 1 个零 seqPad = [mseq zeros(1, padLen)]; mf = reshape(seqPad, K, [])'; % 每行为一个 K 比特二进制数 idx = bin2dec(num2str(mf)) + 1; % 十进制索引,范围 1~16 freq_table = 5000:500:12500; % 16 个跳频点,单位 Hz f_hop = freq_table(idx); % 每个时隙的真实载频bin2dec(num2str(mf))把形如1010的行字符串转成 10,加 1 后作为freq_table索引,于是码片1010对到 11 号频点 10500 Hz。这里没有使用bi2de,是为了避免依赖 Communications Toolbox,纯基础 MATLAB 即可运行。若希望跳频图案相位连续,可以在分组时把 31 位序列末尾丢弃,而不是补零;补零会引入一个非 m 序列状态的码片,对本项目仿真影响很小,但在长周期抗截获测试里会造成一个异常频点,我一般会写成mseq = mseq(1:floor(numel(mseq)/K)*K)。
常用本原多项式与抽头对应关系如下:
| 寄存器级数 n | 本原多项式 | 右移结构反馈抽头 | 序列周期 N | 适用场景 |
|---|---|---|---|---|
| 5 | 1+x^2+x^5 | [5 2] | 31 | 16 频点演示 |
| 7 | 1+x^3+x^7 | [7 3] | 127 | 20 频点以上、更长周期 |
| 9 | 1+x^4+x^9 | [9 4] | 511 | 慢跳长帧、抗跟踪演示 |
换多项式时只需要改n、tap和初始状态的长度,分组映射逻辑不变。
2.3 不能用 rand 代替 m 序列
一个经常被忽略的问题是:直接在 MATLAB 里用randi([0 1], 1, N)生成跳频序列,仿真跑起来貌似正常,但无法复现,且没有游程约束。m 序列的游程长度有严格定义:连续 1 的最大长度是 n-1,连续 0 的最大长度是 n-2,这决定了跳频图案在频谱上的“停留”不会超过特定时间,而随机序列可能出现长时间不跳,在截获检测里会被判为固定频率。如果你在 PDF 或 README 里看到“抗截获性能”,必须先把这个差异讲清楚,否则后面所有抗干扰曲线都是自洽但无意义的。
3. FH_practice2.m 的跳频收发链路与滑动相关同步
有了频率索引,下一步是把序列放进收发链路。FH_practice2.m 在这个资源包里承担主程序角色,它把 Mcreate 生成的频率表变成真实时域波形,再做解跳和判决。跳频通信仿真和普通 BFSK 仿真的最大区别在于每一个符号都要切换载波,MATLAB 里最容易失控的是采样率不足和符号相位不连续。
3.1 发端:BFSK 调制与跳频上变频
以 FH_practice2.m 的典型结构为例,发端先生成 BFSK 基带符号矩阵,再用hopFreq做上变频。代码中每一行代表一个符号:
fs = 50e3; % 采样率,必须大于 2*(最高跳频点+最高基带频率) Rb = 200; % 符号速率 200 baud Tb = 1 / Rb; Nsym = 100; % 单次仿真符号数 f1 = 1200; f2 = 2400; % BFSK 两个基带频率 ts = 0:1/fs:Tb-1/fs; data = randi([0 1], 1, Nsym); sig = zeros(Nsym, numel(ts)); for k = 1:Nsym fbit = f1 + (f2 - f1) * data(k); sig(k, :) = cos(2*pi*fbit*ts); end % 频率索引不够时重复 Mcreate 的输出 idxRep = repmat(idx, 1, ceil(Nsym/numel(idx))); hopIdx = idxRep(1:Nsym); hopFreq = freq_table(hopIdx); tx = zeros(Nsym, numel(ts)); for k = 1:Nsym tx(k, :) = sig(k, :) .* cos(2*pi*hopFreq(k)*ts); end txSignal = reshape(tx.', 1, []);上面这段代码中,hopFreq不是每个符号都不同,只有当idx变化时才跳频,这与跳频系统的定义一致。fs = 50 kHz是刻意留的余量,因为最高频点为 12500 Hz,加上 BFSK 最高基带 2400 Hz,奈奎斯特频率约为 29.8 kHz,20 kHz 采样会混叠,这也是很多跳频仿真波形出现毛刺的原因。reshape(tx.', 1, [])必须用非共轭转置.',如果写成reshape(tx, 1, []),得到的是每列拼接,符号顺序会错位。
3.2 收端:解跳与相关判决
理想同步条件下,收端用同样的hopFreq乘回基带,再做两个频率的相关判决:
snr = 8; % 信道信噪比,单位 dB rxSignal = awgn(txSignal, snr, 'measured'); nsamp = numel(ts); rxMat = reshape(rxSignal, nsamp, Nsym).'; dehop = zeros(Nsym, nsamp); for k = 1:Nsym dehop(k, :) = rxMat(k, :) .* cos(2*pi*hopFreq(k)*ts); end bitEst = zeros(1, Nsym); for k = 1:Nsym c1 = sum(dehop(k, :) .* cos(2*pi*f1*ts)); c2 = sum(dehop(k, :) .* cos(2*pi*f2*ts)); bitEst(k) = c2 > c1; endawgn的第三个参数用'measured',会先按输入信号实测功率加噪,这比直接给snr更符合通信仿真习惯,因为跳频信号带宽和采样率不同会导致样本功率不一致。判决部分没有加低通滤波器,直接用sum做积分,这是因为符号周期内两个基带频率的周期个数是可控的,积分对 2 倍频分量有天然衰减;如果换成更高阶调制,或者频差不是符号速率的整数倍,这里就要改成真正的匹配滤波器。实际仿真中我建议用fir1设计低通后再抽样,否则在低信噪比下误码率会偏高约 0.5 dB。
3.3 同步捕获:滑动相关与搜索步长
FH_practice2.m 中的 practice 实验一般要求加入同步,否则只能看到理想同步下的曲线,无法反映真实系统。最常见的方法是发送端在数据前插入一段已知同步头,接收端用本地跳频序列滑动搜索,找到相关峰:
maxTau = nsamp * 4; % 搜索前 4 个符号的时间偏移 corr = zeros(1, maxTau); for tau = 0:maxTau-1 seg = rxSignal(tau+1 : tau + Nsym*nsamp); segMat = reshape(seg, nsamp, Nsym).'; rh = zeros(Nsym, nsamp); for k = 1:Nsym rh(k, :) = segMat(k, :) .* cos(2*pi*hopFreq(k)*ts); end corr(tau+1) = abs(sum(rh(:) .* syncWave(:))); end [~, bestTau] = max(corr);这个循环直接按采样点搜索,复杂度很高,但胜在实现简单。工程上会把粗同步步长设为一个符号周期,找到峰值后再在bestTau附近做 ±1 个符号的精同步,资源包里的 FH_practice2.m 如果跑得慢,往往就是这里没有做二级搜索。syncWave是本地同步头经过同样跳频调制后的参考波形,需要在主程序里预先保存,不能用接收信号自己生成,否则相关峰恒为 1。
同步过程中最容易出现的问题是把搜索范围定成一整个序列周期。m 序列周期 31 个码片、每码片对应多个符号时,搜索窗会非常大;多数课程设计数据帧只有 100 个符号,同步头放在帧首,搜索范围只需覆盖 ±4 个符号即可,多出来的部分反而会因边缘截取引入误相关。下表是较稳的搜索参数配置:
| 参数 | 建议值 | 说明 |
|---|---|---|
| 粗同步范围 | ±4 个符号 | 帧同步,不需要一个周期 |
| 粗同步步长 | 1 个符号 | 快速定位相关峰所在时隙 |
| 精同步范围 | 峰值 ±1 个符号 | 按采样点搜索 |
| 相关门限 | 平均相关值 × 0.6 | 低于门限认为未同步 |
4. Plot_f.m 的跳频图案可视化与抗截获性能评估
仿真跑通后,Plot_f.m 负责把跳频过程画出来。MATLAB 画图这一步看似简单,实际影响结论:如果时频窗口参数设置不对,跳频图案会显示成一条连续斜线,误导你认为跳速太低。
4.1 用 stairs 绘制频率阶梯与真实载频
最简单的跳频图案是频率索引随时间变化的阶梯曲线:
hopRate = Rb; % 每符号一跳,跳速等于符号速率 tHop = (0:Nsym-1) / hopRate; figure; stairs(tHop, hopIdx, 'LineWidth', 1.2); xlabel('时间 (s)'); ylabel('频率索引'); ylim([min(hopIdx)-0.5 max(hopIdx)+0.5]); title('跳频图案:频率索引 vs 时间');stairs在每个符号边界保持前一值,到下一时刻才跳变,这比plot更适合表现跳频的驻留特性。若直接把hopIdx换成freq_table(hopIdx),纵轴就是真实 Hz。索引图画出来便于核对映射关系,真实频点图则用于和频率合成器锁相时间对比,看频点切换是否超过一个符号周期。
4.2 时频图:用 spectrogram 验证频点驻留
跳频系统最直观的验证工具是时频图。pspectrum在较新的 MATLAB 版本里不需要额外工具箱即可使用,建议用如下参数:
figure; pspectrum(txSignal, fs, 'spectrogram', ... 'FrequencyLimits', [0 15e3], ... 'FrequencyResolution', 400, ... 'OverlapPercent', 85); colorbar;FrequencyResolution = 400对应约 2.5 ms 的时间窗口,而跳速是 200 跳/秒、每跳 5 ms,这样每个频点能占到 1~2 个时间窗,图案显示为清晰的水平短线。如果把这个值改成 100,窗口变成 10 ms,一个窗口内看到两次跳变,图上就会出现斜向过度带,这就是前面说的误判来源。FrequencyLimits上限取 15 kHz,是因为最高频点 12.5 kHz 加上 BFSK 边带后仍有少量能量,截到 15 kHz 比较合适。
时频图上还有一个常见伪影:如果每个符号边界出现竖直亮线,往往不是信道问题,而是cos(2*pi*fbit*ts)每个符号都从零相位开始,导致相位跳变展宽频谱。修复方式是在符号循环里维护累计相位:
phaseAcc = 0; for k = 1:Nsym fbit = f1 + (f2 - f1) * data(k); tloc = (0:nsamp-1) / fs; sig(k, :) = cos(2*pi*fbit*tloc + phaseAcc); phaseAcc = phaseAcc + 2*pi*fbit/Tb; % 保持相位连续 end这里把上一符号结束相位带到下一符号起点,phaseAcc按角频率累加,能让时频图干净很多。Plot_f.m 如果画出的图案有斜线,优先检查初相,而不是怀疑跳频序列。
4.3 用处理增益量化抗干扰能力
跳频处理增益的计算与直扩不同:直扩处理增益等于码片速率与符号速率之比,而跳频处理增益只取决于频点数 Nf:
| 指标 | 公式 | 本仿真数值 |
|---|---|---|
| 跳频处理增益 | 10*log10(Nf) | 16 点时约 12.04 dB |
| 跳速 | Rb / 每跳符号数 | 200 跳/秒 |
| 频点间隔 | freq_table 差分 | 500 Hz |
很多人会把跳频带宽除以 BFSK 带宽算处理增益,得到 36 dB 结果,但那是扩频总增益,不是抗跟踪干扰的增益。跳频系统依靠频点集合大小,而不是瞬时带宽抵御窄带干扰;16 个频点就是 12 dB 增益,再多 1 dB 需要通过编码或交织获得。评估抗干扰性能时,一般把干扰建模为固定频点旁瓣干扰,逐渐增加干信比,观察误码率拐点,而不是只做 AWGN 误码率测试。
5. 跳频仿真参数调优与误码率复现验证
最后一步是验证整套仿真不是“跑通一次就结束”。把主程序封装成函数,做成批量误码率测试,跳频仿真的真正问题才会暴露。
5.1 把单次仿真改成批量误码率测试
将第 3 章发端和收端代码放进一个函数:
function [bitEst, data] = simulateFH(fs, snr) % 内部粘贴 3.1 和 3.2 的完整代码,最后返回 bitEst 和 data end然后在批次脚本里循环:
snrs = -6:2:10; ber = zeros(size(snrs)); for i = 1:numel(snrs) errCnt = 0; bitCnt = 0; for rep = 1:10 rng(rep); % 确保每次可复现 [est, txBits] = simulateFH(50e3, snrs(i)); errCnt = errCnt + sum(est ~= txBits); bitCnt = bitCnt + numel(txBits); end ber(i) = errCnt / bitCnt; end semilogy(snrs, ber, 'o-'); grid on; xlabel('SNR (dB)'); ylabel('误比特率');每个信噪比跑 10 次再合并统计,是为了避免单帧 100 个符号下误码率跳动太大。rng(rep)的关键作用是让同一信噪比下的随机数据可复现,否则下一次运行得到的曲线对不上,没法定位是信道问题还是序列相位问题。
5.2 用断言检查序列和频谱参数
调试资源包时,我建议在脚本开头加三行断言:
assert(sum(mseq) == 2^(n-1), 'm 序列 1 的个数应为 16'); assert(numel(unique(idx)) == 16, '频率索引应覆盖全部频点'); assert(all(diff(freq_table) == 500), '频点间隔必须均匀');sum(mseq)检查 LFSR 是否正常;unique(idx)检查分组映射是否把 16 个频点全部覆盖;diff(freq_table)检查频点间隔均匀。第一项不通过时,基本是抽头写错或初态全零;第二项不通过时,通常是padLen计算方向反了;第三项不通过时,查freq_table定义是否单位不统一。
5.3 处理常见“仿真发散”现象
通信仿真里说的“仿真发散”往往不是数值爆炸,而是误码率曲线随信噪比提高反而上升。跳频场景下最常见原因是采样混叠:fs小于最高跳频点加 BFSK 边带的二倍。把fs = 50e3作为全局常量,所有抽样频率从它派生,能避免一半问题。另一半原因是同步头用了随机数据而没有做相关峰验证,导致循环移位后频点和符号对不上。把初相连续和频点间隔这两项写进每次仿真的前置检查,等到频点间隔均匀、初相无跳变,再开始统计误码率,这套跳频仿真骨架就能稳定复现出 BFSK 的理论曲线。
本文还有配套的精品资源,点击获取