ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

MATLAB线电荷电场仿真:电势叠加、等位线与场强可视化

MATLAB线电荷电场仿真:电势叠加、等位线与场强可视化

简介:这份仿真实验报告面向电子信息、电气工程等专业学生以及刚接触Matlab的读者,围绕线电荷周围电场与电位分布的可视化展开,用于理解库仑定律、电场强度与势函数在数值计算中的实现方式。文档从实验目的、原理公式讲到坐标网格设置、for循环累加电势、surf三维电势图与contour等位线绘制,并给出用quiver绘制矢量场的完整代码与运行结果截图,读者可据此对照复现并改写参数。压缩包内仅有1个docx文件,约227KB,按实验目的、原理、步骤、代码、结论的顺序编排,代码保留逐行注释,便于按模块检索学习。目前该资源已有3041人学习,既可作为电磁场课程实验报告的参考模板,也能帮助读者避开矩阵维度不一致、电荷密度选取不当、累加初值未置零等常见问题。

1. 二十行 MATLAB 代码画出等位线:这份线电荷仿真报告到底能跑出什么

很多人第一次把这份实验报告里的脚本粘进 MATLAB,都会经历两个瞬间:surf出来的曲面陡得像几根针扎在平面上,contour出来的等位线在电荷附近糊成一团,根本看不清分布。这份基于 MATLAB 的线电荷电场分布仿真,主体其实很短:把一条线电荷拆成 51 个等间距点电荷,在 267×267 的网格上逐个叠加电势,再用surf、contour、quiver三个函数把三维电势面、等位线和场强方向一次性展开。它解决的是电磁场课里最抽象的那件事——线电荷周围的场到底长什么样,离散到什么粒度才算可信。适合正在做电磁场仿真实验、需要复现一份交得出去的图,或者想把 MATLAB 矩阵运算和绘图流程串一遍的人。

2. 物理先立住:从库仑定律推到线电荷的离散叠加

动手之前先把公式和参数确认清楚,后面调图、排查、验收才有依据。这一章按公式、离散化、场强三步推进,每一步都对应到脚本里的具体代码和具体数值。

2.1 点电荷电势 U 与真空电容率的取值

真空中一个电量 q 的点电荷,在距离 r 处产生的电势是 U = q / (4πε₀r),其中 ε₀ 是真空电容率,精确值 8.854187817e-12 F/m。原报告里写的是e0=1e-9/(36*pi),算出来 8.8419e-12,比精确值小约 0.14%,这个误差对一张教学仿真图完全够用,但如果要跟解析解逐点对比,这 0.14% 会直接体现在相对误差里,所以心里要有数。

更有用的是先把库仑常数 ke = 1/(4πε₀) ≈ 8.988e9 N·m²/C² 单独提出来。取 q = 1.6e-19 C,则 ke·q ≈ 1.438e-9 V·m,也就是说距离电荷 1 m 处的电势大约 1.44 纳伏。这个量级信息非常关键:后面surf出来的 Z 轴全部在 1e-9 量级,不是程序错了,而是电荷量本来就小。不提前说明,很多人会把图上那一排 10^-9 当成数据异常去反复折腾。

参数原代码取值物理含义建议取值与理由
nr50(循环实际跑 51 次)离散点电荷个数写成 51,与循环次数对齐
q1.6*10e-19单个电荷电量1.6e-19,注意10e-19是 1e-18
e01e-9/(36*pi)真空电容率与 8.854e-12 差 0.14%,教学够用
网格-40:0.3:40场点采样范围与步长步长取电荷间距的 1/3 以下
电荷位置k-25,k=1..51x 从 -24 到 26改用linspace(-25,25,51)显式给出

2.2 为什么 50 个点电荷能近似一条线电荷

无限长线电荷的电势是 U = λ/(2πε₀)·ln(r₀/r),形式上是发散的,所以原报告没有用解析式,而是走离散叠加这条路:把线电荷切成 N 段,每段当成一个点电荷,总电势就是 N 个点电荷电势的代数和。这个做法在 MATLAB 里就是一次for循环加一次矩阵累加,实现成本极低,代价是要接受离散化误差。

误差大小由两个长度之比决定:电荷之间的间距 d,和观测点到线电荷的距离 r。d/r 越小,离散的点列看起来越像连续线。以原代码为例,51 个电荷分布在长度 50 的线段上,间距 d = 1;网格步长 0.3,最近的一圈观测点离电荷大约 0.3 到 0.5,此时 d/r 接近 2,离散误差非常大,那个位置的等位线基本不能信。往外走,r 到 5 时 d/r = 0.2,误差会掉到百分之一量级;r 到 20 时基本看不出区别。

这就是选电荷个数的依据:不是越多越好,而是要让“你到底想看清哪一块”和“d/r 在那一块有多小”对齐。如果只关心远离线电荷的大尺度分布,51 个足够,甚至 21 个也能看;如果要看清电荷附近的细节,就得同时提高电荷密度和网格密度,否则图再好看也是假的。常见的经验做法是让电荷间距不超过网格步长的 3 到 5 倍,同时观测区域边界至少离线电荷端点两倍线长以外,避开端点效应。

2.3 电势到电场:E=-∇U 与 gradient 的离散差分

电势是标量,画出来直观;电场是矢量,方向信息才是电磁场实验真正想看的。两者关系是 E = -∇U,负号不能丢,丢了箭头会整体反向,看起来“电荷在吸引”,非常隐蔽。

MATLAB 里对应的是gradient。它默认按单位步长做中心差分,返回的第一个输出是沿列方向(x)的偏导,第二个是沿行方向(y)的偏导,内部点用前后两点差分,边界点退化成单边差分。所以调用时必须把网格步长传进去:gradient(-U, 0.3, 0.3),否则算出来的场强是“每格电势差”,量纲不对。虽然原报告后面做了归一化、只看方向,量纲错误被掩盖了,但这是运气好,不是写法对。

归一化那一步Ex=Ex./AE; Ey=Ey./AE把每点的场强压成单位向量,好处是箭头长度统一、方向清楚,坏处是彻底丢掉了场强大小信息——靠近电荷和远离电荷的箭头一样长。想要同时表达方向和大小的常用做法有两种:一是先对模值取对数再当箭头长度,二是干脆不归一化,改用streamslice画流线,长度由场强自动决定。这两种方案在后面的图像调优里还会提到。

3. 代码逐行拆:网格、循环、叠加三件事怎么落到 MATLAB 里

原报告的脚本能跑,但有几处写法会把后续修改的人带进坑里。这一章按“定义坐标—累加电势—出图”的顺序重写一遍,每一段都给出可直接运行的代码和参数解释。

3.1 meshgrid 与电荷坐标:先把“谁在哪”定死

第一步是把几何关系写明确:线电荷放在哪、场点网格铺多大。原代码用k-25在循环里隐式推电荷位置,改一个参数就要重新推一遍偏移量,很容易错位。更好的做法是先用linspace把电荷坐标列成一个向量,后面所有计算都引用这个向量。

clear; clc; close all; nr = 51; % 离散点电荷个数 q = 1.6e-19; % 单个点电荷电量,单位 C eps0 = 1e-9/(36*pi); % 真空电容率,约 8.842e-12 F/m ke = 1/(4*pi*eps0); % 库仑常数,约 8.988e9 xk = linspace(-25, 25, nr); % 线电荷位置,间距 1 [X, Y] = meshgrid(-40:0.3:40, -40:0.3:40); % 267x267 场点网格 U = zeros(size(X)); % 电势累加器,按网格尺寸预分配

meshgrid返回的 X、Y 都是 267×267 的矩阵,行列分别对应 y 和 x 的采样点。之所以要预分配zeros(size(X))而不是像原代码那样写U=[0],是因为后者依赖 MATLAB 的标量自动扩展,虽然能跑通,但一旦后面有人把它改成U=zeros(1,nr)之类的形状,累加就会报维度不匹配,而且报错位置在循环内部,排查起来很费劲。

网格范围也有讲究。-40 到 40 覆盖了线电荷两端各 15 的余量,这个余量不能太小,否则等位线在边界被硬切断,看起来像“场到这里就没了”。步长 0.3 使得整张图有 7 万多个场点,对 51 次循环来说计算量很小,现代机器上毫秒级完成。

3.2 for 循环累加电势:初始化与点除运算符

累加部分是整个脚本的核心,也是最容易写错的地方。要点有三个:距离用sqrt而不是.^0.5、除法必须是点除、累加顺序不影响结果但影响可读性。

for k = 1:nr Rk = sqrt((X - xk(k)).^2 + Y.^2); % 场点到第 k 个电荷的距离矩阵 U = U + ke * q ./ Rk; % 逐点叠加:U = Σ ke*q/r end

Rk是一个和 X 同尺寸的矩阵,每一元素是该场点到第 k 个电荷的欧氏距离。写成sqrt(...)比.^0.5快一些,也更符合“距离”的语义。ke*q ./ Rk里的点除必须保留:如果误写成/,MATLAB 会按矩阵右除解释,要么报错,要么给出一个完全无意义的解——这种错误不会崩,只会让图变得莫名其妙,是最难查的一类。

累加本身没有任何顺序要求,U = U + ...写在循环里,跑 51 次,得到的就是 51 个点电荷电势的叠加。如果想让代码更“矩阵化”,也可以把xk扩展成三维数组一次性算完,但对这个规模来说没必要,循环反而更好读、好调、好加断点。

注意:如果网格点恰好落在某个电荷位置上,Rk会是 0,ke*q./0得到 Inf,surf会画出一根冲天的针,contour会产生一堆畸形等位线。0.3 的步长和间距 1 的电荷位置恰好错开,实际不会命中,但把步长改成 0.5 或 1 就会踩上。

3.3 三种出图方式的参数:surf、contour、quiver

三个绘图函数各有各的参数陷阱,直接照抄原报告的默认调用,出来的图基本都是“能看但没法交”。下面给出调过的版本。

figure('Color','w'); surf(X, Y, U, 'EdgeColor','none'); % 关网格线,否则七万个面片全是黑边 shading interp; colormap(parula); colorbar; xlabel('x / m'); ylabel('y / m'); zlabel('U / V'); zlim([0 5e-9]); % 裁掉电荷附近尖峰,主视觉留给 1e-9 量级 view(45, 35);

EdgeColor','none'是这个尺寸网格下的必需品。不关边线,7 万个面片的黑色轮廓会把整个曲面糊成一块深色,什么细节都看不到。shading interp让颜色在面片间插值,曲面看起来才连续。zlim的作用是“舍弃”:电荷附近的电势能到 1e-8 量级,不裁掉的话色阶被这几个点占满,其余 99% 的区域全是同一个颜色。

figure('Color','w'); CV = linspace(0.2e-9, 3e-9, 24); % 手动给定等位线取值,不用 min/max contour(X, Y, U, CV, 'LineWidth', 0.9); hold on; plot(xk, zeros(size(xk)), 'r.', 'MarkerSize', 9); axis equal; xlim([-40 40]); ylim([-15 15]); xlabel('x / m'); ylabel('y / m'); colorbar;

contour的第四个参数是等位线取值向量,这是整张图质量的关键。原报告用linspace(Vmin,Vmax,30)生成,Vmin 是全场最小值、Vmax 是电荷附近的极大值,两者相差好几个数量级,结果就是 30 条线里 29 条挤在电荷周围一小圈。手动指定 0.2e-9 到 3e-9 这个区间,等位线才会均匀铺开。axis equal保证 x、y 等比例,不然等位线会被拉成椭圆,看着像各向异性介质。

[Ex, Ey] = gradient(-U, 0.3, 0.3); % 后两个参数是 x、y 方向网格步长 AE = hypot(Ex, Ey); Ex = Ex ./ AE; Ey = Ey ./ AE; % 归一化,只保留方向 Ex(~isfinite(Ex)) = 0; Ey(~isfinite(Ey)) = 0; step = 8; % 每 8 个网格点取一个箭头 quiver(X(1:step:end,1:step:end), Y(1:step:end,1:step:end), ... Ex(1:step:end,1:step:end), Ey(1:step:end,1:step:end), ... 0.6, 'Color', [0.15 0.55 0.25]);

gradient的两个步长参数不能省,虽然归一化后方向对就行、数值大小无所谓,但把步长传对是让代码在“哪天你想看真实场强”时仍然可用的前提。hypot比sqrt(Ex.^2+Ey.^2)数值上更稳,不会在中途溢出。除零保护必须做:离电荷极近的点上 AE 可能是 0 或极小值,直接除会得到 NaN 或 Inf,quiver遇到这些值会静默跳过,图上出现一片空白,看起来像“那里没有场”,其实是数据被污染了。

quiver的缩放因子 0.6 需要配合抽稀一起看。不抽稀时 7 万个箭头会把整张图涂成一块绿布,抽到每 8 个点取一个还剩约 1100 支箭头,密度刚好。缩放因子越大箭头越长,设成 0 表示关闭自动缩放、按数据真实长度绘制,那种模式下归一化后的箭头全是一个像素长,基本看不见。

4. 图像调优:把“能看”的图改成交得出去的图

代码跑通只是及格线,报告里的图能不能用,取决于几个视觉层面的取舍。这一章讲三件事:箭头怎么不糊、等位线怎么不挤、网格密度怎么不浪费。

4.1 箭头抽稀与等位线的配图策略

把等位线和矢量场画在同一张图上,是这份报告最常见的排版方式,也是最容易翻车的地方。两张图层叠之后,等位线的细线会被密集的箭头盖住,读图的人第一眼看到一片绿色噪点,根本找不到等位线在哪。

处理办法是分层抽稀:等位线保留全部网格精度(contour本身就会做插值,不需要降采样),箭头按 6 到 10 个网格点取一个。上面代码里step = 8就是干这个的。如果想再干净一点,可以把箭头颜色调淡、线宽调细,让等位线在视觉上占主导;反过来,如果这张图的主目的是看场强方向,那就把等位线减到 8 到 10 条,箭头加密到 step = 5。

另一种做法是拆成两张图:一张只画等位线加电荷位置,一张只画箭头加电荷位置。报告里两张图并排,读者一眼就能建立“等位线疏密”和“箭头方向”的对应关系,比硬塞进一张图更清楚。如果一定要合并,建议用streamslice替代quiver——流线天然稀疏,而且长度会随场强变化,视觉上比等长箭头信息量大。

4.2 等值线取值区间与色阶控制

等位线取值区间的选法,本质上是在决定“这张图想讲哪个尺度的故事”。线电荷附近的电势按 1/r 上升,往外按对数缓慢衰减,两个尺度差了三个数量级以上,用一套线性等距的取值不可能同时覆盖。

实际操作里我一般这么定:先算一遍全场电势,看 90 分位数大概在什么量级,把等位线上限设在那个值的 2 到 3 倍,下限设在最大值的 5% 左右。以上面的参数为例,远离电荷的区域电势在 1e-10 量级,靠近电荷 1e-8 量级,取 0.2e-9 到 3e-9 这 24 条线,正好能把中间那段最有信息量的区域铺满。

surf的色阶是同一个道理。zlim不设,MATLAB 自动取全场的 min 和 max,而 max 出现在离电荷最近的那一个网格点上,这个点的值没有任何代表性,却决定了整张图的颜色映射。裁到[0 5e-9]之后,超过上限的点会被压成同一个颜色,视觉上表现为“电荷附近一小片饱和区”,反而更符合物理直觉——那里本来就是奇点,画不准是应该的。

4.3 网格分辨率、内存与运行时间的取舍

网格步长 0.3 对应 267×267 个点,双精度下每个矩阵约 570 KB,循环里同时存在的临时矩阵大概三四个,内存占用不到 10 MB,运行时间在零点几秒。这个规模对任何一台能跑 MATLAB 的机器都不构成压力,所以默认配置不需要优化。

真正需要调分辨率的场景是两种。一种是做参数扫描,比如要跑 20 组不同的电荷个数做对比,每组都 267×267,累计时间就开始可观了,这时候可以把步长放到 0.6,点数降到 1/4,先看趋势,确定参数区间后再用细网格出终图。另一种是想看清靠近线电荷的细节,那就得把步长压到 0.1 甚至更小,点数涨到 80 万,这时候循环 51 次的矩阵运算会开始吃掉几秒钟,同时surf的渲染也会变卡,因为面片数太多。

一个折中技巧是分区加密:整体用 0.5 的粗网格出全景图,另开一个小窗口用 0.05 的细网格只算x∈[-5,5], y∈[-2,2]这一块,专门看电荷附近的局部结构。两张图放一起,既有全局观感又有局部细节,比单张图硬堆分辨率划算得多。这个方法在写报告时特别管用,因为评审看的往往就是“你有没有意识到近场和远场尺度不同”。

5. 避坑与排查:这份报告里最容易翻车的四个地方

下面四条都是照着这份报告复现时真实会撞上的问题,每一条按“看到什么现象—为什么—怎么改”的顺序写,方便对号入座。

5.1 电量写成 1.6*10e-19:结果整体大了十倍

现象:图的形状看起来完全正常,等位线分布、箭头方向都对,但 Z 轴刻度或者 colorbar 上的数字跟同学对不上,差了一个数量级。

原因:原代码q=1.6*10e-19里的10e-19在 MATLAB 中被解析成 10×10^-19 = 1e-18,再乘 1.6 得到 1.6e-18,比本意 1.6e-19 大了整整十倍。这种写法在纸上写科学计数法时很自然,落到代码里就是一个静默的量级错误,程序不会报任何警告。

解决:统一改成1.6e-19,并且在脚本开头加一行注释写清单位。更进一步的习惯是:把这类物理常数集中在一个代码块里定义,后面全部引用变量名,避免同一个数字在多处出现时改漏。

5.2 等位线只剩最里面几圈:Vmin/Vmax 被奇异点绑架

现象:contour画出来,图上只有电荷附近密密的几圈线,往外大片空白,完全看不出线电荷的场分布特征。

原因:用Vmin=min(min(U))和Vmax=max(max(U))生成等位线等级时,Vmax 由离电荷最近的那个网格点决定,通常是 Vmin 的上百倍。30 条等距线里,绝大多数都落在高值区间,低值区间一条线都没有。

解决:放弃自动生成,手动指定CV = linspace(下限, 上限, 条数),上下限按 4.2 节的方法定。判断标准很简单:画出来之后,等位线应该从电荷附近一直铺到图的边界,中间没有大段空白。

5.3 箭头方向反了或者整片空白:gradient 与除零

现象一:箭头整体指向电荷,看起来像正负电荷相吸,但代码里明明全是同号电荷。现象二:图上某一片区域完全没有箭头,或者画出来的箭头长度忽长忽短、毫无规律。

原因:方向反了是漏了负号,gradient(U)少写一个减号,E = -∇U 变成 E = ∇U。整片空白是归一化时除零,AE在电荷附近或场的极值点可能接近 0,Ex./AE得到 NaN 或 Inf,quiver遇到非有限值直接跳过不画。

解决:gradient(-U, dx, dy)里的负号不能省,可以用一个已知点做自检——线电荷右侧的场强应该指向 +x 方向,如果画出来指向 -x,就是符号错了。除零用Ex(~isfinite(Ex)) = 0兜底,或者更保守地AE = max(AE, 1e-12)之后再除。

5.4 电荷跑出画面:k-25 这类隐式偏移的代价

现象:把电荷个数从 51 改到 101,或者把网格范围从 ±40 缩到 ±20,等位线突然变得左右不对称,一侧的线在边界被硬切断,另一侧还有大片余量。

原因:原代码用k-25计算电荷位置,k 从 1 到 51,位置从 -24 到 26,这个偏移量 25 是硬编码的,跟电荷个数强绑定。改个数之后位置跨度跟着变,但偏移量没变,整条线电荷就整体平移了;改网格范围之后,线电荷可能直接超出计算域。

解决:位置一律用linspace显式给:xk = linspace(-25, 25, nr)。这样电荷跨度是固定的,改个数只改间距;再让网格范围比电荷跨度两头各多出至少 50%,就不会出现截断。改参数之后第一件事是plot(xk, zeros(size(xk)))单独看一眼电荷位置和网格边界的相对

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进