
简介可见光通信的MATLAB仿真包面向通信工程专业学生、科研人员及对可见光通信感兴趣的技术开发者用于模拟室内场景下可见光链路的误码率与信噪比空间分布。包内共9个文件6个.m仿真源码为主要核心包含信道冲激响应、朗伯辐射模型、直视链路与非直视链路计算等模块2张jpg图片直观展示仿真输出结果1段avi操作录像完整演示从路径设置到运行出图的全过程。资源包仅3.06MB下载与解压都很轻量目前已有926人学习过具备一定参考价值。代码基于MATLAB 2021a编写房间尺寸、LED数量与位置、接收机视角、反射系数等关键参数均在脚本中显式配置便于按需修改。通过运行Runme.m可一键生成误码率与信噪比的空间分布图操作录像则细致说明了当前文件夹路径等易错细节能有效降低复现门槛适合仿真入门与调参练习。1. 可见光通信的MATLAB仿真为什么先看空间分布“误码率空间分布”和“信噪比空间分布”这两张二维图是判断一个室内可见光通信场景可不可用的最直接证据。只跑一条点到点链路的仿真永远看不出房间角落到底是能稳定通信还是只能勉强点亮LED。现实中的VLC系统LED布局、半功率角、接收器视场角(FOV)、桌面反射面高度都会让不同位置的通信质量差异明显。这篇内容面向通信仿真入门者、物联网方向工程师以及要做智慧照明验证的开发者用一套能在MATLAB里直接跑通的最小仿真模型把朗伯辐射、噪声叠加、误码率映射和空间分布图生成一次说清。标题里的“含仿真操作录像”用MATLAB的VideoWriter逐帧回放来解决不依赖第三方录屏软件整个流程可控可复现。2. 可见光通信信道建模朗伯辐射、接收功率与噪声计算2.1 从坐标到信道增益朗伯辐射模型在MATLAB里的落地可见光通信的物理链路可以看成两段LED把电信号调制成光强变化光电探测器(PD)把接收到的光功率再转回电流。室内短距离场景下直达链路(LOS)贡献了绝大多数接收能量一阶墙面反射通常只有直射分量的百分之几到十几。仿真第一步就是把LOS路径上的光功率衰减算准。LED通常被建模成朗伯辐射体光强随出射角φ按cos的m次方衰减。朗伯阶数m由LED半功率角Φ1/2决定关系式为m -ln2 / ln(cos(Φ1/2))。常规照明LED半功率角在60°附近代入得到m≈1窄光束LED的Φ1/2取30°时m会升到6以上光线更集中覆盖面积也相应变小。接收端是平放的PD入射角θ在平行对射时等于出射角φ只有当cos(θ)大于cos(FOV)时光线才能被接收器有效收集。信道直流增益H(0)的表达式为H(0) (m1)/(2πd²) · cos^m(φ) · cos(θ) · A_pd其中d是LED到PD的直线距离A_pd是探测器有效面积。这个公式是后面所有计算的地基。实际工程中会再乘一个光学前端增益Ts(θ)·g(θ)包含滤光片透过率和聚光器增益仿真时先设成1不会影响整体分布形态。2.2 用meshgrid构造接收平面并逐灯计算接收功率拿到信道增益后接收功率就是P_r P_t · H(0)多只LED在同一接收点上的功率直接叠加。空间分布图需要一个接收平面采样网格典型做法是用meshgrid把房间的X轴和Y轴切成长方形网格每个网格点代表一个虚拟接收机位置。接收平面高度取桌面高度0.85m房间尺寸取5m×5m×3m四只LED对称安装在天花板上。下面这段代码完成参数定义、LED坐标布置和逐灯功率叠加核心是向量化计算避免写三重for循环把仿真拖慢% 房间与链路参数 room [5, 5, 3]; % 房间尺寸长宽高 [m] z_rx 0.85; % 接收面高度桌面[m] Pt 10; % 单灯输出光功率 [W] N_led 4; % LED数量 led_pos [1.25, 1.25, room(3); 3.75, 1.25, room(3); 1.25, 3.75, room(3); 3.75, 3.75, room(3)]; phi_half 60 * pi/180; % 半功率角 [rad] m -log(2)/log(cos(phi_half)); % 朗伯辐射阶数 FOV 70 * pi/180; % 接收器视场角 [rad] A_pd 1e-4; % 探测器有效面积 [m^2] Ts_g 1; % 滤光片与聚光器综合增益 % 接收平面网格 N 60; x linspace(0.1, room(1)-0.1, N); y linspace(0.1, room(2)-0.1, N); [XX, YY] meshgrid(x, y); Pr_grid zeros(N, N); % 逐LED叠加直视链路接收功率 for k 1:N_led dx XX - led_pos(k,1); dy YY - led_pos(k,2); dz led_pos(k,3) - z_rx; % 垂直向下距离 [m] d sqrt(dx.^2 dy.^2 dz^2); cos_phi dz ./ d; % 出射角余弦 in_fov cos_phi cos(FOV); % FOV截断 H (m1)/(2*pi) * cos_phi.^(m1) .* A_pd ./ d.^2; H(~in_fov) 0; Pr_grid Pr_grid Pt * Ts_g * H; end这段代码的关键点在三个地方。第一cos_phi.^(m1)把发射角余弦和入射角余弦合并处理因为在平面平行对射的假设下两者相等第二FOV截断用in_fov逻辑索引实现超出视场角的位置增益直接置零防止物理上不该收到的光线参与叠加第三meshgrid生成的XX和YY是二维网格矩阵所有运算都是逐元素操作循环只保留了LED层。如果后续要扩展到8只或16只LED把led_pos数组加行即可。2.3 接收功率计算的关键参数表仿真参数对结果形态影响极大尤其是半功率角、FOV和探测器面积这三个值。下表是室内VLC仿真里一组在文献和工程实践中都常见的默认参数参数符号典型值对仿真的影响LED半功率角Φ1/260°决定光照覆盖范围越大分布越平坦接收器FOVFOV70°影响边缘位置能否收到斜射光探测器面积A_pd1e-4 m²与接收功率成正比直接拉高SNR光电响应度R_pd0.5 A/W决定光功率到电流的转换效率系统带宽B20 MHz噪声功率正比于带宽带宽越大SNR越低背景光电流I_bg510 μA散粒噪声的主要来源白天阳光直射时更大修改Φ1/2能看到最直观的效果60°时房间四角与中心SNR差距约1520dB换到30°窄光束后中心功率明显变高但角落会跌进噪声底。做空间分布仿真时先固定其他参数只扫Φ1/2能快速理解LED选型对覆盖均匀度的影响。3. 可见光通信仿真输出误码率与信噪比空间分布图的生成3.1 散粒噪声与热噪声的叠加接收功率本身没有通信质量含义真正决定误码率的是信噪比SNR。可见光接收机的噪声主要来自两部分光电探测器的散粒噪声(shot noise)和前端放大电路的热噪声(thermal noise)。散粒噪声由信号光电流和背景光电流共同引起热噪声则与带宽、探测器面积和环境温度相关。仿真里不用把噪声建模成时域波形直接用方差表达式算功率即可。散粒噪声方差为σ_shot² 2qB(R_pd·P_r I_bg)其中q是电子电荷1.6e-19CB是系统带宽R_pd是响应度。热噪声方差为σ_thermal² (8πkT_kηA_pdI_bgB²)/G (16π²kT_kΓη²A_pd²I_bgB³)/g_m前一项是反馈电阻热噪声后一项是沟道热噪声Γ是噪声系数g_m是FET跨导仿真时一般取Γ≈1.5、g_m≈30mS。这两部分噪声相互独立总噪声功率直接相加。信噪比SNR定义为信号电流有效值的平方与总噪声方差之比即SNR (R_pd·P_r)² / (σ_shot² σ_thermal²)。计算时网格上每个点都有自己独立的P_r所以SNR也是一个二维矩阵往空间分布图的方向又近了一步。3.2 OOK调制下误码率与信噪比的映射关系通信仿真必须有调制方式可见光里最基础也最能说明问题的是OOK(On-Off Keying)。OOK在强度调制直检(IM/DD)信道里信号幅度为单极性接收机在最佳判决门限下的误码率为BER Q(√SNR)。MATLAB里Q函数对应的内置函数是qfunc直接调用qfunc(sqrt(SNR))就能得到每个网格点的误码率。对熟练工程师需要明确一点OOK的SNR定义是基于电信号功率的不是光功率。很多新手拿光功率比值当SNR代入公式算出的BER会偏乐观。接收端的信号电功率是(R_pd·P_r)²而不是P_r本身这正是上面SNR公式里分子要平方的原因。如果换用4-PPM调制BER表达式会变成Q(√(SNR/2))再乘修正系数不同调制方式的SNR基准必须对齐后才能横向比较。3.3 生成空间分布图的完整代码与绘图细节计算出SNR矩阵后绘制空间分布图常用两种方式surf画三维曲面imagesc画俯视热力图。实际工程报告里热力图更直观X轴和Y轴直接对应房间坐标颜色代表SNR或BER数值。下面代码把SNR转成dB把BER取以10为底的对数再绘图避免BER量级跨度太大导致色彩全部压在同一段色阶上% 噪声与SNR计算 q 1.6e-19; % 电子电荷 [C] k 1.38e-23; % 玻尔兹曼常数 [J/K] Tk 300; % 环境温度 [K] B 20e6; % 系统带宽 [Hz] R_pd 0.5; % 响应度 [A/W] I_bg 510e-6; % 背景光电流 [A] G_amp 10; % 放大器增益 gm 30e-3; % FET跨导 [S] eta_pd 0.8; % 探测器量子效率 gamma_nf 1.5; % 噪声系数 sigma_shot2 2*q*B*(R_pd*Pr_grid I_bg); sigma_thermal2 (8*pi*k*Tk*eta_pd*A_pd*I_bg*B^2)/G_amp ... (16*pi^2*k*Tk*gamma_nf*eta_pd^2*A_pd^2*I_bg*B^3)/gm; SNR (R_pd*Pr_grid).^2 ./ (sigma_shot2 sigma_thermal2); % OOK误码率与绘图 BER qfunc(sqrt(SNR)); BER_plot max(BER, 1e-12); % 防止log10(0)产生-inf figure(Position, [100 100 1150 420]); subplot(1,2,1); imagesc(x, y, 10*log10(SNR)); axis xy; colorbar; colormap(jet); title(信噪比空间分布 (dB)); xlabel(x / m); ylabel(y / m); subplot(1,2,2); imagesc(x, y, log10(BER_plot)); axis xy; colorbar; title(误码率空间分布 (log10)); xlabel(x / m); ylabel(y / m);绘图部分有两个工程细节值得留意。一是BER_plot的饱和下限房间某些位置SNR很高BER会下溢到真正的0MATLAB里log10(0)会输出-inf图像上出现纯黑噪点而下限截断到1e-12后色彩过渡干净阈值可根据仿真预期动态调整。二是imagesc的坐标轴用x和y而不是直接用XX和YY两个矩阵避免图像行列方向颠倒axis xy把Y轴反转回正常物理方向这样显示的俯视图与房间实际方向一致。这套代码跑完后左图能直接看出SNR高的区域集中在LED正下方附近右图则更突出“哪里完全不可用”两个视角互补。4. 可见光通信仿真参数调节、精度控制与发散排查4.1 网格分辨率与计算量平衡空间分布图的分辨率由网格数N决定。N60意味着房间被切成3600个点每个点要累加4只LED的贡献全部计算量约一万四千次信道增益运算现代MATLAB里毫秒级完成。把N加到200网格点变成四万个显示更平滑但计算量提升一个数量级。实际项目里先跑N40验证参数确认无误后再用N100出正式图是最省时间的节奏。网格分辨率还影响图上出现的伪影。接收点离LED正下方很近时cos_phi接近1、距离d接近垂直高度h如果网格采样刚好错过这些点中心区域的SNR峰值会被低估。要检验分辨率是否足够可以对比N50和N100两张图中心点的SNR差异偏差小于0.5dB即可认为收敛。还有一种常见做法是让网格在LED投影位置局部加密但均匀网格出图更简单通常不需要做这一步。4.2 仿真发散与异常分布的处理办法“仿真发散”这个说法在通信仿真里通常指两类现象计算过程中出现NaN或Inf以及分布图上出现不合理的跳变条纹。第一类多半是除零引起接收点与LED水平距离为0、垂直距离又恰好为0时d.^2为0导致增益无穷大。实际房间里LED挂在天花板接收面在桌面这种几何奇异点不会出现但代码里做通用处理会更稳% 对d设置下限避免奇异值 d max(d, 1e-6); % 检查输出中的非有限值 if any(~isfinite(SNR), all) warning(SNR中存在NaN或Inf检查接收点是否与LED重叠); end第二类跳变条纹通常来自FOV截断。网格上某个点在视场角内相邻网格点在视场角外接收功率从正常值瞬间跌到0反映到SNR图上就是一圈生硬的边界色带。这在实际物理系统中不会发生真实接收器的FOV边缘有过渡区。简单做法是对FOV边界做余弦平滑例如把in_fov从硬逻辑门改为按cos_phi连续衰减的权重代价是引入一个过渡角度参数。如果出图只为了看趋势硬截断也能接受报告里注明假设条件即可。还有一个被忽视的异常来源是背景光电流。I_bg在阳光直射窗口附近可以飙升到毫安级散粒噪声项2qB·I_bg大幅增加SNR整体下拉。做白天场景仿真时把I_bg从510μA改成1mA重跑一次观察分布图整体梯度的变化能提前预判环境光干扰的严重程度。4.3 提高输出稳定性的三个常见做法实际落地时我会在标准仿真流程里加三个加固步骤。第一把接收功率矩阵做一次无偏性核对总接收功率对接收面积积分后应与LED发射功率在一个量级。积分值偏差超过50%说明参数设置或坐标映射有误需要回头查几何定义。第二使用变量脚本化的参数结构体。把Φ1/2、FOV、B这些参数集中定义跑参数扫描时只改struct字段避免散落在脚本各处的魔法数字。配合MATLAB的实时脚本(live script)记录每次运行参数复盘结果时能精确还原当时的仿真环境。第三对贝尔分布做统计特征提取除了看图像还要计算SNR均值和标准差、BER超过前向纠错门限(通常取3.8e-3)的位置占比。只用颜色判断容易受色觉误差影响数值指标才是设计方案对比的依据。下表总结了几种常见异常现象与排查方向异常现象可能原因排查方法中心点SNR异常高网格点接近LED投影加密网格核对收敛性角落BER全部为1FOV过窄或LED功率不足增大FOV或增加LED数量分布图出现同心圆环网格分辨率过低N提升到100以上全图SNR整体偏低I_bg设置过大检查环境光参数图中出现NaN白斑接收点几何奇异d加下限保护5. 仿真操作录像的生成与结果验证5.1 用VideoWriter把空间分布图做成回放视频标题里的“仿真操作录像”在MATLAB里可以直接用VideoWriter对象完成不需要外部录屏工具。思路是先预计算完整的SNR和BER分布矩阵再按扫描线逐帧重绘并抓取当前图形窗口最后合成AVI视频。这样生成的录像自带坐标轴和动态扫描效果比录屏更干净也更容易配上讲解。代码如下vw VideoWriter(vlc_snr_ber_scan.avi, Motion JPEG AVI); vw.FrameRate 15; % 每秒帧数15帧足够看出扫描过程 open(vw); figure(Position, [100 100 1150 420]); for i 1:N % 每次只把扫描到i行的数据填入显示 subplot(1,2,1); imagesc(x, y, 10*log10(SNR)); axis xy; colorbar; hold on; plot([x(1) x(end)], [y(i) y(i)], k--, LineWidth, 1.2); hold off; title(sprintf(SNR分布扫描行 %d/%d, i, N)); xlabel(x / m); ylabel(y / m); subplot(1,2,2); imagesc(x, y, log10(BER_plot)); axis xy; colorbar; hold on; plot([x(1) x(end)], [y(i) y(i)], k--, LineWidth, 1.2); hold off; title(sprintf(BER分布扫描行 %d/%d, i, N)); xlabel(x / m); ylabel(y / m); drawnow; writeVideo(vw, getframe(gcf)); end close(vw);这段代码的核心是把静态的完整分布图通过一条黑色虚线扫描线模拟出“边行进边观察”的动态效果。每帧只更新扫描线位置数据矩阵不用重算录制速度只受显卡显示刷新限制。若想让录像更有操作感可以反过来仿真代码逐点计算、逐帧绘图、再写入视频这样观众看到的是真正从空网格一步步填满的过程但耗时更长。两种方式产物都是AVI文件帧率15fps比30fps更适合展示空间渐变过程体积也更小。5.2 录像与仿真结果的快速验证技巧录像完成后先做三件事再交付。第一抽帧核对用VideoReader读取视频第10帧和第30帧确认扫描线位置与SNR色彩带对应防止录像过程中图形窗口被遮挡或坐标轴刷新异常。第二录制前在图题里写入参数版本号后续修改参数重录时录像自带可追溯信息。第三截取最终帧与单独出图的静态图做像素级对比两者完全一致才能说明录像覆盖了完整仿真流程。数值验证方面取网格中心点用解析公式手算出该位置的SNR与仿真矩阵中心元素对比误差应该在3%以内主要来自网格采样偏移。再把四只LED逐一关闭重新仿真观察SNR分布对称性变化若关闭某只LED后分布出现非预期偏斜说明LED坐标定义或循环累加顺序有误。经得住这三项检查的输出才能作为方案验证材料或技术报告配图。本文还有配套的精品资源点击获取