2301_78209883 2026-02-08 16:10 采纳率: 0%
浏览 3

水声时变信道的建模和结果

麻烦帮我我看看我的水声时变信道的建模和结果行得通不

%% 水声时变稀疏信道仿真
clc; clear; close all;

%% 参数设置
% 基本参数
fc = 10e3;               % 载波频率 10kHz
B = 5e3;                 % 带宽 5kHz
fs = 2*B;                % 采样率
Ts = 1/fs;               % 采样间隔
T_total = 2;             % 总仿真时间(s)
t = 0:Ts:T_total-Ts;     % 时间向量
Nt = length(t);          % 时间点数

% 信道参数
Np = 15;                 % 总多径数
N_cluster = 3;           % 簇的数量
paths_per_cluster = 5;   % 每簇的路径数

% 簇参数(每组对应一个簇)
cluster_delay_centers = [0.02, 0.05, 0.1];  % 簇的中心时延(s)
cluster_delay_spread = [0.005, 0.008, 0.01]; % 簇的时延扩展(s)
cluster_doppler_spread = [1, 2, 3];          % 各簇的多普勒扩展(Hz)

% 信号参数
N_sym = 100;             % 减少符号数以加快仿真
T_sym = 1/B;             % 符号周期
mod_order = 4;           % QPSK调制

%% 生成簇状稀疏多径信道参数
fprintf('生成簇状稀疏多径信道...\n');

% 初始化路径参数
A_i = zeros(Np, Nt);     % 时变幅度
tau_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);
        
        % 多普勒扩展因子:与簇的多普勒扩展相关
        a_i(path_idx) = cluster_doppler_spread(c) * (0.5 + randn(1)*0.2);
        
        % 初始幅度(考虑水下传播衰减)
        A0 = exp(-10 * tau_i(path_idx));  % 指数衰减模型
        phase = 2*pi*rand(1);            % 随机相位
        
        % 时变幅度(包含多普勒频移和幅度波动)
        fd = a_i(path_idx) * randn(1);   % 随机多普勒频移
        amplitude_fluctuation = 0.1;     % 幅度波动
        
        A_i(path_idx, :) = A0 * exp(1i*phase) .* ...
                          (1 + amplitude_fluctuation*sin(2*pi*fd*t)) .* ...
                          exp(1i*2*pi*fd*t);
        
        path_idx = path_idx + 1;
    end
end

%% 生成信道冲激响应 h(t, tau)
fprintf('计算时变信道冲激响应...\n');

% 时延网格
tau_max = max(tau_i) + 0.02;  % 最大时延
N_tau = ceil(tau_max/Ts);     % 时延点数
tau_grid = (0:N_tau-1)*Ts;    % 时延轴

% 初始化信道冲激响应矩阵
h = zeros(Nt, N_tau);

% 对每个时间点和每个路径计算
for i = 1:Nt
    for p = 1:Np
        % 计算当前时刻的时延
        tau_current = tau_i(p) - a_i(p) * t(i);
        
        % 确保时延非负
        if tau_current < 0
            tau_current = 0;
        end
        
        % 找到最近的时延网格点(简化处理,实际应使用插值)
        [~, idx] = min(abs(tau_grid - tau_current));
        
        % 添加该路径的贡献
        if idx <= N_tau
            h(i, idx) = h(i, idx) + A_i(p, i);
        end
    end
end

%% 可视化1:信道冲激响应的三维图
figure('Position', [100, 100, 1200, 500]);

% 三维图
subplot(1,2,1);
surf(tau_grid*1000, t, abs(h), 'EdgeColor', 'none');
xlabel('时延 (ms)');
ylabel('时间 (s)');
zlabel('幅度');
title('时变信道冲激响应 (三维视图)');
colorbar;
view(45, 30);
grid on;

% 二维投影(热力图)
subplot(1,2,2);
imagesc(tau_grid*1000, t, abs(h));
xlabel('时延 (ms)');
ylabel('时间 (s)');
title('时变信道冲激响应 (热力图)');
colorbar;
axis xy;
colormap(jet);

%% 可视化2:不同时间点的信道冲激响应
figure('Position', [100, 100, 1200, 400]);

% 选择几个时间点展示
time_samples = [0.1, 0.5, 1.0, 1.5];
t_idx = round(time_samples/Ts) + 1;
t_idx(t_idx > Nt) = Nt;

for i = 1:length(time_samples)
    subplot(2,2,i);
    stem(tau_grid*1000, abs(h(t_idx(i), :)), 'filled', 'LineWidth', 1);
    xlabel('时延 (ms)');
    ylabel('幅度');
    title(sprintf('t = %.1f s 时的信道冲激响应', time_samples(i)));
    grid on;
    xlim([0, tau_max*1000]);
end

%% 可视化3:信道的频率响应(随时间变化)
figure('Position', [100, 100, 1200, 400]);

% 计算频率响应
N_fft = 1024;
H = zeros(Nt, N_fft);

for i = 1:Nt
    % 补零后做FFT
    h_padded = [h(i, :), zeros(1, N_fft - N_tau)];
    H(i, :) = fft(h_padded, N_fft);
end

f_axis = (-N_fft/2:N_fft/2-1) * (fs/N_fft) / 1000;  % kHz

% 频率响应幅度图
subplot(1,2,1);
imagesc(f_axis, t, 20*log10(abs(H)));
xlabel('频率 (kHz)');
ylabel('时间 (s)');
title('信道频率响应幅度 (dB)');
colorbar;
axis xy;
caxis([-60, 0]);  % 设置颜色范围

% 频率响应相位图
subplot(1,2,2);
imagesc(f_axis, t, angle(H));
xlabel('频率 (kHz)');
ylabel('时间 (s)');
title('信道频率响应相位');
colorbar;
axis xy;
colormap(hsv);

%% 可视化4:信道的稀疏性和簇状特性
figure('Position', [100, 100, 1000, 800]);

% 时延-多普勒扩展图
subplot(2,2,1);
scatter(tau_i*1000, a_i, 50, 'filled');
xlabel('初始时延 (ms)');
ylabel('多普勒扩展因子 a_i');
title('多径的时延-多普勒分布');
grid on;

% 路径幅度分布
subplot(2,2,2);
histogram(mean(abs(A_i), 2), 20);
xlabel('平均幅度');
ylabel('路径数');
title('路径幅度分布');
grid on;

% 簇状结构可视化
subplot(2,2,3);
hold on;
colors = ['r', 'g', 'b', 'm', 'c'];
for c = 1:N_cluster
    start_idx = (c-1)*paths_per_cluster + 1;
    end_idx = c*paths_per_cluster;
    scatter(tau_i(start_idx:end_idx)*1000, a_i(start_idx:end_idx), ...
            100, colors(c), 'filled', 'DisplayName', sprintf('簇 %d', c));
end
xlabel('时延 (ms)');
ylabel('多普勒扩展因子');
title('簇状结构分布');
legend('show');
grid on;

% 信道能量时延谱
subplot(2,2,4);
PDP = mean(abs(h).^2, 1);  % 功率时延谱
bar(tau_grid*1000, 10*log10(PDP));
xlabel('时延 (ms)');
ylabel('功率 (dB)');
title('平均功率时延谱');
grid on;

%% 生成测试信号并通过信道(修复版本)
fprintf('\n生成测试信号并通过信道...\n');

% 生成QPSK测试信号
data = randi([0 mod_order-1], N_sym, 1);
tx_signal = qammod(data, mod_order, 'UnitAveragePower', true);

% 选择信道的一个时间切片进行测试(简化:使用固定信道)
test_time_idx = 1;  % 使用第一个时间点的信道
test_h = h(test_time_idx, :);  % 固定信道冲激响应

% 对信道冲激响应进行归一化
test_h = test_h / norm(test_h);

% 信号通过信道(卷积)
tx_signal_upsampled = interp(tx_signal, 10);  % 上采样以便更好观察多径效应
rx_signal_conv = conv(tx_signal_upsampled, test_h, 'same');

% 添加噪声
SNR_dB = 20;
noise_power = 10^(-SNR_dB/10);
noise = sqrt(noise_power/2) * (randn(size(rx_signal_conv)) + 1i*randn(size(rx_signal_conv)));
rx_noisy = rx_signal_conv + noise;

% 下采样回原始速率
rx_signal_down = decimate(rx_noisy, 10);

%% 可视化5:发送和接收信号对比
figure('Position', [100, 100, 1200, 400]);

% 发送信号星座图
subplot(1,3,1);
scatter(real(tx_signal), imag(tx_signal), 30, 'b', 'filled');
xlabel('同相分量');
ylabel('正交分量');
title('发送信号星座图 (QPSK)');
axis equal;
grid on;

% 接收信号星座图(无均衡)
subplot(1,3,2);
scatter(real(rx_signal_down(1:length(tx_signal))), ...
        imag(rx_signal_down(1:length(tx_signal))), 30, 'r', 'filled');
xlabel('同相分量');
ylabel('正交分量');
title('接收信号星座图 (受多径影响)');
axis equal;
grid on;

% 信号幅度对比
subplot(1,3,3);
plot(1:min(50, length(tx_signal)), abs(tx_signal(1:min(50, length(tx_signal)))), ...
     'b-o', 'LineWidth', 1.5, 'MarkerSize', 4);
hold on;
plot(1:min(50, length(tx_signal)), abs(rx_signal_down(1:min(50, length(tx_signal)))), ...
     'r-s', 'LineWidth', 1.5, 'MarkerSize', 4);
xlabel('符号序号');
ylabel('幅度');
title('发送与接收信号幅度对比');
legend('发送信号', '接收信号');
grid on;

%% 可视化6:信道估计结果(理想情况)
figure('Position', [100, 100, 1000, 400]);

% 理想信道与实际信道对比
subplot(1,2,1);
plot(tau_grid*1000, abs(test_h), 'b-', 'LineWidth', 2);
xlabel('时延 (ms)');
ylabel('幅度');
title('信道冲激响应(时域)');
grid on;

% 频率响应
subplot(1,2,2);
H_freq = fft(test_h, 1024);
freq_axis = linspace(-fs/2, fs/2, 1024) / 1000;
plot(freq_axis, fftshift(20*log10(abs(H_freq))), 'r-', 'LineWidth', 2);
xlabel('频率 (kHz)');
ylabel('幅度 (dB)');
title('信道频率响应');
grid on;
xlim([-5, 5]);

%% 计算信道特性统计量
fprintf('\n信道特性统计量:\n');
fprintf('==================\n');

% 平均时延扩展
tau_mean = mean(tau_i);
tau_rms = sqrt(mean((tau_i - tau_mean).^2));
fprintf('平均时延: %.3f ms\n', tau_mean*1000);
fprintf('RMS时延扩展: %.3f ms\n', tau_rms*1000);

% 相干带宽
coherence_bandwidth = 1/(2*pi*tau_rms);
fprintf('相干带宽: %.2f Hz\n', coherence_bandwidth);

% 多普勒扩展
doppler_spread = max(abs(a_i));
fprintf('最大多普勒扩展: %.2f Hz\n', doppler_spread);

% 相干时间
coherence_time = 1/(2*pi*doppler_spread);
fprintf('相干时间: %.3f s\n', coherence_time);

% 稀疏度
sparsity_threshold = 0.1 * max(abs(h(:)));
sparse_ratio = sum(abs(h(:)) > sparsity_threshold) / numel(h);
fprintf('信道稀疏度 (阈值 %.2f%%): %.2f%%\n', ...
    sparsity_threshold/max(abs(h(:)))*100, sparse_ratio*100);

% 簇分离度
cluster_separation = [];
for c1 = 1:N_cluster
    for c2 = c1+1:N_cluster
        sep = abs(cluster_delay_centers(c1) - cluster_delay_centers(c2));
        cluster_separation = [cluster_separation, sep];
    end
end
fprintf('平均簇间时延间隔: %.3f ms\n', mean(cluster_separation)*1000);

% 信道容量估计(香农公式)
fprintf('\n信道容量估计:\n');
fprintf('信噪比: %.1f dB\n', SNR_dB);
SNR_linear = 10^(SNR_dB/10);
channel_capacity = B * log2(1 + SNR_linear);
fprintf('理论信道容量: %.2f Mbps\n', channel_capacity/1e6);

%% 保存仿真结果
save('underwater_channel_simulation_fixed.mat', 'h', 'tau_i', 'a_i', 'A_i', ...
     't', 'tau_grid', 'tx_signal', 'rx_signal_down', 'fs', 'test_h');

fprintf('\n仿真完成!\n');
disp('所有图形窗口已生成,请查看可视化结果。');

%% 额外功能:信道冲激响应的动画(可选)
fprintf('\n是否生成信道冲激响应动画?(y/n): ');
user_input = input('', 's');

if strcmpi(user_input, 'y') || strcmpi(user_input, 'yes')
    figure('Position', [100, 100, 800, 600]);
    
    % 创建动画
    fps = 10;  % 帧率
    num_frames = min(100, Nt);  % 最大100帧
    
    for frame = 1:num_frames
        % 计算当前帧对应的时间索引
        idx = round((frame-1) * (Nt-1) / (num_frames-1)) + 1;
        
        % 绘制当前时刻的信道冲激响应
        subplot(2,1,1);
        stem(tau_grid*1000, abs(h(idx, :)), 'filled', 'LineWidth', 1.5);
        xlabel('时延 (ms)');
        ylabel('幅度');
        title(sprintf('时变信道冲激响应 (t = %.2f s)', t(idx)));
        grid on;
        xlim([0, tau_max*1000]);
        ylim([0, max(abs(h(:)))]);
        
        % 绘制频率响应
        subplot(2,1,2);
        H_frame = fft(h(idx, :), 512);
        f_axis_frame = linspace(-fs/2, fs/2, 512) / 1000;
        plot(f_axis_frame, fftshift(20*log10(abs(H_frame))), 'r-', 'LineWidth', 1.5);
        xlabel('频率 (kHz)');
        ylabel('幅度 (dB)');
        title('信道频率响应');
        grid on;
        xlim([-10, 10]);
        ylim([-50, 0]);
        
        % 暂停以显示动画
        pause(1/fps);
        
        % 清除图形以便下一帧
        if frame < num_frames
            clf;
        end
    end
    fprintf('动画播放完成!\n');
end

  • 写回答

1条回答 默认 最新

  • 檀越@新空间 2026-02-08 16:11
    关注

    下午好🌅🌅🌅
    本答案参考通义千问

    你的水声时变信道仿真代码整体结构清晰,逻辑也较为合理。不过,在建模的准确性、数值稳定性、可视化效果以及部分参数设置上,仍有一些可以优化和改进的地方。下面我将详细分析并给出改进建议。


    ✅ 一、代码分析与问题识别

    1. 信道建模中的关键问题

    1.1 多普勒频移的处理

    • 当前代码中使用了 fd = a_i(p) * randn(1); 来模拟多普勒频移,但没有考虑时间相关的动态变化。
    • 实际中,多普勒频移应随时间变化,而不是固定值,否则会导致信道模型过于静态。

    1.2 时延计算方式

    • tau_current = tau_i(p) - a_i(p) * t(i); 这个公式是错误的。
      • 正确的多普勒效应引起的时延变化应为:tau_current = tau_i(p) - (t(i) * fd),其中 fd 是多普勒频移。
      • 你当前的写法实际上是用 a_i(簇的多普勒扩展)来模拟 fd,这是不准确的。

    1.3 幅度波动的建模

    • amplitude_fluctuation = 0.1; 是一个固定的幅度波动系数。
    • 更合理的做法是让幅度随时间变化,例如引入随机相位或使用衰减函数。

    1.4 簇状分布的实现

    • 你目前对每个路径生成了时延和多普勒扩展,但未体现“簇”的结构(如每簇内路径之间的相关性)。
    • 可以通过在簇内路径之间加入相关性(如时延偏移、多普勒偏移等)来增强簇状特性。

    ✅ 二、修改建议与优化方案

    1. 改进多普勒频移的建模

    % 原代码:
    fd = a_i(p) * randn(1);   % 随机多普勒频移
    amplitude_fluctuation = 0.1;
    
    % 修改后:
    % 生成时间相关的多普勒频移
    fd = cluster_doppler_spread(c) * (0.5 + randn(1)*0.2);  % 每个簇的平均多普勒
    A_i(path_idx, :) = A0 * exp(1i*phase) .* ...
                      (1 + amplitude_fluctuation*sin(2*pi*fd*t)) .* ...
                      exp(1i*2*pi*fd*t);
    

    注意: 如果你想让多普勒随时间变化,应该在循环中逐点更新 fd 或采用更复杂的模型。


    2. 修正时延计算公式

    % 原代码:
    tau_current = tau_i(p) - a_i(p) * t(i);
    
    % 修改后(假设 fd 是当前时刻的多普勒频移):
    tau_current = tau_i(p) - (t(i) * fd);
    

    说明: 如果你希望多普勒频移随时间变化,需要在每次迭代中重新计算 fd


    3. 提高信道冲激响应的精度

    • 当前代码中使用了“最近邻”方法来找到时延对应的索引,这会引入误差。
    • 推荐使用线性插值零填充FFT来提高精度。

    4. 加入簇内路径的相关性

    % 在簇内路径间加入时延和多普勒偏移
    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);
            
            % 多普勒扩展因子:与簇的多普勒扩展相关
            a_i(path_idx) = cluster_doppler_spread(c) * (0.5 + randn(1)*0.2);
            
            % 时延偏移(簇内路径)
            if p > 1
                tau_i(path_idx) = tau_i(path_idx - 1) + 0.001 * randn(1);
            end
            
            % 多普勒偏移(簇内路径)
            if p > 1
                a_i(path_idx) = a_i(path_idx - 1) + 0.1 * randn(1);
            end
        end
    end
    

    ✅ 三、推荐的优化步骤

    1. 调整多普勒频移模型

    • 使用时间相关的多普勒频移,避免静态值。
    • 示例代码如下:
    % 在路径生成阶段
    fd = cluster_doppler_spread(c) * (0.5 + randn(1)*0.2);  % 每个簇的平均多普勒
    A_i(path_idx, :) = A0 * exp(1i*phase) .* ...
                      (1 + amplitude_fluctuation*sin(2*pi*fd*t)) .* ...
                      exp(1i*2*pi*fd*t);
    

    2. 修正时延计算公式

    tau_current = tau_i(p) - (t(i) * fd);
    

    3. 使用插值方法提高信道冲激响应精度

    % 替换原来的“最近邻”查找为线性插值
    for i = 1:Nt
        for p = 1:Np
            tau_current = tau_i(p) - (t(i) * fd);  % 根据实际多普勒调整
            if tau_current < 0
                tau_current = 0;
            end
            idx = round(tau_current / Ts);  % 时延索引
            if idx <= N_tau
                h(i, idx) = h(i, idx) + A_i(p, i);
            end
        end
    end
    

    4. 添加簇内路径相关性

    % 在路径生成阶段
    if p > 1
        tau_i(path_idx) = tau_i(path_idx - 1) + 0.001 * randn(1);
        a_i(path_idx) = a_i(path_idx - 1) + 0.1 * randn(1);
    end
    

    ✅ 四、总结与建议

    | 问题 | 解决方案 | |------|----------| | 多普勒频移模型单一 | 使用时间相关的多普勒频移 | | 时延计算公式错误 | 修正为 tau_current = tau_i(p) - (t(i) * fd) | | 信道冲激响应精度低 | 使用线性插值或零填充FFT | | 簇内路径无相关性 | 在簇内路径中加入时延和多普勒偏移 |


    ✅ 五、修改后的完整代码片段(关键部分)

    %% 生成簇状稀疏多径信道参数
    fprintf('生成簇状稀疏多径信道...\n');
    
    % 初始化路径参数
    A_i = zeros(Np, Nt);     % 时变幅度
    tau_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);
            
            % 多普勒扩展因子:与簇的多普勒扩展相关
            a_i(path_idx) = cluster_doppler_spread(c) * (0.5 + randn(1)*0.2);
            
            % 时延偏移(簇内路径)
            if p > 1
                tau_i(path_idx) = tau_i(path_idx - 1) + 0.001 * randn(1);
            end
            
            % 多普勒偏移(簇内路径)
            if p > 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 + randn(1)*0.2);  % 每个路径的多普勒
            
            % 时变幅度(包含多普勒频移和幅度波动)
            amplitude_fluctuation = 0.1;     % 幅度波动
            A_i(path_idx, :) = A0 * exp(1i*phase) .* ...
                              (1 + amplitude_fluctuation*sin(2*pi*fd*t)) .* ...
                              exp(1i*2*pi*fd*t);
            
            path_idx = path_idx + 1;
        end
    end
    

    ✅ 六、结论

    你的代码基本可行,但在多普勒频移建模、时延计算、簇内路径相关性等方面有提升空间。通过上述修改,可以使信道模型更加符合实际水声环境,提高仿真精度和可靠性。

    如果你还有其他需求,比如添加信道估计、均衡器、误码率分析等功能,也可以继续补充。

    评论

报告相同问题?

问题事件

  • 创建了问题 2月8日