下面的框架中是一个OFDM ISAC的框架,主要关注delay和doppler的感知。下面写的是主函...

생성일: 2026년 1월 9일

답변에 사용된 모델 GPT-5.2 Thinking by Chat01

질문

下面的框架中是一个OFDM ISAC的框架,主要关注delay和doppler的感知。下面写的是主函数。现在我们想改成afdm,并在ofdmmodulate和demodulate里面把fft换成daft,同时在接收端信道估计的时候也做了如下处理,利用2d-dft来估计我们的位置和速度。先看一下下面的代码并学习一下。
主函数:clc;
clear;
tic
addpath(genpath(pwd)) % include all the subfolders under the current folder into the calling function directory
snrdB = 10; % SNR configuration
simulationNum = 50;
for SNR = snrdB
rng('default');
[sensing] = sensingInit(); % sensing parameter initialization

text
[TxFreqSignal,sensing]=RsMapping(sensing); % sensing reference signal frequency domain mapping %% whether comm rangeErrSet=zeros(sensing.targetNum,simulationNum); veloErrSet=zeros(sensing.targetNum,simulationNum); angleErrSet=zeros(sensing.targetNum,simulationNum); for num=1:simulationNum [sensing,channel]=channelParaConfig(sensing,num); % channel parameter configuration %%target set [sensing,channel] = channelInit(sensing,channel); % initialization of channel parameters %% target add H [TxFreqSignalprecode] = TxAnalogPrecoding(sensing, TxFreqSignal, channel); % multi anteana care [TxTimeSignal,sensing]=ofdmModulate(TxFreqSignalprecode,sensing,num); % ofdm modulation channelOut=channelPass(TxTimeSignal,TxFreqSignalprecode,channel,sensing); % pass channel %%(time/frec) channelOut=awgn(channelOut,SNR); % add Gaussian noise [RxFreqSignal]=ofdmDemodulate(channelOut,sensing); % ofdm demodulation Hest=channelEst(TxFreqSignal,RxFreqSignal,sensing); % frequency domain channel estimation %% (correlation) Hest=clutterCancel(Hest,sensing); % Clutter cancellation [range,velocity,angle]=seningProcess(Hest,sensing); % sensing algorithm processing [rangeErr,veloErr,angleErr]=errStatistics(range,angle,velocity,sensing,channel); % result statistics rangeErrSet(:,num)=rangeErr; veloErrSet(:,num)=veloErr; angleErrSet(:,num)=angleErr; % [Xposi,Yposi]=positionCalcu(range,angle,sensing,channel); end plotfig(sensing,rangeErrSet,veloErrSet,angleErrSet,channel,SNR); % draw the result figure

end
toc

function [Range,Velocity,Angle]=dft_2d(Hest,sensing)
targetNum=sensing.targetNum;
fc=sensing.fc;
Deltaf=sensing.SCS;
slotT=sensing.frameLen*1e-3/sensing.sensingSymbolNum;
c=3e8;
UEdV=sensing.UEdV;
UEdH=sensing.UEdH;
freqSpace=sensing.freqSpace;
pseudoPeakFlag=sensing.pseudoPeakFlag;
Range=zeros(targetNum,1);
Velocity=zeros(targetNum,1);
Angle=zeros(targetNum,1);
ang=0;

if sensing.overSamplFlag==1
lenf=sensing.overSamplNumf;
lent=sensing.overSamplNumt;
else
[lenf,lent]=size(Hest(:,:,1));
end
rxAntNum=sensing.rxAntNum;
initH=zeros(lenf,lent);
dataSet=cell(1,rxAntNum);
for antId=1:rxAntNum
Htemp=Hest(:,:,antId);
Hdft=fft(ifft(Htemp,lenf).',lent).';
dataSet{antId}=fftshift(Hdft,2);
initH=initH+fftshift(abs(Hdft),2);
end
residualH=initH;

for Idx=1:targetNum
loop=1;
flag=0;
while loop
if Idx>1 || flag==1
[Nc,Nt,Np]=size(Hest);

text
for antId=1:rxAntNum for delayIdx=delayTapSet-lent/2-1 for dolpIdx=dolpTapSet-lent/2-1 distance=delayIdx*deltaR; phiA = exp(-1j*2*pi*[0:Np-1]'*0.5*cos(ang*pi/180)); phiR = exp(-1j*2*pi*Deltaf*freqSpace*distance*[0:Nc-1]/c); phiV=exp(1j*2*pi*dolpIdx*2*deltafd*slotT*[0:Nt-1]); phi=kron(phiR,phiV); phiphi=kron(phiA',phi); phi=phiphi; reSignal=abs(fftshift(fft(ifft(phi,lenf).',lent).',2)); reSignal=reSignal/max(reSignal(:)); factor=residualH(delayIdx+1,dolpIdx+1+lent/2+1); DDRxH = factor*reSignal; residualH=residualH-abs(DDRxH); residualH(residualH<0)=0; end end end end end % [Nc,Nt]=size(residualH); % Vset= c*[-Nt/2:Nt/2-1]./(fc*slotT*Nt); % Rset=[0:Nc-1]./(Deltaf*Nc)*c; deltaV=c/(fc*slotT*lent*2); deltafd=1/(lenf*slotT*2); deltaR=c/(freqSpace*Deltaf*lenf); % residualH=residualH(1:floor(lenf/2),:); residualH=residualH(1:floor(lenf/1),:); [~,index]=max(residualH(:)); [maxRow,maxCol]=ind2sub(size(residualH),index); surf(residualH); figure plot(residualH(1:maxCol)); distance=(maxRow-1)*deltaR; rangeReal=sensing.targetRange; realRow = rangeReal/deltaR+1; speed=(maxCol-lent/2-1)*deltaV; if pseudoPeakFlag==1 dolpTapSet=[maxCol-1,maxCol,maxCol+1]; dolpTapSet(dolpTapSet>lent)=[]; dolpTapSet(dolpTapSet<=0)=[]; delayTapSet=[maxRow-1,maxRow,maxRow+1]; delayTapSet(delayTapSet<=0)=[]; else dolpTapSet=maxCol; delayTapSet=maxRow; end % INN=120; % mesh(deltafd*[-lent/2:lent/2-1],deltaR*[0:Nc-1],residualH(1:INN,:)); % xlim([-1000,1000]) % xlabel('Doppler[Hz]'); % ylabel('Range[m]'); % zlabel('Amplitude'); % angle estimate with MUSIC algorithm if rxAntNum>1 && abs(speed)>=min(deltaV,5) Xset=zeros(1,rxAntNum); for rxAntId=1:rxAntNum Xset(1,rxAntId)=dataSet{rxAntId}(maxRow,maxCol); end RxT=Xset; % 补充Xset到RxT的赋值(原代码隐含此步骤) J=flip(eye(rxAntNum)); clear Xset Rv=(RxT*conj(RxT)')/2; [U,Value]=eig(Rv); % Value=diag(Value); sigNum=targetNum; Un=U(:,1:end-sigNum); Pn=Un*Un'; n=0; if sensing.verticalFlag==1 Aset=sensing.AsetV; Psang=zeros(1,length(Aset)); for A=Aset n=n+1; phiA = exp(1j*2*pi*[0:rxAntNum-1]*UEdV*cos(A*pi/180)); % ZOA estimation Psang(n)=1/(abs(phiA'*Pn*phiA)); end else Aset=sensing.AsetH; Psang=zeros(1,length(Aset)); for A=Aset n=n+1; phiA = exp(1j*2*pi*[0:rxAntNum-1]*UEdH*sin(A*pi/180)); % AOA estimation Psang(n)=1/(abs(phiA'*Pn*phiA)); end end [peakPower,peakInd]=findpeaks(Psang); [~,index]=sort(peakPower,'descend'); ang=Aset(peakInd(index(1:1))); end % if abs(speed)<min(deltaV,5) loop=loop+1; flag=1; % else Range(Idx)=distance; Velocity(Idx)=speed; Angle(Idx)=ang; loop=0; flag=0; end if loop>10 break; end

end
end

function [TxTimeSignal,sensing]=ofdmModulate(TxFreqSignal,sensing,frameId)
Nsybmol=sensing.Nsymbol;
txAntNum=sensing.txAntNum;
fftSize=sensing.fftSize;
if sensing.blockCP==1
CplenSet=zeros(1,Nsybmol);
CplenSet(1:14:end)=fftSize;
sensing.CplenSet=CplenSet;
else
CplenSet=sensing.CplenSet;
end

removeCpInd=zeros(1,Nsybmol); % CP position index
TxTimeSignal=zeros(txAntNum,Nsybmol*fftSize+sum(CplenSet(1:Nsybmol)));

for antId=1:txAntNum
TxTimeSignalTemp=[];
% changed:choose AFD
% sensing.useAFDM
if sensing.useAFDM
TxSignalT=idaft(TxFreqSignal(:,:,antId),sensing.afdm.c1,sensing.afdm.c2); % idaft
else
TxSignalT=ifft(TxFreqSignal(:,:,antId),fftSize)*sqrt(fftSize); % ifft
end
%%%
for symInd=1:Nsybmol
removeCpInd(symInd)=length(TxTimeSignalTemp);
Cpdata=TxSignalT(end-CplenSet(symInd)+1:end,symInd);
TxSignalCp=[Cpdata.',TxSignalT(:,symInd).']; % add CP
TxTimeSignalTemp=cat(2,TxTimeSignalTemp,TxSignalCp);
end
TxTimeSignal(antId,:)=TxTimeSignalTemp;
end
removeCpInd(removeCpInd+1)=length(TxTimeSignalTemp);
sensing.removeCpInd=removeCpInd;
sensing.frameId=frameId;
end

function [RxFreqSignal]=ofdmDemodulate(channelOut,sensing)
if sensing.cfr==0
Nsybmol=sensing.Nsymbol;
fftSize=sensing.fftSize;
CplenSet=sensing.CplenSet;
removeCpInd=sensing.removeCpInd;
rxAntNum=sensing.rxAntNum;

text
% remove CP and FFT RxSignal=zeros(fftSize,Nsybmol,rxAntNum); RxFreqSignal=zeros(fftSize,Nsybmol,rxAntNum); for antId=1:rxAntNum for symInd=1:Nsybmol RxSignal(:,symInd,antId)=channelOut(antId, removeCpInd(symInd)+CplenSet(symInd)+1 : removeCpInd(symInd)+CplenSet(symInd)+fftSize); %%% AFD added if sensing.useAFDM RxFreqSignal(:,symInd,antId)=daft(RxSignal(:,symInd,antId),sensing.afdm.c1,sensing.afdm.c2); % daft else RxFreqSignal(:,symInd,antId)=fft(RxSignal(:,symInd,antId))/sqrt(fftSize); % fft end end end

else
RxFreqSignal=channelOut; % if pass frequency domain channel,skip this step
end
end
function Hest=channelEst(TxFreqSignal,RxFreqSignal,sensing)
timeSpace = sensing.timeSpace;
freqSpace = sensing.freqSpace;
Nzc=sensing.Nzc;
Nc=sensing.Nc;
fpattern=sensing.fpattern;
tpattern=sensing.tpattern;
sensingSymbolNum=sensing.sensingSymbolNum;
if sensing.fastchannel==1
tpattern=[1:sensingSymbolNum];
end

rxAntNum=sensing.rxAntNum;

%% AFD
if sensing.useAFDM == 1
txTime = idaft(TxFreqSignal,sensing.afdm.c1,sensing.afdm.c2);
rxTime = zeros(size(RxFreqSignal));
for rx=1:rxAntNum
rxTime(:,:,rx) = idaft(RxFreqSignal(:,:,rx),sensing.afdm.c1,sensing.afdm.c2);
end
TxFreqSignal = fft(txTime,Nc,1)/sqrt(Nc);
RxFreqSignal = fft(rxTime,Nc,1)/sqrt(Nc);
end

TxFreqSignal=circshift(TxFreqSignal,Nc/2,1);
TxSignalTF=TxFreqSignal(fpattern,tpattern);
Hest=zeros(length(sensingSymbolNum),sensingSymbolNum,rxAntNum);

RxFreqSignal=circshift(RxFreqSignal,Nc/2,1); % Frequency domain data passing through the time domain channel

for RxIdx=1:rxAntNum
RxSignalTF=RxFreqSignal(fpattern,tpattern,RxIdx);
Hest(:,:,RxIdx)=RxSignalTF ./ TxSignalTF;
end

if sensing.otfsSensingFlag==1
Hest=RxFreqSignal(1:Nc,tpattern);
end
end

사고

Reviewing code and offering analysis

The user asked me to understand their code and potentially help modify it later. I’ll focus on summarizing the code components and pointing out key considerations for changes to AFD, ADFT vs FFT use, and modifications related to 2D DFT in channel estimation. I’ll also address possible bugs, such as the issue with Hest allocation.

Highlighting variable naming and code analysis

I’ll start by mentioning the variable naming. In dft_2d, they compute Hdft through an IFFT and FFT process. The Htemp represents a channel estimate, where they map delay and Doppler, using lenf for frequency and lent for time. I'll explain their delay and Doppler resolution derivations and note incomplete loop structures, such as a while loop with no termination. They'll need to fix that logic.

Focusing on learning the pipeline and potential issues

I’ll focus on creating a structured overview of the pipeline, modifications for AFDM, key functions, and data shapes. I'll highlight issues and next steps: For replacing FFT with DAFT/ID-AFT, make sure to manage scaling, cyclic prefix (CP), and chirp parameters. In channel estimation, idaft is applied to time-domain data, but for TxFreqSignal, they need to apply idaft and then FFT to retrieve conventional frequency.

Clarifying AFDM to OFDM conversion and channel estimation

It seems like they want to map the AFDM signal back to the OFDM domain for element-wise division on the pilot grid. But maybe they'd prefer estimating the channel in the DAFT domain instead of redoing the FFT. For delay-Doppler sensing, I'd suggest using a 2D DFT of the channel estimate.

Adjusting FFT lengths and correcting indexing

Make sure the FFT length matches the modulation, possibly fftSize, not Nc. For oversampling, employ zero-padding. Ensure circshift aligns with the subcarrier center. Also, be cautious with the removeCpInd indexing—there seems to be a bug where it exceeds the array length. In channel estimation, the allocation for Hest should match fpattern, not sensingSymbolNum.

Clarifying AFDM adjustments and channel estimation

If sensing.fastchannel is used, tpattern is overwritten and should be used to select symbols. In AFDM branch, TxFreqSignal has three dimensions, but channelEst treats it without the antenna dimension. Ensure to adapt the channels and implement a 2D DFT for position and velocity estimation as required.

Proposing test plan and DAFT function guidance

I can suggest a test plan: ensure orthogonality, verify idaft(daft(x)) recovers accurately, check PAPR, and compare with OFDM. If asked to implement daft/idaft functions, I'll provide MATLAB pseudocode without errors. I'll also advise checking that the DAFT/ID-AFT functions are unitary and consistent with scaling.

Thought for 1m 1s

답변

我把你贴的这段代码按“整体链路AFDM改动点2D-DFT感知点我看到的潜在坑/需要对齐的地方”梳理一遍(相当于我先把它“学一遍”,方便你下一步继续改)。


1) 主链路在做什么(从Tx到感知)

你的主函数整体流程是:

  1. sensingInit / RsMapping:初始化感知参数 + 生成/映射参考信号(频域栅格上)。
  2. channelParaConfig / channelInit:按每次仿真配置目标(delay/doppler/angle等)并初始化信道。
  3. TxAnalogPrecoding:做模拟/混合预编码(多天线)。
  4. ofdmModulate(你现在准备改成AFDM):把频域符号 → 时域波形(加CP)。
  5. channelPass + awgn:过时变信道并加噪声。
  6. ofdmDemodulate(你现在准备改成AFDM):去CP并把时域 → “解调域”(OFDM用FFT;AFDM用DAFT)。
  7. channelEst(你也做了AFDM分支处理):频域信道估计(本质是用导频/参考符号做逐点相除)。
  8. clutterCancel:杂波抑制。
  9. seningProcess / dft_2d:把估计到的H做2D处理,得到 range / velocity,再结合多天线做 angle(MUSIC)
  10. errStatistics + plotfig:误差统计画图。

2) 你现在的 AFDM 改动点在哪里

你现在的改动策略非常明确:
“调制解调处把FFT/IFFT换成IDAFT/DAFT,但后面的处理尽量复用原OFDM那套(尤其是信道估计 + 2D-DFT感知)。”

A) 发端:ofdmModulate 里替换 IFFT → IDAFT

你现在写的是:

  • OFDM:TxSignalT = ifft(TxFreqSignal,fftSize)*sqrt(fftSize)
  • AFDM:TxSignalT = idaft(TxFreqSignal,c1,c2)

然后逐符号加CP拼接成连续时域波形。

✅ 这一段逻辑是自洽的:
IDAFT输出的就是每个symbol的时域块,CP照加即可。

关键要对齐的是: IDAFT/DAFT的归一化(是否“能量守恒/单位酉”)要和你原来 *sqrt(N)/sqrt(N) 的能量标定一致,否则SNR和误差曲线会整体偏移。


B) 收端:ofdmDemodulate 里替换 FFT → DAFT

你现在写的是:

  • OFDM:RxFreqSignal = fft(RxSignal)/sqrt(fftSize)
  • AFDM:RxFreqSignal = daft(RxSignal,c1,c2)

✅ 也没问题:
去CP后,每个symbol块直接做DAFT,得到AFDM“解调域”的栅格。


C) 信道估计:channelEst 里你做了一个“回到OFDM域”的桥接

你现在的 AFDM 分支是:

  1. 先把 TxFreqSignalidaft → 得到时域 txTime
  2. RxFreqSignal(DAFT域)idaft → 得到时域 rxTime
  3. 再对 txTime/rxTime 做普通 FFT → 得到“类似OFDM的频域TF表示”
  4. 后面用原来那套:Hest = RxTF ./ TxTF

✅ 这一步的含义是:
你不直接在DAFT域里做“除法估计”,而是把双方都“拉回到时域→再转到普通频域”,等价于在传统TF域继续沿用原来的导频估计框架,从而后面的2D-DFT(delay/doppler)也可以继续用。

这是一条很常见的“工程复用路线”,优点是你后面处理不用大改;缺点是如果你未来想发挥AFDM在双选信道下的“近似对角化优势”,就应该考虑在DAFT域做更匹配的估计/均衡(但这是下一步的事)。


3) 你这版 2D-DFT 感知(delay/doppler)到底怎么算的

dft_2d(Hest,sensing) 里最核心的一句是:

matlab
Hdft = fft( ifft(Htemp,lenf).', lent ).'; dataSet{antId} = fftshift(Hdft,2); initH = initH + fftshift(abs(Hdft),2);

这对应典型的 “频域→delay:IFFT;时间(symbol)→doppler:FFT”

  • ifft(Htemp,lenf):沿着频率/子载波维做IFFT → 得到 delay 维(也就是距离维)
  • fft( ... , lent ):沿着慢时间(symbol)维做FFT → 得到 doppler 维(也就是速度维)
  • fftshift(...,2):把doppler零频移到中间(正负速度对称)

然后你用:

  • deltaR = c/(freqSpace*Deltaf*lenf)
  • deltaV = c/(fc*slotT*lent*2)

把二维峰值索引映射成物理 距离/速度

最后角度用 MUSIC:从 dataSet{antId}(maxRow,maxCol) 取出各天线在该delay-doppler bin上的复值,构造空间谱估计角度。

✅ 所以你的“2D-DFT估计位置速度”这条路是非常清晰的:
Hest(TF) → 2D变换 → Range-Doppler Map → 找峰 → (range, velocity),再用多天线相位差做角度。


4) 我看到的几个需要你特别留意/对齐的点(不改会很容易出bug或结果飘)

(1) removeCpInd 最后那句很可疑

你写的是:

matlab
removeCpInd(removeCpInd+1)=length(TxTimeSignalTemp);

这句在MATLAB里很容易越界或写乱索引(因为 removeCpInd 里面存的是“样点位置”,不是 1..Nsymbol 的合法索引)。

通常想要的是:

  • removeCpInd(symInd) 存每个symbol起点
  • 最后 removeCpInd(end+1) 存帧末尾(可选)

如果你后续 ofdmDemodulateremoveCpInd(symInd) 切片,建议把这里索引逻辑彻底对齐一下(否则CP切片会错一位,后面全崩)。


(2) Hest=zeros(length(sensingSymbolNum),sensingSymbolNum,rxAntNum); 这行维度也不太对

sensingSymbolNum 看起来是一个标量(比如 14),那 length(sensingSymbolNum)=1,这会导致 Hest 第一维只有1。

但你后面:

matlab
RxSignalTF = RxFreqSignal(fpattern,tpattern,RxIdx); Hest(:,:,RxIdx) = RxSignalTF ./ TxSignalTF;

这里 RxSignalTF 的第一维应该是 length(fpattern)

所以更合理的形状通常是:

  • Hest = zeros(length(fpattern), length(tpattern), rxAntNum);

你可能原工程里 sensingSymbolNum 其实不是标量(或者你粘贴时有误),但就你这段看,这行非常值得你核对一下


(3) AFDM分支里 FFT 的长度用 Nc,要确认 Nc == fftSize

你写的是:

matlab
TxFreqSignal = fft(txTime,Nc,1)/sqrt(Nc); RxFreqSignal = fft(rxTime,Nc,1)/sqrt(Nc);

如果 NcfftSize 不一致(比如有保护带、有效子载波Nc<fftSize),那会引入维度/映射不一致。
你后面还 circshift(TxFreqSignal,Nc/2,1),所以这里最好保证:

  • DAFT/IDAFT的NFFT的N频域映射的Nc 三者在你的定义下是一致的,或者你清楚地做了“有效子载波/FFT点数”的转换。

(4) dft_2d 里有些变量使用顺序要小心

你在 while/for 的重构残差部分用到了 deltafddeltaR 等,但它们在你贴的代码里是在后面才定义的(可能是你截断/复制顺序导致)。
如果这段在你真实工程里也是这个顺序,会直接报错或逻辑不对。


(5) 你在 dft_2d 里画 surf/figure/plot 会极大拖慢仿真

simulationNum=50、目标多、还多天线的话,这些绘图会让仿真慢很多,也会影响你统计曲线。建议默认关掉,用 flag 控制。


5) 总结一下我“学到”的你当前方案(给你后续继续改用)

你现在的总体思路是:

  • 调制解调:OFDM 的 IFFT/FFT → AFDM 的 IDAFT/DAFT(CP机制保留)
  • 信道估计:为了复用原导频除法框架,把 Tx/Rx 的“DAFT域”先用 IDAFT 拉回时域,再 FFT 回传统频域做估计
  • 感知:仍然在估计到的 TF 信道上做 2D 变换(IFFT_freq + FFT_time) 得到 Range-Doppler,再取峰值映射距离速度;角度用 MUSIC

如果你下一步要我继续帮你改(比如:把整条链路里变量维度彻底对齐、把 channelEst 改成更“原生AFDM域估计”、或者把 dft_2d 的残差迭代那段补完整并跑通),你直接告诉我你现在工程里这几个量的确切尺寸定义(Nc/fftSize/Nsymbol/fpattern/tpattern 各自含义),我就能按你现有结构把它们一次性改干净,不用你反复试错。

질문

现在很奇怪的是,我们afdm的结果,和实际的结果对应的相应点多了25%。比如原来是164的,afdm到了205.原来241的,现在变成27(一共是272列)。请分析一下是什么问题 并改正

사고

Analyzing Doppler mapping shifts

I’m trying to figure out if there’s a shift or scaling in the range-doppler map of the AFDM results. For example, one index (164) changes to 205, a 25% increase, which looks like it's being scaled by 1.25. But another index (241) shifts in a more complex way. It might be due to normalization or a dimension mismatch. I'm thinking it could involve the difference between Nc and fftSize.

Investigating mapping and scaling factors in AFDM

I’m trying to figure out the relationship between subcarriers and the 272 columns they mention. I’m guessing the index transformation involves a scaling factor. The 25% scaling seems to suggest a change in sampling grid, possibly based on a mismatch between actual FFT size and subcarriers used in AFDM.

Exploring scaling and mapping in AFDM vs. OFDM

I think the scaling factor (1.25) indicates a mismatch between the expected FFT length and what’s actually used. If the transform uses a different length, like 340, instead of 272, there could be resampling. Also, AFDM might involve additional transformations like chirps, which change how indices map to physical delay and doppler, adding further scaling.

Considering the impact of symbol duration in AFDM

They mentioned using 2D DFT for estimating position and speed, but with AFDM, it's possible that the channel is stretched in time-frequency space. The 25% index shift could be due to incorrectly handling parameters like symbol duration or the cyclic prefix. If the symbol duration is altered, Doppler mapping may change and affect index positions.

Considering the impact of CP length on Doppler mapping

If you treat the symbol interval as Tu instead of Ts (which includes cyclic prefix), the velocity mapping changes. The 25% scaling might relate to the inclusion of the CP in the symbol duration. In OFDM, CP doesn't affect modulation, but in AFDM, a change in CP length or model could lead to this scaling, with Ts being 1.25 times Tu.

Examining mismatch with symbol duration between OFDM and AFDM

It seems like in the original OFDM code, the Doppler phase increment was based on the full symbol duration including the cyclic prefix (CP). After the AFDM change, the symbol duration might have been treated differently (without CP), causing a mismatch in the Doppler phase progression. This mismatch could explain the 25% index shift.

Exploring the CP length and column index in AFDM

It seems like there's confusion around the CP length. In blockCP mode, the first symbol gets a CP of fftSize, but others don't, leading to an average CP. This could be impacting how column indices and Doppler scaling are being handled. Also, the number of time symbols versus sensing symbols could contribute to this scaling mismatch.

Adjusting slotT for correct Doppler scaling

The scaling in Doppler relates to slow-time length and symbol duration. It seems like slotT might need to account for CP, so adjusting it to (fftSize + Cplen)/fs could fix the mismatch. The larger-than-expected Doppler shift indicates the need to adjust this time spacing or parameter settings.

Fixing phase rotation scaling with slotT adjustment

The tone rotates faster per symbol, which happens if the actual symbol duration Ts is larger than assumed. To fix this, adjusting slotT to account for CP by setting it as (fftSize + mean(CplenSet)) / fs corrects the scaling factor. This update ensures Doppler estimation accounts for variable CP lengths.

Fixing symbol spacing for accurate residual cancellation

To fix the issue in residual cancellation, I need to adjust slotT to account for the actual symbol spacing, including the cyclic prefix (CP). This should correct the peak position from phase shifts. Since the FFT bin peak depends on the actual phase increment, modifications to symbol times (including CP) will fix the mismatch.

Identifying AFDM to OFDM mismatch causing Doppler scaling

The scaling in Doppler peak indices likely occurs because the AFDM setup changes the symbol duration: idaft uses a different length (Nc=340) than the original FFT size (fftSize=272). This makes the symbol duration longer, causing a 1.25x scaling in time and Doppler. To fix this, the AFDM transform length should match the original OFDM FFT size.

Refining AFDM to OFDM conversion and potential scaling

In the AFDM setup, using Nc instead of fftSize in transforms like idaft and fft causes discrepancies in symbol length, potentially distorting Doppler scaling. The scaling factor of 1.25 could result from mismatched oversampling or incorrect deltaV mapping during the conversion, impacting velocity calculations.

Analyzing AFDM and OFDM mismatch issue

The scaling factor of 1.25 likely results from mismatched symbol duration or Doppler shift. If the channel model or frame length (slotT) changes in AFDM and affects symbol spacing, it could cause length mismatches. Changes in CP length and the use of Deltaf or fs might further explain the observed scaling, needing adjustments to symbol duration or Doppler shift in the model.

Analyzing mismatch in AFDM/OFDM transformation

The 1.25 scaling might come from differences in symbol duration or Doppler shift between AFDM and OFDM. In AFDM, changing slotT, frameLen, or mismatched FFT sizes can affect the time axis and Doppler scaling. Unifying transform sizes and correcting symbol duration could resolve the 25% scaling issue in index location.

Addressing mismatch in AFDM and OFDM index shift

The observed 25% misalignment likely comes from using inconsistent transform sizes (Nc vs fftSize) in AFDM versus OFDM. The fix involves ensuring consistent sizes across transformations and correcting slotT for proper symbol duration computation. The issue could also stem from how Doppler bins are computed, requiring adjustment of deltaV for accurate speed calculation.

Thought for 4m 26s

답변

你这个“点位整体多了 25%(164→205≈×1.25),并且高频端发生取模环绕(241×1.25≈301,301 mod 272≈29,接近你看到的 27)”的现象,非常像一个根因:

AFDM链路里用的“变换长度 N”跟 OFDM 的 FFT 长度不一致,导致每个 symbol 的有效时长(或等效采样数)变成了原来的 1.25 倍,于是 Doppler 维的离散频率(bin 索引)整体按 1.25 缩放,超出长度就环绕。

在你贴的代码里,这种不一致最可能发生在两处:

  1. OFDM 时你用的是
matlab
ifft(TxFreqSignal, fftSize)

它会把输入 自动补零/截断到 fftSize

  1. AFDM 时你用的是
matlab
idaft(TxFreqSignal, c1, c2)

而大多数 idaft/daft 实现会默认用 size(TxFreqSignal,1) 作为 N(不会像 ifft 那样按 fftSize 自动补零到指定长度)。

所以如果你系统里存在 Nc(有效子载波数)和 fftSize(IFFT长度)不一致(典型:fftSize = 340, Nc = 272,刚好 340/272=1.25 或反过来),那么:

  • OFDM 分支:变换长度是 fftSize
  • AFDM 分支:变换长度变成 Nc符号时长不一致 → Doppler bin 缩放 → 164→205、241→(取模后变小的数)

改法(关键:把 AFDM 的 DAFT/IDAFT 也强制用 fftSize)

1)给 TxFreqSignal 做“强制补零到 fftSize”的 pad(和 ifft 行为一致)

新增一个小工具函数(放到同文件末尾或单独 .m):

matlab
function X = pad2fft(Xin, Nfft) % Xin: [N x Ns( x Nant)] % X : [Nfft x Ns( x Nant)] N = size(Xin,1); if N == Nfft X = Xin; return; end X = zeros([Nfft, size(Xin,2), size(Xin,3)], 'like', Xin); % 这里假设你的子载波映射是“居中映射(DC居中)”的思路: % 把 N 点内容放到 Nfft 的中间 st = floor((Nfft - N)/2) + 1; X(st:st+N-1,:,:) = Xin; end

如果你工程里的映射不是“居中映射”,而是通过 fpattern 贴到特定位置,那就把上面这段替换成:X(fpattern,:,:) = Xin;(我后面也给你写了一个版本)。


2)在 ofdmModulate 里:AFDM 分支也用 fftSize 的长度

把你现在的:

matlab
TxSignalT=idaft(TxFreqSignal(:,:,antId),sensing.afdm.c1,sensing.afdm.c2);

改成:

matlab
X = pad2fft(TxFreqSignal(:,:,antId), fftSize); TxSignalT = idaft(X, sensing.afdm.c1, sensing.afdm.c2); % 现在idaft输入长度=fftSize

3)在 channelEst 里:AFDM 分支做“回 OFDM 频域”时也统一用 fftSize

你现在写的是(注意你用 Nc):

matlab
TxFreqSignal = fft(txTime,Nc,1)/sqrt(Nc); RxFreqSignal = fft(rxTime,Nc,1)/sqrt(Nc);

建议改成:

matlab
Nfft = sensing.fftSize; % 先把Tx参考也pad到Nfft,保证idaft长度一致 TxRef = pad2fft(TxFreqSignal, Nfft); % TxFreqSignal可能是Nc txTime = idaft(TxRef, sensing.afdm.c1, sensing.afdm.c2); rxTime = zeros(size(RxFreqSignal), 'like', RxFreqSignal); for rx = 1:rxAntNum rxTime(:,:,rx) = idaft(RxFreqSignal(:,:,rx), sensing.afdm.c1, sensing.afdm.c2); % RxFreqSignal来自demod,一般已是Nfft end TxFreqSignal = fft(txTime, Nfft, 1)/sqrt(Nfft); RxFreqSignal = fft(rxTime, Nfft, 1)/sqrt(Nfft);

并且后面的 shift 也用 Nfft/2(不要混用 Nc):

matlab
TxFreqSignal = circshift(TxFreqSignal, Nfft/2, 1); RxFreqSignal = circshift(RxFreqSignal, Nfft/2, 1);

4)顺便把 Hest 的维度初始化修正(你这行本身也很像 bug)

你现在是:

matlab
Hest=zeros(length(sensingSymbolNum),sensingSymbolNum,rxAntNum);

这很容易变成 1 x sensingSymbolNum x rxAntNum

建议直接按导频/参考抽取后的大小来:

matlab
Hest = zeros(length(fpattern), length(tpattern), rxAntNum, 'like', RxFreqSignal);

如果你不是“居中映射”,而是用 fpattern 映射(更稳)

如果你的 RsMapping 本来就是通过 fpattern 把有效子载波放进大 FFT 栅格,那 pad 推荐写成这样(避免映射错位):

matlab
function X = map_by_fpattern(Xin, Nfft, fpattern) % Xin: [Nc x Ns], X: [Nfft x Ns] X = zeros(Nfft, size(Xin,2), 'like', Xin); X(fpattern,:) = Xin; end

然后在 ofdmModulate 里用:

matlab
X = map_by_fpattern(TxFreqSignal(:,:,antId), fftSize, sensing.fpattern); TxSignalT = idaft(X, sensing.afdm.c1, sensing.afdm.c2);

channelEst AFDM 分支也一样先把 TxRef 映射进 Nfft。


为什么这能“把 205 拉回 164”

因为你观测到的是 ×1.25 的缩放 + 环绕,几乎就是“变换长度/符号时长不一致”的指纹。
把 AFDM 的 DAFT/IDAFT 也强制在 同一个 Nfft 上,就会恢复与 OFDM 相同的符号时长与离散 Doppler 栅格,峰值 bin 就会回到原来的位置(或只剩下一个固定的 shift,那就再检查 fftshift/circshift 的定义是否一致)。


快速自检(你跑一下就能定位是不是这个问题)

在进入 ofdmModulate 前后打印这几个量(只要一次):

matlab
disp([size(TxFreqSignal,1), sensing.Nc, sensing.fftSize])

如果你看到 size(TxFreqSignal,1)sensing.Ncsensing.fftSize 不是同一个数,并且比值接近 1.25 或 0.8,那基本就坐实了。


如果你按上面改完,峰值位置仍然是整体×1.25,那下一嫌疑就是 你在 AFDM 分支里改变了“符号间隔 slotT 的真实定义”(把 CP 算进去了/算错了) 或者 channelPass 的时间轴定义跟解调抽样点对不上。到那一步你把 sensing.fftSize、CplenSet、采样率Fs、slotT 的定义贴出来,我可以把“真实 slow-time 采样时刻 t_n”那条链路也一并对齐。

이 Q&A 공유하기