你现在是一名无线通信方向的专家,详细介绍一下'TDL-A','TDL-B','TDL-C','TDL...
创建于:2025年11月14日
使用 GPT-5.1 Thinking 回答 Chat01
创建于:2025年11月14日
使用 GPT-5.1 Thinking 回答 Chat01
你现在是一名无线通信方向的专家,详细介绍一下'TDL-A','TDL-B','TDL-C','TDL-D','CDL-A''CDL-B''CDL-C这些场景的区别
先把结论说在前面:
下面按层次展开:
TDL 模型(抽头延时线)
CDL 模型(簇延时线)
在 TR 38.901 中:
而且:
特点: (ETSI)
工程直觉:
“房间里有一些反射,但路径不会拖得特别长”,频率选择性适中。
特点: (ETSI)
工程直觉:
还是 NLOS,但天线周围反射/散射物体更多一点,近身密集反射较多。
特点: (ETSI)
工程直觉:
“楼外基站打进楼里 / 街道拐角后的非视距”,多径拖得很长,对 OFDM 来说 频率选择性很强,DMRS 设计、循环前缀长度等都更“吃紧”。
特点: (ETSI)
工程直觉:
“主干道上有直视路径,但周围高楼一圈”,LOS 很强,但多径尾巴也很长。
这三个都是 NLOS 的簇延时线模型,区别主要在:
和 TDL 对应关系大致是:
特点:
TDL-A vs CDL-A:
特点: (ETSI)
对比:
特点: (ETSI)
工程含义:
可以用一个简化对比表(只写相对关系,不写具体数值):
| Profile | 模型类型 | LOS/NLOS | 时延扩展(相对) | 空间信息 | 常见理解/场景示意 |
|---|---|---|---|---|---|
| TDL-A | TDL | NLOS | 短 | 无角度 | 室内/小区 NLOS,中等多径 |
| TDL-B | TDL | NLOS | 中 | 无角度 | 多径更密集的 NLOS |
| TDL-C | TDL | NLOS | 长 | 无角度 | UMi O2I、城市 NLOS,强频率选择性 |
| TDL-D | TDL | LOS | 中~长 + 强 LOS | 无角度 | 视距 + 丰富散射的城市场景 |
| CDL-A | CDL | NLOS | 短 | 有(3D 角度) | Indoor NLOS,小阵列/大阵列都可 |
| CDL-B | CDL | NLOS | 中 | 有 | 城市 NLOS,多径稍丰富 |
| CDL-C | CDL | NLOS | 长 | 有 | UMi O2I / 城市峡谷 NLOS,大带宽下典型“难场景” |
一个很实用的经验(也是 38.101/38.104、NTIA 等文档常用的套路):(Institute for Telecommunication Sciences)
如果你后面打算做 具体仿真(MATLAB / Sionna / 自写仿真),我可以帮你:
详细介绍一下下面每一行代码的功能:function [precodingValue] = TxAnalogPrecoding(sensing, TxFreqSignal, channel)
txAntNum = sensing.txAntNum;
fftSize = sensing.fftSize;
Nsymbol = sensing.Nsymbol;
[Mg,Ng,M,N,P]=deal(channel.bs.Mg_Ng_M_N_P(1),channel.bs.Mg_Ng_M_N_P(2),channel.bs.Mg_Ng_M_N_P(3),channel.bs.Mg_Ng_M_N_P(4),channel.bs.Mg_Ng_M_N_P(5));
N1=sensing.bs.N1N2(1);
N2=sensing.bs.N1N2(2);
[K,L]=deal(channel.bs.txru_size(1),channel.bs.txru_size(2));
if K*L==1
precodingValue=repmat(TxFreqSignal,1,txAntNum);
precodingValue=reshape(precodingValue,fftSize,Nsymbol,txAntNum);
else
texttheta=channel.targetAngle(2); phi=channel.targetAngle(1); dv=channel.bs.spacing(2); dh=channel.bs.spacing(1); wk=exp(-1j*2*pi*([0:K-1])*dv*cos(theta))/sqrt(K); % according to TR36.897 5.2.2 wl=exp(-1j*2*pi*([0:L-1])*dh*sin(phi))/sqrt(L); W=kron(wl,wk); antId=reshape([1:M*N*Mg*Ng],M*Mg,N*Ng); precodingValue=zeros(size(TxFreqSignal,1),size(TxFreqSignal,2),K*L*size(TxFreqSignal,3)); for p=1:P for n1Id=1:N1 for n2Id=1:N2 portId=N2*(n1Id-1)+n2Id+(p-1)*N1*N2; data=TxFreqSignal(:,:,portId); analogValue=kron(data,W); antId_txru=antId(K*(n2Id-1)+1:n2Id*K,L*(n1Id-1)+1:n1Id*L)+(p-1)*M*N; analogValue=reshape(analogValue,size(TxFreqSignal,1),K*L,size(TxFreqSignal,2)); precodingValue(:,:,antId_txru(:))=permute(analogValue,[1,3,2]); end end end
end
我直接按从上到下、逐行给你讲每一句在干嘛,同时尽量说明一下物理/通信含义(混合波束成形、阵列结构之类)。
matlabfunction [precodingValue] = TxAnalogPrecoding(sensing, TxFreqSignal, channel)
TxAnalogPrecoding,输入:
sensing:结构体,包含发射端相关配置(天线数、FFT 长度、符号数、端口排列等)。TxFreqSignal:频域发射信号,一般尺寸是 [fftSize, Nsymbol, Nport]。channel:结构体,包含阵列结构、目标角度、天线间距等。precodingValue:加完模拟预编码(analog beamforming)之后、按物理天线展开的频域信号,一般尺寸 [fftSize, Nsymbol, txAntNum]。matlabtxAntNum = sensing.txAntNum; fftSize = sensing.fftSize; Nsymbol = sensing.Nsymbol;
sensing 结构体中读取关键配置参数:
txAntNum:基站物理发射天线总数。fftSize:OFDM 的 FFT 点数。Nsymbol:本次处理的 OFDM 符号数(时域上有多少个符号)。matlab[Mg,Ng,M,N,P]=deal(channel.bs.Mg_Ng_M_N_P(1),channel.bs.Mg_Ng_M_N_P(2),channel.bs.Mg_Ng_M_N_P(3),channel.bs.Mg_Ng_M_N_P(4),channel.bs.Mg_Ng_M_N_P(5));
channel.bs.Mg_Ng_M_N_P 是一个长度为 5 的向量,依次表示:
Mg:垂直方向上 panel(子阵列)的数量(比如有 Mg 行 panel)。Ng:水平方向上 panel 的数量(Ng 列)。M:每个 panel 内垂直方向天线数。N:每个 panel 内水平方向天线数。P:一般用来表示极化数或“panel 集合数量”等(这里作为一个额外的维度循环)。deal(...) 的作用是把 5 个值分别“发给” Mg, Ng, M, N, P 五个变量。简单理解:整个阵列排成 Mg×Ng 个 panel,每个 panel 里是 M×N 个天线,一共
Mg*Ng*M*N个天线;P是再额外的一个“层”,下面通过(p-1)*M*N偏移把它平铺到索引里。
matlabN1=sensing.bs.N1N2(1); N2=sensing.bs.N1N2(2);
sensing.bs.N1N2 是一个 [N1, N2] 向量。N1:通常表示天线端口(如 TXRU)在某一方向(比如垂直)的个数。N2:表示在另一方向(水平方向)的个数。p, n1Id, n2Id,组合成 portId,即「第 p 个集合里第 (n1Id,n2Id) 个端口」。matlab[K,L]=deal(channel.bs.txru_size(1),channel.bs.txru_size(2));
channel.bs.txru_size = [K, L]:
K:一个 TXRU 在垂直方向控制的天线数。L:一个 TXRU 在水平方向控制的天线数。matlabif K*L==1
K*L == 1,说明一个 TXRU 只管 一根天线,也就是非混合、全数字架构(每端口对应一根天线)。K*L > 1,就是 一个 TXRU 控制多个天线,需要设计 analog precoding(波束赋形)。matlabprecodingValue=repmat(TxFreqSignal,1,txAntNum);
TxFreqSignal 大概是 [fftSize, Nsymbol, Nport]。repmat(...,1,txAntNum):在第 2 维保持不变,在第 3 维重复 txAntNum 次。
1,第三个参数是 txAntNum,对 3 维矩阵来说就是 [1, 1, txAntNum] 的复制。Nport = 1,否则这里会有点奇怪,不过从代码风格看是「简化情况:所有天线发同一端口信号」)。matlabprecodingValue=reshape(precodingValue,fftSize,Nsymbol,txAntNum);
[fftSize, Nsymbol, txAntNum],也就是:
txAntNum 根天线的信号值。if 分支结束。matlabelse
matlabtheta=channel.targetAngle(2); phi=channel.targetAngle(1);
channel.targetAngle 一般是 [phi, theta]:
phi:方位角(azimuth)。theta:仰角/elevation。[phi, theta] 顺序存的,所以:
phi = channel.targetAngle(1);theta = channel.targetAngle(2);matlabdv=channel.bs.spacing(2); dh=channel.bs.spacing(1);
channel.bs.spacing 存的是天线间距(单位通常是相对于波长 λ 的归一化间距,比如 0.5 表示 λ/2):
dh:水平相邻天线间距。dv:垂直相邻天线间距。matlabwk=exp(-1j*2*pi*([0:K-1])*dv*cos(theta))/sqrt(K); % according to TR36.897 5.2.2
wk:
[0:K-1]:垂直方向第 k 根天线的索引。([0:K-1])*dv*cos(theta):每根天线相对相位差对应的「归一化距离」。exp(-1j*2*pi*...):构造相位因子 。/sqrt(K):归一化,使得 wk 的 2 范数为 1(功率归一)。物理意义:对 K 根竖直方向的天线,构造一个指向角
theta的波束方向向量。
matlabwl=exp(-1j*2*pi*([0:L-1])*dh*sin(phi))/sqrt(L);
wl:
[0:L-1]:水平方向天线索引。dh*sin(phi):与方位角有关的投影。matlabW=kron(wl,wk);
kron(wl, wk):对 wl(1×L)与 wk(1×K)做 Kronecker 积,得到长度 K*L 的向量 W。wk,再在水平方向用 wl,形成 K×L 的二维波束,然后按某种顺序展平。物理意义:这是一个 子阵列(K×L 天线)整体的模拟预编码向量,给这个 TXRU 用来生成指向
[phi, theta]的波束。
matlabantId=reshape([1:M*N*Mg*Ng],M*Mg,N*Ng);
antId:
[1:M*N*Mg*Ng]:从 1 到总天线数的向量。reshape(..., M*Mg, N*Ng):把它 reshape 成一个 (M*Mg) × (N*Ng) 的矩阵。后面会从这个矩阵中切出 K×L 的块,对应某一个 TXRU 控制的那一小块天线。
matlabprecodingValue=zeros(size(TxFreqSignal,1),size(TxFreqSignal,2),K*L*size(TxFreqSignal,3));
precodingValue 预分配空间:
size(TxFreqSignal,1) → fftSize;size(TxFreqSignal,2) → Nsymbol;K*L*size(TxFreqSignal,3)。TxFreqSignal 第 3 维是 Nport,那么这里第 3 维是 K*L*Nport,也就是“每个端口展开到 K*L 个天线”。注意:后面通过
antId_txru索引会把这些 KLNport 个“天线”正确填进实际的天线位置(txAntNum一般应该等于 KLNport 或再乘以 P 等)。
matlabfor p=1:P for n1Id=1:N1 for n2Id=1:N2
for p=1:P:遍历极化 / 面板组 / 端口组等第 3 个维度。for n1Id=1:N1:TXRU 在某一方向(比如垂直)的位置索引。for n2Id=1:N2:TXRU 在另一方向(比如水平)的位置索引。(p, n1Id, n2Id)。matlabportId=N2*(n1Id-1)+n2Id+(p-1)*N1*N2;
(p, n1Id, n2Id) 映射到一个线性端口索引 portId:
p,n1Id 和 n2Id 按行优先排成 1...N1*N2;+(p-1)*N1*N2:不同 p 的一组端口整体后移一个块,避免冲突。portId 范围:1 到 P*N1*N2,应该和 TxFreqSignal(:,:,portId) 的第三维对应。matlabdata=TxFreqSignal(:,:,portId);
data 尺寸为 [fftSize, Nsymbol],即某个端口在所有子载波、符号上的复信号。matlabanalogValue=kron(data,W);
W 结合:
data 是 fftSize × Nsymbol。W 是 1 × (K*L)。kron(data,W) 的尺寸为 fftSize × (Nsymbol * K*L)。data(k, n),把它乘上 W 这个长度为 K*L 的模拟权值向量;matlabantId_txru=antId(K*(n2Id-1)+1:n2Id*K,L*(n1Id-1)+1:n1Id*L)+(p-1)*M*N;
这句是整个代码里最关键的索引操作之一,慢慢分解:
antId(K*(n2Id-1)+1:n2Id*K , L*(n1Id-1)+1:n1Id*L)
antId 这个 (M*Mg) × (N*Ng) 矩阵中,取出一个大小为 K × L 的子矩阵:
K*(n2Id-1)+1 : n2Id*KL*(n1Id-1)+1 : n1Id*L+(p-1)*M*N
p 做整体偏移:每个 p 的天线索引都加上一个 M*N 的常数。p 这个维度相当于“再叠了一层 M×N 的天线块”。最终:
antId_txru 是一个 K×L 的矩阵,里面存的是 物理天线编号(考虑了 (n1Id,n2Id) 的 TXRU 位置,以及第 p 层的偏移)。matlabanalogValue=reshape(analogValue,size(TxFreqSignal,1),K*L,size(TxFreqSignal,2));
analogValue 是 fftSize × (Nsymbol*K*L)。[fftSize, K*L, Nsymbol]:
matlabprecodingValue(:,:,antId_txru(:))=permute(analogValue,[1,3,2]);
antId_txru(:):把 K×L 的天线编号矩阵展平为一维向量,长度 K*L。permute(analogValue,[1,3,2]):
analogValue 尺寸 [fftSize, K*L, Nsymbol] → [fftSize, Nsymbol, K*L]。precodingValue 的维度顺序 [子载波, 符号, 天线]。precodingValue(:,:,antId_txru(:)) = ...precodingValue 的这些具体天线索引里。物理意义:
对于当前端口(p, n1Id, n2Id),我们把它的信号按波束向量W拆分到K*L根子阵列天线上,然后再根据antId_txru把这些天线映射到整个大阵列的对应天线编号上,实现“端口 → TXRU → 子阵列天线”的模拟预编码。
matlabend end end end
(p, n1Id, n2Id) 的端口都已经完成 analog precoding,并写入 precodingValue 的相应天线上。if ... else ... end 结束。precodingValue。读取结构参数:
Mg, Ng, M, N, P;K, L;N1, N2;phi, theta;dh, dv。如果 K*L == 1(“一端口一根天线”):
TxFreqSignal 复制到每根天线上,不做复杂模拟预编码。如果 K*L > 1(混合波束成形):
[phi, theta] 和 dh, dv 生成垂直 wk、水平 wl 的 steering vector;W(长度 K*L);antId,用来从大阵列里切出每个 TXRU 控制的 K×L 小块;(p, n1Id, n2Id):
TxFreqSignal(:,:,portId) 取出该端口信号;kron(data, W) 把端口信号扩展到该 TXRU 下的 K×L 根天线;antId 取出对应的天线编号 antId_txru,加上 (p-1)*M*N 做偏移;analogValue 写入 precodingValue(:,:,这些天线索引)。precodingValue 就是“按目标方向做了模拟波束成形、并已经按物理天线展开”的频域信号矩阵。如果你愿意,我可以下一步帮你画一张阵列/端口/TXRU 的示意图,或者根据你现在仿真的参数(Mg,Ng,M,N,K,L,N1,N2 等)把每个维度的大小和对应关系列成一个表,这样用起来会更清晰。
function timeChannel = timeChannelGen(sensing,channel)
coeff=channel.CDL.coefficientTimeIndependent; % channel coefficient
dopplerf=channel.CDL.coefficientTimeDependent; % dopler parameter
fftSize=sensing.fftSize; % fft size
frameId=sensing.frameId; % frame index
Nsymbol=sensing.Nsymbol; % number of symbol
frameLen=sensing.frameLen; % data frame length, in ms
nonInteger = 1; % Whether to add a decimal delay
clusterNum=size(coeff,1); % number of cluster
rxAntNum=size(coeff,3); % number of receiving antennas
txAntNum=size(coeff,4); % number of transmitting antennas
delayTap = channel.tapDelay_dt; % Integer multiple delay
if sensing.fastchannel==0
dealtaT = [0:Nsymbol-1]frameLen1e-3/Nsymbol +(frameId-1)* frameLen1e-3; % time domain symbol time interval
else
dealtaT=(sensing.tpattern-1)sensing.Tsym + (frameId-1) frameLen1e-3;
end
timeChannel=zeros(fftSize, Nsymbol, rxAntNum, txAntNum);
for rxAntId=1:rxAntNum
for txAntId=1:txAntNum
for tId=1:length(dealtaT)
channelTemp = zeros(fftSize, 1);
for cId = 1:clusterNum
delayH = zeros(fftSize,1);
delayH(delayTap(cId) + 1,1)=sum(coeff(cId,:,rxAntId,txAntId).exp(1jdopplerf(cId,:,rxAntId,txAntId)dealtaT(tId))); % add doppler affect
if nonInteger == 1
temp = fft(delayH,fftSize) .exp(-1j2pichannel.deltaDelay(cId)/fftSizecircshift([0:fftSize-1]',fftSize/2)); % add a decimal delay
else
temp = fft(delayH,fftSize);
end
channelTemp = ifft(temp) + channelTemp;
end
timeChannel(:,tId,rxAntId,txAntId)=channelTemp;
end
end
end
我还是按从上到下、逐句+物理含义给你拆开讲一下这段信道生成代码。
matlabfunction timeChannel = timeChannelGen(sensing,channel)
timeChannelGen,输入:
sensing:系统/仿真配置(FFT、大框架长度、符号数、tpattern 等)。channel:信道相关参数(CDL 系数、多普勒、时延等)。timeChannel:一个随时间变化的 离散时域 CIR(channel impulse response),尺寸后面会看到。matlabcoeff=channel.CDL.coefficientTimeIndependent; % channel coefficient dopplerf=channel.CDL.coefficientTimeDependent; % dopler parameter
coeff:CDL 信道的“时间不变系数”,一般是:
[clusterNum, rayPerCluster, rxAntNum, txAntNum]。dopplerf:
coeff 对应。exp(1j*dopplerf * t) 这种形式给不同时间加相位旋转。直观:
coeff是“起始信道”,dopplerf告诉你每条径随时间怎么转相位(多普勒)。
matlabfftSize=sensing.fftSize; % fft size frameId=sensing.frameId; % frame index Nsymbol=sensing.Nsymbol; % number of symbol frameLen=sensing.frameLen; % data frame length, in ms
sensing 里读出:
fftSize:OFDM 的 FFT 点数,也是离散 CIR 的长度(这里用 fftSize 点去表示 CIR)。frameId:第几个帧(从 1 开始计)。Nsymbol:这个帧/时隙里你要模拟的符号数。frameLen:一帧的长度,单位是 ms(后面×1e-3 变成秒)。matlabnonInteger = 1; % Whether to add a decimal delay
1:加上小数时延(fractional delay),用频域相位来实现。0:只用整数采样点位置的时延。matlabclusterNum=size(coeff,1); % number of cluster rxAntNum=size(coeff,3); % number of receiving antennas txAntNum=size(coeff,4); % number of transmitting antennas
coeff 的尺寸提取:
clusterNum:簇数(第 1 维)。rxAntNum:接收天线数(第 3 维)。txAntNum:发射天线数(第 4 维)。sum(coeff(cId,:,rx,tx).* …) 把一个簇内所有射线相加。matlabdelayTap = channel.tapDelay_dt; % Integer multiple delay
delayTap:每个簇对应的整数采样时延(单位:采样点个数)。
clusterNum 的向量,第 c 个元素是第 c 个 cluster 的整数 tap 索引。delayH(delayTap(cId)+1) 置 1 个非零 tap。matlabif sensing.fastchannel==0 dealtaT = [0:Nsymbol-1]*frameLen*1e-3/Nsymbol +(frameId-1)* frameLen*1e-3; % time domain symbol time interval else dealtaT=(sensing.tpattern-1)*sensing.Tsym + (frameId-1)* frameLen*1e-3; end
这里是在生成每个符号对应的实际时间点 dealtaT(应该是 “deltaT” 拼错了)。
情况 1:fastchannel == 0:
matlabdealtaT = [0:Nsymbol-1]*frameLen*1e-3/Nsymbol +(frameId-1)* frameLen*1e-3;
[0:Nsymbol-1]:第 0、1、…、Nsymbol-1 个符号。frameLen*1e-3/Nsymbol:一帧内符号之间的时间间隔(秒)。[0:Nsymbol-1]*...:从这一帧开始时刻起,往后每个符号中心的时间。+(frameId-1)*frameLen*1e-3:第 frameId 帧的起始时间偏移。dealtaT 是长度为 Nsymbol 的向量,第 tId 项是当前帧中第 tId 个符号的绝对时间(秒)。情况 2:fastchannel ~= 0:
matlabdealtaT=(sensing.tpattern-1)*sensing.Tsym + (frameId-1)* frameLen*1e-3;
sensing.tpattern:某种符号时隙模式的索引(比如只在一部分符号上取信道)。Tsym:每个符号时间(秒)。(tpattern-1)*Tsym:把每个符号的时间位置扩展成一个向量。(frameId-1)*frameLen*1e-3。总之:
dealtaT(tId)就是第 tId 个 time sample 对应的真实时间,供 Doppler 相位用。
matlabtimeChannel=zeros(fftSize, Nsymbol, rxAntNum, txAntNum);
timeChannel,尺寸:
fftSize → 表示 CIR 的 tap 索引(0 ~ fftSize-1)。Nsymbol → 不同时间(符号)位置。rxAntNum。txAntNum。timeChannel(k, tId, rx, tx):第 tId 个时间点、从 tx 到 rx 的 第 k 个采样点的时域信道系数。matlabfor rxAntId=1:rxAntNum for txAntId=1:txAntNum for tId=1:length(dealtaT) channelTemp = zeros(fftSize, 1);
rxAntId:当前接收天线;txAntId:当前发射天线;tId:当前时间点(符号时刻)。(rxAntId, txAntId) 和每个 tId,我们要生成一个长度 fftSize 的 CIR:
channelTemp 为全 0 列向量,用于累加所有簇的贡献。matlabfor cId = 1:clusterNum delayH = zeros(fftSize,1);
clusterNum 个簇。delayH,长度为 fftSize 的全零向量,表示“该簇在当前时间点的 CIR”。matlabdelayH(delayTap(cId) + 1,1)=sum(coeff(cId,:,rxAntId,txAntId).*exp(1j*dopplerf(cId,:,rxAntId,txAntId)*dealtaT(tId))); % add doppler affect
这一句非常关键,拆开看:
coeff(cId,:,rxAntId,txAntId)
cId 个 cluster、所有射线(第二维 :)、当前 (rxAntId, txAntId) 对应的 复幅度,是一个行向量(射线数)。dopplerf(cId,:,rxAntId,txAntId)
t,看上去像 Hz)。exp(1j*dopplerf(...)*dealtaT(tId))
e^{j 2π f_d t} 类似的时间相关相位(这里只缺个 2π,可能 dopplerf 已经包含 2π)。coeff .* exp(...)
sum(...)
delayTap(cId) + 1
+1)。所以整句意思就是:
对 cluster cId:
在当前(rxAnt, tx, t)下,把簇内所有射线根据 Doppler 旋转后相加,形成一个复系数,然后放到delayH的第delayTap(cId)+1个 tap 上,其余位置为 0。
matlabif nonInteger == 1 temp = fft(delayH,fftSize) .*exp(-1j*2*pi*channel.deltaDelay(cId)/fftSize*circshift([0:fftSize-1]',fftSize/2)); % add a decimal delay else temp = fft(delayH,fftSize); end
这里是在处理 小数时延(fractional delay):
先对 delayH 做 FFT:
matlabfft(delayH, fftSize)
H(f)(实际上是离散频率点上的值)。如果 nonInteger == 1,则再乘一个频域相位项:
matlabexp(-1j*2*pi*channel.deltaDelay(cId)/fftSize*circshift([0:fftSize-1]',fftSize/2))
拆开讲:
[0:fftSize-1]':列向量,对应频率索引 k = 0,1,...,fftSize-1。circshift(..., fftSize/2):把频率索引平移 fftSize/2,相当于把 DC 移到中间,使频率索引在 [-fftSize/2, ..., fftSize/2-1] 对称。channel.deltaDelay(cId):这个簇的小数时延部分(单位:采样间隔)。数学上:时移 对应频域乘以 ,这里 f 用归一化频率 k/N 表示,所以用
2π * deltaDelay / fftSize * k形式。
nonInteger == 0:
temp = fft(delayH, fftSize);结果 temp 是考虑了多普勒+(可选)小数时延后的频域响应。
matlabchannelTemp = ifft(temp) + channelTemp;
temp 做 IFFT:
ifft(temp) → 回到时域上的 CIR,但已经包括了:
+ channelTemp:
所以
channelTemp最终是“对所有簇累加后的、当前(rx,tx,t)时刻的整条 CIR”。
matlabend timeChannel(:,tId,rxAntId,txAntId)=channelTemp;
cId 循环结束后:
channelTemp 已经包含了所有簇对当前 (rxAntId,txAntId,tId) 的贡献。timeChannel(:, tId, rxAntId, txAntId) = channelTemp;matlabend end end
timeChannel 填满,函数结束返回。给定 CDL 信道的簇/射线系数、各射线的 Doppler、每簇整数+小数时延,按时间 tId 对每对 (rx, tx) 生成一个长度为
fftSize的、随时间变化的离散时域信道脉冲响应(CIR),并存入timeChannel(k, t, rx, tx)。
coeff(cId, ray, rx, tx):
第 cId 个簇、第 ray 射线、rx-tx 对,在 t=0 时刻的复系数。
dopplerf(cId, ray, rx, tx):
同一射线的 Doppler 参数,用来算 相位旋转。
delayTap(cId):
第 cId 个簇的整数采样时延(单位:采样点个数)。
channel.deltaDelay(cId):
第 cId 个簇的小数采样时延(0~1 之类),用于频域线性相位。
dealtaT(tId):
第 tId 个符号对应的真实时间(秒),用于 Doppler 相位。
timeChannel(k, tId, rx, tx):
时间 tId 下,从 tx 到 rx 的 CIR 第 k 个 tap 的值。
如果你愿意,我可以帮你把这段代码“等价”改写成更易懂的伪代码 / 带注释 MATLAB 版本,或者结合一个具体 CDL 配置(比如 CDL-A、2×2 MIMO)画一下:
这个代码里有放我们目标导致的时延和多普勒么
有的,但这段代码本身只是在“应用”时延和多普勒,不负责“根据目标距离/速度去算”它们。
可以分两块看:
delayTapmatlabdelayTap = channel.tapDelay_dt; % Integer multiple delay ... delayH(delayTap(cId) + 1,1)= ...
cId 个簇,它在 CIR 里的主 tap 位置是 delayTap(cId)(采样点数),在代码里表现为:
delayH(delayTap(cId) + 1) 这个 tap 置为非零,其余 tap 为 0。channel.tapDelay_dt 的时候,已经把目标距离对应的往返时延换算成采样点数(取整),那这个“目标造成的时延”就已经体现在这里了。channel.deltaDelaymatlabif nonInteger == 1 temp = fft(delayH,fftSize) .* ... exp(-1j*2*pi*channel.deltaDelay(cId)/fftSize * circshift([0:fftSize-1]',fftSize/2)); else temp = fft(delayH,fftSize); end
channel.deltaDelay(cId) 是第 cId 个簇的小数部分时延(0~1 之类,单位是“采样间隔”)。delayTap(cId)(整数) + deltaDelay(cId)(小数)。tapDelay_dt 和 deltaDelay 中,那么这段代码就把它完整用上了。是的,多普勒就是在下面这句里加的:
matlabdelayH(delayTap(cId) + 1,1) = ... sum( coeff(cId,:,rxAntId,txAntId) .* ... exp( 1j * dopplerf(cId,:,rxAntId,txAntId) * dealtaT(tId) ) );
dopplerf(cId,:,rxAntId,txAntId):每条射线对应的 多普勒参数;dealtaT(tId):当前符号的绝对时间;exp(1j * dopplerf * t):就是给每条射线乘上随时间旋转的相位因子(多普勒效应);sum(...),得到该簇在当前时间的总系数。也就是说:
你在
channel.CDL.coefficientTimeIndependent里面放的是 t=0 时刻的初始系数,
在channel.CDL.coefficientTimeDependent里放的是 多普勒频率(一般跟目标径向速度有关),
这段代码在每个时间t = dealtaT(tId)时,用exp(j*dopplerf*t)把多普勒引起的相位变化加进来。
所以总结一句话:
delayTap(cId) + channel.deltaDelay(cId) 决定;dopplerf(cId,:,rx,tx) 决定,通过 exp(j*dopplerf*t) 体现;channel 结构体时有没有把目标的距离和速度映射进去。👉 换句话说:
channel.tapDelay_dt / channel.deltaDelay 和 dopplerf 的时候,已经按目标的 R、v算好了,这段 timeChannelGen 的代码就确实在把目标的时延和多普勒注入到信道里;如果你愿意,我可以帮你推一推:比如目标距离 R、速度 v,采样频率 Fs、载频 fc,应该如何算出:
delayTap 和 deltaDelay;dopplerf;然后直接对接到这个函数里。