你现在是无线通信的专家。我们现在一起来分析一个问题,就是OFDM在分析AF时候的性能。我们都知道IC...
創建於:2026年1月21日
使用 GPT-5.2 Thinking 回答 Chat01
創建於:2026年1月21日
使用 GPT-5.2 Thinking 回答 Chat01
你现在是无线通信的专家。我们现在一起来分析一个问题,就是OFDM在分析AF时候的性能。我们都知道ICI对OFDM造成的影响很大,原因是快时间doppler的影响。我们下面的代码是分别分析相干积分前后的2D-FFT的AF和逐点匹配的AF。我们现在想对于相干积分前的AF,直接对每一个doppler的点进行快时间部分的多普勒补偿,来消除这个干扰。请在下面这个代码里面实现,并与补偿前的进行对比,我们要对比的就是相干积分前的AFfs进行补偿前后的对比:clc
clear
format long
times = 1;
M = 16; % slow time index 脉冲数量 16
N = 32*times; % fast time index 每个脉冲的采样点数 32
Nmc = 10;
rng(1545);
tau = 4;
range1 = -M:M;
rec = zeros(length(range1),1);
count = 0;
for nu = 8
count = count + 1;
cAF = zeros(N,MN2); % 初始化常规模糊函数 cAF
for mc = 1:Nmc
text%OFDM gen s = randi(16,[N,M])-1; x = pskmod(s,16); F = dftmtx(N)./sqrt(N); y = repmat(F'*x,[2,1]); % delay doppler OFDM yy1 = y(:); yy2 = circshift(yy1,tau); yy3 = yy2.*exp(1i*2*pi*(0:M*N*2-1)/M/N/2*nu).'; % transmit OFDM xx = repmat(F'*x,[2,1]); xx = xx(:); y2 = reshape(yy3,N*2,M); z = y2(:); AF = zeros(N,M*N*2); % 初始化常规模糊函数 AF parfor i = 1:N row_AF = zeros(1, M*N*2); for j = 1:M*N*2 temp1 = z .* exp(-1i*2*pi*(0:M*N*2-1)'/(M*N*2)*j); temp2 = temp1 .* circshift(conj(xx), i); temp3 = reshape(temp2, N*2, M); temp4 = temp3(N+1:end, :); row_AF(j) = sum(temp4(:)); end AF(i, :) = row_AF; end cAF = cAF + abs(AF).^2; end AFfs = zeros(N,M); % 初始化修改后的快慢时间模糊函数 F2 = dftmtx(M)./sqrt(dftmtx(M)); AFfs = abs(fft((F'*((F*y2(N+1:end,:)).*conj(x))).')).^2; % 快慢时间模糊函数的功率谱计算 %figure; %surf(ifftshift(20*log10(AFfs))); % PSR calc if nu~=0 rec(count) = 10*log10(max(max(AFfs))./ (sum(sum(AFfs))-max(max(AFfs))).*(M*N+1)); else [~, idx] = max(AFfs(:)); AFfs_filtered = AFfs; AFfs_filtered(idx) = 0; rec(count) = 10*log10(max(AFfs, [], 'all') / sum(AFfs_filtered, 'all') * (M*N+1)); end
end
figure;
plot(range1,rec-max(rec),'o-');
xlabel('Doppler Shift Index')
ylim([-350,0])
title('N = 16*32')
grid on
figure;
plot(range1,rec,'o-');
xlabel('Doppler Shift Index')
title('N = 16*32')
grid on
%% 非相干累积
AF3 = zeros(N,N*2);
for i = 1:M
AF3 = AF3 + cAF(:,i:M:end);
end
AF3 = AF3 / M;
figure
surf(ifftshift(10*log10(AF3./max(max(AF3)))));
shading interp;
zlabel('Ambiguity Function/dB')
xlabel('Doppler Index');
ylabel('Delay Index');
title('After Non-Coherent Intergration')
% 绘图
figure;
imagesc(ifftshift(10log10(AF3./max(max(AF3)))));
colormap jet;
colorbar;
clim([-30 0]);
xlabel('Doppler Index (Cyclic Shifted)');
ylabel('Delay Index');
title('After Non-Coherent Intergration')
axis xy;
set(gca, 'XTick', [1, N, 2N]);
set(gca, 'XTickLabel', {'-N', '0', 'N'});
set(gca, 'YTick', [1, N/2, N]);
set(gca, 'YTickLabel', {'0', 'N/2', 'N'});
%% 未进行非相干累积
AF2 = zeros(N, N2); % 修正为正确的行维度
for i = 1:M
AF2 = AF2 + abs(AF(:, N2*(i-1)+1:N2i)).^2; % 逐块累加
end
AF2 = AF2 ./ M; % 平均操作
figure
surf(ifftshift(10*log10(AF2./max(max(AF2)))));
shading interp;
zlabel('Ambiguity Function/dB')
xlabel('Doppler Index');
ylabel('Delay Index');
title('Before Non-Coherent Intergration')
figure;
imagesc(ifftshift(10log10(AF2./max(max(AF2)))));
colormap jet;
colorbar;
clim([-30 0]);
xlabel('Doppler Index (Cyclic Shifted)');
ylabel('Delay Index');
title('Before Non-Coherent Intergration')
axis xy;
set(gca, 'XTick', [1, N, 2N]);
set(gca, 'XTickLabel', {'-N', '0', 'N'});
set(gca, 'YTick', [1, N/2, N]);
set(gca, 'YTickLabel', {'0', 'N/2', 'N'});
%% zero delay and doppler cut
% zero Doppler
zero_doppler_AF2 = AF2(:, 1);
zero_doppler_AF3 = AF3(:, 1);
figure;
plot(10log10(abs(zero_doppler_AF2./max(zero_doppler_AF2))), 'r', 'LineWidth', 1.5);
hold on;
plot(10log10(abs(zero_doppler_AF3./max(zero_doppler_AF3))), 'b', 'LineWidth', 1.5);
xlabel('Delay Index');
legend('AF2', 'AF3');
title('Zero Doppler Cut')
grid on
% zero delay
doppler_index = -(N-1):N;
zero_delay_AF2 = AF2(tau, :);
zero_delay_AF3 = AF3(tau, :);
figure;
plot(doppler_index,ifftshift(10log10(abs(zero_delay_AF2./max(zero_delay_AF2)))), 'r', 'LineWidth', 1.5);
hold on;
plot(doppler_index,ifftshift(10log10(abs(zero_delay_AF3./max(zero_delay_AF3)))), 'b', 'LineWidth', 1.5);
xlabel('Doppler Index');
legend('AF2', 'AF3');
title('Zero Delay Cut')
grid on
下面给你一个**“逐 Doppler 点做快时间 Doppler 补偿”的实现方式,并且把补偿前/补偿后**的 **AFfs(相干积分前 2D-FFT AF)**直接对比画出来。
核心想法是:
AFfs 做法等价于:先做快时间 FFT(子载波域),再乘 conj(x) 匹配滤波,再做快时间 IFFT 得到延迟像,最后沿慢时间做 FFT 得到 Doppler。你原来 AFfs = ... 那一段有维度不一致的隐患(.' 之后是 M×N,但你定义了 AFfs=zeros(N,M))。我这里给出一个更明确的写法:沿慢时间维(第2维)做 FFT,得到 N×M 的 AFfs。
把下面这段放到你每次 mc 里、得到 y2 之后(即 y2 = reshape(yy3,N*2,M); 之后),并把你原来的 AFfs = ... 替换掉即可。
matlab% ====== 在 mc 循环内:y2 已经得到之后加入/替换 ====== y_fast = y2(N+1:end, :); % 取后半段: N×M % --- (A) 补偿前:原始 AFfs(2D-FFT 形式,先快时间处理,再慢时间FFT) --- range_mat = F' * ((F*y_fast) .* conj(x)); % N×M AFfs_raw_mc = abs( fft(range_mat, M, 2) ).^2; % 沿慢时间(第2维)做FFT => N×M % --- (B) 逐 Doppler bin 的快时间 Doppler 补偿 AFfs --- AFfs_comp_mc = zeros(N, M); n_fast = (0:N-1).'; % 快时间采样索引(每个脉冲内重置) p_idx = (0:M-1).'; % 慢时间脉冲索引 for k = 1:M % 把 k 映射到“居中”的 Doppler bin(便于同时覆盖正负频率) k0 = k-1; if k0 > M/2 k0 = k0 - M; end % 该 Doppler bin 对应的“每采样”归一化频率 cycles/sample % 推导:慢时间FFT bin 满足 exp(j2π f_d * (N*2) * p) <-> exp(j2π k p/M) % => f_d = k/(M*N*2) fd = k0 / (M*N*2); % 只做“快时间内”的去旋转(消ICI) rot_fast = exp(-1i*2*pi*fd*n_fast); % N×1 y_fast_comp = y_fast .* rot_fast; % N×M (隐式扩展) % 快时间处理(子载波域匹配 + IFFT 到 delay) range_mat_comp = F' * ((F*y_fast_comp) .* conj(x)); % N×M % 该 Doppler 点的慢时间相干和(等价于取慢时间FFT的第k个bin) steering = exp(-1i*2*pi*p_idx*(k-1)/M); % M×1 AFfs_comp_mc(:, k) = abs(range_mat_comp * steering).^2; % N×1 end
mc 外做累加平均 + 画图你原代码里 AFfs 没有在 Nmc 上平均(cAF 平均了,但 AFfs 没有)。为了公平对比补偿前后,建议你在 nu 循环里加两行累加器:
在 for nu = 8 内,for mc = 1:Nmc 前面加:
matlabAFfs_raw_acc = zeros(N, M); AFfs_comp_acc = zeros(N, M);
然后在每次 mc 结束时累加:
matlabAFfs_raw_acc = AFfs_raw_acc + AFfs_raw_mc; AFfs_comp_acc = AFfs_comp_acc + AFfs_comp_mc;
mc 循环结束后得到平均:
matlabAFfs_raw = AFfs_raw_acc / Nmc; AFfs_comp = AFfs_comp_acc / Nmc;
把下面画图代码接在 AFfs_raw / AFfs_comp 得到之后即可:
matlab% 归一化到各自峰值,转 dB AFfs_raw_dB = 10*log10(AFfs_raw ./ max(AFfs_raw(:))); AFfs_comp_dB = 10*log10(AFfs_comp ./ max(AFfs_comp(:))); figure; imagesc(ifftshift(AFfs_raw_dB, 2)); % 只对Doppler维做shift(第2维) axis xy; colormap jet; colorbar; clim([-30 0]); xlabel('Doppler Bin (shifted)'); ylabel('Delay Bin'); title('AFfs BEFORE fast-time Doppler compensation (coherent, pre-NCI)'); figure; imagesc(ifftshift(AFfs_comp_dB, 2)); axis xy; colormap jet; colorbar; clim([-30 0]); xlabel('Doppler Bin (shifted)'); ylabel('Delay Bin'); title('AFfs AFTER fast-time Doppler compensation (per-Doppler, coherent, pre-NCI)'); figure; imagesc(ifftshift(AFfs_comp_dB - AFfs_raw_dB, 2)); axis xy; colormap jet; colorbar; xlabel('Doppler Bin (shifted)'); ylabel('Delay Bin'); title('AFfs Improvement (AFfs\_comp - AFfs\_raw) in dB');
如果你也想像原来那样用 PSR 比较一眼看提升,可以加:
matlabpeak_raw = max(AFfs_raw(:)); psr_raw = 10*log10( peak_raw / (sum(AFfs_raw(:)) - peak_raw) * (M*N+1) ); peak_comp = max(AFfs_comp(:)); psr_comp = 10*log10( peak_comp / (sum(AFfs_comp(:)) - peak_comp) * (M*N+1) ); fprintf('PSR raw = %.3f dB\n', psr_raw); fprintf('PSR comp = %.3f dB\n', psr_comp); fprintf('Gain = %.3f dB\n', psr_comp - psr_raw);
AFfs_raw:主峰会被 ICI“糊开”,旁瓣/杂散抬高。AFfs_comp:主峰更集中,杂散显著下降(尤其是 Doppler 不小的时候),PSR 上升。如果你接下来想更“严格”地对齐你逐点匹配的 AF(你 parfor 那个),我们还可以把 fd 的映射和 Doppler 轴定义完全统一(比如和你 exp(-j2π n/(M*N*2)*j) 的 j 对齐),这样补偿会更精确。
给我一个完整的,对比这两个方案的代码
下面是一份完整可运行的 MATLAB 脚本:同时计算并对比
AFfs_rawAFfs_comp并给出:
AFfs_raw / AFfs_comp 的 2D 图对比(以 nu_show 为例)PSR 随 nu 变化的曲线对比(两个方案)你只要把下面整段脚本保存为一个
.m文件运行即可。
matlabclc; clear; format long %% ===================== 参数区 ===================== times = 1; M = 16; % slow time pulses N = 32*times; % fast time samples per pulse (useful part) Nmc = 10; % Monte Carlo runs rng(1545); tau = 4; % delay (samples) range1 = -M:M; % Doppler index scan (for PSR curve) nu_list = range1; % 你也可以改成 nu_list = 8; 只看一个 Doppler nu_show = 8; % 用于画 AFfs 2D 对比图的 Doppler(必须在 nu_list 里) F = dftmtx(N)./sqrt(N); % unitary DFT matrix % 记录 PSR rec_raw = zeros(length(nu_list),1); rec_comp = zeros(length(nu_list),1); % 保存 nu_show 下的结果用于画图 AFfs_raw_show = []; AFfs_comp_show = []; cAF_show = []; % 也保存逐点匹配的 cAF(用于你原来的 AF2/AF3 部分对照) %% ===================== 主循环:扫 Doppler ===================== for idx_nu = 1:length(nu_list) nu = nu_list(idx_nu); % 逐点匹配 AF 的非相干累积容器(和你原来一致) cAF = zeros(N, M*N*2); % 2D-FFT AFfs 的 MC 平均容器(新增:raw & comp) AFfs_raw_acc = zeros(N, M); AFfs_comp_acc = zeros(N, M); for mc = 1:Nmc %% -------- OFDM gen -------- s = randi(16,[N,M]) - 1; x = pskmod(s,16); % N×M (subcarrier symbols) y = repmat(F'*x,[2,1]); % time-domain (N×M)->(2N×M), repeat twice %% -------- delay + Doppler (fast-time Doppler causes ICI) -------- yy1 = y(:); yy2 = circshift(yy1, tau); L = M*N*2; % total samples % Doppler across global sample index yy3 = yy2 .* exp(1i*2*pi*(0:L-1)'/L * nu); %% -------- transmit reference -------- xx = repmat(F'*x,[2,1]); xx = xx(:); %% -------- reshape received -------- y2 = reshape(yy3, N*2, M); % (2N)×M z = y2(:); %% ============================================================ % (1) 逐点匹配的 AF(和你原来一致)-> 累积到 cAF % ============================================================ AF = zeros(N, M*N*2); parfor i = 1:N row_AF = zeros(1, M*N*2); for j = 1:M*N*2 temp1 = z .* exp(-1i*2*pi*(0:L-1)'/L * j); temp2 = temp1 .* circshift(conj(xx), i); temp3 = reshape(temp2, N*2, M); temp4 = temp3(N+1:end, :); row_AF(j) = sum(temp4(:)); end AF(i,:) = row_AF; end cAF = cAF + abs(AF).^2; %% ============================================================ % (2) 相干(2D-FFT) AFfs:补偿前 & 逐 Doppler 点快时间补偿后 % ============================================================ % 取后半段(对应你原来 temp4 的那段) y_fast = y2(N+1:end, :); % N×M % ---------- (A) 补偿前:原始 AFfs_raw ---------- range_mat = F' * ((F*y_fast) .* conj(x)); % N×M (delay×pulse) AFfs_raw_mc = abs( fft(range_mat, M, 2) ).^2; % 沿慢时间(第2维)FFT -> N×M AFfs_raw_acc = AFfs_raw_acc + AFfs_raw_mc; % ---------- (B) 逐 Doppler bin 的快时间 Doppler 补偿:AFfs_comp ---------- AFfs_comp_mc = zeros(N, M); n_fast = (0:N-1).'; % fast-time sample index within each pulse p_idx = (0:M-1).'; % pulse index for k = 1:M % 将 k 映射到居中的 Doppler bin(覆盖正负频率) k0 = k-1; if k0 > M/2 k0 = k0 - M; end % slow-time FFT bin k0 对应的“每采样”归一化频率 cycles/sample % fd = k0 / (M * N * 2) fd = k0 / (M*N*2); % 只补偿“快时间内”的相位滚动,用于抑制 ICI rot_fast = exp(-1i*2*pi*fd*n_fast); % N×1 y_fast_comp = y_fast .* rot_fast; % N×M (隐式扩展) % 快时间 OFDM 匹配(子载波域乘 conj(x))+ IFFT 到 delay range_mat_comp = F' * ((F*y_fast_comp) .* conj(x)); % N×M % 取慢时间 FFT 的第 k 个 bin(等价相干合成该 Doppler 点) steering = exp(-1i*2*pi*p_idx*(k-1)/M); % M×1 AFfs_comp_mc(:,k) = abs(range_mat_comp * steering).^2; end AFfs_comp_acc = AFfs_comp_acc + AFfs_comp_mc; end %% -------- MC 平均 -------- AFfs_raw = AFfs_raw_acc / Nmc; AFfs_comp = AFfs_comp_acc / Nmc; %% -------- PSR(raw vs comp)-------- peak_raw = max(AFfs_raw(:)); rec_raw(idx_nu) = 10*log10( peak_raw / (sum(AFfs_raw(:)) - peak_raw) * (M*N+1) ); peak_comp = max(AFfs_comp(:)); rec_comp(idx_nu) = 10*log10( peak_comp / (sum(AFfs_comp(:)) - peak_comp) * (M*N+1) ); %% -------- 保存 nu_show 的 2D 图数据(用于画图)-------- if nu == nu_show AFfs_raw_show = AFfs_raw; AFfs_comp_show = AFfs_comp; cAF_show = cAF; end end %% ===================== 画 PSR 曲线对比 ===================== figure; plot(nu_list, rec_raw - max(rec_raw), 'o-', 'LineWidth', 1.2); hold on; plot(nu_list, rec_comp - max(rec_comp), 's-', 'LineWidth', 1.2); xlabel('Doppler Shift Index'); ylabel('PSR (normalized to each max) / dB'); title('PSR vs Doppler: BEFORE vs AFTER fast-time Doppler compensation'); grid on; legend('Raw AFfs', 'Compensated AFfs', 'Location', 'best'); figure; plot(nu_list, rec_raw, 'o-', 'LineWidth', 1.2); hold on; plot(nu_list, rec_comp, 's-', 'LineWidth', 1.2); xlabel('Doppler Shift Index'); ylabel('PSR / dB'); title('PSR vs Doppler (absolute): BEFORE vs AFTER compensation'); grid on; legend('Raw AFfs', 'Compensated AFfs', 'Location', 'best'); %% ===================== 画 nu_show 下的 AFfs 2D 对比 ===================== if ~isempty(AFfs_raw_show) AFfs_raw_dB = 10*log10(AFfs_raw_show ./ max(AFfs_raw_show(:))); AFfs_comp_dB = 10*log10(AFfs_comp_show ./ max(AFfs_comp_show(:))); figure; imagesc(ifftshift(AFfs_raw_dB,2)); axis xy; colormap jet; colorbar; caxis([-30 0]); xlabel('Doppler Bin (shifted)'); ylabel('Delay Bin'); title(['AFfs BEFORE compensation (nu = ', num2str(nu_show), ')']); figure; imagesc(ifftshift(AFfs_comp_dB,2)); axis xy; colormap jet; colorbar; caxis([-30 0]); xlabel('Doppler Bin (shifted)'); ylabel('Delay Bin'); title(['AFfs AFTER compensation (nu = ', num2str(nu_show), ')']); figure; imagesc(ifftshift(AFfs_comp_dB - AFfs_raw_dB,2)); axis xy; colormap jet; colorbar; xlabel('Doppler Bin (shifted)'); ylabel('Delay Bin'); title(['AFfs improvement (comp - raw) in dB (nu = ', num2str(nu_show), ')']); end %% ===================== (可选)保留你原来的 AF2/AF3 对照:用 nu_show 的 cAF_show ===================== if ~isempty(cAF_show) % 注意:cAF_show 是对 mc 累加后的 abs(AF)^2,因此平均时建议除以 Nmc cAF_avg = cAF_show / Nmc; %% 非相干累积(AF3) AF3 = zeros(N, N*2); for i = 1:M AF3 = AF3 + cAF_avg(:, i:M:end); end AF3 = AF3 / M; figure; imagesc(ifftshift(10*log10(AF3./max(AF3(:))))); axis xy; colormap jet; colorbar; caxis([-30 0]); xlabel('Doppler Index (Cyclic Shifted)'); ylabel('Delay Index'); title(['After Non-Coherent Integration (nu = ', num2str(nu_show), ')']); %% 未进行非相干累积(AF2):按脉冲块累加 AF2 = zeros(N, N*2); for i = 1:M AF2 = AF2 + cAF_avg(:, N*2*(i-1)+1:N*2*i); end AF2 = AF2 / M; figure; imagesc(ifftshift(10*log10(AF2./max(AF2(:))))); axis xy; colormap jet; colorbar; caxis([-30 0]); xlabel('Doppler Index (Cyclic Shifted)'); ylabel('Delay Index'); title(['Before Non-Coherent Integration (nu = ', num2str(nu_show), ')']); %% zero Doppler cut zero_doppler_AF2 = AF2(:, 1); zero_doppler_AF3 = AF3(:, 1); figure; plot(10*log10(abs(zero_doppler_AF2./max(zero_doppler_AF2))), 'r', 'LineWidth', 1.5); hold on; plot(10*log10(abs(zero_doppler_AF3./max(zero_doppler_AF3))), 'b', 'LineWidth', 1.5); xlabel('Delay Index'); grid on; legend('AF2', 'AF3'); title(['Zero Doppler Cut (nu = ', num2str(nu_show), ')']); %% zero delay cut doppler_index = -(N-1):N; zero_delay_AF2 = AF2(tau, :); zero_delay_AF3 = AF3(tau, :); figure; plot(doppler_index, ifftshift(10*log10(abs(zero_delay_AF2./max(zero_delay_AF2)))), 'r', 'LineWidth', 1.5); hold on; plot(doppler_index, ifftshift(10*log10(abs(zero_delay_AF3./max(zero_delay_AF3)))), 'b', 'LineWidth', 1.5); xlabel('Doppler Index'); grid on; legend('AF2', 'AF3'); title(['Zero Delay Cut (nu = ', num2str(nu_show), ')']); end
如果你想进一步“更精准地对齐”你逐点匹配 AF 里用的 Doppler 栅格(比如把 k 映射成和 j 一样的循环频率定义),我也可以帮你把 fd 的定义改成严格同一套频率采样,这样补偿会更贴近你 point-wise AF 的 Doppler 轴。
逐点的af不用留着 就比较我让你比较的就好
下面是完整精简版脚本:只计算并对比你要的 相干积分前 AFfs(2D-FFT AF) 的两种方案:
AFfs_rawAFfs_comp并输出:
PSR 随 nu 扫描的曲线对比nu_show 下的 AFfs_raw / AFfs_comp 2D 图对比 + 提升量图直接复制保存为
.m运行即可(逐点 AF 已删除)。
matlabclc; clear; format long %% ===================== 参数区 ===================== times = 1; M = 16; % slow-time pulses N = 32*times; % fast-time samples per pulse (useful part) Nmc = 10; % Monte Carlo runs rng(1545); tau = 4; % delay (samples) nu_list = -M:M; % Doppler index scan(和你原来 range1 一致) nu_show = 8; % 用于画 2D AFfs 对比的 Doppler(必须在 nu_list 里) F = dftmtx(N)./sqrt(N); % unitary DFT (N×N) % 记录 PSR rec_raw = zeros(length(nu_list),1); rec_comp = zeros(length(nu_list),1); % 保存 nu_show 下的 2D AFfs 用于画图 AFfs_raw_show = []; AFfs_comp_show = []; %% ===================== 主循环:扫 Doppler ===================== for idx_nu = 1:length(nu_list) nu = nu_list(idx_nu); % 2D-FFT AFfs 的 MC 累加容器(raw & comp) AFfs_raw_acc = zeros(N, M); AFfs_comp_acc = zeros(N, M); for mc = 1:Nmc %% -------- OFDM gen -------- s = randi(16,[N,M]) - 1; % N×M x = pskmod(s,16); % N×M (subcarrier symbols) % time-domain OFDM (repeat twice -> 2N×M) y = repmat(F' * x, [2,1]); % (2N)×M %% -------- delay + Doppler(快时间 Doppler 导致 ICI)-------- yy1 = y(:); yy2 = circshift(yy1, tau); L = M * N * 2; % total samples yy3 = yy2 .* exp(1i*2*pi*(0:L-1)'/L * nu); % global fast-time Doppler %% -------- reshape received -------- y2 = reshape(yy3, N*2, M); % (2N)×M % 取后半段(与你原来 temp4 / y2(N+1:end,:) 一致) y_fast = y2(N+1:end, :); % N×M %% ============================================================ % 方案A:补偿前 AFfs_raw(2D-FFT) % 处理链:快时间FFT->乘conj(x)->快时间IFFT(=F') 得delay像 -> 慢时间FFT %% ============================================================ range_mat = F' * ((F*y_fast) .* conj(x)); % N×M (delay×pulse) AFfs_raw_mc = abs( fft(range_mat, M, 2) ).^2; % N×M (delay×DopplerBin) AFfs_raw_acc = AFfs_raw_acc + AFfs_raw_mc; %% ============================================================ % 方案B:逐 Doppler bin 快时间 Doppler 补偿 AFfs_comp % 对每个 Doppler bin k: % 先 y_fast(n,p) * exp(-j2π fd(k) n) 去旋转(只补偿快时间相位滚动) % 再做与方案A同样的快时间处理 % 最后取慢时间FFT的第k个bin(steering 相干合成) %% ============================================================ AFfs_comp_mc = zeros(N, M); n_fast = (0:N-1).'; % fast-time index within each pulse p_idx = (0:M-1).'; % pulse index for k = 1:M % centered bin index k0 in [-M/2, M/2-1] k0 = k-1; if k0 > M/2 k0 = k0 - M; end % slow-time bin k0 对应的“每采样”归一化频率 cycles/sample % 因为 pulse-to-pulse 间隔是 2N 个采样点: % fd = k0 / (M * 2N) fd = k0 / (M * N * 2); % 快时间 Doppler 去旋转(抑制 ICI) rot_fast = exp(-1i*2*pi*fd*n_fast); % N×1 y_fast_comp = y_fast .* rot_fast; % N×M (implicit expand) % 与方案A同样的快时间处理得到 delay×pulse range_mat_comp = F' * ((F*y_fast_comp) .* conj(x)); % N×M % 取慢时间 FFT 第 k 个 Doppler bin(相干合成) steering = exp(-1i*2*pi*p_idx*(k-1)/M); % M×1 AFfs_comp_mc(:,k) = abs(range_mat_comp * steering).^2; end AFfs_comp_acc = AFfs_comp_acc + AFfs_comp_mc; end %% -------- MC 平均 -------- AFfs_raw = AFfs_raw_acc / Nmc; AFfs_comp = AFfs_comp_acc / Nmc; %% -------- PSR(raw vs comp)-------- peak_raw = max(AFfs_raw(:)); rec_raw(idx_nu) = 10*log10( peak_raw / (sum(AFfs_raw(:)) - peak_raw) * (M*N+1) ); peak_comp = max(AFfs_comp(:)); rec_comp(idx_nu) = 10*log10( peak_comp / (sum(AFfs_comp(:)) - peak_comp) * (M*N+1) ); %% -------- 保存 nu_show 用于 2D 对比图 -------- if nu == nu_show AFfs_raw_show = AFfs_raw; AFfs_comp_show = AFfs_comp; end end %% ===================== PSR 曲线对比 ===================== figure; plot(nu_list, rec_raw, 'o-', 'LineWidth', 1.2); hold on; plot(nu_list, rec_comp, 's-', 'LineWidth', 1.2); xlabel('Doppler Shift Index \nu'); ylabel('PSR / dB'); title('PSR vs Doppler: AFfs BEFORE vs AFTER fast-time Doppler compensation'); grid on; legend('Raw AFfs', 'Compensated AFfs', 'Location', 'best'); figure; plot(nu_list, rec_raw - max(rec_raw), 'o-', 'LineWidth', 1.2); hold on; plot(nu_list, rec_comp - max(rec_comp),'s-', 'LineWidth', 1.2); xlabel('Doppler Shift Index \nu'); ylabel('PSR (normalized) / dB'); title('PSR vs Doppler (normalized): Raw vs Compensated'); grid on; legend('Raw AFfs', 'Compensated AFfs', 'Location', 'best'); %% ===================== nu_show 下的 AFfs 2D 对比 ===================== if ~isempty(AFfs_raw_show) AFfs_raw_dB = 10*log10(AFfs_raw_show ./ max(AFfs_raw_show(:))); AFfs_comp_dB = 10*log10(AFfs_comp_show ./ max(AFfs_comp_show(:))); figure; imagesc(ifftshift(AFfs_raw_dB, 2)); % 只对 Doppler 维做 shift axis xy; colormap jet; colorbar; caxis([-30 0]); xlabel('Doppler Bin (shifted)'); ylabel('Delay Bin'); title(['AFfs BEFORE compensation (nu = ', num2str(nu_show), ')']); figure; imagesc(ifftshift(AFfs_comp_dB, 2)); axis xy; colormap jet; colorbar; caxis([-30 0]); xlabel('Doppler Bin (shifted)'); ylabel('Delay Bin'); title(['AFfs AFTER compensation (nu = ', num2str(nu_show), ')']); figure; imagesc(ifftshift(AFfs_comp_dB - AFfs_raw_dB, 2)); axis xy; colormap jet; colorbar; xlabel('Doppler Bin (shifted)'); ylabel('Delay Bin'); title(['AFfs improvement (comp - raw) in dB (nu = ', num2str(nu_show), ')']); end
如果你希望把 “逐 Doppler 点补偿”的 fd 定义改成严格按你原来 Doppler index(nu)那套去对齐(包括循环频率/shift 方式/频率标定),我也可以把 Doppler 轴从 bin 映射到 -(M-1):M 或者按你 nu_list 的定义重建,这样对比会更“同一坐标系”。
我们希望的psr应该是越低越好么
不是。按你代码里这个 PSR 定义,PSR 越大越好(越高表示主峰越“尖”、旁瓣/杂波越小)。
你这里算的是(本质上):
因此:
你图里如果出现 rec-max(rec) 全是负值,那只是做了“相对最大值归一化”,0 dB 那个点是最好,越往下越差;但在“绝对 PSR(rec)”那张图里,仍然是数值越大越好。
如果你想让“越低越好”,那通常用的是 ISLR/PSLR 这类“旁瓣比”指标(例如旁瓣能量/主瓣能量),那种确实是越低越好;但你现在这个 PSR 不是那个定义。
PSR 按你现在这套定义(主峰 / 其余能量)是 越大越好。你现在看到“补偿后 PSR 更低”,通常不是“补偿把主峰做坏了”,而是补偿把整张 AF 图的“其余能量”抬高了,导致分母变大 → PSR 变小。
下面是最常见、也最符合你这张曲线形状的原因(按重要性排序):
原始 AFfs_raw 是对 同一个 range_mat 做慢时间 FFT 得到所有 Doppler bin:
但你的 AFfs_comp 是:
每个 Doppler bin 都先用不同的快时间去旋转,再各算一列。
这等价于做了一个“多假设匹配滤波器组”,每一列用的都是不同预处理后的数据,于是:
AFfs_comp 的“旁瓣/杂散总能量”变大这也是你图里“补偿后整条曲线都更低”的典型现象。
你 PSR 的分母是 sum(AFfs(:)) - peak(全图除主峰外的所有能量)。
但你逐 Doppler 点补偿后,错误 Doppler 假设对应的列可能被抬高很多;这些能量全部进入分母,PSR 自然变差。
换句话说:你现在的 PSR 更像是在惩罚“整张图是不是很稀疏”。
而逐 Doppler 点补偿本质是“每列都做一次匹配”,会让图变得没那么稀疏。
nu_list = -M:M 本身在慢时间(M 点)上是混叠的慢时间只有 M=16 个 bin,但你扫了 33 个 nu。
nu 在慢时间上会 mod M 混叠,但它在快时间造成的频偏(ICI 强弱)并不等价,所以你用“bin 对应的 fd(k)”去补偿时,某些 nu 会出现“补偿不对味”。
这会让“补偿后曲线更平滑、更低”更明显。
最直接的验证方法:不要用全图 PSR,而是只在“目标 Doppler 列”上算一个 delay 维的 PSR(或 PSLR)。
对每个真值 nu,它对应的慢时间 Doppler bin 是:
matlabk_true = mod(nu, M); if k_true < 0, k_true = k_true + M; end k_true = k_true + 1; % MATLAB index
然后只用这一列算“列内 PSR”:
matlabcol_raw = AFfs_raw(:, k_true); col_comp = AFfs_comp(:, k_true); psr_col_raw = 10*log10( max(col_raw) / (sum(col_raw) - max(col_raw)) * (N+1) ); psr_col_comp = 10*log10( max(col_comp) / (sum(col_comp) - max(col_comp)) * (N+1) );
你大概率会看到:列内指标 comp ≥ raw(尤其是 Doppler 不小的时候),说明快时间补偿确实在抑制 ICI;只是“全图 PSR”被错误假设的列能量抬高给拖累了。
想让全图 PSR 也提升,你需要保证 Doppler 维仍然是对同一个数据矩阵做一个一致的变换。两条常用路线:
如果你愿意,我可以在你那份“完整代码”里直接加上 (a) 全图 PSR + (b) 目标列 PSR 两套曲线一起画出来,你就能一眼看到:全图 PSR 为什么掉、但目标列为什么其实提升了。
我们这样 不在原来的代码里面补偿,在我下面这个为基础来补偿:function [AFfs, tau_idx, nu_idx, peak_vals] = calc_AFfs_multi( ...
N, M, Nmc, tau, nu, flag, K, alpha, Kest, guard_r, guard_c)
% calc_AFfs_multi (N-structure, no 2N)
% 多目标 Monte-Carlo 期望 |RDM|^2,标准 2D-FFT 处理
texttau = tau(:).'; nu = nu(:).'; if nargin < 8 || isempty(alpha), alpha = 1; end if nargin < 9 || isempty(Kest), Kest = max(1, numel(tau)); end if nargin < 10 || isempty(guard_r), guard_r = 2; end if nargin < 11 || isempty(guard_c), guard_c = 2; end alpha = alpha(:).'; AF_sum = zeros(N,M); rng(1545,'twister'); seeds = randi(2^31-1, Nmc, 1, 'uint32'); parfor mc = 1:Nmc rng(double(seeds(mc)),'twister'); [Y, Xtd, Xf] = simulate_ofdm_echo_multi(N,M,tau,nu,flag,K,alpha); % 快时间 FFT -> 频域匹配滤波 -> 快时间 IFFT Yf = fft(Y, [], 1); % N×M R = ifft( Yf .* conj(Xf), [], 1 ); % N×M,range 压缩 % 慢时间 FFT -> Doppler 轴 RDM = fft(R, [], 2); % N×M AF_trial = abs(RDM).^2; AF_sum = AF_sum + AF_trial; end AFfs = AF_sum / Nmc; [tau_idx, nu_idx, peak_vals] = topK_peaks(AFfs, Kest, guard_r, guard_c);
end
%% ---------- Top-K 峰值 + 保护单元 ----------
function [r_idx, c_idx, vals] = topK_peaks(A, K, guard_r, guard_c)
Awork = A;
r_idx = zeros(K,1);
c_idx = zeros(K,1);
vals = zeros(K,1);
textfor k = 1:K [val, lin] = max(Awork(:)); if ~isfinite(val) || val <= 0 r_idx = r_idx(1:k-1); c_idx = c_idx(1:k-1); vals = vals(1:k-1); break; end [r, c] = ind2sub(size(Awork), lin); r_idx(k) = r; c_idx(k) = c; vals(k) = val; r1 = max(1, r-guard_r); r2 = min(size(Awork,1), r+guard_r); c1 = max(1, c-guard_c); c2 = min(size(Awork,2), c+guard_c); Awork(r1:r2, c1:c2) = -Inf; end
end
function [Y, Xtd, Xf] = simulate_ofdm_echo_multi(N,M,tau_vec,nu_vec,flag,K,amp)
tau_vec = tau_vec(:).';
nu_vec = nu_vec(:).';
amp = amp(:).';
textP = max([numel(tau_vec), numel(nu_vec), numel(amp)]); if numel(tau_vec)==1, tau_vec = repmat(tau_vec,1,P); end if numel(nu_vec)==1, nu_vec = repmat(nu_vec, 1,P); end if numel(amp)==1, amp = repmat(amp, 1,P); end tau_vec = mod(round(tau_vec), N); nu_vec = mod(round(nu_vec), M); s = randi(K,[N,M]) - 1; if flag == 1 Xf = pskmod(s, K); else Xf = qammod(s, K); end Xtd = sqrt(N) * ifft(Xf, [], 1); k = (0:N-1).'; m = 0:M-1; Y = complex(zeros(N,M)); for p = 1:P tau_p = tau_vec(p); nu_p = nu_vec(p); X_shift = circshift(Xtd, tau_p, 1); dop_fast = exp(1j*2*pi*nu_p * k/(M*N)); dop_slow = exp(1j*2*pi*nu_p * m/M); Dop = dop_fast * dop_slow; Y = Y + amp(p) * (X_shift .* Dop); end
end
看看应该补偿在哪一行是比较合理的,我认为是要和DAFT补偿的逻辑一样的
你这个版本里,最合理、也最“像 DAFT/预调制再FFT”的补偿位置就是:
在
simulate_ofdm_echo_multi得到Y之后、做快时间 FFT (Yf = fft(Y,[],1)) 之前,对Y做快时间去旋转(de-rotation)。
原因很简单:ICI 是在你对含有快时间线性相位的信号做 FFT 时产生的(子载波正交性被破坏),所以要在 FFT 之前把这段线性相位“拿掉”,才能抑制 ICI。
并且你在仿真里快时间 Doppler 项就是这句生成的:
matlabdop_fast = exp(1j*2*pi*nu_p * k/(M*N));
所以补偿项就应该是它的共轭(反相位):
matlabexp(-1j*2*pi*nu_h * k/(M*N))
下面给你一份基于你函数的完整“对比两种方案”的实现:
AFfs_raw:原始标准 2D-FFTAFfs_comp:对每个 Doppler bin 单独做快时间补偿(你想要的方式)⚠️ 关键点:你
simulate_ofdm_echo_multi里把nu做了mod(...,M),也就是 Doppler 是 0…M-1 的“环形索引”。
所以下面补偿时 也用同样的 0…M-1 去补偿(否则会对不上,补偿会变差)。
matlabfunction [AFfs_raw, AFfs_comp, peaks_raw, peaks_comp] = calc_AFfs_multi_compare( ... N, M, Nmc, tau, nu, flag, K, alpha, Kest, guard_r, guard_c) % calc_AFfs_multi_compare % 输出两套:标准2D-FFT的AFfs_raw,以及“逐Doppler点快时间补偿”的AFfs_comp tau = tau(:).'; nu = nu(:).'; if nargin < 8 || isempty(alpha), alpha = 1; end if nargin < 9 || isempty(Kest), Kest = max(1, numel(tau)); end if nargin < 10 || isempty(guard_r), guard_r = 2; end if nargin < 11 || isempty(guard_c), guard_c = 2; end alpha = alpha(:).'; AF_sum_raw = zeros(N, M); AF_sum_comp = zeros(N, M); % 用于 Doppler bin 提取的慢时间 steering(与 fft(R,[],2) 同相位定义) m = (0:M-1).'; W = exp(-1j * 2*pi/M * (m * (0:M-1))); % M×M,列对应 Doppler bin 0..M-1 % 快时间索引 k = (0:N-1).'; rng(1545,'twister'); seeds = randi(2^31-1, Nmc, 1, 'uint32'); parfor mc = 1:Nmc rng(double(seeds(mc)),'twister'); [Y, ~, Xf] = simulate_ofdm_echo_multi(N, M, tau, nu, flag, K, alpha); % Y: N×M %% ====================== % (A) RAW:标准 2D-FFT %% ====================== Yf = fft(Y, [], 1); % N×M R = ifft(Yf .* conj(Xf), [], 1); % N×M (range) RDM = fft(R, [], 2); % N×M (doppler) AF_trial_raw = abs(RDM).^2; %% ========================================== % (B) COMP:逐 Doppler bin 的快时间补偿 % 对每个 Doppler bin q=0..M-1: % 先 Y .* exp(-j2π q k/(M N)) % 再走同样的“快时间FFT-匹配-IFFT” % 最后只取该 bin(用 steering 等价 fft 的第 q 列) %% ========================================== AF_trial_comp = zeros(N, M); for q = 0:M-1 rot_fast = exp(-1j * 2*pi * q * k/(M*N)); % N×1 Yc = Y .* rot_fast; % N×M(隐式扩展;旧版可用bsxfun) Yf_c = fft(Yc, [], 1); R_c = ifft(Yf_c .* conj(Xf), [], 1); % 取 Doppler bin q(等价于 RDM(:,q+1)) AF_trial_comp(:, q+1) = abs(R_c * W(:, q+1)).^2; end AF_sum_raw = AF_sum_raw + AF_trial_raw; AF_sum_comp = AF_sum_comp + AF_trial_comp; end AFfs_raw = AF_sum_raw / Nmc; AFfs_comp = AF_sum_comp / Nmc; % 可选:输出 topK 峰值信息,方便你后续算PSR/定位 [r1,c1,v1] = topK_peaks(AFfs_raw, Kest, guard_r, guard_c); [r2,c2,v2] = topK_peaks(AFfs_comp, Kest, guard_r, guard_c); peaks_raw = struct('tau_idx', r1, 'nu_idx', c1, 'vals', v1); peaks_comp = struct('tau_idx', r2, 'nu_idx', c2, 'vals', v2); end %% ---------- Top-K 峰值 + 保护单元 ---------- function [r_idx, c_idx, vals] = topK_peaks(A, K, guard_r, guard_c) Awork = A; r_idx = zeros(K,1); c_idx = zeros(K,1); vals = zeros(K,1); for k = 1:K [val, lin] = max(Awork(:)); if ~isfinite(val) || val <= 0 r_idx = r_idx(1:k-1); c_idx = c_idx(1:k-1); vals = vals(1:k-1); break; end [r, c] = ind2sub(size(Awork), lin); r_idx(k) = r; c_idx(k) = c; vals(k) = val; r1 = max(1, r-guard_r); r2 = min(size(Awork,1), r+guard_r); c1 = max(1, c-guard_c); c2 = min(size(Awork,2), c+guard_c); Awork(r1:r2, c1:c2) = -Inf; end end function [Y, Xtd, Xf] = simulate_ofdm_echo_multi(N,M,tau_vec,nu_vec,flag,K,amp) tau_vec = tau_vec(:).'; nu_vec = nu_vec(:).'; amp = amp(:).'; P = max([numel(tau_vec), numel(nu_vec), numel(amp)]); if numel(tau_vec)==1, tau_vec = repmat(tau_vec,1,P); end if numel(nu_vec)==1, nu_vec = repmat(nu_vec, 1,P); end if numel(amp)==1, amp = repmat(amp, 1,P); end tau_vec = mod(round(tau_vec), N); nu_vec = mod(round(nu_vec), M); % 注意:这里把 Doppler 变成 0..M-1 的环形索引 s = randi(K,[N,M]) - 1; if flag == 1 Xf = pskmod(s, K); else Xf = qammod(s, K); end Xtd = sqrt(N) * ifft(Xf, [], 1); k = (0:N-1).'; m = 0:M-1; Y = complex(zeros(N,M)); for p = 1:P tau_p = tau_vec(p); nu_p = nu_vec(p); X_shift = circshift(Xtd, tau_p, 1); dop_fast = exp(1j*2*pi*nu_p * k/(M*N)); dop_slow = exp(1j*2*pi*nu_p * m/M); Dop = dop_fast * dop_slow; Y = Y + amp(p) * (X_shift .* Dop); end end
就在你原函数里这两行之间:
matlab[Y, Xtd, Xf] = simulate_ofdm_echo_multi(...); Yf = fft(Y, [], 1);
补偿就是插在中间(对 Y 乘 exp(-j2π nu_h k/(MN))),这就是最标准的“DAFT式:先预相位/去相位,再做FFT”。
如果你用的是全图 PSR(主峰 / 其余所有能量),那么“逐 Doppler 假设”这种做法会让很多错误假设的列也被某些东西“部分对齐”,分母会变大,所以 PSR 可能看起来更差。
更公平的评价方式是:
topK_peaks 找到主峰后,在其保护单元外算 ISLR/PSLR。如果你把你现在算 PSR 的方式贴出来(你希望用全图还是列内),我可以把对比指标那部分也给你改成“更符合你想看的 ICI 改善”的版本。
把你现在这个思路 写成一个m文件,而不是函数
下面给你一份完整的 MATLAB 脚本(.m 文件),不是函数;直接运行即可对比两套方案:
Y -> FFT快时间 -> 频域匹配 -> IFFT快时间 -> FFT慢时间q,在快时间 FFT 之前做同时我给了两种 PSR:
把下面保存为例如:demo_AFfs_fastDopplerComp.m 直接运行。
matlabclc; clear; close all; format long; %% ===================== 参数区 ===================== N = 32; % fast-time samples per pulse M = 16; % slow-time pulses Nmc = 10; % Monte-Carlo runs tau0 = 4; % delay flag = 1; % 1: PSK, else: QAM Kmod = 16; % modulation order alpha = 1; % target amplitude (single target) nu_list = -M:M; % 扫描的 Doppler index(注意:仿真里 nu 会 mod M) nu_show = 8; % 画2D图用的 Doppler index(必须在 nu_list 里) % 保护单元(如果你想找峰值也可用;本脚本主要画图/算PSR) guard_r = 2; guard_c = 2; % 快时间/慢时间索引 k_fast = (0:N-1).'; m_slow = (0:M-1).'; % slow-time FFT 的 steering(与 fft(R,[],2) 的相位定义一致) W = exp(-1j * 2*pi/M * (m_slow * (0:M-1))); % M×M % 记录 PSR:两种口径(全图/真列) PSR_full_raw = zeros(numel(nu_list),1); PSR_full_comp = zeros(numel(nu_list),1); PSR_col_raw = zeros(numel(nu_list),1); PSR_col_comp = zeros(numel(nu_list),1); % 保存用于展示的 2D AFfs(nu_show) AFfs_raw_show = []; AFfs_comp_show = []; %% ===================== 主循环:扫 Doppler ===================== rng(1545,'twister'); % 固定随机性(可复现) seeds = randi(2^31-1, Nmc, 1, 'uint32'); % parfor 可复现 for idx = 1:numel(nu_list) nu0 = nu_list(idx); AF_sum_raw = zeros(N,M); AF_sum_comp = zeros(N,M); parfor mc = 1:Nmc rng(double(seeds(mc)),'twister'); % ---------- 生成回波(N-structure:Y 是 N×M) ---------- [Y, ~, Xf] = simulate_ofdm_echo_multi(N, M, tau0, nu0, flag, Kmod, alpha); %% ============ 方案 A:RAW(标准2D-FFT) ============ Yf = fft(Y, [], 1); % 快时间 FFT R = ifft(Yf .* conj(Xf), [], 1); % 匹配滤波 + 快时间 IFFT(range 压缩) RDM = fft(R, [], 2); % 慢时间 FFT(Doppler) AF_trial_raw = abs(RDM).^2; %% ============ 方案 B:逐 Doppler bin 快时间补偿 ============ % 关键:补偿位置 = 在快时间 FFT 之前,对 Y 乘 e^{-j2π q k/(MN)} AF_trial_comp = zeros(N,M); for q = 0:M-1 rot_fast = exp(-1j * 2*pi * q * k_fast/(M*N)); % N×1 % 兼容老版本 MATLAB:用 bsxfun 做维度扩展 Yc = bsxfun(@times, Y, rot_fast); % N×M Yf_c = fft(Yc, [], 1); R_c = ifft(Yf_c .* conj(Xf), [], 1); % 只取 Doppler bin = q(等价于 fft(R_c,[],2) 的第 q+1 列) AF_trial_comp(:, q+1) = abs(R_c * W(:, q+1)).^2; end % parfor reduction AF_sum_raw = AF_sum_raw + AF_trial_raw; AF_sum_comp = AF_sum_comp + AF_trial_comp; end AFfs_raw = AF_sum_raw / Nmc; AFfs_comp = AF_sum_comp / Nmc; %% ===================== PSR 计算(两种口径) ===================== % (1) 全图 PSR(你之前用的那种:peak / (sum-peak)) peak_raw = max(AFfs_raw(:)); peak_comp = max(AFfs_comp(:)); PSR_full_raw(idx) = 10*log10( peak_raw / (sum(AFfs_raw(:)) - peak_raw ) * (M*N+1) ); PSR_full_comp(idx) = 10*log10( peak_comp / (sum(AFfs_comp(:)) - peak_comp) * (M*N+1) ); % (2) 真值 Doppler 对应列的 PSR(更贴近“ICI抑制是否有效”) % 注意:simulate_ofdm_echo_multi 内部 nu 会 mod M,所以真值列为: q_true = mod(round(nu0), M); % 0..M-1 col_raw = AFfs_raw(:, q_true+1); col_comp = AFfs_comp(:, q_true+1); pk1 = max(col_raw); pk2 = max(col_comp); PSR_col_raw(idx) = 10*log10( pk1 / (sum(col_raw) - pk1) * (N+1) ); PSR_col_comp(idx) = 10*log10( pk2 / (sum(col_comp) - pk2) * (N+1) ); %% 保存展示用 2D 图 if nu0 == nu_show AFfs_raw_show = AFfs_raw; AFfs_comp_show = AFfs_comp; end end %% ===================== 画 PSR 曲线对比 ===================== figure; plot(nu_list, PSR_full_raw, 'o-', 'LineWidth', 1.2); hold on; plot(nu_list, PSR_full_comp, 's-', 'LineWidth', 1.2); grid on; xlabel('Doppler index \nu'); ylabel('PSR\_full / dB'); title('PSR\_full (全图口径):Raw vs Per-bin Fast-time Compensation'); legend('Raw', 'Comp', 'Location', 'best'); figure; plot(nu_list, PSR_col_raw, 'o-', 'LineWidth', 1.2); hold on; plot(nu_list, PSR_col_comp, 's-', 'LineWidth', 1.2); grid on; xlabel('Doppler index \nu'); ylabel('PSR\_col / dB'); title('PSR\_col(真值列口径):Raw vs Per-bin Fast-time Compensation'); legend('Raw', 'Comp', 'Location', 'best'); %% ===================== 画 2D AFfs 对比(nu_show) ===================== if ~isempty(AFfs_raw_show) AF_raw_dB = 10*log10(AFfs_raw_show ./ max(AFfs_raw_show(:))); AF_comp_dB = 10*log10(AFfs_comp_show ./ max(AFfs_comp_show(:))); figure; imagesc(fftshift(AF_raw_dB, 2)); axis xy; colormap jet; colorbar; caxis([-30 0]); xlabel('Doppler bin (fftshift)'); ylabel('Delay bin'); title(['AFfs RAW (nu = ', num2str(nu_show), ')']); figure; imagesc(fftshift(AF_comp_dB, 2)); axis xy; colormap jet; colorbar; caxis([-30 0]); xlabel('Doppler bin (fftshift)'); ylabel('Delay bin'); title(['AFfs COMP (nu = ', num2str(nu_show), ')']); figure; imagesc(fftshift(AF_comp_dB - AF_raw_dB, 2)); axis xy; colormap jet; colorbar; xlabel('Doppler bin (fftshift)'); ylabel('Delay bin'); title(['AFfs improvement (COMP - RAW) dB (nu = ', num2str(nu_show), ')']); end %% ===================== 本脚本用到的本地函数 ===================== function [Y, Xtd, Xf] = simulate_ofdm_echo_multi(N,M,tau_vec,nu_vec,flag,K,amp) tau_vec = tau_vec(:).'; nu_vec = nu_vec(:).'; amp = amp(:).'; P = max([numel(tau_vec), numel(nu_vec), numel(amp)]); if numel(tau_vec)==1, tau_vec = repmat(tau_vec,1,P); end if numel(nu_vec)==1, nu_vec = repmat(nu_vec, 1,P); end if numel(amp)==1, amp = repmat(amp, 1,P); end tau_vec = mod(round(tau_vec), N); nu_vec = mod(round(nu_vec), M); % 这里把 Doppler index 做了 mod M(环形) s = randi(K,[N,M]) - 1; if flag == 1 Xf = pskmod(s, K); else Xf = qammod(s, K); end Xtd = sqrt(N) * ifft(Xf, [], 1); k = (0:N-1).'; m = 0:M-1; Y = complex(zeros(N,M)); for p = 1:P tau_p = tau_vec(p); nu_p = nu_vec(p); X_shift = circshift(Xtd, tau_p, 1); % 你原模型:快时间 dop_fast + 慢时间 dop_slow dop_fast = exp(1j*2*pi*nu_p * k/(M*N)); dop_slow = exp(1j*2*pi*nu_p * m/M); Dop = dop_fast * dop_slow; Y = Y + amp(p) * (X_shift .* Dop); end end
就在脚本里这段的位置(与 DAFT 的“先去相位再 FFT”完全一致):
matlab[Y, ~, Xf] = simulate_ofdm_echo_multi(...); % ——就在这里对 Y 做快时间去旋转(de-rotation)—— % 然后再做 Yf = fft(Y,[],1) Yf = fft(Y, [], 1);
如果你运行后仍然发现 PSR_full 变差、但 PSR_col 变好,这是正常的:逐 bin 补偿本质是“多假设匹配”,会把很多“错误 bin”也抬起来,从而拉大全图分母;但对“真值 bin”会更聚焦、更能体现 ICI 被压下去。你要我把指标改成 PSLR/ISLR(更常用于 AF 旁瓣评价)也可以。
不用imagesc来画图 而是用surf来对比
下面给你一份完整脚本 .m(不是函数),和我上一版逻辑一致,只是把 2D 图对比的绘图全部改成 surf(Raw / Comp / 差值),并且用了 fftshift 把 Doppler 维居中显示。直接复制保存为 demo_AFfs_fastDopplerComp_surf.m 运行即可。
matlabclc; clear; close all; format long; %% ===================== 参数区 ===================== N = 32; % fast-time samples per pulse M = 16; % slow-time pulses Nmc = 10; % Monte-Carlo runs tau0 = 4; % delay flag = 1; % 1: PSK, else: QAM Kmod = 16; % modulation order alpha = 1; % target amplitude (single target) nu_list = -M:M; % 扫描的 Doppler index(注意:仿真里 nu 会 mod M) nu_show = 8; % 用于画 2D surf 对比的 Doppler index(必须在 nu_list 里) % 快时间/慢时间索引 k_fast = (0:N-1).'; m_slow = (0:M-1).'; % slow-time FFT 的 steering(与 fft(R,[],2) 的相位定义一致) W = exp(-1j * 2*pi/M * (m_slow * (0:M-1))); % M×M % 记录 PSR:两种口径(全图/真列) PSR_full_raw = zeros(numel(nu_list),1); PSR_full_comp = zeros(numel(nu_list),1); PSR_col_raw = zeros(numel(nu_list),1); PSR_col_comp = zeros(numel(nu_list),1); % 保存用于展示的 2D AFfs(nu_show) AFfs_raw_show = []; AFfs_comp_show = []; %% ===================== 主循环:扫 Doppler ===================== rng(1545,'twister'); % 固定随机性(可复现) seeds = randi(2^31-1, Nmc, 1, 'uint32'); % parfor 可复现 for idx = 1:numel(nu_list) nu0 = nu_list(idx); AF_sum_raw = zeros(N,M); AF_sum_comp = zeros(N,M); parfor mc = 1:Nmc rng(double(seeds(mc)),'twister'); % ---------- 生成回波(N-structure:Y 是 N×M) ---------- [Y, ~, Xf] = simulate_ofdm_echo_multi(N, M, tau0, nu0, flag, Kmod, alpha); %% ============ 方案 A:RAW(标准2D-FFT) ============ Yf = fft(Y, [], 1); % 快时间 FFT R = ifft(Yf .* conj(Xf), [], 1); % 匹配滤波 + 快时间 IFFT(range 压缩) RDM = fft(R, [], 2); % 慢时间 FFT(Doppler) AF_trial_raw = abs(RDM).^2; %% ============ 方案 B:逐 Doppler bin 快时间补偿 ============ % 补偿位置:在快时间 FFT 之前,对 Y 乘 e^{-j2π q k/(MN)} AF_trial_comp = zeros(N,M); for q = 0:M-1 rot_fast = exp(-1j * 2*pi * q * k_fast/(M*N)); % N×1 Yc = bsxfun(@times, Y, rot_fast); % N×M Yf_c = fft(Yc, [], 1); R_c = ifft(Yf_c .* conj(Xf), [], 1); % 只取 Doppler bin = q(等价于 fft(R_c,[],2) 的第 q+1 列) AF_trial_comp(:, q+1) = abs(R_c * W(:, q+1)).^2; end AF_sum_raw = AF_sum_raw + AF_trial_raw; AF_sum_comp = AF_sum_comp + AF_trial_comp; end AFfs_raw = AF_sum_raw / Nmc; AFfs_comp = AF_sum_comp / Nmc; %% ===================== PSR 计算(两种口径) ===================== % (1) 全图 PSR peak_raw = max(AFfs_raw(:)); peak_comp = max(AFfs_comp(:)); PSR_full_raw(idx) = 10*log10( peak_raw / (sum(AFfs_raw(:)) - peak_raw ) * (M*N+1) ); PSR_full_comp(idx) = 10*log10( peak_comp / (sum(AFfs_comp(:)) - peak_comp) * (M*N+1) ); % (2) 真值 Doppler 对应列 PSR(更能反映 ICI 抑制) q_true = mod(round(nu0), M); % 0..M-1(因为仿真里 nu 会 mod M) col_raw = AFfs_raw(:, q_true+1); col_comp = AFfs_comp(:, q_true+1); pk1 = max(col_raw); pk2 = max(col_comp); PSR_col_raw(idx) = 10*log10( pk1 / (sum(col_raw) - pk1) * (N+1) ); PSR_col_comp(idx) = 10*log10( pk2 / (sum(col_comp) - pk2) * (N+1) ); %% 保存展示用 2D 图 if nu0 == nu_show AFfs_raw_show = AFfs_raw; AFfs_comp_show = AFfs_comp; end end %% ===================== PSR 曲线对比 ===================== figure; plot(nu_list, PSR_full_raw, 'o-', 'LineWidth', 1.2); hold on; plot(nu_list, PSR_full_comp, 's-', 'LineWidth', 1.2); grid on; xlabel('Doppler index \nu'); ylabel('PSR\_full / dB'); title('PSR\_full (全图口径):Raw vs Per-bin Fast-time Compensation'); legend('Raw', 'Comp', 'Location', 'best'); figure; plot(nu_list, PSR_col_raw, 'o-', 'LineWidth', 1.2); hold on; plot(nu_list, PSR_col_comp, 's-', 'LineWidth', 1.2); grid on; xlabel('Doppler index \nu'); ylabel('PSR\_col / dB'); title('PSR\_col(真值列口径):Raw vs Per-bin Fast-time Compensation'); legend('Raw', 'Comp', 'Location', 'best'); %% ===================== 用 surf 画 2D AFfs 对比(nu_show) ===================== if ~isempty(AFfs_raw_show) % 归一化到各自峰值并转 dB AF_raw_dB = 10*log10(AFfs_raw_show ./ max(AFfs_raw_show(:))); AF_comp_dB = 10*log10(AFfs_comp_show ./ max(AFfs_comp_show(:))); AF_impr_dB = AF_comp_dB - AF_raw_dB; % Doppler 维居中显示(只 shift 第2维) AF_raw_dB_s = fftshift(AF_raw_dB, 2); AF_comp_dB_s = fftshift(AF_comp_dB, 2); AF_impr_dB_s = fftshift(AF_impr_dB, 2); % 轴 delay_axis = 0:N-1; doppler_axis = (-floor(M/2)):(ceil(M/2)-1); % 对应 fftshift 后的列顺序 [DOP, DEL] = meshgrid(doppler_axis, delay_axis); % --- RAW surf --- figure; surf(DOP, DEL, AF_raw_dB_s); shading interp; colorbar; xlabel('Doppler bin (shifted)'); ylabel('Delay bin'); zlabel('Normalized Power / dB'); title(['AFfs RAW (surf) nu = ', num2str(nu_show)]); zlim([-40 0]); % 你想看更深可改 % --- COMP surf --- figure; surf(DOP, DEL, AF_comp_dB_s); shading interp; colorbar; xlabel('Doppler bin (shifted)'); ylabel('Delay bin'); zlabel('Normalized Power / dB'); title(['AFfs COMP (surf) nu = ', num2str(nu_show)]); zlim([-40 0]); % --- Improvement surf --- figure; surf(DOP, DEL, AF_impr_dB_s); shading interp; colorbar; xlabel('Doppler bin (shifted)'); ylabel('Delay bin'); zlabel('Delta / dB'); title(['AFfs Improvement (COMP - RAW) (surf) nu = ', num2str(nu_show)]); end %% ===================== 本脚本用到的本地函数 ===================== function [Y, Xtd, Xf] = simulate_ofdm_echo_multi(N,M,tau_vec,nu_vec,flag,K,amp) tau_vec = tau_vec(:).'; nu_vec = nu_vec(:).'; amp = amp(:).'; P = max([numel(tau_vec), numel(nu_vec), numel(amp)]); if numel(tau_vec)==1, tau_vec = repmat(tau_vec,1,P); end if numel(nu_vec)==1, nu_vec = repmat(nu_vec, 1,P); end if numel(amp)==1, amp = repmat(amp, 1,P); end tau_vec = mod(round(tau_vec), N); nu_vec = mod(round(nu_vec), M); % Doppler index 做 mod M(环形) s = randi(K,[N,M]) - 1; if flag == 1 Xf = pskmod(s, K); else Xf = qammod(s, K); end Xtd = sqrt(N) * ifft(Xf, [], 1); k = (0:N-1).'; m = 0:M-1; Y = complex(zeros(N,M)); for p = 1:P tau_p = tau_vec(p); nu_p = nu_vec(p); X_shift = circshift(Xtd, tau_p, 1); dop_fast = exp(1j*2*pi*nu_p * k/(M*N)); dop_slow = exp(1j*2*pi*nu_p * m/M); Dop = dop_fast * dop_slow; Y = Y + amp(p) * (X_shift .* Dop); end end
如果你还想把 surf 的视角(view)、或者把 z 轴改成线性幅度而不是 dB、或者把 zlim 做成自动/一致(raw 和 comp 用同一个峰值归一化)我也可以顺手帮你改。
你这个现象不是算法坏了,而是Doppler bin 的“循环频率 + fftshift 显示方式”导致的,尤其 M 为偶数时 M/2 那个 bin 是 Nyquist 点,在 fftshift 后必然跑到边界。
你仿真里 Doppler 被写成了 循环索引:
matlabnu_vec = mod(round(nu_vec), M); % 0..M-1
而 fft(R,[],2) 的 Doppler bin 本来就是 0..M-1。
你画图时又做了:
matlabAF = fftshift(AF, 2); doppler_axis = -M/2 : M/2-1;
对于 M=64:
q = 63(你说的“最大”)在“居中坐标”里等价于 -1fftshift 后会出现在 0 附近(中间),所以你看到它“跑到中央”。q = 32 = M/2 是 Nyquist bin(等价于 -32)fftshift 会把 Nyquist 分量放到第一列(最边上),所以你看到它“跑到边上”。这完全是 FFT/fftshift 的标准行为。
最简单:画图不要 fftshift,横轴直接用 0:M-1。
这样:
nu = 32 就会在横轴中间附近nu = 63 就会在横轴末端(不会跑回中间)把你脚本里 surf 画图那一段替换成下面这个(RAW/COMP/提升都改好了):
matlab% ===================== 用 surf 画 2D AFfs 对比(不 fftshift) ===================== if ~isempty(AFfs_raw_show) % 归一化到各自峰值并转 dB AF_raw_dB = 10*log10(AFfs_raw_show ./ max(AFfs_raw_show(:))); AF_comp_dB = 10*log10(AFfs_comp_show ./ max(AFfs_comp_show(:))); AF_impr_dB = AF_comp_dB - AF_raw_dB; % 轴(注意:这里是 0..M-1,不做 shift) delay_axis = 0:N-1; doppler_axis = 0:M-1; [DOP, DEL] = meshgrid(doppler_axis, delay_axis); figure; surf(DOP, DEL, AF_raw_dB); shading interp; colorbar; xlabel('Doppler bin (0..M-1)'); ylabel('Delay bin'); zlabel('Normalized Power / dB'); title(['AFfs RAW (surf) nu\_in = ', num2str(nu_show), ... ', nu\_bin = ', num2str(mod(round(nu_show),M))]); zlim([-40 0]); figure; surf(DOP, DEL, AF_comp_dB); shading interp; colorbar; xlabel('Doppler bin (0..M-1)'); ylabel('Delay bin'); zlabel('Normalized Power / dB'); title(['AFfs COMP (surf) nu\_in = ', num2str(nu_show), ... ', nu\_bin = ', num2str(mod(round(nu_show),M))]); zlim([-40 0]); figure; surf(DOP, DEL, AF_impr_dB); shading interp; colorbar; xlabel('Doppler bin (0..M-1)'); ylabel('Delay bin'); zlabel('\Delta / dB'); title(['AFfs Improvement (COMP-RAW) (surf) nu\_in = ', num2str(nu_show)]); end
fftshift 的“物理频率轴 [-M/2, M/2-1]”怎么办?那就要接受一个事实:偶数点 FFT 的 Nyquist(±M/2)在 shift 后就是在边上。
也就是说:nu = M/2 显示在边界是“正确的”,不是错。
你要我可以给你同时画两张:
0..M-1(工程 bin 索引)fftshift(正负频率)你现在更偏向哪种坐标系:0..M-1(按 bin)还是 [-M/2..M/2-1](按正负频率)?我可以把整份脚本统一成你要的那一种。
刚才这个没啥问题了,再看看真值列,结果好像有点一般,因为真值的补偿的感觉很好了。真值列要不我们扩大一个口径,比如周边几列这种?然后同时在下面的代码里面再加上zero delay 和zero doppler的slice,以及实际值的delay和doppler的slice:clc; clear; close all;
format long;
%% ===================== 参数区 =====================
N = 64; % fast-time samples per pulse
M = 64; % slow-time pulses
Nmc = 100; % Monte-Carlo runs
tau0 = 4; % delay
flag = 1; % 1: PSK, else: QAM
Kmod = 16; % modulation order
alpha = 1; % target amplitude (single target)
nu_list = -M:M; % 扫描的 Doppler index(注意:仿真里 nu 会 mod M)
nu_show = M-1; % 用于画 2D surf 对比的 Doppler index(必须在 nu_list 里)
% 快时间/慢时间索引
k_fast = (0:N-1).';
m_slow = (0:M-1).';
% slow-time FFT 的 steering(与 fft(R,[],2) 的相位定义一致)
W = exp(-1j * 2*pi/M * (m_slow * (0:M-1))); % M×M
% 记录 PSR:两种口径(全图/真列)
PSR_full_raw = zeros(numel(nu_list),1);
PSR_full_comp = zeros(numel(nu_list),1);
PSR_col_raw = zeros(numel(nu_list),1);
PSR_col_comp = zeros(numel(nu_list),1);
% 保存用于展示的 2D AFfs(nu_show)
AFfs_raw_show = [];
AFfs_comp_show = [];
%% ===================== 主循环:扫 Doppler =====================
rng(1545,'twister'); % 固定随机性(可复现)
seeds = randi(2^31-1, Nmc, 1, 'uint32'); % parfor 可复现
for idx = 1:numel(nu_list)
nu0 = nu_list(idx);
textAF_sum_raw = zeros(N,M); AF_sum_comp = zeros(N,M); parfor mc = 1:Nmc rng(double(seeds(mc)),'twister'); % ---------- 生成回波(N-structure:Y 是 N×M) ---------- [Y, ~, Xf] = simulate_ofdm_echo_multi(N, M, tau0, nu0, flag, Kmod, alpha); %% ============ 方案 A:RAW(标准2D-FFT) ============ Yf = fft(Y, [], 1); % 快时间 FFT R = ifft(Yf .* conj(Xf), [], 1); % 匹配滤波 + 快时间 IFFT(range 压缩) RDM = fft(R, [], 2); % 慢时间 FFT(Doppler) AF_trial_raw = abs(RDM).^2; %% ============ 方案 B:逐 Doppler bin 快时间补偿 ============ % 补偿位置:在快时间 FFT 之前,对 Y 乘 e^{-j2π q k/(MN)} AF_trial_comp = zeros(N,M); for q = 0:M-1 rot_fast = exp(-1j * 2*pi * q * k_fast/(M*N)); % N×1 Yc = bsxfun(@times, Y, rot_fast); % N×M Yf_c = fft(Yc, [], 1); R_c = ifft(Yf_c .* conj(Xf), [], 1); % 只取 Doppler bin = q(等价于 fft(R_c,[],2) 的第 q+1 列) AF_trial_comp(:, q+1) = abs(R_c * W(:, q+1)).^2; end AF_sum_raw = AF_sum_raw + AF_trial_raw; AF_sum_comp = AF_sum_comp + AF_trial_comp; end AFfs_raw = AF_sum_raw / Nmc; AFfs_comp = AF_sum_comp / Nmc; %% ===================== PSR 计算(两种口径) ===================== % (1) 全图 PSR peak_raw = max(AFfs_raw(:)); peak_comp = max(AFfs_comp(:)); PSR_full_raw(idx) = 10*log10( peak_raw / (sum(AFfs_raw(:)) - peak_raw ) * (M*N+1) ); PSR_full_comp(idx) = 10*log10( peak_comp / (sum(AFfs_comp(:)) - peak_comp) * (M*N+1) ); % (2) 真值 Doppler 对应列 PSR(更能反映 ICI 抑制) q_true = mod(round(nu0), M); % 0..M-1(因为仿真里 nu 会 mod M) col_raw = AFfs_raw(:, q_true+1); col_comp = AFfs_comp(:, q_true+1); pk1 = max(col_raw); pk2 = max(col_comp); PSR_col_raw(idx) = 10*log10( pk1 / (sum(col_raw) - pk1) * (N+1) ); PSR_col_comp(idx) = 10*log10( pk2 / (sum(col_comp) - pk2) * (N+1) ); %% 保存展示用 2D 图 if nu0 == nu_show AFfs_raw_show = AFfs_raw; AFfs_comp_show = AFfs_comp; end
end
%% ===================== PSR 曲线对比 =====================
figure;
plot(nu_list, PSR_full_raw, 'o-', 'LineWidth', 1.2); hold on;
plot(nu_list, PSR_full_comp, 's-', 'LineWidth', 1.2);
grid on; xlabel('Doppler index \nu'); ylabel('PSR_full / dB');
title('PSR_full (全图口径):Raw vs Per-bin Fast-time Compensation');
legend('Raw', 'Comp', 'Location', 'best');
figure;
plot(nu_list, PSR_col_raw, 'o-', 'LineWidth', 1.2); hold on;
plot(nu_list, PSR_col_comp, 's-', 'LineWidth', 1.2);
grid on; xlabel('Doppler index \nu'); ylabel('PSR_col / dB');
title('PSR_col(真值列口径):Raw vs Per-bin Fast-time Compensation');
legend('Raw', 'Comp', 'Location', 'best');
%% ===================== 用 surf 画 2D AFfs 对比(nu_show) =====================
% ===================== 用 surf 画 2D AFfs 对比(不 fftshift) =====================
if ~isempty(AFfs_raw_show)
% 归一化到各自峰值并转 dB
AF_raw_dB = 10log10(AFfs_raw_show ./ max(AFfs_raw_show(:)));
AF_comp_dB = 10log10(AFfs_comp_show ./ max(AFfs_comp_show(:)));
AF_impr_dB = AF_comp_dB - AF_raw_dB;
text% 轴(注意:这里是 0..M-1,不做 shift) delay_axis = 0:N-1; doppler_axis = 0:M-1; [DOP, DEL] = meshgrid(doppler_axis, delay_axis); figure; surf(DOP, DEL, AF_raw_dB); shading interp; colorbar; xlabel('Doppler bin (0..M-1)'); ylabel('Delay bin'); zlabel('Normalized Power / dB'); title(['AFfs RAW (surf) nu\_in = ', num2str(nu_show), ... ', nu\_bin = ', num2str(mod(round(nu_show),M))]); %zlim([-60 0]); figure; surf(DOP, DEL, AF_comp_dB); shading interp; colorbar; xlabel('Doppler bin (0..M-1)'); ylabel('Delay bin'); zlabel('Normalized Power / dB'); title(['AFfs COMP (surf) nu\_in = ', num2str(nu_show), ... ', nu\_bin = ', num2str(mod(round(nu_show),M))]); %zlim([-60 0]); figure; surf(DOP, DEL, AF_impr_dB); shading interp; colorbar; xlabel('Doppler bin (0..M-1)'); ylabel('Delay bin'); zlabel('\Delta / dB'); title(['AFfs Improvement (COMP-RAW) (surf) nu\_in = ', num2str(nu_show)]);
end
%% ===================== 本脚本用到的本地函数 =====================
function [Y, Xtd, Xf] = simulate_ofdm_echo_multi(N,M,tau_vec,nu_vec,flag,K,amp)
tau_vec = tau_vec(:).';
nu_vec = nu_vec(:).';
amp = amp(:).';
textP = max([numel(tau_vec), numel(nu_vec), numel(amp)]); if numel(tau_vec)==1, tau_vec = repmat(tau_vec,1,P); end if numel(nu_vec)==1, nu_vec = repmat(nu_vec, 1,P); end if numel(amp)==1, amp = repmat(amp, 1,P); end tau_vec = mod(round(tau_vec), N); nu_vec = mod(round(nu_vec), M); % Doppler index 做 mod M(环形) s = randi(K,[N,M]) - 1; if flag == 1 Xf = pskmod(s, K); else Xf = qammod(s, K); end Xtd = sqrt(N) * ifft(Xf, [], 1); k = (0:N-1).'; m = 0:M-1; Y = complex(zeros(N,M)); for p = 1:P tau_p = tau_vec(p); nu_p = nu_vec(p); X_shift = circshift(Xtd, tau_p, 1); dop_fast = exp(1j*2*pi*nu_p * k/(M*N)); dop_slow = exp(1j*2*pi*nu_p * m/M); Dop = dop_fast * dop_slow; Y = Y + amp(p) * (X_shift .* Dop); end
end
你现在的 **PSR_col(只取真值 Doppler 那一列)**之所以“看起来一般”,最常见原因是:
所以可以把“真值列口径”扩大成 真值 Doppler 附近 ±B 列的能量合成(band integration),再算一个 PSR_band,更符合你想观察的“补偿后能量回聚”。
另外你要的切片我也加上了(Raw vs Comp 同图对比):
下面是你给的脚本基础上直接改好的完整 .m 文件(仍然用 surf 画 2D,对切片用 plot):
matlabclc; clear; close all; format long; %% ===================== 参数区 ===================== N = 64; % fast-time samples per pulse M = 64; % slow-time pulses Nmc = 100; % Monte-Carlo runs tau0 = 4; % true delay (samples) flag = 1; % 1: PSK, else: QAM Kmod = 16; % modulation order alpha = 1; % target amplitude (single target) nu_list = -M:M; % scan input Doppler index (will mod M inside sim) nu_show = M-1; % choose one nu for 2D/slices visualization Bdop = 2; % >>> 真值 Doppler 周边口径:±Bdop 列合成(建议 1~3) % 索引 k_fast = (0:N-1).'; m_slow = (0:M-1).'; % slow-time FFT steering (consistent with fft(.,[],2)) W = exp(-1j * 2*pi/M * (m_slow * (0:M-1))); % M×M, column q+1 is bin q % 记录 PSR:全图、真值列、真值邻域列合成 PSR_full_raw = zeros(numel(nu_list),1); PSR_full_comp = zeros(numel(nu_list),1); PSR_col_raw = zeros(numel(nu_list),1); PSR_col_comp = zeros(numel(nu_list),1); PSR_band_raw = zeros(numel(nu_list),1); PSR_band_comp = zeros(numel(nu_list),1); % 保存用于展示的 2D AFfs(nu_show) AFfs_raw_show = []; AFfs_comp_show = []; q_true_show = []; %% ===================== 主循环:扫 Doppler ===================== rng(1545,'twister'); % reproducible seeds = randi(2^31-1, Nmc, 1, 'uint32'); % parfor reproducible for idx = 1:numel(nu_list) nu0 = nu_list(idx); AF_sum_raw = zeros(N,M); AF_sum_comp = zeros(N,M); parfor mc = 1:Nmc rng(double(seeds(mc)),'twister'); % ---------- 生成回波(N-structure:Y 是 N×M) ---------- [Y, ~, Xf] = simulate_ofdm_echo_multi(N, M, tau0, nu0, flag, Kmod, alpha); %% ============ 方案 A:RAW(标准2D-FFT) ============ Yf = fft(Y, [], 1); % fast-time FFT R = ifft(Yf .* conj(Xf), [], 1); % match + IFFT (range) RDM = fft(R, [], 2); % slow-time FFT (Doppler) AF_trial_raw = abs(RDM).^2; %% ============ 方案 B:逐 Doppler bin 快时间补偿 ============ % 补偿位置:在快时间 FFT 之前,对 Y 乘 e^{-j2π q k/(MN)} AF_trial_comp = zeros(N,M); for q = 0:M-1 rot_fast = exp(-1j * 2*pi * q * k_fast/(M*N)); % N×1 Yc = bsxfun(@times, Y, rot_fast); % N×M Yf_c = fft(Yc, [], 1); R_c = ifft(Yf_c .* conj(Xf), [], 1); % 只取 Doppler bin = q AF_trial_comp(:, q+1) = abs(R_c * W(:, q+1)).^2; end AF_sum_raw = AF_sum_raw + AF_trial_raw; AF_sum_comp = AF_sum_comp + AF_trial_comp; end AFfs_raw = AF_sum_raw / Nmc; AFfs_comp = AF_sum_comp / Nmc; %% ===================== PSR 计算 ===================== % (1) 全图 PSR peak_raw = max(AFfs_raw(:)); peak_comp = max(AFfs_comp(:)); PSR_full_raw(idx) = 10*log10( peak_raw / (sum(AFfs_raw(:)) - peak_raw ) * (M*N+1) ); PSR_full_comp(idx) = 10*log10( peak_comp / (sum(AFfs_comp(:)) - peak_comp) * (M*N+1) ); % 真值 Doppler bin(因为仿真内部 nu 做了 mod M) q_true = mod(round(nu0), M); % 0..M-1 % (2) 真值列口径 PSR_col(只看 q_true 那一列) col_raw = AFfs_raw(:, q_true+1); col_comp = AFfs_comp(:, q_true+1); pk1 = max(col_raw); pk2 = max(col_comp); PSR_col_raw(idx) = 10*log10( pk1 / (sum(col_raw) - pk1) * (N+1) ); PSR_col_comp(idx) = 10*log10( pk2 / (sum(col_comp) - pk2) * (N+1) ); % (3) 扩大口径:真值 Doppler 周边 ±Bdop 列合成(band integration) q_band = mod((q_true-Bdop):(q_true+Bdop), M); % wrap-around cols = q_band + 1; band_raw = sum(AFfs_raw(:, cols), 2); % N×1 (delay profile) band_comp = sum(AFfs_comp(:, cols), 2); pkb1 = max(band_raw); pkb2 = max(band_comp); PSR_band_raw(idx) = 10*log10( pkb1 / (sum(band_raw) - pkb1) * (N+1) ); PSR_band_comp(idx) = 10*log10( pkb2 / (sum(band_comp) - pkb2) * (N+1) ); %% 保存展示用 2D 图 if nu0 == nu_show AFfs_raw_show = AFfs_raw; AFfs_comp_show = AFfs_comp; q_true_show = q_true; end end %% ===================== PSR 曲线对比 ===================== figure; plot(nu_list, PSR_full_raw, 'o-', 'LineWidth', 1.2); hold on; plot(nu_list, PSR_full_comp, 's-', 'LineWidth', 1.2); grid on; xlabel('Doppler index \nu'); ylabel('PSR\_full / dB'); title('PSR\_full(全图口径):Raw vs Comp'); legend('Raw', 'Comp', 'Location', 'best'); figure; plot(nu_list, PSR_col_raw, 'o-', 'LineWidth', 1.2); hold on; plot(nu_list, PSR_col_comp, 's-', 'LineWidth', 1.2); grid on; xlabel('Doppler index \nu'); ylabel('PSR\_col / dB'); title('PSR\_col(真值列口径):Raw vs Comp'); legend('Raw', 'Comp', 'Location', 'best'); figure; plot(nu_list, PSR_band_raw, 'o-', 'LineWidth', 1.2); hold on; plot(nu_list, PSR_band_comp, 's-', 'LineWidth', 1.2); grid on; xlabel('Doppler index \nu'); ylabel('PSR\_band / dB'); title(['PSR\_band(真值±', num2str(Bdop), '列合成口径):Raw vs Comp']); legend('Raw', 'Comp', 'Location', 'best'); %% ===================== 用 surf 画 2D AFfs 对比(nu_show) ===================== if ~isempty(AFfs_raw_show) % 归一化到各自峰值并转 dB AF_raw_dB = 10*log10(AFfs_raw_show ./ max(AFfs_raw_show(:))); AF_comp_dB = 10*log10(AFfs_comp_show ./ max(AFfs_comp_show(:))); AF_impr_dB = AF_comp_dB - AF_raw_dB; delay_axis = 0:N-1; doppler_axis = 0:M-1; [DOP, DEL] = meshgrid(doppler_axis, delay_axis); figure; surf(DOP, DEL, AF_raw_dB); shading interp; colorbar; xlabel('Doppler bin (0..M-1)'); ylabel('Delay bin'); zlabel('Norm Power / dB'); title(['AFfs RAW (surf) nu\_in=', num2str(nu_show), ', nu\_bin=', num2str(mod(round(nu_show),M))]); figure; surf(DOP, DEL, AF_comp_dB); shading interp; colorbar; xlabel('Doppler bin (0..M-1)'); ylabel('Delay bin'); zlabel('Norm Power / dB'); title(['AFfs COMP (surf) nu\_in=', num2str(nu_show), ', nu\_bin=', num2str(mod(round(nu_show),M))]); figure; surf(DOP, DEL, AF_impr_dB); shading interp; colorbar; xlabel('Doppler bin (0..M-1)'); ylabel('Delay bin'); zlabel('\Delta / dB'); title(['AFfs Improvement (COMP-RAW) (surf) nu\_in=', num2str(nu_show)]); %% ===================== slices:zero / true ===================== % 为了 slice 显示更直观:Doppler 维用 signed 轴(fftshift) dop_signed = (-floor(M/2)):(ceil(M/2)-1); % 工具:安全归一化转 dB to_dB = @(v) 10*log10( max(v, eps) ./ max(max(v), eps) ); % ---- Zero Doppler slice (Doppler bin = 0, column 1), along delay ---- zeroD_raw = AFfs_raw_show(:, 1); zeroD_comp = AFfs_comp_show(:,1); figure; plot(delay_axis, to_dB(zeroD_raw), 'o-', 'LineWidth', 1.2); hold on; plot(delay_axis, to_dB(zeroD_comp), 's-', 'LineWidth', 1.2); grid on; xlabel('Delay bin'); ylabel('Norm Power / dB'); title('Zero Doppler slice (bin=0): Raw vs Comp'); legend('Raw','Comp','Location','best'); % ---- True Doppler slice (column q_true_show+1), along delay ---- trueD_raw = AFfs_raw_show(:, q_true_show+1); trueD_comp = AFfs_comp_show(:, q_true_show+1); figure; plot(delay_axis, to_dB(trueD_raw), 'o-', 'LineWidth', 1.2); hold on; plot(delay_axis, to_dB(trueD_comp), 's-', 'LineWidth', 1.2); grid on; xlabel('Delay bin'); ylabel('Norm Power / dB'); title(['True Doppler slice (bin=', num2str(q_true_show), '): Raw vs Comp']); legend('Raw','Comp','Location','best'); % ---- Zero Delay slice (Delay bin = 0, row 1), along doppler ---- zeroTau_raw = AFfs_raw_show(1, :); zeroTau_comp = AFfs_comp_show(1,:); figure; plot(dop_signed, to_dB(fftshift(zeroTau_raw)), 'o-', 'LineWidth', 1.2); hold on; plot(dop_signed, to_dB(fftshift(zeroTau_comp)), 's-', 'LineWidth', 1.2); grid on; xlabel('Doppler bin (signed, fftshift)'); ylabel('Norm Power / dB'); title('Zero Delay slice (tau=0): Raw vs Comp'); legend('Raw','Comp','Location','best'); % ---- True Delay slice (Delay bin = tau0, row tau0+1), along doppler ---- if tau0+1 <= N trueTau_raw = AFfs_raw_show(tau0+1, :); trueTau_comp = AFfs_comp_show(tau0+1,:); figure; plot(dop_signed, to_dB(fftshift(trueTau_raw)), 'o-', 'LineWidth', 1.2); hold on; plot(dop_signed, to_dB(fftshift(trueTau_comp)), 's-', 'LineWidth', 1.2); grid on; xlabel('Doppler bin (signed, fftshift)'); ylabel('Norm Power / dB'); title(['True Delay slice (tau=', num2str(tau0), '): Raw vs Comp']); legend('Raw','Comp','Location','best'); end % ---- 扩大口径的 true Doppler band(±Bdop)也给一个 delay slice ---- q_band_show = mod((q_true_show-Bdop):(q_true_show+Bdop), M); cols_show = q_band_show + 1; band_raw_show = sum(AFfs_raw_show(:, cols_show), 2); band_comp_show = sum(AFfs_comp_show(:, cols_show), 2); figure; plot(delay_axis, to_dB(band_raw_show), 'o-', 'LineWidth', 1.2); hold on; plot(delay_axis, to_dB(band_comp_show), 's-', 'LineWidth', 1.2); grid on; xlabel('Delay bin'); ylabel('Norm Power / dB'); title(['True Doppler band slice (bin ', num2str(q_true_show), ' ±', num2str(Bdop), '): Raw vs Comp']); legend('Raw','Comp','Location','best'); end %% ===================== 本脚本用到的本地函数 ===================== function [Y, Xtd, Xf] = simulate_ofdm_echo_multi(N,M,tau_vec,nu_vec,flag,K,amp) tau_vec = tau_vec(:).'; nu_vec = nu_vec(:).'; amp = amp(:).'; P = max([numel(tau_vec), numel(nu_vec), numel(amp)]); if numel(tau_vec)==1, tau_vec = repmat(tau_vec,1,P); end if numel(nu_vec)==1, nu_vec = repmat(nu_vec, 1,P); end if numel(amp)==1, amp = repmat(amp, 1,P); end tau_vec = mod(round(tau_vec), N); nu_vec = mod(round(nu_vec), M); % Doppler index -> 0..M-1 cyclic s = randi(K,[N,M]) - 1; if flag == 1 Xf = pskmod(s, K); else Xf = qammod(s, K); end Xtd = sqrt(N) * ifft(Xf, [], 1); k = (0:N-1).'; m = 0:M-1; Y = complex(zeros(N,M)); for p = 1:P tau_p = tau_vec(p); nu_p = nu_vec(p); X_shift = circshift(Xtd, tau_p, 1); dop_fast = exp(1j*2*pi*nu_p * k/(M*N)); dop_slow = exp(1j*2*pi*nu_p * m/M); Dop = dop_fast * dop_slow; Y = Y + amp(p) * (X_shift .* Dop); end end
Bdop 从 0/1/2/3 试一下:Bdop=0 就退化成你原来的 PSR_colBdop=1~2 往往能明显把“补偿后能量回聚”的提升体现出来True Doppler band slice 那张 delay 曲线:如果你还想更“雷达味儿”的指标(比如 PSLR/ISLR,用保护单元排除主瓣后再算旁瓣),我也能按你现在的 peak/guard 逻辑把它加进去,会比 PSR 更稳定。
我们的比较方法就不用PSR了 这个方法很奇怪。然后我们现在从解析解的角度,把这种每一个doppler都补偿的滤波器组的方法,和afdm的方法进行对比,从理论上分析一下哪一种对于ICI的抑制效果更好。下面是一个可以参考的思路,但是不一定对:
\documentclass{article}
\usepackage{amsmath,amssymb}
\usepackage{geometry}
\geometry{a4paper,margin=1in}
\title{ICI Suppression Performance Comparison: AFDM vs. Doppler-Compensated/Uncompensated OFDM}
\author{Wireless Communication Analysis}
\date{}
\begin{document}
\maketitle
\begin{abstract}
This paper presents an analytical derivation of Inter-Carrier Interference (ICI) for uncompensated OFDM, Doppler-compensated OFDM, and Affine Frequency Division Multiplexing (AFDM) over double-selective channels. The ICI power expressions are derived to quantify the suppression performance, revealing the inherent advantage of AFDM's slant compensation over OFDM's linear compensation.
\end{abstract}
\section{1. Assumptions and Channel Model}
To ensure a fair comparison, a unified double-selective channel model (frequency-selective and time-varying, i.e., Doppler spread + delay spread) is established with the following key assumptions:
\begin{enumerate}
\item The channel is a multipath fading channel with independent paths. For the -th path, the delay is , Doppler shift is , and complex gain is (). It satisfies , where is the length of Cyclic Prefix (CP) or Chirp Periodic Prefix (CPP) to eliminate Inter-Symbol Interference (ISI).
\item The number of subcarriers is , symbol period is , subcarrier spacing is , and normalized Doppler shift is (characterizing the Doppler impact on symbol period).
\item Doppler-compensated OFDM can only perfectly compensate for integer multiple Doppler shifts, leaving a residual fractional Doppler shift (), which is the core source of ICI.
\item AFDM adopts Discrete Affine Fourier Transform (DAFT): Inverse DAFT (IDAFT) for modulation and DAFT for demodulation. The chirp parameters are (time-domain chirp) and (frequency-domain chirp), satisfying the optimization condition ( is the maximum Doppler shift, is the guard parameter) and .
\end{enumerate}
The channel impulse response (Linear Time-Varying, LTV model) is:
\section{2. ICI Analysis of Uncompensated OFDM}
\subsection{2.1 Transmit and Receive Signal Model}
The OFDM transmit signal after IDFT modulation is:
After inserting CP, the time-domain received signal over the double-selective channel is:
where (delay quantized to sampling points), and is Additive White Gaussian Noise (AWGN).
\subsection{2.2 FFT Demodulation and ICI Power}
The received signal is demodulated by FFT. For the -th subcarrier, the received signal is:
Substituting and separating the desired signal, ICI, and noise:
where (channel frequency response), is the noise component, and the ICI term is:
The ICI power is the second moment of the ICI term:
\section{3. ICI Analysis of Doppler-Compensated OFDM}
\subsection{3.1 Doppler Compensation and Received Signal}
The Doppler compensation operation multiplies the received signal by to eliminate integer multiple Doppler shifts. The compensated signal is:
\subsection{3.2 ICI Power Expression}
After FFT demodulation, the ICI term for the -th subcarrier is:
The corresponding ICI power is:
\section{4. ICI Analysis of AFDM}
\subsection{4.1 Transmit and Receive Signal Model}
The AFDM transmit signal after IDAFT modulation (core of slant compensation with chirp parameters) is:
After inserting CPP, the time-domain received signal is:
The DAFT demodulation kernel at the receiver is:
\subsection{4.2 ICI Suppression Mechanism and Power}
Substituting the received signal into DAFT and simplifying using the optimized , let , the demodulated signal is:
Due to the sparse response of AFDM in the DAFT domain, ICI is confined to a narrow bandwidth. The ICI power is:
where is the interference bandwidth, and the exponential sum approaches zero when .
\section{5. Performance Comparison Conclusion}
\end{document}
可以,把“PSR”先放一边,用解析解来对比更干净。下面我用一个统一的离散基带模型,把:
放在同一框架下比较 ICI(子载波间干扰)的“结构”和“能量规模”,并说明在什么条件下谁更强。
取一帧长度 (快时间采样),慢时间索引先不引入(单个 OFDM 符号内看 ICI 就够了):
OFDM 发射:
接收 FFT:
代入后得到一个标准形式(把“期望项”和“ICI项”统一写成矩阵):
其中耦合系数为
而
结论 1(非常关键):
于是 ICI 功率(以每个子载波平均、符号独立同分布)可用“非对角能量”刻画:
这里 。
你现在做的方案(每个 Doppler bin 都做一次快时间去旋转)本质是:
对某个假设 (可以是整数 bin,也可以做细网格):
再做 FFT。
那么耦合系数直接变成:
也就是把每条径的 Doppler 从 变成了残差
因此,对“某个固定的 ”而言,ICI 能量就是:
所以滤波器组的“上限”取决于:信道是不是“近似单 Doppler”。
这其实是在算一个“多假设匹配滤波输出集合”。
它不是一个能量守恒的正交变换(每一列都用不同预处理),所以“全图能量/旁瓣指标”会显得怪——这也是你之前用 PSR 会很纠结的根源之一。
真正公平的使用方式是:用估计/检测选出最可能的 ,然后只拿这个 的输出做后续解调/成像。
AFDM 的调制/解调可抽象成:
其中 是 DAFT 矩阵(含 chirp 参数 的二次相位核)。
在满足典型 AFDM 设计条件(CPP 足够长、 选取覆盖最大 Doppler、并满足论文里的“可分离/可稀疏化”条件)时,AFDM 在 DAFT 域把每条径近似映射成二维移位(delay-Doppler 的稀疏 tap):
你参考里写的:
就是这种二次指数和的影子。它与 OFDM 的线性相位和(Dirichlet 核)相比,一个关键差别是:
(严格的界可以用高斯和性质给出:在不少参数取值下,离开主支持区的幅度上界可做到比 Dirichlet 更“瘦”。)
✅ 结论:单 Doppler 场景,滤波器组(选对 )不输 AFDM,甚至可“零 ICI”。
✅ 结论:多 Doppler 多径时,AFDM 通常比“单 ”滤波器组更能整体压住 ICI。
如果你允许滤波器组做“多 分支联合估计 + 多径分离/联合检测”,那能逼近 ML,但复杂度会飙升,且本质上你在做“二维稀疏估计/多假设检测”,就和 AFDM 的优势区间重叠了。
✅ 结论:离栅 Doppler 下,AFDM 的“局部扩散 + 稀疏结构”往往更占优;滤波器组要靠更细网格和更复杂的选择/联合检测来追。
如果要纯理论比较 ICI 抑制,我建议直接比有效信道矩阵的非对角能量比(ODR / ICI ratio):
如果你愿意,我也可以把上面这个 (或“主邻域外能量占比”)直接接到你们的仿真里当评价指标,比 PSR 更贴近“ICI 抑制”。
如果你把你们要对比的“AFDM 参数设计”( 的取法、是否 CPP、最大 Doppler 假设)给我,我可以把上面这套解析推导进一步“落到你们的符号体系”,写成一段更像论文的推导(包括从 到 ICI 功率闭式/上界,以及 AFDM 二次指数和的界)。