主题070:城市与室内电波传播

一、引言

电波传播是无线通信系统设计的核心问题之一。随着5G/6G移动通信、物联网(IoT)、智能交通系统(ITS)等技术的快速发展,对城市和室内环境中电波传播特性的精确建模和预测变得愈发重要。城市峡谷中的多径效应、建筑物的穿透损耗、室内复杂的结构布局等因素都会显著影响信号覆盖质量和通信性能。

本教程将系统介绍城市与室内电波传播的基本理论、建模方法和仿真技术,包括射线追踪算法、主导路径模型、统计信道模型等内容,并通过Python代码实现多种传播场景的仿真分析。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、电波传播基础理论

2.1 自由空间传播模型

自由空间传播是最基本的电波传播模型,假设发射机和接收机之间没有任何障碍物。接收功率可由Friis传输方程描述:

Pr=PtGtGr(λ4πd)2P_r = P_t G_t G_r \left(\frac{\lambda}{4\pi d}\right)^2Pr=PtGtGr(4πdλ)2

其中:

  • PtP_tPt:发射功率(W)
  • PrP_rPr:接收功率(W)
  • GtG_tGt:发射天线增益
  • GrG_rGr:接收天线增益
  • λ\lambdaλ:波长(m)
  • ddd:传播距离(m)

自由空间路径损耗(以dB为单位):

Lfs=32.45+20log⁡10(f)+20log⁡10(d)L_{fs} = 32.45 + 20\log_{10}(f) + 20\log_{10}(d)Lfs=32.45+20log10(f)+20log10(d)

其中fff为频率(MHz),ddd为距离(km)。

2.2 大尺度衰落模型

2.2.1 对数距离路径损耗模型

实际环境中,路径损耗通常遵循对数距离规律:

PL(d)=PL(d0)+10nlog⁡10(dd0)+XσPL(d) = PL(d_0) + 10n\log_{10}\left(\frac{d}{d_0}\right) + X_\sigmaPL(d)=PL(d0)+10nlog10(d0d)+Xσ

其中:

  • PL(d0)PL(d_0)PL(d0):参考距离d0d_0d0处的路径损耗(dB)
  • nnn:路径损耗指数(自由空间n=2n=2n=2,城市环境n=2.7∼4.0n=2.7\sim 4.0n=2.74.0)
  • XσX_\sigmaXσ:阴影衰落,服从零均值高斯分布,标准差为σ\sigmaσ
2.2.2 Okumura-Hata模型

Okumura-Hata模型是城市宏蜂窝最常用的经验模型之一,适用于150MHz-1500MHz频段:

城市地区:

Lurban=69.55+26.16log⁡10(f)−13.82log⁡10(hb)−a(hm)+[44.9−6.55log⁡10(hb)]log⁡10(d)L_{urban} = 69.55 + 26.16\log_{10}(f) - 13.82\log_{10}(h_b) - a(h_m) + [44.9 - 6.55\log_{10}(h_b)]\log_{10}(d)Lurban=69.55+26.16log10(f)13.82log10(hb)a(hm)+[44.96.55log10(hb)]log10(d)

其中:

  • fff:频率(MHz)
  • hbh_bhb:基站天线高度(m),30-200m
  • hmh_mhm:移动台天线高度(m),1-10m
  • ddd:距离(km),1-20km
  • a(hm)a(h_m)a(hm):移动台天线高度修正因子

对于中小城市:

a(hm)=[1.1log⁡10(f)−0.7]hm−[1.56log⁡10(f)−0.8]a(h_m) = [1.1\log_{10}(f) - 0.7]h_m - [1.56\log_{10}(f) - 0.8]a(hm)=[1.1log10(f)0.7]hm[1.56log10(f)0.8]

对于大城市:

a(hm)=8.29[log⁡10(1.54hm)]2−1.1,f≤200MHza(h_m) = 8.29[\log_{10}(1.54h_m)]^2 - 1.1, \quad f \leq 200\text{MHz}a(hm)=8.29[log10(1.54hm)]21.1,f200MHz

a(hm)=3.2[log⁡10(11.75hm)]2−4.97,f≥400MHza(h_m) = 3.2[\log_{10}(11.75h_m)]^2 - 4.97, \quad f \geq 400\text{MHz}a(hm)=3.2[log10(11.75hm)]24.97,f400MHz

郊区:

Lsuburban=Lurban−2[log⁡10(f/28)]2−5.4L_{suburban} = L_{urban} - 2[\log_{10}(f/28)]^2 - 5.4Lsuburban=Lurban2[log10(f/28)]25.4

开阔地:

Lopen=Lurban−4.78[log⁡10(f)]2+18.33log⁡10(f)−40.94L_{open} = L_{urban} - 4.78[\log_{10}(f)]^2 + 18.33\log_{10}(f) - 40.94Lopen=Lurban4.78[log10(f)]2+18.33log10(f)40.94

2.2.3 COST-231 Hata模型

COST-231 Hata模型将频率范围扩展到2GHz:

L=46.3+33.9log⁡10(f)−13.82log⁡10(hb)−a(hm)+[44.9−6.55log⁡10(hb)]log⁡10(d)+CML = 46.3 + 33.9\log_{10}(f) - 13.82\log_{10}(h_b) - a(h_m) + [44.9 - 6.55\log_{10}(h_b)]\log_{10}(d) + C_ML=46.3+33.9log10(f)13.82log10(hb)a(hm)+[44.96.55log10(hb)]log10(d)+CM

其中CMC_MCM为修正因子:

  • 中等城市和郊区:CM=0C_M = 0CM=0 dB
  • 大都市中心:CM=3C_M = 3CM=3 dB

2.3 小尺度衰落模型

2.3.1 瑞利衰落

当不存在直射路径(LOS)时,接收信号包络服从瑞利分布:

f(r)=rσ2exp⁡(−r22σ2),r≥0f(r) = \frac{r}{\sigma^2}\exp\left(-\frac{r^2}{2\sigma^2}\right), \quad r \geq 0f(r)=σ2rexp(2σ2r2),r0

其中σ2\sigma^2σ2是多径分量的平均功率。

2.3.2 莱斯衰落

当存在强直射路径时,接收信号包络服从莱斯分布:

f(r)=rσ2exp⁡(−r2+A22σ2)I0(rAσ2),r≥0f(r) = \frac{r}{\sigma^2}\exp\left(-\frac{r^2 + A^2}{2\sigma^2}\right)I_0\left(\frac{rA}{\sigma^2}\right), \quad r \geq 0f(r)=σ2rexp(2σ2r2+A2)I0(σ2rA),r0

其中:

  • AAA:直射路径幅度
  • I0I_0I0:第一类零阶修正贝塞尔函数
  • K=A2/(2σ2)K = A^2/(2\sigma^2)K=A2/(2σ2):莱斯K因子(dB)
2.3.3 多普勒频移

移动引起的多普勒频移:

fd=vλcos⁡θ=fcvccos⁡θf_d = \frac{v}{\lambda}\cos\theta = f_c\frac{v}{c}\cos\thetafd=λvcosθ=fccvcosθ

其中:

  • vvv:移动速度(m/s)
  • θ\thetaθ:入射波与移动方向的夹角
  • fcf_cfc:载波频率(Hz)
  • ccc:光速(m/s)

最大多普勒频移:

fd,max=vλ=fcvcf_{d,max} = \frac{v}{\lambda} = f_c\frac{v}{c}fd,max=λv=fccv

三、城市电波传播建模

3.1 城市传播环境特征

城市环境电波传播的主要特征包括:

  1. 多径传播:信号经建筑物反射、散射后沿多条路径到达接收机
  2. 阴影衰落:大型建筑物遮挡造成的信号衰减
  3. 穿透损耗:信号穿透建筑物外墙、窗户等结构产生的损耗
  4. 街道峡谷效应:高楼之间的街道形成波导-like传播

3.2 射线追踪方法

射线追踪(Ray Tracing)是基于几何光学(GO)和几何绕射理论(GTD/UTD)的确定性传播预测方法。

3.2.1 基本射线类型

直射射线(LOS)

  • 发射机与接收机之间无遮挡
  • 场强计算:ELOS=E0e−jkrrE_{LOS} = E_0\frac{e^{-jkr}}{r}ELOS=E0rejkr

反射射线

  • 遵循反射定律:入射角等于反射角
  • 反射系数:

对于垂直极化:

R⊥=cos⁡θi−εr−sin⁡2θicos⁡θi+εr−sin⁡2θiR_\perp = \frac{\cos\theta_i - \sqrt{\varepsilon_r - \sin^2\theta_i}}{\cos\theta_i + \sqrt{\varepsilon_r - \sin^2\theta_i}}R=cosθi+εrsin2θi cosθiεrsin2θi

对于水平极化:

R∥=εrcos⁡θi−εr−sin⁡2θiεrcos⁡θi+εr−sin⁡2θiR_\parallel = \frac{\varepsilon_r\cos\theta_i - \sqrt{\varepsilon_r - \sin^2\theta_i}}{\varepsilon_r\cos\theta_i + \sqrt{\varepsilon_r - \sin^2\theta_i}}R=εrcosθi+εrsin2θi εrcosθiεrsin2θi

其中εr=εr′−jσωε0\varepsilon_r = \varepsilon'_r - j\frac{\sigma}{\omega\varepsilon_0}εr=εrjωε0σ为复介电常数。

绕射射线:

  • 当射线遇到建筑物边缘或角落时发生绕射
  • 使用UTD计算绕射系数
  • 单刃绕射损耗近似:

Ld=−20log⁡10∣12−1212(12+C(v)+S(v))∣L_d = -20\log_{10}\left|\frac{1}{2} - \frac{1}{2}\sqrt{\frac{1}{2}}\left(\frac{1}{2} + C(v) + S(v)\right)\right|Ld=20log10 212121 (21+C(v)+S(v))

其中C(v)C(v)C(v)S(v)S(v)S(v)为Fresnel积分,vvv为绕射参数:

v=h2(d1+d2)λd1d2v = h\sqrt{\frac{2(d_1 + d_2)}{\lambda d_1 d_2}}v=hλd1d22(d1+d2)

散射射线:

  • 粗糙表面或不规则结构引起的散射
  • 散射场强通常远小于反射和绕射
3.2.2 射线追踪算法实现

射线追踪的基本步骤:

  1. 场景建模:建立建筑物的三维几何模型
  2. 射线发射:从发射点发射大量射线(通常采用镜像法或射线发射法)
  3. 射线追踪:计算射线与场景中物体的交点
  4. 场强计算:累加所有到达接收机的射线贡献
  5. 路径损耗:转换为路径损耗或接收功率

加速技术

  • 空间划分(八叉树、KD树)
  • 并行计算(GPU加速)
  • 射线束追踪(Beam Tracing)

3.3 主导路径模型

主导路径模型(Dominant Path Model, DPM)是一种简化的射线追踪方法,只考虑对总场贡献最大的几条路径。

主导路径识别

  1. 计算直射路径(如果存在)
  2. 识别主要的反射面(地面、大型建筑物墙面)
  3. 计算关键绕射点(建筑物边缘、屋顶)
  4. 评估每条路径的损耗,选择损耗最小的几条

路径损耗计算

Ltotal=Lfs+∑iLreflection,i+∑jLdiffraction,j+LpenetrationL_{total} = L_{fs} + \sum_i L_{reflection,i} + \sum_j L_{diffraction,j} + L_{penetration}Ltotal=Lfs+iLreflection,i+jLdiffraction,j+Lpenetration

3.4 城市微蜂窝模型

3.4.1 街道峡谷模型

街道峡谷中的传播可以用波导模型近似:

PL=−10log⁡10(λ2πd)2+10log⁡10(dd0)n+LexcessPL = -10\log_{10}\left(\frac{\lambda}{2\pi d}\right)^2 + 10\log_{10}\left(\frac{d}{d_0}\right)^n + L_{excess}PL=10log10(2πdλ)2+10log10(d0d)n+Lexcess

其中nnn通常为4-6,LexcessL_{excess}Lexcess为额外损耗。

COST-231 Walfisch-Ikegami模型

适用于城市微蜂窝,频率800MHz-2GHz:

L=L0+Lrts+LmsdL = L_0 + L_{rts} + L_{msd}L=L0+Lrts+Lmsd

其中:

  • L0L_0L0:自由空间损耗
  • LrtsL_{rts}Lrts:屋顶到街道的绕射和散射损耗
  • LmsdL_{msd}Lmsd:多屏绕射损耗

屋顶到街道损耗

Lrts=−16.9−10log⁡10(w)+10log⁡10(f)+20log⁡10(Δhm)+LoriL_{rts} = -16.9 - 10\log_{10}(w) + 10\log_{10}(f) + 20\log_{10}(\Delta h_m) + L_{ori}Lrts=16.910log10(w)+10log10(f)+20log10(Δhm)+Lori

其中:

  • www:街道宽度(m)
  • Δhm=hroof−hm\Delta h_m = h_{roof} - h_mΔhm=hroofhm:建筑物高度与移动台高度差
  • LoriL_{ori}Lori:方向损耗

多屏绕射损耗

Lmsd=Lbsh+ka+kdlog⁡10(d)+kflog⁡10(f)−9log⁡10(b)L_{msd} = L_{bsh} + k_a + k_d\log_{10}(d) + k_f\log_{10}(f) - 9\log_{10}(b)Lmsd=Lbsh+ka+kdlog10(d)+kflog10(f)9log10(b)

其中bbb为建筑物间距。

四、室内电波传播建模

4.1 室内传播环境特征

室内环境相比城市环境更加复杂:

  1. 密集的多径:墙壁、地板、天花板、家具等造成大量反射
  2. 穿透损耗变化大:不同材料(混凝土、砖、石膏板、玻璃)的损耗差异显著
  3. 楼层间传播:信号通过楼层间的穿透或楼梯/电梯传播
  4. 人员活动影响:人体遮挡和移动引起信号波动

4.2 室内路径损耗模型

4.2.1 对数距离模型(室内)

PL(d)=PL(d0)+10nSFlog⁡10(dd0)+FAF+XσPL(d) = PL(d_0) + 10n_{SF}\log_{10}\left(\frac{d}{d_0}\right) + FAF + X_\sigmaPL(d)=PL(d0)+10nSFlog10(d0d)+FAF+Xσ

其中:

  • nSFn_{SF}nSF:同楼层路径损耗指数(1.6-3.3)
  • FAFFAFFAF:楼层衰减因子(Floor Attenuation Factor)
  • XσX_\sigmaXσ:阴影衰落(3-6dB)

典型参数值

环境类型 路径损耗指数nnn 标准差σ\sigmaσ(dB)
自由空间 2 0
走廊 1.6-1.8 3-5
办公室(软隔断) 2.2-2.8 4-6
办公室(硬隔断) 2.8-3.3 5-7
工厂 2.0-3.0 5-8
4.2.2 楼层衰减因子(FAF)

FAF=α⋅NFFAF = \alpha \cdot N_FFAF=αNF

其中NFN_FNF为楼层数,α\alphaα为每层衰减(通常10-20dB/层)。

4.2.3 穿透损耗

不同建筑材料的穿透损耗:

材料 1GHz损耗(dB) 2.4GHz损耗(dB) 5.8GHz损耗(dB)
混凝土墙(20cm) 10-15 15-20 20-25
砖墙 5-8 8-12 12-18
石膏板 2-4 3-5 5-8
玻璃窗 2-3 3-5 5-8
金属门 10-15 15-20 20-25
电梯 25-35 30-40 35-45

4.3 室内射线追踪

室内射线追踪需要考虑更多细节:

  1. 精细几何建模:包括墙壁厚度、门窗位置、家具布局
  2. 材料属性:不同表面的介电常数和电导率
  3. 多次反射:通常考虑3-6次反射
  4. 绕射:门缝、墙角等边缘绕射

加速技术

  • 可见性预处理
  • 射线分类(直达、一次反射、二次反射等)
  • 空间加速结构(BSP树、网格划分)

4.4 室内统计模型

4.4.1 Saleh-Valenzuela模型

室内多径信道的经典统计模型:

多径到达时间

  • 射线簇(Cluster)按泊松过程到达,速率Λ\LambdaΛ
  • 簇内射线按泊松过程到达,速率λ\lambdaλ

功率延迟分布

P(τ)=∑l=0∞∑k=0∞Pk,lδ(τ−Tl−τk,l)P(\tau) = \sum_{l=0}^{\infty}\sum_{k=0}^{\infty} P_{k,l}\delta(\tau - T_l - \tau_{k,l})P(τ)=l=0k=0Pk,lδ(τTlτk,l)

其中:

  • TlT_lTl:第lll个簇的到达时间
  • τk,l\tau_{k,l}τk,l:第lll个簇中第kkk条射线的相对到达时间
  • Pk,lP_{k,l}Pk,l:对应射线的功率

功率衰减

  • 簇内功率按指数衰减:β2‾(Tl,τk,l)=β2(0,0)‾e−Tl/Γe−τk,l/γ\overline{\beta^2}(T_l,\tau_{k,l}) = \overline{\beta^2(0,0)}e^{-T_l/\Gamma}e^{-\tau_{k,l}/\gamma}β2(Tl,τk,l)=β2(0,0)eTleτk,l/γ
  • Γ\GammaΓ:簇衰减时间常数
  • γ\gammaγ:射线衰减时间常数
4.4.2 IEEE 802.11信道模型

IEEE 802.11标准定义了多种室内信道模型:

Model A(办公室环境,LOS)

  • RMS时延扩展:50ns
  • 最大时延:100ns

Model B(办公室环境,NLOS)

  • RMS时延扩展:100ns
  • 最大时延:200ns

Model C(大型开放空间/室内NLOS)

  • RMS时延扩展:150ns
  • 最大时延:500ns

Model D(大型开放空间,NLOS)

  • RMS时延扩展:140ns
  • 最大时延:390ns

Model E(大型开放空间,NLOS)

  • RMS时延扩展:250ns
  • 最大时延:730ns

五、5G/6G毫米波传播特性

5.1 毫米波传播特点

毫米波(24GHz以上)传播与低频段有显著差异:

  1. 高路径损耗:自由空间损耗随频率平方增加
  2. 强方向性:需要使用高增益定向天线
  3. 大气吸收:氧气(60GHz)和水蒸气(183GHz)吸收峰
  4. 穿透损耗大:难以穿透建筑物和人体
  5. 雨衰严重:高频段受降雨影响显著

5.2 毫米波信道模型

5.2.1 3GPP TR 38.901模型

3GPP为5G NR定义的信道模型,支持0.5-100GHz:

路径损耗模型

UMi(城市微蜂窝)

PLUMi=32.4+21log⁡10(d3D)+20log⁡10(fc),LOSPL_{UMi} = 32.4 + 21\log_{10}(d_{3D}) + 20\log_{10}(f_c), \quad \text{LOS}PLUMi=32.4+21log10(d3D)+20log10(fc),LOS

PLUMi=35.3log⁡10(d3D)+22.4+21.3log⁡10(fc)−0.3(hUT−1.5),NLOSPL_{UMi} = 35.3\log_{10}(d_{3D}) + 22.4 + 21.3\log_{10}(f_c) - 0.3(h_{UT}-1.5), \quad \text{NLOS}PLUMi=35.3log10(d3D)+22.4+21.3log10(fc)0.3(hUT1.5),NLOS

UMa(城市宏蜂窝)

PLUMa=28.0+22log⁡10(d3D)+20log⁡10(fc),LOSPL_{UMa} = 28.0 + 22\log_{10}(d_{3D}) + 20\log_{10}(f_c), \quad \text{LOS}PLUMa=28.0+22log10(d3D)+20log10(fc),LOS

PLUMa=13.54+39.08log⁡10(d3D)+20log⁡10(fc)−0.6(hUT−1.5),NLOSPL_{UMa} = 13.54 + 39.08\log_{10}(d_{3D}) + 20\log_{10}(f_c) - 0.6(h_{UT}-1.5), \quad \text{NLOS}PLUMa=13.54+39.08log10(d3D)+20log10(fc)0.6(hUT1.5),NLOS

RMa(农村宏蜂窝)

PLRMa=31.4+21.5log⁡10(d3D)+19.1log⁡10(fc),LOSPL_{RMa} = 31.4 + 21.5\log_{10}(d_{3D}) + 19.1\log_{10}(f_c), \quad \text{LOS}PLRMa=31.4+21.5log10(d3D)+19.1log10(fc),LOS

PLRMa=max(PLRMa−LOS,33.83+31.94log⁡10(d3D)+20log⁡10(fc)),NLOSPL_{RMa} = max(PL_{RMa-LOS}, 33.83 + 31.94\log_{10}(d_{3D}) + 20\log_{10}(f_c)), \quad \text{NLOS}PLRMa=max(PLRMaLOS,33.83+31.94log10(d3D)+20log10(fc)),NLOS

InH(室内热点)

PLInH=32.4+17.3log⁡10(d3D)+20log⁡10(fc),LOSPL_{InH} = 32.4 + 17.3\log_{10}(d_{3D}) + 20\log_{10}(f_c), \quad \text{LOS}PLInH=32.4+17.3log10(d3D)+20log10(fc),LOS

PLInH=33.6+21.9log⁡10(d3D)+20log⁡10(fc),NLOSPL_{InH} = 33.6 + 21.9\log_{10}(d_{3D}) + 20\log_{10}(f_c), \quad \text{NLOS}PLInH=33.6+21.9log10(d3D)+20log10(fc),NLOS

其中:

  • d3Dd_{3D}d3D:三维距离(m)
  • fcf_cfc:载波频率(GHz)
  • hUTh_{UT}hUT:用户终端高度(m)
5.2.2 毫米波穿透损耗

室外到室内(O2I)

PLO2I=PLoutdoor+PLtw+PLinPL_{O2I} = PL_{outdoor} + PL_{tw} + PL_{in}PLO2I=PLoutdoor+PLtw+PLin

其中:

  • PLtwPL_{tw}PLtw:穿透外墙损耗(5-20dB,取决于材料和频率)
  • PLinPL_{in}PLin:室内传播损耗

标准穿透损耗值(3GPP)

场景 低频(<6GHz) 高频(>6GHz)
标准玻璃 3.5 dB 6.5 dB
低辐射玻璃 15 dB 30 dB
混凝土墙 15 dB 30 dB
木门 4 dB 8 dB

5.3 波束管理与覆盖

毫米波系统依赖波束赋形来克服高路径损耗:

波束扫描

  • 发射端和接收端通过扫描窄波束寻找最佳路径
  • 波束宽度通常为10°-30°

波束跟踪

  • 用户移动时动态调整波束方向
  • 需要快速跟踪算法

波束切换

  • 当主波束被遮挡时切换到备用波束
  • 切换时间要求<10ms

六、Python仿真实现

6.1 仿真1:自由空间与基本路径损耗模型

"""
仿真1:自由空间与基本路径损耗模型
比较不同路径损耗模型的预测结果
"""

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
import os

# 设置Agg后端,不弹出窗口
import matplotlib
matplotlib.use('Agg')

# 创建输出目录
output_dir = os.path.dirname(os.path.abspath(__file__))

print("=" * 60)
print("仿真1: 自由空间与基本路径损耗模型")
print("=" * 60)

# 参数设置
frequencies = [900e6, 1800e6, 2100e6, 2600e6, 3500e6, 28e9]  # Hz
freq_labels = ['900MHz', '1.8GHz', '2.1GHz', '2.6GHz', '3.5GHz', '28GHz']
distances = np.linspace(1, 1000, 1000)  # m

# 自由空间路径损耗
def free_space_path_loss(f, d):
    """计算自由空间路径损耗 (dB)"""
    c = 3e8  # 光速
    lambda_ = c / f
    # 确保距离大于0
    d = np.maximum(d, 0.001)
    fspl = 20 * np.log10(d) + 20 * np.log10(f) + 20 * np.log10(4*np.pi/c)
    return fspl

# 对数距离路径损耗模型
def log_distance_path_loss(f, d, d0, n, sigma=0):
    """
    对数距离路径损耗模型
    f: 频率(Hz)
    d: 距离(m)
    d0: 参考距离(m)
    n: 路径损耗指数
    sigma: 阴影衰落标准差(dB)
    """
    d = np.maximum(d, 0.001)
    pl0 = free_space_path_loss(f, d0)
    pl = pl0 + 10 * n * np.log10(d / d0)
    if sigma > 0:
        pl += np.random.normal(0, sigma, size=np.shape(d))
    return pl

# Okumura-Hata模型 (城市)
def okumura_hata_urban(f, d, hb, hm):
    """
    Okumura-Hata城市模型
    f: 频率(MHz)
    d: 距离(km)
    hb: 基站天线高度(m)
    hm: 移动台天线高度(m)
    """
    # 频率范围检查
    if f < 150 or f > 1500:
        print(f"警告: 频率{f}MHz超出Okumura-Hata模型适用范围(150-1500MHz)")
    
    # 移动台天线高度修正因子 (中小城市)
    a_hm = (1.1 * np.log10(f) - 0.7) * hm - (1.56 * np.log10(f) - 0.8)
    
    # 路径损耗
    L = 69.55 + 26.16 * np.log10(f) - 13.82 * np.log10(hb) - a_hm
    L += (44.9 - 6.55 * np.log10(hb)) * np.log10(d)
    
    return L

# COST-231 Hata模型
def cost231_hata(f, d, hb, hm, urban_type='medium'):
    """
    COST-231 Hata模型
    f: 频率(MHz)
    d: 距离(km)
    hb: 基站天线高度(m)
    hm: 移动台天线高度(m)
    urban_type: 'medium'或'metropolitan'
    """
    # 频率范围检查
    if f < 1500 or f > 2000:
        print(f"警告: 频率{f}MHz超出COST-231模型最佳适用范围(1500-2000MHz)")
    
    # 移动台天线高度修正因子
    a_hm = (1.1 * np.log10(f) - 0.7) * hm - (1.56 * np.log10(f) - 0.8)
    
    # 大都市修正因子
    C_M = 3 if urban_type == 'metropolitan' else 0
    
    # 路径损耗
    L = 46.3 + 33.9 * np.log10(f) - 13.82 * np.log10(hb) - a_hm
    L += (44.9 - 6.55 * np.log10(hb)) * np.log10(d) + C_M
    
    return L

# 计算各种模型的路径损耗
print("\n计算路径损耗模型...")

# 选择代表性频率进行分析
f_analysis = 1800e6  # 1.8GHz
f_mhz = f_analysis / 1e6
d_km = distances / 1000

# 1. 自由空间路径损耗
fspl = free_space_path_loss(f_analysis, distances)

# 2. 对数距离模型 (不同路径损耗指数)
pl_n2 = log_distance_path_loss(f_analysis, distances, d0=100, n=2.0)
pl_n3 = log_distance_path_loss(f_analysis, distances, d0=100, n=3.0)
pl_n4 = log_distance_path_loss(f_analysis, distances, d0=100, n=4.0)

# 3. Okumura-Hata模型
hata_urban = okumura_hata_urban(f_mhz, d_km, hb=30, hm=1.5)

# 4. COST-231 Hata模型
cost231_medium = cost231_hata(f_mhz, d_km, hb=30, hm=1.5, urban_type='medium')
cost231_metro = cost231_hata(f_mhz, d_km, hb=30, hm=1.5, urban_type='metropolitan')

print("  完成路径损耗计算")

# 可视化
fig, axes = plt.subplots(2, 2, figsize=(14, 10))

# 图1: 不同频率的自由空间路径损耗
ax = axes[0, 0]
colors = plt.cm.viridis(np.linspace(0, 1, len(frequencies)))
for f, label, color in zip(frequencies, freq_labels, colors):
    pl = free_space_path_loss(f, distances)
    ax.plot(distances/1000, pl, color=color, linewidth=2, label=label)
ax.set_xlabel('Distance (km)')
ax.set_ylabel('Path Loss (dB)')
ax.set_title('Free Space Path Loss vs Frequency')
ax.legend()
ax.grid(True, alpha=0.3)
ax.set_xlim(0, 1)

# 图2: 不同路径损耗模型的比较
ax = axes[0, 1]
ax.plot(distances/1000, fspl, 'k-', linewidth=2, label='Free Space (n=2)')
ax.plot(distances/1000, pl_n3, 'b--', linewidth=2, label='Log-Distance (n=3)')
ax.plot(distances/1000, pl_n4, 'r-.', linewidth=2, label='Log-Distance (n=4)')
ax.plot(distances/1000, hata_urban, 'g:', linewidth=2, label='Okumura-Hata')
ax.plot(distances/1000, cost231_medium, 'm-', linewidth=2, label='COST-231')
ax.set_xlabel('Distance (km)')
ax.set_ylabel('Path Loss (dB)')
ax.set_title(f'Path Loss Models Comparison @ {f_mhz:.0f}MHz')
ax.legend()
ax.grid(True, alpha=0.3)
ax.set_xlim(0, 1)

# 图3: 阴影衰落的影响
ax = axes[1, 0]
np.random.seed(42)
pl_shadow = log_distance_path_loss(f_analysis, distances, d0=100, n=3.0, sigma=6)
ax.plot(distances/1000, pl_n3, 'b-', linewidth=2, label='Median (σ=0)')
ax.fill_between(distances/1000, pl_n3 - 6, pl_n3 + 6, alpha=0.3, label='±1σ')
ax.fill_between(distances/1000, pl_n3 - 12, pl_n3 + 12, alpha=0.2, label='±2σ')
ax.plot(distances/1000, pl_shadow, 'r-', alpha=0.5, linewidth=1, label='Sample with σ=6dB')
ax.set_xlabel('Distance (km)')
ax.set_ylabel('Path Loss (dB)')
ax.set_title('Shadow Fading Effect (Log-Normal)')
ax.legend()
ax.grid(True, alpha=0.3)
ax.set_xlim(0, 1)

# 图4: 频率对路径损耗的影响
ax = axes[1, 1]
d_fixed = 500  # m
f_range = np.linspace(100e6, 6e9, 100)
fspl_freq = free_space_path_loss(f_range, d_fixed)
# 转换为MHz用于显示
f_mhz_range = f_range / 1e6
ax.plot(f_mhz_range, fspl_freq, 'b-', linewidth=2)
ax.axvline(x=700, color='r', linestyle='--', alpha=0.5, label='LTE Band')
ax.axvline(x=3500, color='g', linestyle='--', alpha=0.5, label='5G Sub-6')
ax.axvline(x=28000, color='m', linestyle='--', alpha=0.5, label='5G mmWave')
ax.set_xlabel('Frequency (MHz)')
ax.set_ylabel('Path Loss (dB)')
ax.set_title(f'Path Loss vs Frequency @ d={d_fixed}m')
ax.legend()
ax.grid(True, alpha=0.3)

plt.tight_layout()
output_path = os.path.join(output_dir, 'path_loss_models.png')
plt.savefig(output_path, dpi=150, bbox_inches='tight')
plt.close()
print(f"Saved: {output_path}")

# 打印关键数值
print("\n关键数值结果:")
print(f"  1.8GHz, 1km处:")
print(f"    自由空间损耗: {free_space_path_loss(1800e6, 1000):.1f} dB")
print(f"    Okumura-Hata(城市): {okumura_hata_urban(1800, 1, 30, 1.5):.1f} dB")
print(f"    COST-231(中等城市): {cost231_hata(1800, 1, 30, 1.5, 'medium'):.1f} dB")
print(f"    COST-231(大都市): {cost231_hata(1800, 1, 30, 1.5, 'metropolitan'):.1f} dB")

6.2 仿真2:城市街道峡谷传播模型

"""
仿真2:城市街道峡谷传播模型
模拟城市街道峡谷中的电波传播特性
"""

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle, FancyBboxPatch
import os

matplotlib.use('Agg')

print("\n" + "=" * 60)
print("仿真2: 城市街道峡谷传播模型")
print("=" * 60)

# COST-231 Walfisch-Ikegami模型
def walfisch_ikegami(f, d, hb, hm, hroof, w, phi, environment='urban'):
    """
    COST-231 Walfisch-Ikegami模型
    f: 频率(MHz)
    d: 距离(km)
    hb: 基站天线高度(m)
    hm: 移动台天线高度(m)
    hroof: 建筑物平均高度(m)
    w: 街道宽度(m)
    phi: 街道与发射方向的夹角(度)
    environment: 'urban', 'suburban', 'rural'
    """
    # 自由空间损耗
    L0 = 32.45 + 20*np.log10(f) + 20*np.log10(d*1000)  # d转换为m
    
    # 检查是否为LOS条件
    delta_hb = hb - hroof
    delta_hm = hroof - hm
    
    # LOS条件简化处理:如果基站高于屋顶且距离较近
    if delta_hb > 0 and d < 0.5:
        return L0  # 近似LOS
    
    # 屋顶到街道损耗
    if phi < 35:
        Lori = -10 + 0.354*phi
    elif phi < 55:
        Lori = 2.5 + 0.075*(phi - 35)
    else:
        Lori = 4.0 - 0.114*(phi - 55)
    
    Lrts = -8.2 - 10*np.log10(w) + 10*np.log10(f) + 20*np.log10(delta_hm) + Lori
    
    # 多屏绕射损耗
    if hb > hroof:
        Lbsh = -18*np.log10(1 + delta_hb)
        ka = 54
        kd = 18
    else:
        Lbsh = 0
        ka = 54 - 0.8*delta_hb
        kd = 18 - 15*delta_hb/hroof
    
    # 频率修正
    kf = -4 + 0.7*(f/925 - 1)
    
    # 建筑物间距(假设)
    b = 50  # m
    
    Lmsd = Lbsh + ka + kd*np.log10(d) + kf*np.log10(f) - 9*np.log10(b)
    
    # 总损耗
    L = L0 + Lrts + Lmsd
    
    # 郊区修正
    if environment == 'suburban':
        L -= 2*(np.log10(f/28))**2 - 5.4
    elif environment == 'rural':
        L -= 4.78*(np.log10(f))**2 - 18.33*np.log10(f) - 40.94
    
    return L

# 街道峡谷场景参数
f = 1800  # MHz
d_range = np.linspace(0.1, 2, 100)  # km
hb = 30  # m (基站高度)
hm = 1.5  # m (移动台高度)
hroof = 20  # m (建筑物高度)
w = 20  # m (街道宽度)

# 不同街道角度
phi_values = [0, 45, 90]  # 度
phi_labels = ['0° (平行)', '45°', '90° (垂直)']

print("\n计算街道峡谷传播损耗...")

# 计算不同角度的路径损耗
losses = {}
for phi, label in zip(phi_values, phi_labels):
    losses[label] = [walfisch_ikegami(f, d, hb, hm, hroof, w, phi) for d in d_range]

print("  完成计算")

# 可视化
fig, axes = plt.subplots(2, 2, figsize=(14, 10))

# 图1: 不同街道角度的路径损耗
ax = axes[0, 0]
colors = ['b', 'g', 'r']
for (label, loss), color in zip(losses.items(), colors):
    ax.plot(d_range, loss, color=color, linewidth=2, label=label)
ax.set_xlabel('Distance (km)')
ax.set_ylabel('Path Loss (dB)')
ax.set_title(f'Street Canyon Propagation @ {f}MHz\n(hb={hb}m, hroof={hroof}m, w={w}m)')
ax.legend()
ax.grid(True, alpha=0.3)

# 图2: 建筑物高度的影响
ax = axes[0, 1]
hroof_values = [10, 15, 20, 25, 30]
colors = plt.cm.viridis(np.linspace(0, 1, len(hroof_values)))
for hroof_test, color in zip(hroof_values, colors):
    loss_hroof = [walfisch_ikegami(f, d, hb, hm, hroof_test, w, 90) for d in d_range]
    ax.plot(d_range, loss_hroof, color=color, linewidth=2, label=f'hroof={hroof_test}m')
ax.set_xlabel('Distance (km)')
ax.set_ylabel('Path Loss (dB)')
ax.set_title('Effect of Building Height')
ax.legend()
ax.grid(True, alpha=0.3)

# 图3: 街道宽度的影响
ax = axes[1, 0]
w_values = [10, 20, 30, 40, 50]
colors = plt.cm.plasma(np.linspace(0, 1, len(w_values)))
for w_test, color in zip(w_values, colors):
    loss_w = [walfisch_ikegami(f, d, hb, hm, hroof, w_test, 90) for d in d_range]
    ax.plot(d_range, loss_w, color=color, linewidth=2, label=f'w={w_test}m')
ax.set_xlabel('Distance (km)')
ax.set_ylabel('Path Loss (dB)')
ax.set_title('Effect of Street Width')
ax.legend()
ax.grid(True, alpha=0.3)

# 图4: 场景示意图
ax = axes[1, 1]
ax.set_xlim(-50, 150)
ax.set_ylim(-5, 40)

# 绘制建筑物
building1 = Rectangle((-40, 0), 40, hroof, facecolor='gray', edgecolor='black')
building2 = Rectangle((w, 0), 40, hroof, facecolor='gray', edgecolor='black')
ax.add_patch(building1)
ax.add_patch(building2)

# 绘制基站
ax.plot([0], [hb], 'ro', markersize=12, label='Base Station')
ax.plot([0, 0], [0, hb], 'r--', alpha=0.5)

# 绘制移动台
ax.plot([100], [hm], 'bs', markersize=10, label='Mobile')
ax.plot([100, 100], [0, hm], 'b--', alpha=0.5)

# 绘制射线
ax.plot([0, 100], [hb, hm], 'g-', linewidth=2, alpha=0.6, label='Direct path')
ax.plot([0, w/2, 100], [hb, hroof, hm], 'm:', linewidth=2, alpha=0.6, label='Diffracted path')

ax.set_xlabel('Distance (m)')
ax.set_ylabel('Height (m)')
ax.set_title('Street Canyon Scenario')
ax.legend(loc='upper right')
ax.grid(True, alpha=0.3)
ax.set_aspect('equal', adjustable='box')

plt.tight_layout()
output_path = os.path.join(output_dir, 'street_canyon_propagation.png')
plt.savefig(output_path, dpi=150, bbox_inches='tight')
plt.close()
print(f"Saved: {output_path}")

print("\n关键结果:")
print(f"  1.8GHz, 1km, 垂直街道:")
print(f"    路径损耗: {walfisch_ikegami(1800, 1, 30, 1.5, 20, 20, 90):.1f} dB")

6.3 仿真3:室内传播模型与穿透损耗

"""
仿真3:室内传播模型与穿透损耗
分析室内环境中的电波传播特性
"""

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
import os

matplotlib.use('Agg')

print("\n" + "=" * 60)
print("仿真3: 室内传播模型与穿透损耗")
print("=" * 60)

# 室内路径损耗模型
def indoor_path_loss(f, d, n, d0=1, sigma=0, FAF=0):
    """
    室内对数距离路径损耗模型
    f: 频率(GHz)
    d: 距离(m)
    n: 路径损耗指数
    d0: 参考距离(m)
    sigma: 阴影衰落标准差(dB)
    FAF: 楼层衰减因子(dB)
    """
    # 参考距离处的自由空间损耗
    c = 3e8
    lambda_ = c / (f * 1e9)
    PL0 = 20 * np.log10(4 * np.pi * d0 / lambda_)
    
    # 对数距离损耗
    d = np.maximum(d, 0.1)
    PL = PL0 + 10 * n * np.log10(d / d0) + FAF
    
    if sigma > 0:
        PL += np.random.normal(0, sigma)
    
    return PL

# 穿透损耗数据 (dB)
penetration_loss = {
    'Concrete (20cm)': {'1GHz': 12, '2.4GHz': 18, '5.8GHz': 25},
    'Brick Wall': {'1GHz': 6, '2.4GHz': 10, '5.8GHz': 15},
    'Drywall': {'1GHz': 3, '2.4GHz': 5, '5.8GHz': 8},
    'Glass Window': {'1GHz': 2, '2.4GHz': 4, '5.8GHz': 7},
    'Wooden Door': {'1GHz': 3, '2.4GHz': 5, '5.8GHz': 8},
    'Metal Door': {'1GHz': 15, '2.4GHz': 25, '5.8GHz': 35},
}

# 不同环境的路径损耗指数
environment_params = {
    'Free Space': {'n': 2.0, 'sigma': 0},
    'Corridor': {'n': 1.7, 'sigma': 3.0},
    'Office (Soft Partition)': {'n': 2.4, 'sigma': 5.0},
    'Office (Hard Partition)': {'n': 3.0, 'sigma': 6.0},
    'Factory': {'n': 2.5, 'sigma': 7.0},
}

print("\n计算室内传播损耗...")

# 频率和距离范围
frequencies = [0.9, 2.4, 5.8]  # GHz
distances = np.linspace(1, 100, 100)  # m

# 计算不同环境的损耗
losses_env = {}
for env, params in environment_params.items():
    losses_env[env] = [indoor_path_loss(2.4, d, params['n'], sigma=params['sigma']) 
                       for d in distances]

print("  完成计算")

# 可视化
fig, axes = plt.subplots(2, 2, figsize=(14, 10))

# 图1: 不同室内环境的路径损耗
ax = axes[0, 0]
colors = plt.cm.tab10(np.linspace(0, 1, len(environment_params)))
for (env, loss), color in zip(losses_env.items(), colors):
    ax.plot(distances, loss, color=color, linewidth=2, label=env)
ax.set_xlabel('Distance (m)')
ax.set_ylabel('Path Loss (dB)')
ax.set_title('Indoor Path Loss by Environment @ 2.4GHz')
ax.legend(fontsize=8)
ax.grid(True, alpha=0.3)
ax.set_xlim(0, 100)

# 图2: 不同频率的室内损耗
ax = axes[0, 1]
np.random.seed(42)
colors = ['b', 'g', 'r']
for f, color in zip(frequencies, colors):
    # 办公室环境(软隔断)
    loss_f = [indoor_path_loss(f, d, 2.4, sigma=5) for d in distances]
    ax.plot(distances, loss_f, color=color, linewidth=2, label=f'{f}GHz')
ax.set_xlabel('Distance (m)')
ax.set_ylabel('Path Loss (dB)')
ax.set_title('Indoor Path Loss vs Frequency\n(Office, Soft Partition)')
ax.legend()
ax.grid(True, alpha=0.3)
ax.set_xlim(0, 100)

# 图3: 穿透损耗比较
ax = axes[1, 0]
materials = list(penetration_loss.keys())
freqs_plot = ['1GHz', '2.4GHz', '5.8GHz']
x = np.arange(len(materials))
width = 0.25

for i, freq in enumerate(freqs_plot):
    losses_material = [penetration_loss[m][freq] for m in materials]
    ax.bar(x + i*width, losses_material, width, label=freq)

ax.set_xlabel('Material')
ax.set_ylabel('Penetration Loss (dB)')
ax.set_title('Penetration Loss by Material and Frequency')
ax.set_xticks(x + width)
ax.set_xticklabels(materials, rotation=45, ha='right', fontsize=8)
ax.legend()
ax.grid(True, alpha=0.3, axis='y')

# 图4: 楼层衰减因子
ax = axes[1, 1]
floors = np.arange(0, 6)
FAF_values = [0, 15, 28, 38, 45, 50]  # dB (典型值)
ax.bar(floors, FAF_values, color='steelblue', alpha=0.7)
ax.set_xlabel('Number of Floors')
ax.set_ylabel('Floor Attenuation Factor (dB)')
ax.set_title('Floor Attenuation Factor (FAF)\n@ 2.4GHz')
ax.grid(True, alpha=0.3, axis='y')

plt.tight_layout()
output_path = os.path.join(output_dir, 'indoor_propagation.png')
plt.savefig(output_path, dpi=150, bbox_inches='tight')
plt.close()
print(f"Saved: {output_path}")

print("\n关键结果:")
print("  2.4GHz, 50m处:")
for env, params in environment_params.items():
    loss = indoor_path_loss(2.4, 50, params['n'])
    print(f"    {env}: {loss:.1f} dB")

6.4 仿真4:射线追踪基础实现

"""
仿真4:射线追踪基础实现
实现简单的2D射线追踪算法
"""

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle, Circle, FancyArrowPatch
import os

matplotlib.use('Agg')

print("\n" + "=" * 60)
print("仿真4: 射线追踪基础实现")
print("=" * 60)

# 简单的射线类
class Ray:
    def __init__(self, origin, direction):
        self.origin = np.array(origin)
        self.direction = np.array(direction) / np.linalg.norm(direction)
        self.path = [self.origin.copy()]
        self.reflections = 0
    
    def point_at(self, t):
        return self.origin + t * self.direction
    
    def reflect(self, normal):
        """计算反射方向"""
        n = np.array(normal) / np.linalg.norm(normal)
        self.direction = self.direction - 2 * np.dot(self.direction, n) * n
        self.reflections += 1

# 墙壁类
class Wall:
    def __init__(self, x1, y1, x2, y2, material='concrete'):
        self.p1 = np.array([x1, y1])
        self.p2 = np.array([x2, y2])
        self.material = material
        # 计算法向量(指向外侧)
        dx = x2 - x1
        dy = y2 - y1
        self.normal = np.array([-dy, dx])
        self.normal = self.normal / np.linalg.norm(self.normal)
    
    def intersect(self, ray):
        """计算射线与线段的交点"""
        # 线段参数方程: P = p1 + t*(p2-p1)
        # 射线参数方程: P = origin + s*direction
        v1 = ray.origin - self.p1
        v2 = self.p2 - self.p1
        v3 = np.array([-ray.direction[1], ray.direction[0]])
        
        denom = np.dot(v2, v3)
        if abs(denom) < 1e-6:
            return None  # 平行
        
        t1 = np.cross(v2, v1) / denom
        t2 = np.dot(v1, v3) / denom
        
        if t1 >= 0 and 0 <= t2 <= 1:
            return ray.point_at(t1)
        return None

# 场景设置
print("\n设置射线追踪场景...")

# 创建简单的室内场景(房间)
walls = [
    Wall(0, 0, 20, 0, 'concrete'),      # 底墙
    Wall(20, 0, 20, 15, 'concrete'),    # 右墙
    Wall(20, 15, 0, 15, 'concrete'),    # 顶墙
    Wall(0, 15, 0, 0, 'concrete'),      # 左墙
    Wall(8, 0, 8, 6, 'drywall'),        # 内墙1
    Wall(12, 9, 12, 15, 'drywall'),     # 内墙2
]

# 发射机和接收机位置
tx_pos = np.array([5, 7.5])
rx_pos = np.array([15, 7.5])

# 反射系数(简化)
reflection_coeff = {
    'concrete': 0.7,
    'drywall': 0.5,
    'glass': 0.3,
}

print("  场景设置完成")
print(f"  发射机位置: ({tx_pos[0]}, {tx_pos[1]})")
print(f"  接收机位置: ({rx_pos[0]}, {rx_pos[1]})")

# 发射射线
print("\n发射射线并追踪...")
n_rays = 36  # 发射36条射线,间隔10度
rays = []
received_power = []

for i in range(n_rays):
    angle = 2 * np.pi * i / n_rays
    direction = np.array([np.cos(angle), np.sin(angle)])
    ray = Ray(tx_pos, direction)
    
    # 追踪射线(最多3次反射)
    max_reflections = 3
    current_pos = tx_pos.copy()
    
    for _ in range(max_reflections + 1):
        # 找到最近的交点
        closest_intersection = None
        closest_wall = None
        min_distance = float('inf')
        
        for wall in walls:
            intersection = wall.intersect(ray)
            if intersection is not None:
                dist = np.linalg.norm(intersection - current_pos)
                if dist > 0.01 and dist < min_distance:  # 避免重复检测同一点
                    min_distance = dist
                    closest_intersection = intersection
                    closest_wall = wall
        
        if closest_intersection is not None:
            # 记录路径点
            ray.path.append(closest_intersection.copy())
            
            # 检查是否到达接收机附近
            if np.linalg.norm(closest_intersection - rx_pos) < 0.5:
                received_power.append({
                    'ray_id': i,
                    'angle': np.rad2deg(angle),
                    'reflections': ray.reflections,
                    'path_length': sum([np.linalg.norm(ray.path[j+1] - ray.path[j]) 
                                       for j in range(len(ray.path)-1)]),
                    'material': closest_wall.material if closest_wall else 'none'
                })
                break
            
            # 反射
            if ray.reflections < max_reflections:
                ray.origin = closest_intersection
                # 确保法向量指向正确的方向
                if np.dot(ray.direction, closest_wall.normal) > 0:
                    wall_normal = -closest_wall.normal
                else:
                    wall_normal = closest_wall.normal
                ray.reflect(wall_normal)
                current_pos = closest_intersection.copy()
            else:
                break
        else:
            # 射线射出场景
            ray.path.append(ray.point_at(30))  # 延伸到远处
            break
    
    rays.append(ray)

print(f"  发射了 {n_rays} 条射线")
print(f"  到达接收机的射线: {len(received_power)} 条")

# 可视化
fig, axes = plt.subplots(1, 2, figsize=(14, 6))

# 图1: 射线追踪场景
ax = axes[0]

# 绘制墙壁
for wall in walls:
    color = 'gray' if wall.material == 'concrete' else 'lightblue'
    ax.plot([wall.p1[0], wall.p2[0]], [wall.p1[1], wall.p2[1]], 
            'k-', linewidth=3)
    ax.fill_between([wall.p1[0], wall.p2[0]], 
                    [wall.p1[1], wall.p2[1]], 
                    [wall.p1[1], wall.p2[1]], 
                    alpha=0.3, color=color)

# 绘制射线(只显示部分以避免混乱)
for i, ray in enumerate(rays):
    if len(ray.path) > 1:
        path_array = np.array(ray.path)
        alpha = 0.3 if len(received_power) == 0 or i not in [p['ray_id'] for p in received_power] else 0.8
        linewidth = 1 if alpha == 0.3 else 2
        color = 'blue' if alpha == 0.3 else 'red'
        ax.plot(path_array[:, 0], path_array[:, 1], 
                color=color, alpha=alpha, linewidth=linewidth)

# 绘制发射机和接收机
ax.plot(tx_pos[0], tx_pos[1], 'g^', markersize=15, label='Transmitter')
ax.plot(rx_pos[0], rx_pos[1], 'ro', markersize=12, label='Receiver')

ax.set_xlabel('X (m)')
ax.set_ylabel('Y (m)')
ax.set_title('2D Ray Tracing Simulation')
ax.legend()
ax.grid(True, alpha=0.3)
ax.set_aspect('equal')
ax.set_xlim(-1, 21)
ax.set_ylim(-1, 16)

# 图2: 到达接收机的射线分析
ax = axes[1]

if len(received_power) > 0:
    angles = [p['angle'] for p in received_power]
    path_lengths = [p['path_length'] for p in received_power]
    reflections = [p['reflections'] for p in received_power]
    
    # 极坐标图显示到达角度
    ax2 = plt.subplot(122, projection='polar')
    theta = np.deg2rad(angles)
    r = [20 - pl/2 for pl in path_lengths]  # 路径越短,距离中心越近
    colors = plt.cm.viridis(np.array(reflections) / max(reflections))
    ax2.scatter(theta, r, c=reflections, s=100, cmap='viridis', alpha=0.7)
    ax2.set_title('Arrival Angles at Receiver\n(color = # reflections)')
    ax2.set_ylim(0, 20)
else:
    ax.text(0.5, 0.5, 'No rays reached receiver\nin this configuration', 
            ha='center', va='center', transform=ax.transAxes, fontsize=14)
    ax.set_xlim(0, 1)
    ax.set_ylim(0, 1)
    ax.axis('off')

plt.tight_layout()
output_path = os.path.join(output_dir, 'ray_tracing_basic.png')
plt.savefig(output_path, dpi=150, bbox_inches='tight')
plt.close()
print(f"Saved: {output_path}")

if len(received_power) > 0:
    print("\n到达接收机的射线信息:")
    for i, p in enumerate(received_power[:5]):  # 显示前5条
        print(f"  射线 {p['ray_id']}: 角度={p['angle']:.1f}°, "
              f"反射={p['reflections']}次, 路径长={p['path_length']:.2f}m")

6.5 仿真5:5G毫米波传播特性

"""
仿真5:5G毫米波传播特性
分析毫米波频段的传播特性,包括路径损耗、穿透损耗、雨衰等
"""

import numpy as np
import matplotlib.pyplot as plt
import os

matplotlib.use('Agg')

print("\n" + "=" * 60)
print("仿真5: 5G毫米波传播特性")
print("=" * 60)

# 3GPP TR 38.901路径损耗模型
def path_loss_3gpp_umi_los(f, d):
    """3GPP UMi街道峡谷LOS模型"""
    # f in GHz, d in m
    PL = 32.4 + 21*np.log10(d) + 20*np.log10(f)
    return PL

def path_loss_3gpp_umi_nlos(f, d, h_ut=1.5):
    """3GPP UMi街道峡谷NLOS模型"""
    PL = 35.3*np.log10(d) + 22.4 + 21.3*np.log10(f) - 0.3*(h_ut - 1.5)
    return PL

def path_loss_3gpp_uma_los(f, d):
    """3GPP UMa LOS模型"""
    PL = 28.0 + 22*np.log10(d) + 20*np.log10(f)
    return PL

def path_loss_3gpp_uma_nlos(f, d, h_ut=1.5):
    """3GPP UMa NLOS模型"""
    PL = 13.54 + 39.08*np.log10(d) + 20*np.log10(f) - 0.6*(h_ut - 1.5)
    return PL

def path_loss_3gpp_inh_los(f, d):
    """3GPP InH LOS模型"""
    PL = 32.4 + 17.3*np.log10(d) + 20*np.log10(f)
    return PL

def path_loss_3gpp_inh_nlos(f, d):
    """3GPP InH NLOS模型"""
    PL = 33.6 + 21.9*np.log10(d) + 20*np.log10(f)
    return PL

# 大气吸收损耗
def atmospheric_absorption(f, d):
    """
    计算大气吸收损耗
    f: 频率(GHz)
    d: 距离(km)
    返回: 损耗(dB)
    """
    # 简化的氧气和水蒸气吸收模型
    # 氧气吸收峰在60GHz
    # 水蒸气吸收峰在183GHz
    
    if 50 <= f <= 70:
        # 氧气吸收带
        alpha = 0.1 * np.exp(-((f - 60)**2) / 50)  # dB/km
    elif 170 <= f <= 200:
        # 水蒸气吸收带
        alpha = 0.5 * np.exp(-((f - 183)**2) / 200)  # dB/km
    else:
        # 其他频率
        alpha = 0.01 + 0.001 * f  # dB/km, 简化模型
    
    return alpha * d

# 雨衰模型 (简化ITU-R模型)
def rain_attenuation(f, d, rain_rate):
    """
    计算雨衰
    f: 频率(GHz)
    d: 距离(km)
    rain_rate: 降雨率(mm/h)
    返回: 损耗(dB)
"""
    # 简化模型
    if rain_rate <= 0:
        return 0
    
    # 频率相关性
    k = 0.0001 * f**1.5  # 简化系数
    alpha = 0.8 + 0.02 * f  # 简化指数
    
    # 特定衰减 (dB/km)
    gamma = k * rain_rate**alpha
    
    # 有效路径长度修正
    deff = d * (1 - np.exp(-d/5)) / (d/5) if d > 0 else 0
    
    return gamma * deff

# 穿透损耗 (3GPP标准值)
penetration_loss_3gpp = {
    'Standard Glass': {'LF': 3.5, 'HF': 6.5},      # dB
    'Low-E Glass': {'LF': 15, 'HF': 30},
    'Concrete Wall': {'LF': 15, 'HF': 30},
    'Wooden Door': {'LF': 4, 'HF': 8},
}

print("\n计算5G毫米波传播特性...")

# 频率范围
frequencies = [0.7, 1.8, 2.6, 3.5, 28, 39, 60]  # GHz
freq_labels = ['0.7GHz', '1.8GHz', '2.6GHz', '3.5GHz', '28GHz', '39GHz', '60GHz']

# 距离范围
distances = np.linspace(10, 500, 100)  # m

# 计算不同场景的路径损耗
print("  计算UMi场景...")
loss_umi_los = [path_loss_3gpp_umi_los(28, d) for d in distances]
loss_umi_nlos = [path_loss_3gpp_umi_nlos(28, d) for d in distances]

print("  计算UMa场景...")
loss_uma_los = [path_loss_3gpp_uma_los(28, d) for d in distances]
loss_uma_nlos = [path_loss_3gpp_uma_nlos(28, d) for d in distances]

print("  计算InH场景...")
loss_inh_los = [path_loss_3gpp_inh_los(28, d) for d in distances]
loss_inh_nlos = [path_loss_3gpp_inh_nlos(28, d) for d in distances]

print("  完成计算")

# 可视化
fig, axes = plt.subplots(2, 2, figsize=(14, 10))

# 图1: 不同场景的路径损耗比较
ax = axes[0, 0]
ax.plot(distances, loss_umi_los, 'b-', linewidth=2, label='UMi LOS')
ax.plot(distances, loss_umi_nlos, 'b--', linewidth=2, label='UMi NLOS')
ax.plot(distances, loss_uma_los, 'r-', linewidth=2, label='UMa LOS')
ax.plot(distances, loss_uma_nlos, 'r--', linewidth=2, label='UMa NLOS')
ax.plot(distances, loss_inh_los, 'g-', linewidth=2, label='InH LOS')
ax.plot(distances, loss_inh_nlos, 'g--', linewidth=2, label='InH NLOS')
ax.set_xlabel('Distance (m)')
ax.set_ylabel('Path Loss (dB)')
ax.set_title('3GPP Path Loss Models @ 28GHz')
ax.legend(fontsize=8)
ax.grid(True, alpha=0.3)

# 图2: 频率对路径损耗的影响
ax = axes[0, 1]
d_fixed = 100  # m
colors = plt.cm.viridis(np.linspace(0, 1, len(frequencies)))

loss_vs_freq = []
for f in frequencies:
    loss = path_loss_3gpp_umi_los(f, d_fixed)
    loss_vs_freq.append(loss)

ax.bar(range(len(frequencies)), loss_vs_freq, color=colors, alpha=0.7)
ax.set_xticks(range(len(frequencies)))
ax.set_xticklabels(freq_labels, rotation=45, ha='right')
ax.set_ylabel('Path Loss (dB)')
ax.set_title(f'Path Loss vs Frequency @ d={d_fixed}m\n(UMi LOS)')
ax.grid(True, alpha=0.3, axis='y')

# 添加数值标签
for i, loss in enumerate(loss_vs_freq):
    ax.text(i, loss + 2, f'{loss:.0f}', ha='center', fontsize=9)

# 图3: 大气吸收和雨衰
ax = axes[1, 0]
f_range = np.linspace(1, 100, 100)  # GHz
d_km = 1  # km

# 大气吸收
atm_loss = [atmospheric_absorption(f, d_km) for f in f_range]

# 不同降雨率下的雨衰
rain_rates = [0, 5, 25, 50]  # mm/h
rain_labels = ['No Rain', 'Light (5mm/h)', 'Moderate (25mm/h)', 'Heavy (50mm/h)']
colors = ['b', 'g', 'orange', 'r']

for rain_rate, label, color in zip(rain_rates, rain_labels, colors):
    rain_loss = [rain_attenuation(f, d_km, rain_rate) for f in f_range]
    ax.plot(f_range, rain_loss, color=color, linewidth=2, label=label)

ax.plot(f_range, atm_loss, 'k--', linewidth=2, alpha=0.7, label='Atmospheric Absorption')
ax.set_xlabel('Frequency (GHz)')
ax.set_ylabel('Attenuation (dB)')
ax.set_title(f'Atmospheric and Rain Attenuation @ d={d_km}km')
ax.legend()
ax.grid(True, alpha=0.3)
ax.set_yscale('log')

# 图4: 穿透损耗比较
ax = axes[1, 1]
materials = list(penetration_loss_3gpp.keys())
lf_losses = [penetration_loss_3gpp[m]['LF'] for m in materials]
hf_losses = [penetration_loss_3gpp[m]['HF'] for m in materials]

x = np.arange(len(materials))
width = 0.35

ax.bar(x - width/2, lf_losses, width, label='Low Freq (<6GHz)', alpha=0.8)
ax.bar(x + width/2, hf_losses, width, label='High Freq (>6GHz)', alpha=0.8)

ax.set_xlabel('Material')
ax.set_ylabel('Penetration Loss (dB)')
ax.set_title('Penetration Loss: Low vs High Frequency')
ax.set_xticks(x)
ax.set_xticklabels(materials, rotation=45, ha='right')
ax.legend()
ax.grid(True, alpha=0.3, axis='y')

plt.tight_layout()
output_path = os.path.join(output_dir, 'mmwave_propagation.png')
plt.savefig(output_path, dpi=150, bbox_inches='tight')
plt.close()
print(f"Saved: {output_path}")

print("\n关键结果:")
print(f"  28GHz, 100m处:")
print(f"    UMi LOS: {path_loss_3gpp_umi_los(28, 100):.1f} dB")
print(f"    UMi NLOS: {path_loss_3gpp_umi_nlos(28, 100):.1f} dB")
print(f"    UMa LOS: {path_loss_3gpp_uma_los(28, 100):.1f} dB")
print(f"    UMa NLOS: {path_loss_3gpp_uma_nlos(28, 100):.1f} dB")
print(f"    InH LOS: {path_loss_3gpp_inh_los(28, 100):.1f} dB")
print(f"    InH NLOS: {path_loss_3gpp_inh_nlos(28, 100):.1f} dB")

七、工程应用案例

7.1 5G网络规划案例

场景描述:某城市商业区需要部署5G基站,工作频段3.5GHz,要求覆盖半径500m,边缘速率100Mbps。

传播模型选择

  • 宏站覆盖:使用3GPP UMa模型
  • 街道峡谷:使用Walfisch-Ikegami模型
  • 室内深度覆盖:考虑穿透损耗

链路预算分析

参数 数值
发射功率 46 dBm (40W)
天线增益 18 dBi
馈线损耗 3 dB
EIRP 61 dBm
路径损耗(500m, NLOS) 约135 dB
穿透损耗 15 dB
阴影衰落余量 8 dB
接收机灵敏度 -95 dBm
链路余量 约8 dB

基站布局建议

  • 站间距:300-400m
  • 天线高度:25-35m
  • 采用3扇区配置
  • 重点区域部署微站补充覆盖

7.2 室内分布系统设计案例

场景描述:某大型购物中心(5层,每层10000m²)需要设计4G/5G室内分布系统。

设计步骤

  1. 覆盖目标确定

    • 覆盖率:>95%
    • 边缘场强:>-85dBm
    • 数据速率:下行50Mbps,上行10Mbps
  2. 传播模型选择

    • 使用室内对数距离模型
    • 路径损耗指数n=2.5
    • 阴影衰落标准差σ=6dB
  3. 天线布点规划

    • 吸顶天线覆盖半径:15-20m
    • 天线间距:25-30m
    • 每层天线数量:约16个
  4. 功率分配设计

    • 信源功率:43dBm
    • 干放增益:30dB
    • 馈线损耗:约10dB
    • 天线口功率:约10dBm
  5. 系统仿真验证

    • 使用射线追踪或主导路径模型
    • 验证覆盖均匀性
    • 检查切换区域

7.3 毫米波固定无线接入(FWA)案例

场景描述:使用28GHz毫米波为郊区住宅提供宽带接入。

系统参数

  • 基站:4T4R,EIRP 60dBm
  • 用户终端:室外安装,高增益天线(24dBi)
  • 目标覆盖距离:300m

传播特性分析

  • 自由空间损耗(300m, 28GHz):109 dB
  • 大气吸收:可忽略
  • 雨衰余量(99.9%可用性):5 dB
  • 植被损耗:3-5 dB

链路预算

  • 总损耗:约120 dB
  • 接收功率:60 + 24 - 120 = -36 dBm
  • 接收机灵敏度:-80 dBm
  • 链路余量:44 dB,支持高阶调制(256QAM)

部署要点

  • 视距(LOS)传播至关重要
  • 需要精确的天线对准
  • 考虑季节性植被变化
  • 备用链路规划应对遮挡

八、总结

本教程系统介绍了城市与室内电波传播的理论基础和建模方法,包括:

  1. 基础理论:自由空间传播、大尺度衰落、小尺度衰落模型
  2. 城市传播:射线追踪、主导路径模型、街道峡谷效应
  3. 室内传播:穿透损耗、楼层衰减、室内射线追踪
  4. 毫米波特性:5G/6G高频段传播特点、波束管理
  5. 工程应用:网络规划、室内分布系统、固定无线接入

关键要点:

  • 不同环境需要选择合适的传播模型
  • 射线追踪提供高精度但计算复杂
  • 经验模型适合快速估算但精度有限
  • 毫米波传播高度依赖视距条件
  • 穿透损耗是室内外覆盖的关键挑战

随着5G/6G和物联网的发展,电波传播建模将继续向高精度、实时化、智能化方向发展,结合机器学习和数字孪生技术,为无线通信系统优化提供更强大的支撑。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐