超奈奎斯特(FTN)容量仿真的MATLAB实现与参数边界解析
2026/9/12 14:48:08 网站建设 项目流程

简介:面向通信专业研究人员与高年级学生的超奈奎斯特(FTN)信道容量仿真资源包,聚焦在不增加带宽的前提下突破奈奎斯特速率极限的理论验证与算法实现。压缩包共18个文件(37.36MB),以MATLAB脚本(.m)为核心,附带滤波/脉冲成型参数(.mat)与结果图(.fig),可支撑信道建模、信号调制、误码率分析及容量计算等环节的复现实验。当前已有149人学习下载。通过运行capacity系列脚本与on_orthogonal示例,可直观查看alpha、beta、脉冲成型因子等参数对FTN系统容量与性能的影响,并对比传统奈奎斯特系统的差异,尤其适合用于科研预研、课程设计或毕业设计中的仿真验证。资源内包含RRC、RC脉冲成型的多组系数和波形图,便于研究非正交信号条件下的信道容量优化策略。

1. 超奈奎斯特容量仿真:先从一组反直觉参数说起

压缩包里反复出现alpha = 0.8, beta = [0.2 0.5], T = 0.5这样一组参数,乍看之下T = 0.5很容易被理解成“把符号速率翻一倍”,但真正跑过 FTN 仿真的人都知道,这里提速的幅度远没有想象中大。因为奈奎斯特速率对应的符号间隔不是 1,而是(1 + alpha) / 2B这个与滚降系数强相关的值。alpha = 0.8意味着频谱占用被撑得很宽,留给 FTN 压缩的空间反而变小了。这个压缩包里的on capacity系列脚本和capacity0/1/2.m,处理的正是这套参数下“脉冲不再正交时,信道容量该怎么算”的问题。适合波形设计、物理层仿真和需要复现超奈奎斯特结果的工程师阅读,下文会从准则本身一路拆到 MATLAB 实现和参数边界。

2. 奈奎斯特第一准则、根升余弦与 FTN 的符号间干扰模型

2.1 先厘清奈奎斯特速率的准确定义

很多资料把奈奎斯特准则写成C = 2B,这其实混淆了“符号速率上限”和“信道容量”两个概念。奈奎斯特第一准则说的是:在带宽为B的理想低通信道中,若要实现无符号间干扰(ISI)传输,符号速率Rs不能超过2B,且要求脉冲响应在整数倍符号间隔处过零。至于单位时间内能可靠传输多少比特,还要在这个基础上叠加上信噪比因素,由香农容量公式给出。所以更严谨的描述是Rs = 2B是无 ISI 传输的符号速率上限,而容量是C = B * log2(1 + SNR)这一层。

超奈奎斯特(Faster-than-Nyquist, FTN)打破的正是第一准则里的“整数倍符号间隔过零”这一条件。当符号间隔T小于奈奎斯特间隔时,相邻脉冲的拖尾会在采样点处互相叠加,形成可控的符号间干扰。这个压缩包里的.fig文件标题,比如alpha = 0.8, beta = [0.2 0.5], T = 0.5(2).fig,记录的便是不同参数组合下这种干扰对容量的影响。理解这一点是跑通后面所有脚本的前提:FTN 并没用更高阶调制,而是用“允许串扰 + 接收端补偿”换取了额外的符号速率。

2.2 RRC/RC 脉冲与 L=100 截断的工程取舍

压缩包里的RRC_L_100_alpha_03_order_1E6_win_rec.matRC_L_100_alpha_03_order_1E6_win_rec.mat给出了两组不同的脉冲波形数据。RRC是根升余弦,RC是升余弦,两者在 FTN 仿真中的作用不同。下表列出二者的工程差异:

脉冲类型频带占用有无 ISI典型用途
根升余弦 RRC(1+alpha)/2T发射成型滤波器
升余弦 RC(1+alpha)/2T发射+接收级联后的等效响应

RRC之所以叫“根”升余弦,是因为发射端和接收端各放一个 RRC,级联后的频谱乘积正好等于升余弦频谱。压缩包里同时存在 RC 和 RRC 的.mat文件,说明作者在对比两种做法:一种是用 RRC 成型再用 RRC 匹配滤波,另一种是直接观察 RC 脉冲在 FTN 采样点上的串扰能量。L=100表示滤波器单边抽头数,总抽头数2L+1 = 201,在order = 1E6个符号的仿真里,滤波器截断引入的边界效应大约占符号总数的2L/order = 2e-4,可以忽略。win_recwin_hamming则代表滤波器截断时加的窗类型,矩形窗旁瓣高但主瓣窄,汉明窗相反,这在 FTN 场景下会直接影响远端串扰的估计精度。

2.3 把 beta 纳入串扰模型

压缩包参数里alphabeta成对出现,我理解beta在这里是接收端频域处理相关的一个滚降参数,常见做法是把它定义为接收端匹配滤波器带宽边缘的过渡带占比,或者用来控制频域加窗后的残余串扰水平。alpha控制发射成型脉冲的滚降,而beta控制的是接收端对频谱边缘的加权方式。当beta小于alpha时,接收窗会主动削掉一部分信号边带,导致信噪比损失;当beta大于alpha时,接收窗保留更多频谱,但也会引入更多邻道干扰。

在 FTN 仿真里,需要把这种干扰量化成具体的功率值。常见做法是直接计算整体脉冲响应的旁瓣能量占比:

% isi_power_check.m % 计算 RRC 成型 + RRC 匹配滤波后的整体脉冲响应旁瓣能量 alpha = 0.8; L = 100; sps = 32; % 每符号采样点数 T = 0.5; h = rrc_design(alpha, L, sps); % 需要自行实现或从 mat 文件加载 g = conv(h, h(end:-1:1)); % 整体脉冲响应:发射成型 + 匹配滤波 % 采样点对应的索引:目标时刻在正中间 center = (length(g) + 1) / 2; isi_idx = center + round((1:50) * T * sps); % 相邻 50 个符号位置 isi_pow = sum(g(isi_idx).^2); total_pow = sum(g.^2); fprintf('ISI 能量占比: %.4f\n', isi_pow / total_pow);

这段代码先把发射和接收的 RRC 脉冲做卷积,得到级联后的等效脉冲响应g,然后在距离中心点k*T*sps的位置采样,把这些旁瓣能量和全部能量相比,得到的就是 FTN 场景下相邻符号串扰占总信号能量的比例。sps = 32alpha = 0.8时可以保证成形滤波器的频谱不会因为采样率不足而混叠。跑完这段脚本,如果 ISI 能量占比超过 0.1,就需要考虑在接收端引入串扰消除,否则容量计算会明显偏低。

3. 用 MATLAB 跑通 on capacity 容量仿真主线

3.1 capacity0 / capacity1 / capacity2 三条主线的分工

压缩包里有三个名字相近的脚本:capacity0.mcapacity1.mcapacity2.m。从命名规律和on_orthogonal.m系列脚本来看,这三者应该是容量计算的三级递进:

脚本关注对象是否建模 ISI输出形式
capacity0.m奈奎斯特基线容量香农极限点
capacity1.m匹配滤波后的容量点部分高斯近似下的可达速率
capacity2.m含残余串扰的最终容量修正后的容量曲线

capacity0.m通常只算一个理论基线,即相同带宽和 SNR 下奈奎斯特传输的香农容量。capacity1.m开始把 FTN 发射端引入,但假设接收端匹配滤波器能完全对齐,只计算理想同步下的容量上界。capacity2.m则把 ISI 当作噪声功率的一部分计入 SINR,得到更接近实际接收机的容量值。我跑这类脚本的习惯是先用capacity0.m确认信道模型与 SNR 的定义理顺了,再逐步打开 FTN 开关。

3.2 完整脚本骨架:从脉冲生成到容量点估计

下面这个脚本整合了capacity2.m的核心计算流程,把 FTN 容量点的估计拆成发送、加噪、匹配滤波、采样、ISI 功率估计和容量计算六步:

% ftn_capacity_point.m % FTN 容量点估计主流程 alpha = 0.8; beta = [0.2 0.5]; % 接收端滚降参数,按压缩包原始参数保持 T = 0.5; % FTN 符号间隔 sps = 32; % 每符号采样点数 L = 100; % 滤波器单边抽头数 order = 1e6; % 仿真符号数 snr_dB = 10; % 1) 根升余弦成形滤波器 h = rrc_design(alpha, L, sps); h = h / sqrt(sum(h.^2)); % 能量归一化,保证滤波器增益为 1 % 2) 发射端:BPSK 符号上采样后经过成型滤波器 sym = 2 * randi([0 1], order, 1) - 1; x = upsample(sym, sps); x = conv(x, h, 'same'); % 3) 加噪 Pn = 10^(-snr_dB/10); r = x + sqrt(Pn) * randn(size(x)); % 4) 接收端匹配滤波 + 按 T 间隔采样 z = conv(r, h(end:-1:1), 'same'); y = z(L*sps + 1 : sps : end); % 丢弃边界抽头,避免截断效应 y = y(1:order); % 5) 无噪声通道下估计 ISI 功率 z0 = conv(x, h(end:-1:1), 'same'); y0 = z0(L*sps + 1 : sps : end); y0 = y0(1:order); isi_pow = var(y0 - sym); % 理想符号与实际采样值之差的方差 % 6) 容量点估计(高斯干扰近似) SINR = 1 / (Pn + isi_pow); % 信号功率归一化为 1 C = 0.5 * log2(1 + SINR); fprintf('SNR = %.1f dB, SINR = %.2f dB, C = %.4f bit/symbol\n', ... snr_dB, 10*log10(SINR), C);

逻辑说明如下。第一步的rrc_design负责生成根升余弦时域脉冲,能量归一化很关键,否则后面信号功率不是 1,SINR 会带一个固定偏差。第二步用upsample把符号映射到采样域,再和滤波器卷积,模拟发射端的成型过程。第三步加噪时,噪声功率Pn是按 SNR 反推的,这里隐含了信号功率为 1 的约定。第四步匹配滤波后从L*sps + 1开始采样,目的是跳过滤波器截断造成的无效边界区。第五步通过一次无噪声运行来估计 ISI 功率:无噪声时采样值和理想符号的偏差完全来自相邻符号串扰,这个方差的估计比从理论公式推导更贴近实际滤波器实现。第六步把 ISI 功率和噪声功率一起放到 SINR 的分母里,用0.5 * log2(1 + SINR)得到每符号容量。

需要说明的是,0.5 * log2(1 + SINR)是一个高斯干扰近似下的可达速率下界,不是 BPSK 在 AWGN 信道下的精确互信息。对工程仿真来说,它的价值在于能直观对比不同 FTN 参数组合下的容量变化趋势,且和误码率曲线有明确的对应关系。若要更精确的值,需要用数值积分计算I(s; y) = 1 - E[log2(1 + exp(-2y/σ^2))],但那个计算量在order = 1E6下会显著变慢。

3.3 结果怎么读:alpha=0.8 与 beta 组合下的容量曲线

压缩包里alpha = 0.8, beta = [0.2 0.5], T = 0.5.fig(2).fig两个图,我判断是通过get_figdata.m从仿真结果里提取数据后绘制的容量曲线。读图时先看容量曲线在 SNR 轴上的起点,再看它和香农极限曲线的间距。间距小于 0.1 bit 说明 FTN 的串扰代价很小;间距大于 0.3 bit 就要检查是不是接收窗参数beta取得太小,把信号边带削掉了。alpha = 0.8时频谱占用宽,beta = 0.2意味着接收端只保留中心区域频谱,这种组合下容量曲线会明显低于beta = 0.5

另一个值得关注的细节是fm_alpha_08.fig里的眼图或散点图。FTN 的眼图在采样点处不会像奈奎斯特传输那样收成一个点,而是有一条很宽的“眼皮”。这条眼皮的厚度大致对应 ISI 功率的均方根,可以直接和isi_pow的估计值互相印证。如果眼图眼皮厚度远大于仿真估计的sqrt(isi_pow),优先怀疑同步偏移或采样时刻没对准。

4. 复现过程中最容易翻车的五个参数边界

4.1 过采样率不足导致的奈奎斯特混叠

FTN 仿真的一个典型误区是沿用普通 QAM 仿真的sps = 8sps = 16。当alpha = 0.8时,RRC 滤波器的频谱在(1+alpha)/(2T)处仍有能量,而采样率fs = sps / T必须大于两倍信号最高频率,否则频谱会折叠回基带,等效于额外注入了一部分噪声。判断方法是画出滤波器的幅频响应,在fs/2处能量应该低于 -60 dB:

% check_sps.m alpha = 0.8; L = 100; T = 0.5; for sps = [8 16 32] h = rrc_design(alpha, L, sps); [H, f] = freqz(h, 1, 4096, sps/T); idx = find(f <= (1+alpha)/(2*T), 1, 'last'); edge_db = 20*log10(abs(H(idx)) + eps); fprintf('sps=%2d, 频谱边缘能量 %.1f dB\n', sps, edge_db); end

sps=8时频谱边缘能量往往只能到 -20 dB 左右,折合到功率就是 1% 的混叠失真,对容量估计的影响在alpha=0.8这种宽谱场景下会被明显放大。我一般把sps=32作为 FTN 仿真的默认值,sps=64也不过分,只是内存和仿真时间会成倍增加。

4.2 滤波器截断 L=100 与首尾符号剔除

L=100在 1E6 个符号的场景下看起来足够,但要注意conv的边界处理。使用'same'选项时,卷积输出和输入等长,但两端的L*sps个采样点实际上是滤波器未完全覆盖的边界区,数据不可信。如果直接把这部分采样纳入容量估计,ISI 功率会被严重高估,因为边界处的脉冲拖尾是残缺的。正确做法是从L*sps + 1开始抽样,并丢弃末尾同样长度的点。如果仿真符号数较少,比如order = 1E4,边界占比达到 2%,这时需要把order增大或在结果里标注这部分损失。

4.3 蒙特卡洛阶数与容量估计的置信区间

order = 1E6的容量点估计并非没有抖动。isi_pow = var(y0 - sym)里用的是样本方差,在 1E6 个符号下,方差估计的相对波动大约在1/sqrt(order)量级,也就是 0.1% 左右。但容量估计对 SINR 误差的敏感度取决于工作点:SNR 较高时,SINR 的微小波动会被log2放大。实践中,如果对比两个beta值下的容量差异小于 0.005 bit/symbol,需要先用rng(固定种子)把噪声流固定下来再比较,否则分不清差异来自参数还是随机波动。

4.4 alpha 与 beta 反向搭配导致的容量塌陷

压缩包的参数alpha = 0.8, beta = 0.2是一个很特别的组合。alpha = 0.8意味着成型脉冲的频谱延伸到1.8/(2T)的位置,而beta = 0.2若代表接收端频域窗的过渡带占比,则接收窗的有效带宽只有约1.2/(2T)。此时信号边带能量被接收窗大量抑制,等效于主动引入了约10*log10(1.8/1.2) ≈ 1.8 dB的信噪比损失。这个坑的特点是:误码率曲线看起来还行,但容量曲线明显低于理论值。排查方法是固定alpha,把beta从 0.2 扫到 0.8,观察容量曲线是否有一个明显的拐点,拐点位置通常在beta ≈ alpha附近。

4.5 窗函数选择对远端串扰估计的影响

win_recwin_hamming两个.mat文件的存在说明作者比较了矩形窗和汉明窗截断滤波器的影响。矩形窗的频谱旁瓣只以1/f衰减,远端串扰能量不可忽略;汉明窗旁瓣衰减快,但主瓣宽,会让脉冲的有效时域长度变长。在 FTN 场景下,这直接影响isi_pow的估计值。我建议仿真的两种窗都跑一遍:如果两种窗下的容量差异超过 0.02 bit/symbol,说明滤波器截断长度不够,需要同时增大L而不是纠结哪个窗更优。

5. 用 PSD 积分和 fig 数据反查验证容量损失

5.1 用 calcRcPSD.m 的思路复核能量守恒

压缩包里的calcRcPSD.m是计算升余弦脉冲功率谱密度的工具。FTN 仿真里它有一个容易被忽略的用途:验证滤波器实现是否损失了能量。对一个实现正确的 RC 脉冲,其 PSD 在带内的积分应该等于时域能量。如果积分结果明显小于 1(比如 0.95),说明滤波器的频域采样点不够密或截断窗把一部分边带切掉了:

% rc_psd_integral.m alpha = 0.3; T = 0.5; N = 4096; fs = 64/T; f = linspace(-fs/2, fs/2, N); G = zeros(size(f)); inband = abs(f) <= (1-alpha) / (2*T); edge = abs(f) > (1-alpha)/(2*T) & abs(f) <= (1+alpha)/(2*T); G(inband) = T; G(edge) = T/2 * (1 + cos(pi*T/alpha * ... (abs(f(edge)) - (1-alpha)/(2*T)))); energy = sum(G) * (fs/N); fprintf('RC 脉冲带内能量占比: %.4f\n', energy / T);

这段代码用解析表达式直接生成升余弦 PSD 并做数值积分。如果输出接近 1,说明滤波器实现没有额外损耗;如果偏差超过 1%,需要回到rrc_design检查时域采样点数是否足够。这个检查对win_recwin_hamming两个版本分别做一遍,就能解释为什么压缩包里两个.mat文件的容量结果会存在差异。

5.2 用 get_figdata.m 的思路把 fig 变成可对比的数据

作者留下的.fig文件是判断仿真环境的参照物。用get_figdata.m相同的思路,可以把fm_alpha_08.fig里的曲线数据导出,和本地重算的结果做数值对比:

% extract_fig_curve.m fig = openfig('fm_alpha_08.fig', 'invisible'); ax = findobj(fig, 'Type', 'axes'); ln = findobj(ax(1), 'Type', 'line'); snr_orig = get(ln(1), 'XData'); cap_orig = get(ln(1), 'YData'); close(fig); % 固定随机种子重算同一组参数 rng(42); cap_local = zeros(size(snr_orig)); for k = 1:length(snr_orig) cap_local(k) = ftn_capacity_point(snr_orig(k)); end max_diff = max(abs(cap_orig - cap_local)); fprintf('和原 fig 曲线最大偏差: %.4f bit/symbol\n', max_diff);

openfig'invisible'参数让 MATLAB 在后台打开图形而不弹窗,适合批量处理。提取出Line对象的坐标后,就能把作者当时的仿真结果当成基准。最大偏差在 0.01 以内说明仿真环境和原脚本基本一致;偏差较大时优先检查Pn的 SNR 定义是否一致——有的脚本把 SNR 定义为每比特能量Eb/N0,有的是每符号能量Es/N0,两者相差log2(M)倍,这个是最常见的系统性偏差来源。最后跑仿真时把随机种子固定在rng(42),不同平台间的randn序列可能有细微差异,对曲线抖动的影响远小于beta参数变化产生的容量差,这样对比出来的结论才站得住。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询