ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

5G毫米波信道仿真中的快速射线追踪:原理、实现与验证

5G毫米波信道仿真中的快速射线追踪:原理、实现与验证 简介一份面向5G毫米波信道仿真的快速射线追踪MATLAB源码包适用于通信工程、网络规划相关的研究者与工程师帮助在密集城区环境下预测毫米波信号的传播路径、损耗与多径效应。压缩包共23个文件其中15个.m源码文件为核心算法实现如直线求交、墙体识别、镜像点计算等5个.json文件提供了曼哈顿、法兰克福、北京、清华等多组城市建筑地图数据另附结果图、LICENSE与README说明文档。整包仅117KB结构紧凑便于二次开发与教学演示。已有243人学习下载适合正在研究5G毫米波传播特性、波束赋形策略或基站布局优化的读者。通过运行源码可快速还原典型城市场景下的射线追踪流程观察不同建筑遮挡对覆盖的影响也可修改地图参数扩展实验为理解5G技术中mmWave频段的关键挑战提供直观工具。1. 射线追踪在5G通信毫米波仿真里为什么又火起来了快速实现对信道研究意味着什么射线追踪这几年在5G通信的毫米波频段里几乎是绕不开的工具。原因不复杂工作在28GHz甚至更高的频段时波长只有厘米级传统的统计信道模型很难刻画反射、绕射、遮挡这些几何效应而射线追踪直接从三维场景出发能算出每条路径的具体走向。3dengjunquan的MmWave_FastRayTracing项目正是一个轻量级的快速射线追踪实现输入城市级三维建筑面输出发射点到接收点的多径射线路径、路径损耗和时延信息。它解决的痛点是做5G毫米波信道仿真时不需要重型商业软件用公开数据和自己写的几十行核心代码就能在可接受的时间内拿到可信的多径分布。适合无线信道方向的研究生、做小区覆盖仿真的工程师以及想在离线数据集上验证波束管理算法的从业者。今天这篇笔记我把这个项目的核心逻辑、跑通步骤和踩过的坑一次说清楚。2. 快速射线追踪的核心逻辑发射点、接收点和三维建筑面的三角化关系2.1 射线从哪来、到哪去TX/RX坐标和三维建筑面数据的输入约定射线追踪的第一步不是算而是把场景说清楚。这个项目里的场景由两部分组成一是发射点TX和接收点RX的坐标二是建筑物模型。建筑物模型在常见开源实现里通常用OBJ或STL格式的三维三角面描述整个场景就是一大堆三角形的集合。这个项目的输入约定和多数开源射线追踪工具一致把三维地图中建筑物的外表面先做一次三角化网格化然后为每条射线去遍历这些三角形面找交点。我一般会先准备一份城市区域的简化三维模型来自OpenStreetMap的building footprint经过高度拉伸或者直接用仿真软件导出的OBJ。关键是单位要统一毫米波仿真的坐标单位通常用米如果模型是从别处转换来的先确认坐标尺度和原点位置否则后续路径损耗算出来全是错的。发射点高度按真实部署习惯设室外宏站一般25到35米微站设在灯杆或楼顶边缘接收点高度按UE场景取1.5米人行道或某个楼层高度。这个项目对TX和RX的建模方式非常直接它们就是两个三维坐标点射线从TX按一定角度间隔发射经过场景里的三角形面反射最终落在RX附近某个接收球或接收圆盘内即视为命中路径。2.2 射线与三角面求交的背后Möller-Trumbore算法为什么适合毫米波反射路径这是整个FastRayTracing项目里快速二字的来源。射线与三角形求交如果先求平面方程、再判断交点是否在三角形内每次求交要做很多次向量运算。Möller-Trumbore算法用重心坐标一步到位把射线表示成 O tD把三角形内部点表示成重心组合联立解方程一次叉乘加两次点乘就能得到交点的t值和重心坐标(u,v)。import numpy as np def moller_trumbore(origin, direction, v0, v1, v2): eps 1e-8 edge1 v1 - v0 edge2 v2 - v0 pvec np.cross(direction, edge2) det np.dot(edge1, pvec) if abs(det) eps: return None inv_det 1.0 / det tvec origin - v0 u np.dot(tvec, pvec) * inv_det if u -eps or u 1.0 eps: return None qvec np.cross(tvec, edge1) v np.dot(direction, qvec) * inv_det if v -eps or u v 1.0 eps: return None t np.dot(edge2, qvec) * inv_det if t 0: return None return t, u, v这段代码里origin是射线起点direction是单位方向向量v0、v1、v2是三角形三个顶点。返回的t表示射线参数方程里交点的位置u和v是交点在三角形上的重心坐标直接用于判断交点是否落在三角形内部。我特别提醒一点direction不归一化求出来的t就没有物理意义。所以每次发射射线前先做一次归一化让t值直接代表距离后面算路径长度和时延时能少很多麻烦。这个算法在毫米波场景里特别合适的原因在于毫米波反射路径通常次数不多一阶反射和二阶反射占主导。每次反射就是一次射线段与场景三角形集合的求交而求交速度决定了整体仿真耗时的下限。把三角形集合预先用空间网格或八叉树分桶每次求交只测邻近的面片单条射线耗时能从毫秒级降到微秒级。这个优化在原项目中体现得很直接场景面片数越多加速结构带来的收益越明显我用一个两平方公里的小区模型试过不加加速结构要跑十几分钟加上空间桶之后几十秒出结果。2.3 可视化输出从TX出发的射线是怎么画到地图坐标上的仿真结果不能只给一张数字表射线追踪的优势本来就是直观展示路径。项目输出的可视化通常是两张图一张是三维俯视图画所有命中路径的折线一张是带建筑物轮廓的二维平面图强调路径在地面上的投影。坐标变换的坑集中在坐标系上。三维模型文件的坐标系可能是任意定义的而TX/RX坐标用的是经纬度或工程坐标两者之间需要做一个刚体变换。我一般先取场景内三个已知地标点计算旋转矩阵和平移向量把模型坐标统一到仿真坐标系里再绘制射线路径。渲染层的处理比较直接一条命中路径包含一串三维点从TX出发经过反射点最后到达RX把这些点依次连线再叠加建筑面的半透明色块就得到常见的射线追踪可视化图。3. 把项目跑起来环境配置、参数设定与第一张射线图3.1 环境依赖与启动方式这个项目是Python实现依赖库集中在numpy、matplotlib部分版本还用到scipy做空间索引以及pyyaml读配置文件。我建议直接用conda建一个干净环境Python版本选3.8以上都可以。conda create -n mmwave_ray python3.10 conda activate mmwave_ray pip install numpy matplotlib scipy pyyaml git clone https://github.com/3dengjunquan/MmWave_FastRayTracing.git cd MmWave_FastRayTracing python main.py --config configs/demo.yamlmain.py是入口脚本--config指定场景配置文件。如果目录里没有configs文件夹那多半是把参数写在脚本顶部或者用一个单独的settings.py这种情况直接把配置文件路径换成对应文件即可。跑起来之后终端会先打印场景的面片数量、建筑物数量、TX/RX坐标然后开始发射射线。这里有个容易被忽略的点OpenStreetMap数据下载下来通常是WGS84经纬度而射线追踪求交时用经纬度计算距离误差很大必须先把经纬度投影到平面坐标。常见做法是用UTM投影或者简单的等距圆柱投影。项目自带demo场景一般已经做过处理但如果要换成自己的城市数据这一步必须自己接上。3.2 关键参数频点、反射次数、射线条数与计算时间的权衡射线追踪的效果几乎完全由参数决定。我列一份常用参数表网上大多数开源项目也是这套框架。参数名典型值作用调参方向Frequency28 GHz决定波长影响路径损耗计算和反射系数按目标频段设MaxReflection2最大反射次数提高次数增加精度耗时指数级上升RayDensity0.5°发射射线角间隔间隔越小路径越全耗时越大ReceiveRadius0.5 m接收球半径半径越大越容易命中但路径误差越大TransmitPower30 dBm发射功率仅影响绝对电平按实际基站配置BuildingHeightSource默认高度没有高度数据时的建筑高度用楼层数乘以3米估算频点26GHz和28GHz在5G毫米波里是主流项目参数设的反射次数如果超过2建议先测一下单条射线的平均求交时间。一般来说反射次数每增加1需要发射的射线数量不变但每条射线的求交次数增加一个量级而接收球命中率却会下降。我自己的习惯是一阶反射必开二阶反射按场景复杂度决定三阶及以上在大多数城市宏站场景里贡献的路径占比不到百分之五直接关掉能省大量时间。射线密度这个参数最影响体验。0.5°间隔意味着TX发射的射线总数是4π steradian除以角间隔对应的立体角大约几十万条量级配合二阶反射在普通台式机上跑一个中等场景要几分钟。如果只是看趋势把角间隔放到1°到2°结果差异肉眼基本看不出来但速度能快四倍。数据要发表的话再用小间隔精算一轮。3.3 输出文件里有什么路径损耗、时延、到达角的字段解读运行结束后的输出通常包含两类文件一类是路径列表另一类是汇总统计。路径列表的每一行代表一条命中路径字段格式多为路径编号、离开方位角、离开俯仰角、到达方位角、到达俯仰角、路径长度、路径损耗、时延。我见过很多人在这一步直接懵掉因为不同项目的输出字段名不一样。最稳妥的办法是先看脚本里写输出语句的那一段确认每个字段的物理单位。path length单位是米delay单位是纳秒path loss单位是dB。时延等于路径长度除以光速如果同时给出了这两个字段算一下乘积是否等于光速可以直接验证数据是否正确。路径损耗的计算公式各项目有差异有的是基于Friis公式加反射系数有的直接按自由空间损耗加上反射面损耗。项目里如果提供的是每个反射点的入射角和反射系数那路径损耗就是多段自由空间损耗累加后减去反射增益这个可以手工验算一条路径来确认。下面这行命令是我常用来快速查看输出文件结构的head -20 output/paths.csv | column -t -s ,先确认字段顺序再决定怎么做后处理。我建议把输出整理成DataFrame之后按路径损耗排序前几条最强路径对应的物理路径画出来看一下确认射线确实是从合理的反射面过来的。这一步能筛掉大部分坐标系错误和模型错误比直接看统计指标靠谱得多。4. 毫米波信道特征在射线追踪结果里怎么读路径损耗、时延扩展与阻塞4.1 视距与非视距路径在射线图上的表现差异射线追踪结果里最先应该看的是视距LOS和非视距NLOS路径的结构差异。视距路径在图上就是从TX到RX的一条直线没有反射点路径损耗跟自由空间损耗曲线完全一致。非视距路径则是折线每个折点对应一次反射。在毫米波频段这两者差异非常明显。28GHz下一条非视距路径如果只经过一次反射路径损耗通常比视距路径高出15到20dB以上原因是反射面的反射系数在毫米波频段通常小于1而且反射路径的总长度比视距长。如果反射次数达到两次路径损耗普遍比视距高出30dB以上基本可以认为这条路径对信道容量的贡献可以忽略。读射线图的时候我习惯把LOS路径和NLOS路径分开统计。如果NLOS路径数量占比过高先检查是不是接收球半径设得过大、导致大量不合理的反射路径被判定为命中。一个常见做法是把接收球半径从0.5米改成0.2米再看路径数量变化。真实信道里NLOS路径数量远多于LOS但强路径的占比应该集中在少数几条一阶反射路径上。4.2 反射路径与时延扩展为什么毫米波对反射面平整度敏感时延扩展是从射线追踪结果里最容易读出的信道指标也是波束管理和均衡器设计的核心输入。把每条命中路径的时延按到达时间排序最大时延和最小时延之差就是时延扩展。城市宏站场景下一阶反射路径的额外时延通常在几十到几百纳秒之间对应反射路径比视距路径长几米到几十米。这里有个毫米波特有的问题波长只有10毫米量级反射面平整度对反射系数影响极大。射线追踪模型默认反射是镜面反射但真实墙面在毫米波下往往呈现漫反射成分粗糙表面的反射系数需要乘一个衰减因子。很多开源项目不处理这个细节导致仿真出的NLOS路径损耗偏低时延扩展偏大。我一般处理方法是在反射点位置查一下对应的建筑物材质粗糙墙面在28GHz下的镜面反射衰减按3到6dB估算。如果项目没提供这个接口至少对结果做一个保守解读别直接拿NLOS路径损耗绝对值去做链路预算。4.3 阻塞识别射线追踪做覆盖预测时最容易高估的一点人体、车辆、树木这些在低频可以忽略的遮挡物在毫米波频段会造成10dB以上的额外损耗。射线追踪项目里通常只包含建筑物模型所以对这类动态阻塞是无能为力的。还有个更隐蔽的问题——建筑物模型本身不包含窗户。玻璃在毫米波频段的穿透损耗相对墙体低一些但反射特性跟混凝土墙完全不同。我在做覆盖预测时踩过一个大坑射线追踪算出来的信号强度在某个区域显示是强覆盖但实测信号很差原因就是反射面是玻璃幕墙28GHz下镜面反射方向性很强仿真用的理想镜面反射高估了反射增益再叠加幕墙对来波方向的散射真实到达接收点的能量远低于预测值。从那以后我做覆盖预测时都会在射线追踪结果上加一个2到4dB的阻塞余量。5. 避坑我从这个项目里踩过的五个真实问题5.1 现象电脑配置不低但仿真特别慢原因用的网格加速结构没生效所有射线都在遍历全部三角形面片复杂度直接是射线数乘面片数。我刚开始跑项目时一个两平方公里场景大概三万个三角面射线密度设成0.2°跑了一个多小时没出结果。解决检查项目是否真的启用了空间分桶或八叉树索引。如果算法实现里就是线性遍历那就自己加一个简单的体素网格把三角形面片按包围盒分到格子求交之前先算出射线经过的格子只访问相关格子里的面片。加上之后同样的场景几分钟就出来了这是整个项目中最值得动手优化的一段代码。5.2 现象渲染出来的射线图有大量异常折线路径交叉乱跳原因两个坐标系没对齐。模型文件的建筑底图和TX/RX坐标可能来自不同数据源导致射线穿进建筑内部或者从建筑背面反射出来。我第一次换到自己的城市数据时射线图里的路径一大堆穿楼而过以为算法有问题后来确认是建筑高度坐标轴和TX/RX坐标差了大概十米的偏移。解决先在可视化里同时画出建筑物轮廓和TX/RX点位检查坐标偏移方向然后做一个刚体变换把两套坐标对齐。如果射线仍然穿楼就检查建筑三角面的法向朝向射线和三角面求交时如果法向反了反射方向会算错表现为路径穿墙。用MeshLab或者Trimesh库批量翻转法向即可。5.3 现象接收点收不到任何射线路径数为零原因接收球半径设置小于射线到达的空间密度或者反射次数设置太低。射线追踪本质上是对连续空间做离散采样发射角间隔越大到达RX附近区域的射线越少半径太小就越可能一条都落不进来。解决先逐步调大接收球半径从0.1米到0.5米再到1米看路径数是否线性增长。如果仍然为零把最大反射次数加1试试。还有一个容易被忽略的点检查TX是否被建筑物模型包裹住了如果发射点落在建筑实体内部射线根本出不去路径数为零是必然结果。5.4 现象路径损耗数值比理论自由空间损耗低很多原因路径损耗计算里漏掉了反射系数或者反射增益被重复计算。我遇到过输出里一阶反射路径的路径损耗竟然比视距路径还低5dB这显然不符合物理规律。翻代码发现反射点的反射系数计算里加了天线方向图增益而方向图增益在传播路径计算里已经算过一次重复加了。解决手工选一条简单路径按自由空间损耗公式计算基准值再逐段叠加反射损耗和输出做比对。单条路径的链路级验算能快速定位是重复计增益还是漏计损耗。如果项目输出包含每个反射点的入射角那反射系数应该按频点和入射角查表或按公式算不要用固定值代替。5.5 现象换了城市地图后TX/RX坐标对不上地图显示空白原因下载的OpenStreetMap数据是WGS84经纬度直接当成米制坐标用了。经纬度数值大概在120度量级而本地坐标数值是几十万米量级两者混用导致TX/RX点位落在离建筑物十万八千里远的地方地图看起来就是一片空白。解决在预处理阶段先把经纬度统一投影到UTM平面坐标系。用pyproj做转换时注意UTM分带国内城市用对应分带值。转换完成后验证地标点的距离关系比如两个已知点之间转换后的距离和实际GPS测距误差应该在一米以内确认无误再喂给射线追踪程序。6. 用数据验证结果从射线追踪输出反推自由空间损耗的快速检查法射线追踪程序跑完不代表结果可信我每次都会用一套快速检查法验证输出前后不超过五分钟。拿到路径列表后挑最早到达的那条路径它一般都是视距路径。检查它的路径长度按光速换算成时延再和输出里的时延字段比对误差应该小于纳秒级验证时延计算没问题。然后按自由空间路径损耗公式单独算一下这条路径的理论损耗值import math freq_hz 28e9 dist_m 120.0 fspl_db 20 * math.log10(dist_m) 20 * math.log10(freq_hz) - 147.55 print(fFree-space path loss: {fspl_db:.2f} dB)把理论值和输出里的LOS路径损耗对比如果误差在1dB以内说明波长、距离、损耗计算这三个基础环节都是对的。误差超过3dB就停下来查单位——最常见的是频率填了MHz而不是Hz或者距离用了公里。反射路径的验证更简单取一条一阶反射路径用反射点坐标算出TX到反射点、反射点到RX两段距离相加和输出的路径长度比对。如果长度一致但时延对不上查是不是路径输出里存的是平面投影长度而不是三维空间距离。这两项检查做完仿真结果的基本可靠性就有底了。最后我还会做一步统计验证所有命中路径的时延画成直方图正常情况下应该是在最小路径时延之后出现一个衰减尾巴如果直方图在某个时延处出现奇怪的尖峰多半是接收球设置过大导致同一路径被重复计数回查参数。最近一次做28GHz城市信道仿真我按这套流程先验算再批量跑数据全程没有出现方向性错误。从那以后我每次拿到射线追踪输出都强制走一遍自由空间损耗反推和路径长度复算虽然只花五分钟但省下的返工时间远远不止这些。射线追踪的最大价值本来就是几何直观如果连基础物理都不对那画出来的图再漂亮也只是废图希望这篇笔记能帮你在自己的数据上少走一圈弯路。本文还有配套的精品资源点击获取
返回列表