麻烦大家帮我看看这个水声通信多径时变信道的单输入单输出和多输入多输出的仿真对不对
是不是在时变信道下单输入单输出的效果会比多输入多输出好
%% 在水声时变稀疏信道模型下运行压缩感知算法(修正版,与代码5图像一致)
clear; close all; clc;
rng(12345);
% 基本参数
fc = 10e3; % 载波频率 10kHz
B = 5e3; % 带宽 5kHz
fs = 2*B; % 采样率
Ts = 1/fs; % 采样间隔
T_total = 0.1; % 总仿真时间
t = 0:Ts:T_total-Ts;
Nt_time = length(t); % 时间点数
% 信道参数
Np = 15; % 总多径数
N_cluster = 3; % 簇的数量
paths_per_cluster = 5; % 每簇路径数
cluster_delay_centers = [0.02, 0.05, 0.1];
cluster_delay_spread = [0.005, 0.008, 0.01];
cluster_doppler_spread = [1, 2, 3];
% 压缩感知参数
N_siso = 128; % 信道长度
K_siso = 8; % 稀疏度
M_siso = 64; % 测量数
SNRdB_siso = 0:5:30;
numTrials = 50; % 试验次数
% MIMO参数
Nt = 4; % 发射天线
Nr = 16; % 接收天线
K_mimo = 2; % 活跃用户数
SNRdB_mimo = 0:5:30;
numSymbols = 500; % 符号数
% 算法参数
lambda_BP = 0.1; % 固定正则化参数(与代码5一致)
maxIter_BP = 200; % 减少迭代次数(与代码5一致)
tol_BP = 1e-4; % 收敛容差(与代码5一致)
maxIter_CoSaMP = 20;
maxIter_SAMP = 20;
%% 水声信道生成函数句柄
generate_channel = @(L) generate_underwater_channel_simplified(...
L, fs, N_cluster, paths_per_cluster, ...
cluster_delay_centers, cluster_delay_spread, cluster_doppler_spread);
%% 1. SISO水声信道估计(使用改进的BP-ISTA,但参数与代码5一致)
fprintf('=== SISO水声信道估计 ===\n');
A_siso = randn(M_siso, N_siso);
A_siso = A_siso ./ vecnorm(A_siso);
mse_OMP_siso = zeros(length(SNRdB_siso), 1);
mse_CoSaMP_siso = zeros(length(SNRdB_siso), 1);
mse_SAMP_siso = zeros(length(SNRdB_siso), 1);
mse_BP_siso = zeros(length(SNRdB_siso), 1);
for i = 1:length(SNRdB_siso)
snr = SNRdB_siso(i);
acc1 = 0; acc2 = 0; acc3 = 0; acc4 = 0;
for t = 1:numTrials
x0 = generate_channel(N_siso);
if length(x0) > N_siso
x0 = x0(1:N_siso);
elseif length(x0) < N_siso
x0 = [x0; zeros(N_siso - length(x0), 1)];
end
x0 = x0 / norm(x0);
y0 = A_siso * x0;
sigma2 = norm(y0)^2 / (M_siso * 10^(snr/10));
y = y0 + sqrt(sigma2) * (randn(M_siso, 1) + 1i*randn(M_siso, 1))/sqrt(2);
% 使用改进的BP-ISTA进行SISO估计,但参数与代码5一致
r1 = OMP_reconstruct(A_siso, y, K_siso);
r2 = CoSaMP_reconstruct(A_siso, y, K_siso, maxIter_CoSaMP);
r3 = SAMP_reconstruct(A_siso, y, K_siso, maxIter_SAMP);
r4 = BP_ISTA_improved(A_siso, y, lambda_BP, maxIter_BP, tol_BP);
acc1 = acc1 + mean(abs(r1 - x0).^2);
acc2 = acc2 + mean(abs(r2 - x0).^2);
acc3 = acc3 + mean(abs(r3 - x0).^2);
acc4 = acc4 + mean(abs(r4 - x0).^2);
if i == 1 && t == 1
x_imp = x0;
imp1 = r1; imp2 = r2; imp3 = r3; imp4 = r4;
end
end
mse_OMP_siso(i) = acc1 / numTrials;
mse_CoSaMP_siso(i) = acc2 / numTrials;
mse_SAMP_siso(i) = acc3 / numTrials;
mse_BP_siso(i) = acc4 / numTrials;
fprintf('SNR = %d dB: OMP=%.2e, CoSaMP=%.2e, SAMP=%.2e, BP=%.2e\n', ...
snr, mse_OMP_siso(i), mse_CoSaMP_siso(i), mse_SAMP_siso(i), mse_BP_siso(i));
end
%% 2. MIMO水声通信系统(使用固定正则化参数,与代码5一致)
fprintf('\n=== MIMO水声通信系统 ===\n');
BER = zeros(4, length(SNRdB_mimo));
MSE = zeros(4, length(SNRdB_mimo));
TIME = zeros(4, length(SNRdB_mimo));
failed_simulations = 0;
for i = 1:length(SNRdB_mimo)
snr = SNRdB_mimo(i);
sigma2 = 1 / 10^(snr/10); % 噪声方差
% 注意:此处不使用自适应lambda,固定为lambda_BP = 0.1,与代码5一致
lambda_fixed = lambda_BP; % 固定正则化参数
eb = zeros(4, 1);
acc = zeros(4, 1);
tt = zeros(4, 1);
valid_mc_count = 0;
% 统计变量
bp_zero_count = 0;
correct_support = zeros(4, 1);
for mc = 1:numSymbols
% 生成活跃用户和BPSK符号
sup = randperm(Nt, K_mimo);
bits = randi([0 1], K_mimo, 1);
s0 = zeros(Nt, 1);
s0(sup) = 2*bits - 1;
% 生成水声MIMO信道矩阵
H = zeros(Nr, Nt);
for tx = 1:Nt
for rx = 1:Nr
h_tr = generate_channel(32);
if length(h_tr) > 10
h_tr = h_tr(1:10);
end
if ~isempty(h_tr) && norm(h_tr) > 0
[~, max_idx] = max(abs(h_tr));
H(rx, tx) = h_tr(max_idx);
else
H(rx, tx) = (randn(1) + 1i*randn(1))/sqrt(2);
end
end
end
if any(isnan(H(:))) || any(isinf(H(:)))
failed_simulations = failed_simulations + 1;
continue;
end
H_norm = norm(H, 'fro');
if H_norm > 0
H = H / H_norm * sqrt(Nr * Nt);
end
% 接收信号
y = H * s0 + sqrt(sigma2/2) * (randn(Nr, 1) + 1i*randn(Nr, 1));
% 信道白化(增加正则化)
try
C = H * H' + 1e-3 * eye(Nr);
[V, D] = eig(C);
W = V * diag(1./sqrt(max(diag(D), 1e-6))) * V';
Hw = W * H;
yw = W * y;
catch
Hw = H;
yw = y;
end
% 压缩感知检测
t1 = tic; sh1 = OMP_reconstruct(Hw, yw, K_mimo); tt(1) = tt(1) + toc(t1);
t2 = tic; sh2 = CoSaMP_reconstruct(Hw, yw, K_mimo, maxIter_CoSaMP); tt(2) = tt(2) + toc(t2);
t3 = tic; sh3 = SAMP_reconstruct(Hw, yw, K_mimo, maxIter_SAMP); tt(3) = tt(3) + toc(t3);
t4 = tic;
try
% 使用固定lambda,迭代次数和容差与代码5一致
sh4 = BP_ISTA_improved(Hw, yw, lambda_fixed, maxIter_BP, tol_BP);
if all(sh4 == 0)
bp_zero_count = bp_zero_count + 1;
end
catch
sh4 = zeros(Nt, 1);
bp_zero_count = bp_zero_count + 1;
end
tt(4) = tt(4) + toc(t4);
% BER和MSE计算
decs = {sh1, sh2, sh3, sh4};
for k = 1:4
% 支撑集检测
[~, idx] = sort(abs(decs{k}), 'descend');
detected_support = idx(1:K_mimo);
if all(ismember(sup, detected_support))
correct_support(k) = correct_support(k) + 1;
end
% 符号判决(对实部取符号,但幅度太小时视为0)
dec = zeros(Nt, 1);
for j = 1:K_mimo
est_val = decs{k}(detected_support(j));
if abs(est_val) > 1e-3 % 阈值,防止噪声导致错误符号
dec(detected_support(j)) = sign(real(est_val));
end
end
% 计算误比特数
for j = 1:K_mimo
tx_idx = sup(j);
if dec(tx_idx) ~= 0
dec_bit = (dec(tx_idx) + 1) / 2;
eb(k) = eb(k) + (dec_bit ~= bits(j));
else
eb(k) = eb(k) + 1; % 未检测到
end
end
% MSE
acc(k) = acc(k) + mean(abs(decs{k} - s0).^2);
end
valid_mc_count = valid_mc_count + 1;
if i == 1 && mc == 1 && valid_mc_count == 1
s_imp = s0;
simps = {sh1, sh2, sh3, sh4};
figure('Name', '水声MIMO信道矩阵');
imagesc(abs(H));
colorbar; xlabel('发射天线'); ylabel('接收天线');
title('水声MIMO信道矩阵幅度');
end
end
if valid_mc_count == 0
BER(:, i) = 0.5;
MSE(:, i) = 1;
TIME(:, i) = 0;
fprintf('SNR = %d dB: 无有效仿真,跳过\n', snr);
continue;
end
% 计算平均性能
BER(:, i) = eb / (valid_mc_count * K_mimo);
MSE(:, i) = acc / valid_mc_count;
TIME(:, i) = tt / valid_mc_count;
% 输出详细统计
fprintf('SNR = %d dB: BER=[OMP %.2e, CoSaMP %.2e, SAMP %.2e, BP %.2e], ', ...
snr, BER(1,i), BER(2,i), BER(3,i), BER(4,i));
fprintf('BP零输出=%d/%d (%.2f%%), 支撑集正确率: OMP=%.1f%%, CoSaMP=%.1f%%, SAMP=%.1f%%, BP=%.1f%%\n', ...
bp_zero_count, valid_mc_count, bp_zero_count/valid_mc_count*100, ...
correct_support(1)/valid_mc_count*100, correct_support(2)/valid_mc_count*100, ...
correct_support(3)/valid_mc_count*100, correct_support(4)/valid_mc_count*100);
end
fprintf('\n总失败仿真次数: %d\n', failed_simulations);
%% 3. 可视化结果
% 图1: SISO水声信道估计MSE
figure('Name', 'SISO水声信道估计: MSE vs SNR', 'Position', [100, 100, 800, 600]);
semilogy(SNRdB_siso, mse_OMP_siso, '-o', ...
SNRdB_siso, mse_CoSaMP_siso, '-s', ...
SNRdB_siso, mse_SAMP_siso, '-^', ...
SNRdB_siso, mse_BP_siso, '-x', 'LineWidth', 1.5);
grid on; xlabel('SNR (dB)'); ylabel('Average MSE');
legend('OMP', 'CoSaMP', 'SAMP', 'BP-ISTA', 'Location', 'SouthWest');
title('SISO水声信道估计: MSE vs SNR');
% 图2: MIMO水声系统BER
figure('Name', 'MIMO水声通信: BER vs SNR', 'Position', [100, 100, 800, 600]);
semilogy(SNRdB_mimo, BER(1, :), '-o', ...
SNRdB_mimo, BER(2, :), '-s', ...
SNRdB_mimo, BER(3, :), '-^', ...
SNRdB_mimo, BER(4, :), '-x', 'LineWidth', 1.5);
grid on; xlabel('SNR (dB)'); ylabel('BER');
legend('OMP', 'CoSaMP', 'SAMP', 'BP', 'Location', 'SouthWest');
title('MIMO水声通信系统: BER vs SNR (Nr=16, Nt=4)');
ylim([1e-4, 1]); % 扩大y轴范围以显示BP的高BER
% 图3: MIMO水声系统MSE
figure('Name', 'MIMO水声通信: MSE vs SNR', 'Position', [100, 100, 800, 600]);
semilogy(SNRdB_mimo, MSE(1, :), '-o', ...
SNRdB_mimo, MSE(2, :), '-s', ...
SNRdB_mimo, MSE(3, :), '-^', ...
SNRdB_mimo, MSE(4, :), '-x', 'LineWidth', 1.5);
grid on; xlabel('SNR (dB)'); ylabel('Average MSE');
legend('OMP', 'CoSaMP', 'SAMP', 'BP', 'Location', 'SouthWest');
title('MIMO水声通信系统: MSE vs SNR');
% 图4: MIMO水声系统运行时间
figure('Name', 'MIMO水声通信: Time vs SNR', 'Position', [100, 100, 800, 600]);
plot(SNRdB_mimo, TIME(1, :), '-o', ...
SNRdB_mimo, TIME(2, :), '-s', ...
SNRdB_mimo, TIME(3, :), '-^', ...
SNRdB_mimo, TIME(4, :), '-x', 'LineWidth', 1.5);
grid on; xlabel('SNR (dB)'); ylabel('Time (s)');
legend('OMP', 'CoSaMP', 'SAMP', 'BP', 'Location', 'NorthEast');
title('MIMO水声通信系统: 运行时间 vs SNR');
% 图5: SISO vs MIMO MSE对比
figure('Name', 'SISO vs MIMO水声系统: MSE对比', 'Position', [100, 100, 1000, 600]);
semilogy(SNRdB_siso, mse_OMP_siso, '-o', ...
SNRdB_mimo, MSE(1, :), '--o', ...
SNRdB_siso, mse_CoSaMP_siso, '-s', ...
SNRdB_mimo, MSE(2, :), '--s', ...
SNRdB_siso, mse_SAMP_siso, '-^', ...
SNRdB_mimo, MSE(3, :), '--^', ...
SNRdB_siso, mse_BP_siso, '-x', ...
SNRdB_mimo, MSE(4, :), '--x', 'LineWidth', 1.5);
grid on; xlabel('SNR (dB)'); ylabel('Average MSE');
legend('SISO-OMP', 'MIMO-OMP', 'SISO-CoSaMP', 'MIMO-CoSaMP', ...
'SISO-SAMP', 'MIMO-SAMP', 'SISO-BP', 'MIMO-BP', 'Location', 'SouthWest');
title('SISO vs MIMO水声系统: MSE对比');
% 图6: 水声信道脉冲响应重构结果
figure('Name', '水声信道脉冲响应重构', 'Position', [100, 100, 1200, 800]);
t_ms = linspace(0, 50, N_siso); % 0-50ms时延范围
subplot(4,2,1); stem(t_ms, abs(x_imp), 'filled'); title('原始水声信道'); ylabel('幅度'); grid on;
subplot(4,2,2); stem(t_ms, angle(x_imp), 'filled'); title('原始水声信道相位'); ylabel('相位 (rad)'); grid on;
subplot(4,2,3); stem(t_ms, abs(imp1), 'filled'); title('OMP重构'); ylabel('幅度'); grid on;
subplot(4,2,4); stem(t_ms, angle(imp1), 'filled'); title('OMP重构相位'); ylabel('相位 (rad)'); grid on;
subplot(4,2,5); stem(t_ms, abs(imp2), 'filled'); title('CoSaMP重构'); ylabel('幅度'); grid on;
subplot(4,2,6); stem(t_ms, angle(imp2), 'filled'); title('CoSaMP重构相位'); ylabel('相位 (rad)'); grid on;
subplot(4,2,7); stem(t_ms, abs(imp3), 'filled'); title('SAMP重构'); ylabel('幅度'); xlabel('时延 (ms)'); grid on;
subplot(4,2,8); stem(t_ms, angle(imp3), 'filled'); title('SAMP重构相位'); ylabel('相位 (rad)'); xlabel('时延 (ms)'); grid on;
%% 输出误差统计
err_siso = [norm(imp1 - x_imp), norm(imp2 - x_imp), norm(imp3 - x_imp), norm(imp4 - x_imp)];
if exist('simps', 'var') && ~isempty(simps)
err_mimo = cellfun(@(sh) norm(sh - s_imp), simps);
else
err_mimo = [NaN, NaN, NaN, NaN];
end
fprintf('\n=== 误差统计 ===\n');
fprintf('SISO水声信道估计误差: [OMP %.2e, CoSaMP %.2e, SAMP %.2e, BP %.2e]\n', err_siso);
fprintf('MIMO水声用户检测误差: [OMP %.2e, CoSaMP %.2e, SAMP %.2e, BP %.2e]\n', err_mimo);
%% 以下为算法函数(均使用改进版本,但BP参数与代码5一致)
function x_hat = OMP_reconstruct(A, y, K)
[~, N] = size(A);
res = y;
supp = false(1, N);
for k = 1:K
[~, idx] = max(abs(A' * res));
supp(idx) = true;
xs = A(:, supp) \ y;
res = y - A(:, supp) * xs;
end
x_hat = zeros(N, 1);
x_hat(supp) = xs;
end
function x_hat = CoSaMP_reconstruct(A, y, K, maxIt)
[~, N] = size(A);
res = y;
supp = false(1, N);
for it = 1:maxIt
proxy = abs(A' * res);
[~, idx] = sort(proxy, 'descend');
Omega = idx(1:min(2*K, length(idx)));
T = union(find(supp), Omega);
if length(T) > size(A, 1)
break;
end
b = A(:, T) \ y;
[~, bidx] = sort(abs(b), 'descend');
Tnew = T(bidx(1:min(K, length(b))));
x_temp = zeros(N, 1);
x_temp(Tnew) = A(:, Tnew) \ y;
res = y - A * x_temp;
supp = false(1, N);
supp(Tnew) = true;
x_hat = x_temp;
if norm(res) < 1e-6
break;
end
end
end
function x_hat = SAMP_reconstruct(A, y, K, maxIt)
[~, N] = size(A);
res = y;
supp = false(1, N);
x_hat = zeros(N, 1);
t = 1;
while t <= maxIt
L = min(2^t * K, N);
proxy = abs(A' * res);
[~, idx] = sort(proxy, 'descend');
Omega = idx(1:min(L, length(idx)));
T = union(find(supp), Omega);
if length(T) > size(A, 1)
break;
end
b = A(:, T) \ y;
[~, bidx] = sort(abs(b), 'descend');
Tnew = T(bidx(1:min(K, length(b))));
x_temp = zeros(N, 1);
x_temp(Tnew) = A(:, Tnew) \ y;
res_new = y - A * x_temp;
if norm(res_new) >= norm(res)
break;
else
res = res_new;
supp = false(1, N);
supp(Tnew) = true;
x_hat = x_temp;
t = t + 1;
end
end
end
function x_hat = BP_ISTA_improved(A, y, lam, maxIt, tol)
% 改进的BP-ISTA,使用精确Lipschitz常数
[~, N] = size(A);
x_hat = zeros(N, 1);
% 精确计算Lipschitz常数(矩阵2-范数的平方)
L = norm(A, 2)^2;
L = max(L, 1e-6);
step = 1 / L;
for it = 1:maxIt
grad = A' * (A * x_hat - y);
z = x_hat - step * grad;
x_new = sign(z) .* max(abs(z) - lam * step, 0);
if norm(x_new - x_hat) / (norm(x_hat) + eps) < tol
x_hat = x_new;
return;
end
x_hat = x_new;
end
end
function h = generate_underwater_channel_simplified(L, fs, N_cluster, paths_per_cluster, ...
cluster_delay_centers, cluster_delay_spread, cluster_doppler_spread)
Np = N_cluster * paths_per_cluster;
tau_i = zeros(Np, 1);
a_i = zeros(Np, 1);
A_i = zeros(Np, 1);
path_idx = 1;
for c = 1:N_cluster
for p = 1:paths_per_cluster
tau_i(path_idx) = cluster_delay_centers(c) + raylrnd(cluster_delay_spread(c)/3);
tau_i(path_idx) = max(tau_i(path_idx), 0);
a_i(path_idx) = cluster_doppler_spread(c) * (0.5 + 0.2*randn(1));
if p > 1
tau_i(path_idx) = tau_i(path_idx - 1) + 0.001 * abs(randn(1));
a_i(path_idx) = a_i(path_idx - 1) + 0.1 * randn(1);
end
A0 = exp(-10 * tau_i(path_idx));
phase = 2*pi*rand(1);
fd = a_i(path_idx) * (0.5 + 0.2*randn(1));
A_i(path_idx) = A0 * exp(1i*phase) * exp(1i*2*pi*fd*rand(1));
path_idx = path_idx + 1;
end
end
tau_samples = round(tau_i * fs) + 1;
tau_samples(tau_samples > L) = L;
tau_samples(tau_samples < 1) = 1;
h = zeros(L, 1);
for p = 1:Np
idx = tau_samples(p);
if idx > 1 && idx < L
h(idx-1) = h(idx-1) + 0.25 * A_i(p);
h(idx) = h(idx) + 0.5 * A_i(p);
h(idx+1) = h(idx+1) + 0.25 * A_i(p);
elseif idx == 1
h(1) = h(1) + 0.75 * A_i(p);
h(2) = h(2) + 0.25 * A_i(p);
elseif idx == L
h(L-1) = h(L-1) + 0.25 * A_i(p);
h(L) = h(L) + 0.75 * A_i(p);
end
end
if norm(h) > 0
h = h / norm(h);
end
end