第【18】期--基于深度学习的信道估计优化及在OFDM系统中的应用-python完整代码+参考文献
摘要
在无线通信系统中,信道估计的准确性直接影响接收机的均衡、解调和译码性能。经典的最小二乘(LS)信道估计算法虽然实现简单,但在低信噪比环境下会受到严重的噪声放大影响,性能较差。最小均方误差(MMSE)估计器通过利用信道和噪声的二阶统计信息,可以获得比LS更优的性能,但其计算复杂度过高,且需要准确的统计先验,实际应用受限。本文提出了一种基于深度神经网络的信道估计增强方法,核心思想是学习并纠正LS估计的误差,仿真体现了算法的有效性。
1 基础回顾
- 在无线通信系统中,接收端必须知道信道状态信息(CSI),才能正确解调信号、均衡衰落、解码数据。无论是物理层安全、室内定位,还是OFDM系统的均衡与解调,都依赖于准确的信道估计。然而,无线信道受到多径衰落、噪声、硬件损伤等多种因素的影响,使得信道估计成为一个极具挑战的问题。
考虑一般的接收信号模型

其中 y为接收信号向量, h为信道向量, X发送信号矩阵(通常为导频矩阵), z为噪声向量。
1.1 最小二乘(LS)估计

1.2 MMSE估计
MMSE算法的核心目标是,寻找一个线性滤波矩阵 C,使得信道可以由接收信号进行表征 h^=Cy。 为了找到这个最优的用于表征信道的矩阵,我们的手段是,最小化该表征信道和真实信道之间的误差(代价函数):

- 从理论可以看出,LS算法实现简单,不需要任何信道统计先验信息,仅通过接收信号除以前导序列即可完成估计,但对噪声非常敏感,在低信噪比下误差较大;而MMSE估计算法利用了信道的自相关特性和信噪比信息,涉及矩阵求逆计算复杂度较高且需要预先估计信道统计量,在各种信噪比条件下均能获得比LS更低的估计误差,尤其在中高信噪比时优势更加明显,
1.3 完整maltalb代码实现
以下代码实现了一个OFDM信道估计的仿真系统,主要功能是不同环境下的多径衰落信道,发送带循环前缀的OFDM前导序列,在接收端分别采用最小二乘法和最小均方误差法对信道频率响应进行估计,通过对比理论值与多次蒙特卡洛仿真的归一化均方误差,评估不同信噪比下两种估计算法的性能。
%文件主函数 直接运行
clc;clearvars;close all;
ch_func = Channel_functions();
est_func = Estimation_functions();
%% 仿真参数
ChType = 'RTV'; % 信道模型
fs = 64*156250; % 采样频率(Hz),此处为802.11p情况,64个子载波,子载波间隔156250 Hz
fc = 5.2e9; % 载波频率(Hz)
v = 0; % 用户移动速度(km/h)
c = 3e8; % 光速(m/s)
fD = (v/3.6)/c*fc; % 多普勒频移(Hz)
rchan = ch_func.GenFadingChannel(ChType, fD, fs); % 生成信道
K = 64; % 子载波数量
K_cp = K/4; % 循环前缀子载波数量
% 频域预定义前导序列
dp = [ 0 0 0 0 0 0 +1 +1 -1 -1 +1 +1 -1 +1 -1 +1 +1 +1 +1 +1 +1 -1 -1 +1 +1 -1 +1 -1 +1 +1 +1 +1 0 +1 -1 -1 +1 +1 -1 +1 -1 +1 -1 -1 -1 -1 -1 +1 +1 -1 -1 +1 -1 +1 -1 +1 +1 +1 +1 0 0 0 0 0];
Kset = find(dp~=0); % 活跃子载波
Kon = length(Kset); % 活跃子载波数量
Ep = 1; % 前导序列功率
dp = sqrt(Ep)*dp.'; % 归一化
xp = ifft(dp); % 频域-时域转换
xp_cp = [xp(end-K_cp+1:end); xp]; % 添加循环前缀
SNR_p = (0:5:30)'; % 信噪比范围
N_SNR = length(SNR_p); % 信噪比点数
N0 = Ep/K*10.^(-SNR_p/10); % 噪声功率:snr_p = Ep/KN0 => N0 = Ep/(K*snr_p)
N_CH = 1000; % 信道实现次数
Err_Ls = zeros(N_SNR,1); % LS归一化均方误差向量
Err_MMSE = zeros(N_SNR,1); % MMSE归一化均方误差向量
Phf = zeros(N_SNR,1); % 平均信道功率 E(|hf|^2)
%% Rh估计
release(rchan);
init_seed = 22;
rchan.Seed = init_seed;
Rh = est_func.Estimat_Rh(rchan, K_cp, K, Kset);
release(rchan);
rchan.Seed = init_seed;
%% 主仿真循环
for n_snr = 1:N_SNR
disp(['正在运行仿真,SNR = ', num2str(SNR_p(n_snr))]);
tic;
Hfe_LS = zeros(Kon, N_CH);
Hfe_MMSE = zeros(Kon, N_CH);
Hf = zeros(Kon, N_CH);
% MMSE滤波器随信噪比变化
W = est_func.MMSE_matrix (dp(Kset), Rh, Ep/N0(n_snr)/K);
for n_ch = 1:N_CH % 遍历信道实现
% 理想估计
[ h, y ] = ch_func.ApplyChannel( rchan, xp_cp, K_cp);
release(rchan);
rchan.Seed = rchan.Seed+1;
yp = y((K_cp+1):end);
h = h((K_cp+1):end);
yfp = fft(yp); % 频域前导序列
hf = fft(h); % 频域信道
Phf(n_snr) = Phf(n_snr) + norm(hf(Kset))^2;
% 添加噪声
yfp_r = yfp+ sqrt(K*N0(n_snr))*ch_func.GenRandomNoise([1,1], 1);
% LS估计
[hfe_ls, err_ls] = est_func.LS(yfp_r(Kset), dp(Kset), hf(Kset));
Err_Ls (n_snr) = Err_Ls (n_snr) + err_ls;
% MMSE估计
[hfe_mmse, err_mmse] = est_func.MMSE(yfp_r(Kset), W, hf(Kset));
Err_MMSE (n_snr) = Err_MMSE (n_snr) + err_mmse;
% 保存信道供后续使用
Hf(:,n_ch) = hf(Kset);
Hfe_LS(:,n_ch) = hfe_ls;
Hfe_MMSE(:,n_ch) = hfe_mmse;
end
% 保存 Hf, Hfe_LS
save(['./Dataset_' num2str(n_snr)], 'Hf', 'Hfe_LS');
toc;
end
%% 对信道实现取平均
Phf = Phf/N_CH;
Err_Ls = Err_Ls/N_CH;
Err_MMSE = Err_MMSE/N_CH;
%% 理论LS归一化均方误差计算
Err_Ls_th = Kon*K*N0/Ep;
%% 理论MMSE归一化均方误差计算
release(rchan);
init_seed = 22;
rchan.Seed = init_seed;
Rh = est_func.Estimat_Rh(rchan, K_cp, K, Kset);
release(rchan);
rchan.Seed = init_seed;
Sig = real(eig(Rh));
Err_MMSE_th = zeros(N_SNR,1);
for n_snr = 1:N_SNR
Err_MMSE_th(n_snr) = Err_MMSE_th(n_snr) + sum(Sig./(Sig+K*N0(n_snr)./Ep));
end
Err_MMSE_th = K*N0/Ep .* Err_MMSE_th;
%% 通过信道功率归一化
Err_LSth = Err_Ls_th./Phf;
Err_LSsim = Err_Ls./Phf;
Err_MMSEth = Err_MMSE_th./Phf;
Err_MMSEsim = Err_MMSE./Phf;
%% 绘制归一化均方误差结果图
figure,
semilogy(SNR_p, Err_LSth ,'r--','LineWidth',2);
hold on;
semilogy(SNR_p,Err_LSsim,'r*','LineWidth',2);
hold on;
semilogy(SNR_p,Err_MMSEth,'b--','LineWidth',2);
hold on;
semilogy(SNR_p,Err_MMSEsim,'bo','LineWidth',2);
hold on;
grid on;
legend('LS 理论', 'LS仿真', 'MMSE 理论', 'MMSE 仿真')
xlabel('SNR')
ylabel('子载波平均BER')
save('ErrSet.mat','Err_LSth','Err_LSsim', 'Err_MMSEth', 'Err_MMSEsim')
%%调用函数 命名为Estimation_functions.m
function func = Estimation_functions()
func.LS = @LS;
func.MMSE = @MMSE;
func.MMSE_matrix = @MMSE_matrix;
func.Estimat_Rh = @Estimat_Rh;
end
% LS估计
function [he, err] = LS(yp, xp, h)
he = yp./xp; % LS估计的信道频率响应
err = norm(he-h)^2; % 估计误差的平方范数
end
function [he, err] = MMSE(yp, W, h)
% W 根据前导序列生成的MMSE滤波器
he = W*yp; % MMSE估计的信道频率响应
err = norm(he-h)^2; % 估计误差的平方范数
% 修正偏差(此处未实现)
end
function W = MMSE_matrix(xp, Rh, SNR)
K = size(Rh,1);
% 执行 A*diag(xb)^{-1} 运算
Lamp_p_inv = repmat(1./xp', K,1);
W = (Rh/(Rh + 1/SNR * eye(K))) .* Lamp_p_inv; % MMSE滤波器矩阵
end
function Rh = Estimat_Rh(rchan, K_cp, K, Kset)
% Kset 活跃子载波索引
Kon = length(Kset);
Rh = zeros(Kon, Kon); % 初始化信道自相关矩阵
NR_CH = 1000; % 用于估计的信道实现次数
% 虚拟信号
xp_cp = rand(K_cp+K, 1);
for n_ch = 1:NR_CH % 遍历信道实现
% 理想信道估计
ch_func = Channel_functions();
[ h, ~ ] = ch_func.ApplyChannel(rchan, xp_cp, K_cp);
release(rchan);
rchan.Seed = rchan.Seed + 1;
h = h((K_cp+1):end); % 去除循环前缀
hf = fft(h); % 频域信道响应
Rh = Rh + hf(Kset) * hf(Kset)'; % 累加自相关
end
Rh = Rh / NR_CH; % 取平均得到估计的信道自相关矩阵
end
///////
%% 调用函数 文件命名为Channel_functions.m
function func = Channel_functions()
%% --------------- 成员变量 --------------------------------------
% 可用于存储变量,例如常量。
%% --------------- 成员函数声明 ----------------------------------
% 函数引用
%gain 功率分布, L 抽头数, NR 实现次数
%H = DummyChannel(gain, L, NR)
func.DummyChannel = @DummyChannel;
%v = GenRandomNoise(siz, 0)
func.GenRandomNoise = @GenRandomNoise;
% fs 采样频率
% fD 多普勒频率
%rchan = GenFadingChannel( ChType, fD, fs)
func.GenFadingChannel = @GenFadingChannel;
% He 去除循环前缀后的估计信道
%[ He, Y ] = ApplyChannel( rchan, X, Ncp)
func.ApplyChannel = @ApplyChannel;
func.ApplyChannel2 = @ApplyChannel2;
func.UpdateSeed = @UpdateSeed;
func.GetSeed = @GetSeed;
func.SetSeed = @SetSeed;
func.PreambleAutoCorrection = @PreambleAutoCorrection;
%% --------------- 包含库函数 ------------------------------------
% 调用其他结构
%% --------------- 实现部分 ----------------------------------------
% 函数实现
function H = DummyChannel(gain, NR)
L = numel(gain);
H = repmat(gain, 1, NR).*GenRandomNoise([L, NR], 1);
end
function v = GenRandomNoise(siz, N0)
v = sqrt(N0/2) * (randn(siz)+1j*randn(siz));
end
function s = UpdateSeed(rchan)
release(rchan);
rchan.Seed = rchan.Seed + 1;
s = rchan.Seed;
end
function ChannelSeed = GetSeed(rchan)
ChannelSeed = rchan.Seed;
end
function SetSeed(rchan,seed)
release(rchan);
rchan.Seed = seed;
end
function [ He, Y ] = ApplyChannel( rchan, X, Ncp)
[Ns, NB] = size(X);
D = zeros(Ns, NB);
D(Ncp+1, :) = 1;
He = zeros(size(D));
for nb = 1:NB
He(:, nb) = step(rchan, D(:, nb));
end
reset(rchan);
release(rchan); % ← 关键:允许改变输入数据特性
y = step(rchan, X(:));
Y = reshape(y, Ns, NB);
end
function [He, Hf_Preamble] = PreambleAutoCorrection(rchan,Ncp,Nsc,Ns)
release(rchan);
D = zeros(Nsc,Ns);
% 应用脉冲估计信道
D(Ncp+1,:) = 1;
He = zeros(size(D));
for nb=1:Ns
He(:,nb) = step(rchan, D(:,nb));
end
H = fft(He);
Hf_Preamble = H(:,1);
end
function [ He, Y,Y2 ] = ApplyChannel2( rchan, X,X2, Ncp)
release(rchan);
%rchan.Seed = rchan.Seed+1; % 改变实现
[Ns, NB] = size(X);
D = zeros(Ns,NB);
% 应用脉冲估计信道
D(Ncp+1,:) = 1;
He = zeros(size(D));
for nb=1:NB
He(:,nb) = step(rchan, D(:,nb));
end
% 将信道重置到与估计对应的初始状态
reset(rchan);
y = step(rchan, X(:));
Y = reshape(y,Ns, NB);
reset(rchan);
y2 = step(rchan, X2(:));
Y2 = reshape(y2,Ns, NB);
end
% ChType = EPA, EVA, TGn, FLAT
function rchan = GenFadingChannel( ChType, fD, fs)
%GENFADINGCHANNEL 此函数的作用
% 详细说明
switch ChType
case 'PedA'
PathDelays = 1e-9.*[0 110 190 410];
avgPathGains = [0 -9.7 -19.2 -22.8];
case 'PedB'
PathDelays = 1e-9.*[0 200 800 1200 2300 3700];
avgPathGains = [0 -0.9 -4.9 -8.0 -7.8 -23.9];
case 'VehA'
PathDelays = 1e-9.*[0 310 710 1090 1730 2510];
avgPathGains = [0 -1 -9 -10 -15 -20];
case 'EVA'
PathDelays = 1e-9.*[0 30 150 310 370 710 1090 1730 2510];
avgPathGains = [0 -1.5 -1.4 -3.6 -0.6 -9.1 -7.0 -12.0 -16.9];
case 'EPA'
PathDelays = 1e-9.*[0 30 70 90 110 190 410];
avgPathGains = [0 -1 -2 -3 -8 -17.2 -20.8];
case 'TU'
PathDelays = 1e-9.*[0 50 120 200 230 500 1600 2300 5000];
avgPathGains = [-1 -1 -1 0 0 0 -3 -5 -7];
case 'VehB'
PathDelays = 1e-9.*[0 300 8900 12900 17100 20000];
avgPathGains = [-2.5 0 -12.8 -10.0 -25.2 -16];
case 'HT'
PathDelays = 1e-9.*[0 356 441 528 546 609 625 842 916 941 15000 16172 16492 16876 16882 16978 17615 17827 17849 18016];
avgPathGains = [-3.6 -8.9 -10.2 -11.5 -11.8 -12.7 -13.0 -16.2 -17.3 -17.7 -17.6 -22.7 -24.1 -25.8 -25.8 -26.2 -29.0 -29.9 -30.0 -30.7];
case 'ETU'
PathDelays = 1e-9.*[0 217 512 514 517 674 882 1230 1287 1311 1349 1533 1535 1622 1818 1836 1884 1943 2048 2140];
avgPathGains = [-5.7 -7.6 -10.1 -10.2 -10.2 -11.5 -13.4 -16.3 -16.9 -17.1 -17.4 -19.0 -19.0 -19.8 -21.5 -21.6 -22.1 -22.6 -23.5 -24.30];
case 'RA'
PathDelays = 1e-9.*[0 42 101 129 149 245 312 410 469 528];
avgPathGains = [-5.2 -6.4 -8.4 -9.3 -10 -13.1 -15.3 -18.5 -20.4 -22.4];
case 'IOA'
PathDelays = 1e-9.*[0 50 110 170 290 310];
avgPathGains = [0 -3 -10 -18 -26 -32];
case 'IOB'
PathDelays = 1e-9.*[0 100 200 300 500 700];
avgPathGains = [0 -3.6 -7.2 -10.8 -18.0 -25.2];
%------- 车载通信中使用的信道模型 ----------------
case 'VTV'
PathDelays = 1e-9.*[0, 1, 2, 100, 101, 200, 201,202,300,301,302];
avgPathGains = [0,0,0,-6.3,-6.3,-25.1,-25.1, -25.1,-22.7,-22.7,-22.7];
case 'RTV'
PathDelays = 1e-9.*[0, 1, 2, 100, 101, 102, 200, 201, 300, 301, 400, 401];
avgPathGains = [0, 0, 0, -9.3, -9.3, -9.3, -20.3, -20.3, -21.3, -21.3, -28.8,-28.8];
case 'VTV-SDWW'
PathDelays = 1e-9.*[0, 1, 100, 101, 200, 300, 400, 401, 500, 600, 700, 701];
avgPathGains = [0, 0, -11.2,-11.2,-19,-21.9, -25.3, -25.3, -24.4, -28.0, -26.1,-26.1];
case 'RTV-UC'
PathDelays = 1e-9.*[0, 1, 2, 100, 101, 102, 200, 201, 300, 301, 500, 501];
avgPathGains = [0, 0, 0, -11.5, -11.5, -11.5, -19.0, -19.0, -25.6, -25.6, -28.1,-28.1];
case 'RTV-SUS'
PathDelays = 1e-9.*[0, 1, 100, 101, 200, 201, 300, 301, 400, 500, 600, 700];
avgPathGains = [0, 0, -9.3, -9.3, -14, -14, -18, -18, -19.4, -24.9, -27.5,-29.8];
case 'VTV-UC'
PathDelays = 1e-9.*[0, 1, 100, 101, 102, 200, 201, 202, 300, 301, 400, 401];
avgPathGains = [0, 0, -10, -10, -10, -17.8, -17.8, -17.8, -21.1, -21.1, -26.3,-26.3];
case 'HIPERLAN-E'
PathDelays = 1e-9.*[0, 10, 20, 40, 70, 100, 140, 190, 240, 320, 430, 560, 710, 880, 1070, 1280, 1510, 1760];
avgPathGains = [-4.9, -5.1, -5.2, -0.8, -1.3, -1.9, -0.3, -1.2, -2.1, 0.0, -1.9, -2.8, -5.4, -7.3, -10.6, -13.4,-17.4,-20.9];
otherwise
error('未知信道模型');
end
rchan = comm.RayleighChannel('SampleRate',fs, ...
'PathDelays',PathDelays, ...
'AveragePathGains',avgPathGains, ...
'MaximumDopplerShift',fD,...
'RandomStream','mt19937ar with seed', ...
'Seed',22);
end
%% --------------- 实现结束 ----------------------------------------
end

- 结果显示了,随着信噪比增加,LS和MMSE估计的归一化均方误差均呈下降趋势,但MMSE利用信道统计相关性有效抑制了噪声,其误差曲线在整个信噪比范围内均显著低于LS,且两条理论曲线分别与对应的仿真点高度吻合,验证了算法实现的正确性。
2 研究背景意义
- 在OFDM等现代无线通信系统中,接收端必须准确知道信道状态信息(CSI),才能完成信号均衡、解调、解码等操作。CSI的质量直接影响系统的误码率、吞吐量和覆盖范围。
- 传统的ls虽然简单但性能差,MMSE性能好但复杂且依赖先验信息
- 已有一些工作尝试将深度学习用于信道估计,但大多采用端到端黑盒方式(输入接收信号,直接输出信道估计或),存在可解释性差、训练复杂度高、泛化能力不稳定等问题。
本文提出,不把深度神经网络DNN当作一个完全的“黑盒估计器”,而是将其作为LS的辅助纠错模块。这样既能利用LS的简单性作为初始值,又能通过DNN学习到噪声和信道的高阶非线性关系,实现性能提升[1]。
3 深度学习算法设计
残差学习的核心洞察在于,LS 估计值已经捕捉到了信道的粗略结构;剩下的部分是一种结构化的噪声模式,而 DNN 可以通过学习将其减去,即

也就是说,DNN学习的是从带噪LS估计到真实信道的映射。相比于传统的DNN信道估计方法(DNN输入为发送信号,输出为信道轨迹)而言,是一个更平滑、方差更小的目标。网络的输出空间也从信道系数的完整动态范围收缩至估计误差的范围内——后者通常要小一个数量级,在中高 SNR 环境下尤为明显。
通俗地说,传统的dnn估计,是给你一张白纸,从头画整张脸;本文提出的方法,是给一张已经很像但有些噪点的草稿(LS 估计),只需要修掉瑕疵。
-
DNN的输入为LS的估计结果,为复数,代码实现时通将每个复数的实部和虚部分开,形成一个长度翻倍的向量输入
-
DNN的输出代表修正后信道的实部和虚部,实际使用时需要合并
-
损失函数和传统的DNN一致,为

其中,Z表示DNN 输出,即修正后信道的实虚部拼接;h_true表示真实信道的实虚部拼接。
| 层 | 结构 | 参数量 | 激活 |
|---|---|---|---|
| 输入 | (128,) |
— | — |
| 隐藏层 1 | Dense(256) |
128×256 + 256 = 33,024 | ReLU |
| 隐藏层 2 | Dense(256) |
256×256 + 256 = 65,792 | ReLU |
| 输出层 | Dense(128) |
256×128 + 128 = 32,896 | 无 |
参数量计算公式:
Dense(N)层的参数 =输入维度 × N + N(权重 + 偏置)
4 仿真结果
| 参数 | 默认值 |
|---|---|
子载波数 |
64 |
循环前缀长度 |
16 |
相邻导频子载波之间的间距 |
4 |
调制 |
QPSK |
导频 |
1.0 + 0.0j |
学习率 |
1e-3 |
batch_size |
64 |
epochs |
100 |
loss |
mse |
优化器 |
Adam |




可以看到:
- LS-DNN 架构均优于 传统的LS 和MMSE
- DNN 能够学习到比 MMSE(仅利用二阶统计)更高阶的信道统计特征,从而获得更低的 NMSE。
5 总结
本文利用全连接DNN学习从含噪LS估计到真实信道的非线性映射,所提方法在性能与复杂度之间取得了优越的平衡成功展示了深度学习在物理层信号处理中的一个典型应用——用小的线计算开销,显著提升经典算法的性能,为未来智能接收机的设计提供了有价值的参考。下一步可将所提思路扩展至高移动性场景,利用循环神经网络或Transformer等结构实现时变信道下的跟踪与估计。
- 源代码 出图所见即所得,代码获取方式见VX公众号
参考文献:
[1] Gizzini, Abdulkarim , et al. “Enhancing Least Square Channel Estimation Using Deep Learning.” #i{IEEE} (2020).
[2] https://zhuanlan.zhihu.com/p/358985352
更多推荐

所有评论(0)