简介:一份面向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 python=3.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 关键参数:频点、反射次数、射线条数与计算时间的权衡
射线追踪的效果几乎完全由参数决定。我列一份常用参数表,网上大多数开源项目也是这套框架。
| 参数名 | 典型值 | 作用 | 调参方向 |
|---|---|---|---|
| Frequency | 28 GHz | 决定波长,影响路径损耗计算和反射系数 | 按目标频段设 |
| MaxReflection | 2 | 最大反射次数 | 提高次数增加精度,耗时指数级上升 |
| RayDensity | 0.5° | 发射射线角间隔 | 间隔越小路径越全,耗时越大 |
| ReceiveRadius | 0.5 m | 接收球半径 | 半径越大越容易命中,但路径误差越大 |
| TransmitPower | 30 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(f"Free-space path loss: {fspl_db:.2f} dB")把理论值和输出里的LOS路径损耗对比,如果误差在1dB以内,说明波长、距离、损耗计算这三个基础环节都是对的。误差超过3dB,就停下来查单位——最常见的是频率填了MHz而不是Hz,或者距离用了公里。
反射路径的验证更简单:取一条一阶反射路径,用反射点坐标算出TX到反射点、反射点到RX两段距离相加,和输出的路径长度比对。如果长度一致但时延对不上,查是不是路径输出里存的是平面投影长度,而不是三维空间距离。这两项检查做完,仿真结果的基本可靠性就有底了。
最后我还会做一步统计验证:所有命中路径的时延画成直方图,正常情况下应该是在最小路径时延之后出现一个衰减尾巴,如果直方图在某个时延处出现奇怪的尖峰,多半是接收球设置过大导致同一路径被重复计数,回查参数。
最近一次做28GHz城市信道仿真,我按这套流程先验算再批量跑数据,全程没有出现方向性错误。从那以后我每次拿到射线追踪输出,都强制走一遍自由空间损耗反推和路径长度复算,虽然只花五分钟,但省下的返工时间远远不止这些。射线追踪的最大价值本来就是几何直观,如果连基础物理都不对,那画出来的图再漂亮也只是废图,希望这篇笔记能帮你在自己的数据上少走一圈弯路。
本文还有配套的精品资源,点击获取