电力线载波通信(PLC)OFDM调制解调 — 可视化完整实现
一、系统总框图
比特源 ──→ 星座映射(QPSK/QAM) ──→ 子载波分配
↓
IFFT(N点) ──→ 加CP ──→ **电力线信道**
↑ ↓
接收端:去CP → FFT → 均衡 → 解调 → 判决策 → BER
二、参数与电力线信道模型(最关键的部分)
2.1 主脚本(plc_ofdm_main.m)
%% 电力线载波通信 PLC-OFDM 调制解调可视化
clear; clc; close all;
fprintf('=== PLC-OFDM 调制解调仿真 ===\n');
%% ========== 1. OFDM 参数 ==========
Nfft = 64; % FFT点数
Ncp = 16; % 循环前缀长度
Ndata = 52; % 数据子载波数(其余导频/空)
Nsym = 10; % OFDM符号数
M = 4; % 调制阶数:4=QPSK, 16=16QAM
mod_name= 'QPSK'; % 显示用
Fs = 10e6; % 采样率(标称)
Ts = 1/Fs;
% 子载波索引分配
all_idx = (1:Nfft).';
data_idx = (2:2+Ndata-1).'; % 数据子载波
pilot_idx= [1, Nfft/2+1].'; % 导频位置(简化)
null_idx = setdiff(1:Nfft, [data_idx; pilot_idx]);
fprintf('OFDM参数: Nfft=%d, CP=%d, 数据子载波=%d, 符号数=%d, 调制=%s\n', ...
Nfft,Ncp,Ndata,Nsym,mod_name);
%% ========== 2. 生成比特流 ==========
Nbits_per_sym = Ndata * log2(M);
total_bits = Nbits_per_sym * Nsym;
bits = randi([0 1], total_bits, 1);
%% ========== 3. 星座映射 ==========
symbols = qammod(bits, M, ...
InputType='bit', UnitAveragePower=true);
% 重塑为每符号一行
sym_mat = reshape(symbols, Ndata, Nsym);
%% ========== 4. 组装OFDM符号(插子载波) ==========
X = zeros(Nfft, Nsym); % 频域
X(data_idx,:) = sym_mat; % 数据
X(pilot_idx,:) = ones(length(pilot_idx), Nsym); % 导频=1(可改成PN)
%% ========== 5. IFFT + 加CP ==========
tx_no_cp = zeros(Nfft + Ncp, Nsym);
tx = zeros(Nfft + Ncp, Nsym);
for k = 1:Nsym
x_time = ifft(ifftshift(X(:,k)), Nfft);
tx(1:Ncp,k) = x_time(end-Ncp+1:end); % CP
tx(Ncp+1:end,k)= x_time;
tx_no_cp(1:Nfft,k)=x_time;
end
tx_wave = tx(:); % 发射波形(一维)
%% ========== 6. 电力线信道模型 ==========
fprintf('生成电力线信道冲激响应(多径+频率选择性)...\n');
h_plc = plc_channel_model(Nfft, Fs);
% 线性卷积信道
chan = dsp.FIRFilter('Numerator', h_plc);
rx_wave = chan(tx_wave);
% 加电力线噪声(背景AWGN + 窄带干扰)
SNRdB = 18;
rx_wave = awgn_noise(rx_wave, SNRdB);
% 可选:加脉冲噪声(开关)
add_impulse = false;
if add_impulse
rx_wave = rx_wave + 0.8*(rand(size(rx_wave))<1e-3).*sign(randn(size(rx_wave)));
end
%% ========== 7. 接收端:去CP → FFT → 信道估计 → 均衡 ==========
fprintf('接收端处理:去CP → FFT → MMSE均衡...\n');
rx_mat = reshape(rx_wave, Nfft+Ncp, Nsym);
Y = zeros(Nfft, Nsym);
for k = 1:Nsym
y_cp_removed = rx_mat(Ncp+1:end, k);
Y(:,k) = fftshift(fft(y_cp_removed, Nfft));
end
% --- 信道估计(导频辅助,最小二乘)---
H_hat = zeros(Nfft, Nsym);
for k = 1:Nsym
H_hat(pilot_idx,k) = Y(pilot_idx,k) ./ X(pilot_idx,k);
% 相邻子载波线性内插填其它位置(简化)
H_hat(:,k) = interp1(pilot_idx, H_hat(pilot_idx,k), ...
(1:Nfft)', 'linear', 'extrap');
end
% --- MMSE均衡 ---
rx_eq = zeros(Ndata, Nsym);
for k = 1:Nsym
Hd = H_hat(data_idx,k);
noise_var = 10^(-SNRdB/10) * mean(abs(Y(data_idx,k)).^2);
% MMSE: W = conj(H) / (|H|^2 + σ²)
W_mmse = conj(Hd) ./ (abs(Hd).^2 + noise_var);
rx_eq(:,k) = Y(data_idx,k) .* W_mmse;
end
%% ========== 8. 解调 + BER ==========
rx_symbols = rx_eq(:);
rx_bits = qamdemod(rx_symbols, M, InputType='bit', UnitAveragePower=true);
[num_err, ber] = biterr(bits, rx_bits);
fprintf('BER = %d/%d = %.4e\n', num_err, length(bits), ber);
%% ========== 9. 可视化 ==========
plot_plc_ofdm_results( ...
tx_no_cp, rx_mat, tx_wave, rx_wave, ...
h_plc, H_hat, X, Y, rx_eq, symbols, rx_symbols, ...
Nfft, Ncp, data_idx, pilot_idx, Nsym);
fprintf('完成!\n');
三、电力线信道模型
3.1 多径+衰减模型(含典型PLC频响)
function h = plc_channel_model(Nfft, Fs)
% PLC信道模型(底层配电线简化多径)
% 冲激响应:h[n] = Σ α_k δ[n-τ_k]
% 参考:G. Zimmermann et al., "A Multipath Model for the Power-line Channel"
% 路径参数:衰减 α(dB) 与延迟 τ(μs)
paths = [ ...
1.00, 0.00; ... % 直射路径
0.45, 1.50; ... % 反射1
0.28, 3.80; ... % 反射2
0.16, 7.20; ... % 反射3
0.09, 12.0; ... % 反射4
];
% 转换为线性冲激响应
tap_gain = paths(:,1) .* db2mag(-[0;0;0;0;0]); % 这里直接用幅度比
tap_delay_samples = round(paths(:,2)*1e-6 / (1/Fs));
max_tap = max(tap_delay_samples);
h_len = max_tap + 1;
h = zeros(h_len,1);
for k = 1:size(paths,1)
gain = paths(k,1); % α_k(线性)
d = tap_delay_samples(k);
h(d+1) = h(d+1) + gain;
end
% 归一化(可选保持能量)
h = h / norm(h);
% 画信道冲激/频响
freq_resp = fft(h, Nfft);
f_MHz = (0:Nfft-1)*Fs/1e6/Nfft;
figure('Name','PLC信道','Position',[200 200 900 280]);
subplot(1,2,1); stem(0:length(h)-1, abs(h),'filled');
xlabel('样点'); ylabel('|h[n]|'); title('PLC信道冲激响应'); grid on;
subplot(1,2,2); plot(f_MHz, mag2db(abs(freq_resp)), 'b-','LineWidth',1.5);
xlabel('频率 (MHz)'); ylabel('增益 (dB)'); title('PLC信道频响 |H(f)|'); grid on;
xlim([0 Fs/2/1e6]);
end
3.2 AWGN噪声注入
function y = awgn_noise(x, snr_db)
sig_power = mean(abs(x).^2);
noise_power = sig_power / (10^(snr_db/10));
noise = sqrt(noise_power/2)*(randn(size(x)) + 1j*randn(size(x)));
y = x + real(noise); % 这里用实发射,你也可改成复基带(更标准)
end
四、可视化函数
4.1 plot_plc_ofdm_results.m
function plot_plc_ofdm_results(...
tx_no_cp, rx_mat, tx_wave, rx_wave,...
h_plc, H_hat, X, Y, rx_eq, sym_tx, sym_rx,...
Nfft, Ncp, data_idx, pilot_idx, Nsym)
figure('Name','PLC-OFDM 可视化','Position',[100 80 1400 860]);
sgtitle('电力线载波 OFDM 调制解调可视化','FontSize',14,'FontWeight','bold');
% 1) 发射时域波形(一个符号)
subplot(3,4,1);
plot(real(tx_no_cp(:,1)),'b','LineWidth',1.2);
xlabel('样点'); ylabel('Re\{x[n]\}'); title('发射时域(一个OFDM符号,无CP)'); grid on;
% 2) 频域幅度谱(TX)
subplot(3,4,2);
bar((1:Nfft)-Nfft/2, abs(fftshift(X(:,1))),'blue');
xlabel('子载波索引'); ylabel('|X[k]|'); title('发射频域符号(子载波谱)'); grid on;
% 3) CP添加示意
subplot(3,4,3);
stem(1:Nfft+Ncp, tx_wave(1:Nfft+Ncp),'filled','MarkerSize',3);
xlabel('样点'); ylabel('x'); title('加循环前缀 CP区'); grid on;
% 4) 接收时域波形
subplot(3,4,4);
plot(real(rx_wave(1:min(300,length(rx_wave)))),'r','LineWidth',1.1);
xlabel('样点'); ylabel('y'); title('接收时域(带信道畸变)'); grid on;
% 5) 信道频响(幅频)
H_avg = mean(abs(H_hat),2);
subplot(3,4,5);
plot((1:Nfft)-Nfft/2, mag2db(max(eps,fftshift(H_avg))),'b-','LineWidth',1.5);
xlabel('子载波索引'); ylabel('|H| (dB)'); title('估计信道频响(平均)'); grid on;
% 6) 均衡前 vs 均衡后星座
subplot(3,4,6);
plot(real(sym_tx),imag(sym_tx),'bo','MarkerSize',5,'MarkerFaceColor','b'); hold on;
plot(real(rx_eq(:)),imag(rx_eq(:)),'r.','MarkerSize',6);
xlabel('I'); ylabel('Q'); title('均衡前(蓝○) vs 均衡后(红·)');
axis equal; grid on; legend('Tx','Rx(均衡后)');
% 7) 子载波SNR分布
snr_per_sc = abs(H_avg(data_idx)).^2 ./ (0.01 + (1-abs(H_avg(data_idx)).^2));
subplot(3,4,7);
plot(data_idx, 10*log10(max(eps,snr_per_sc)),'g-','LineWidth',1.5);
xlabel('子载波'); ylabel('SNR估计 (dB)'); title('子载波SNR分布'); grid on;
% 8) 眼-like:实部采样点(去CP后)
subplot(3,4,8);
y_cp = rx_mat(Ncp+1:end,1);
plot(real(y_cp(1:min(200,Nfft))),'k.','MarkerSize',6);
xlabel('样点'); ylabel('Re\{y\}'); title('去CP后波形(实部)'); grid on;
% 9) 发射 vs 接收频谱对比
subplot(3,4,[9 10]);
Nfft_show = Nfft;
Xf = fftshift(fft(tx_no_cp(:,1), Nfft_show));
Yf = fftshift(fft(rx_mat(Ncp+1:end,1), Nfft_show));
fidx = (-Nfft_show/2:Nfft_show/2-1)/Nfft_show;
plot(fidx, mag2db(abs(Xf)),'b','LineWidth',1.2); hold on;
plot(fidx, mag2db(abs(Yf)),'r','LineWidth',1.1);
xlabel('归一化频率'); ylabel('幅度(dB)'); title('TX频谱 vs RX频谱'); grid on;
legend('TX','RX(畸变)'); xlim([-0.5 0.5]);
% 10) 误码率 vs SNR扫(快速版本)
subplot(3,4,[11 12]);
snr_range = 6:4:26;
ber_scan = nan(size(snr_range));
fprintf(' 快速BER扫描:');
for si=1:length(snr_range)
y_tmp = awgn_noise(tx_wave, snr_range(si));
% 简化:只看硬判决(跳过均衡细节,这里用等增益合并估BER量级)
y_mat2 = reshape(y_tmp,Nfft+Ncp,Nsym);
Y2 = zeros(Nfft,Nsym);
for k=1:Nsym
y2n = y_mat2(Ncp+1:end,k);
Y2(:,k)=fftshift(fft(y2n,Nfft));
end
Hd2 = mean(H_hat(data_idx,:),2);
rx2_eq = Y2(data_idx,:)./max(eps,Hd2);
rx2_sym = rx2_eq(:);
rx2_bits= qamdemod(rx2_sym,M,InputType='bit',UnitAveragePower=true);
ber_scan(si)=biterr(bits,rx2_bits)/length(bits);
fprintf('.');
end
fprintf('\n');
semilogy(snr_range, ber_scan,'ko-','LineWidth',1.5,'MarkerFaceColor','k');
xlabel('SNR (dB)'); ylabel('BER'); title('BER vs SNR'); grid on;
end
参考代码 电力线载波通讯OFDM调制解调可视化实现 www.youwenfan.com/contentcnv/80881.html
五、运行效果
| 图 | 含义 |
|---|---|
| 冲激响应 | PLC的典型多径结构(几个离散回波) |
| 信道频响 | 频率选择性衰落:某些子载波深衰(PLC典型) |
| 时域波形 | 有CP保护,信道卷积混叠但仍可恢复 |
| 星座图 | 均衡前发散 → 均衡后聚拢(QPSK四象限清晰) |
| BER曲线 | 随SNR下降,验证系统可达性 |