带电粒子在匀强磁场中的圆周运动交互课件
在圆周运动的基础上,顺便做一个带电粒子在匀强磁场中的圆周运动课件,实现的是沪科版选择性必修二第五章 第三节 带电粒子在匀强磁场中的圆周运动中的图 5–31。如下图所示。
原本以为只要在原有的基础上绘制磁场就可以了,类似于火花学院的这种,后来在飞象老师上看到了这个课件挺好的,就多花了点时间实现了类似的轨迹线效果。
做出的成品如下所示:
数据设置
为了避免犯科学性错误,查了一下真实情况中的典型数值:
小型实验/教学用回旋加速器:B 可能在 0.5 T 到 1.5 T 之间,质子能量在 10 MeV 以下。
医用质子回旋加速器(用于癌症治疗):能量通常 70 MeV 到 250 MeV,采用紧凑型设计时可达更高。现代紧凑型回旋加速器主要用于生产医用放射性同位素(如氟-18 用于PET-CT)或进行中子活化分析,其典型半径:约 0.3 m 到 1.2 m,磁场强度约 1 T 到 2 T,质子能量通常在 10 MeV 到 30 MeV 之间。整个加速器系统(包括磁铁、真空室、高频系统、屏蔽等)通常像一个房间里的中型设备,占地面积从几平方米到几十平方米不等。核心的磁铁直径大概在 1 ~ 3 m。
若采用小型回旋加速器的数值,在不考虑相对论的情况下,质子的速度
\[v = \sqrt {\frac{{2{E_{\rm{k}}}}}{m}} = \sqrt {\frac{{2 \times 10 \times {{10}^6} \times 1.6 \times {{10}^{ - 19}}}}{{1.67 \times {{10}^{ - 27}}}}} \;{\rm{m/s}} \approx 4.37 \times {10^6}\;{\rm{m/s}} \approx 0.146c\]
考虑相对论时求出的速度会再小一点。因此程序中磁感应强度的取值范围为 – 1 ~ 1 T,速度取值范围为 1 ~ 5×107 m/s。
质子的比荷 \(\dfrac{e}{{{m_{\rm{p}}}}}\) ≈ 9.58×107 C/kg,是电子比荷的 \(\dfrac{1}{{1\;836}}\),在稳定、长寿命的常见带电粒子中,除了电子(及其反粒子正电子)以外,质子的荷质比是最大的。因此比荷的取值范围为 − 1×108 ~ 1×108 C/kg。
若 v = 5×107 m/s,B = 1 T,q/m = 1×108 C/kg,求得运转半径 r = 0.5 m,周期约 0.628 ns。
核心代码解读
这次 AI 竟然还创建了一个 Particle 类,使代码逻辑更清晰一点。在这个类中保存了带电粒子水平方向、竖直方向的速度和位置信息:vx、vy,x、y。
在代码中先求出当前角速度 ω = \(\frac{m}{{qB}}\),由 θ = ωΔt 求出一帧中转过的角度,根据当前帧的速度 v0x、v0y 和 θ 求出下一帧的速度 v1x、v2y,进一步求出下一帧粒子的位置 x1、y1。
绘制轨迹线的逻辑是:由 200 个点组成轨迹,在 update 方法中每隔 5 帧将粒子的位置信息保存到 trail 数组中,若点数超过 200,则移除第 1 个。在 draw 方法中由这 200 点生成 199 条线段,并根据顺序设置透明度,这样就实现了轨迹线渐隐的效果。
// 粒子类
class Particle {
constructor(x, y, vx, vy, qm) {
this.pos = { x, y, opacity: 1 };
this.vel = { x: vx, y: vy };
this.qm = qm;
this.trail = [];
this.color = qm > 0 ? '#f43f5e' : (qm < 0 ? '#3b82f6' : '#94a3b8');
this.trailFrameCounter = 0; // 轨迹记录帧计数器
}
update(dt, B) {
// 速度因子,用于在不改变物理参数的情况下加快粒子在屏幕上的移动速度
const speedFactor = 2.0;
// 如果比荷为0或B为0,不受力
if (Math.abs(this.qm) < 0.1 || Math.abs(B) < 0.1) {
this.pos.x += this.vel.x * dt * CONFIG.scale * speedFactor;
this.pos.y += this.vel.y * dt * CONFIG.scale * speedFactor;
} else {
// omega = -(q/m) * B * direction
const omega = -this.qm * B;
const angle = omega * dt * speedFactor;
const cos = Math.cos(angle);
const sin = Math.sin(angle);
const newVx = this.vel.x * cos - this.vel.y * sin;
const newVy = this.vel.x * sin + this.vel.y * cos;
this.vel.x = newVx;
this.vel.y = newVy;
// 更新位置
this.pos.x += this.vel.x * dt * CONFIG.scale * speedFactor;
this.pos.y += this.vel.y * dt * CONFIG.scale * speedFactor;
}
// 记录轨迹 - 每5帧记录一次,减少粒子密度但保持轨迹长度不变
// 每个轨迹点携带自己的颜色信息
this.trailFrameCounter++;
if (this.trailFrameCounter % 5 === 0) {
this.trail.push({
x: this.pos.x,
y: this.pos.y,
color: this.color // 记录当前颜色
});
// 限制轨迹点数量
if (this.trail.length > CONFIG.trailLength) {
this.trail.shift();
}
}
}
draw() {
// 更新粒子位置
const cx = this.pos.x;
const cy = this.pos.y;
this.particleEl.setAttribute('cx', cx);
this.particleEl.setAttribute('cy', cy);
this.particleEl.setAttribute('opacity', this.pos.opacity);
// 绘制轨迹 - 使用多个线段,每段根据生命周期设置透明度
if (this.trail.length > 1) {
// 先清空旧的轨迹线段
this.trailContainer.innerHTML = '';
// 创建轨迹线段
for (let i = 1; i < this.trail.length; i++) {
const prevPoint = this.trail[i - 1];
const currPoint = this.trail[i];
// 计算透明度:根据轨迹点在数组中的位置
// 最旧的点(索引0)透明度为0,最新的点(索引length-1)透明度为1
const opacity = i / (this.trail.length - 1);
// 创建线段
const line = document.createElementNS(NS, 'line');
line.setAttribute('x1', prevPoint.x);
line.setAttribute('y1', prevPoint.y);
line.setAttribute('x2', currPoint.x);
line.setAttribute('y2', currPoint.y);
line.setAttribute('stroke', currPoint.color); // 使用当前点的颜色
line.setAttribute('stroke-width', '5');
line.setAttribute('opacity', opacity);
this.trailContainer.appendChild(line);
}
}
}
欧拉积分法
高中阶段解决一维匀变速直线运动的思路如下:
- 先由牛顿第二定律求出加速度 a = \(\dfrac{F}{m}\);
- 然后由 v = v0 + at 求速度;
- 由 x = v0t + \(\dfrac{1}{2}\)at2 求位移。
但在真实场景中,通常不会有像这样美好的解析解,对于更通用的问题,我们必须用数值方法进行积分,才能求得速度及位置。最基本的方法叫做欧拉积分法。基本的欧拉积分法有 2 种。
1.显式欧拉法(Explicit Euler)
用当前点的切线方向来估计下一个点,就像只看脚下走路。它的缺点是稳定性差、能量不守恒,模拟物理系统会发散。若用 n 表示当前状态,n + 1 表示下一时刻的状态,则积分运算过程可以表示为:
vn+1 = vn + anΔt
xn+1 = xn + vnΔt
2.半隐式欧拉法(Semi-Implicit Euler)
又称辛欧拉法,是一种改进的欧拉方法,它部分使用未来信息,但保持显式可解性。是显式欧拉和完全隐式欧拉之间的折中方案。积分运算过程可以表示为:
vn+1 = vn + anΔt
xn+1 = xn + vn+1Δt
与显式欧拉法相比,唯一的区别是新位置 xn+1 是用新速度 vn+1 隐式更新的。用物理直观解释,就像一个谨慎的行人,先看路计算下一步的速度(基于当前位置),用新速度走——用刚算出的速度决定走多远,比显式更安全:不会“走过头”。它更接近真实物理:物体确实是先加速,然后用新速度位移。显式欧拉法能量单调增长,可能会数值爆炸,而半隐式欧拉法能量有界振荡,可以保持长期稳定。推荐看一下Bilibili上的视频——颠覆轨道模拟的代码:辛积分与相空间不变量如何革新小行星带长期模拟?——加深理解。
若用这两种方法分析匀加速直线运动,显式欧拉法相当于 x = v0t,位移偏小,隐式欧拉法相当于x = (v0 + at)t,位移偏大,而精确值为 x = \(\dfrac{{{ v_0} + ({v_0} + at)}}{2}\)t。
在本例的代码中:
const newVx = this.vel.x * cos - this.vel.y * sin;
const newVy = this.vel.x * sin + this.vel.y * cos;
this.vel.x = newVx;
this.vel.y = newVy;
// 更新位置
this.pos.x += this.vel.x * dt * CONFIG.scale * speedFactor;
this.pos.y += this.vel.y * dt * CONFIG.scale * speedFactor;
可见,用的是半隐式欧拉法。
完整代码
code
发布时间:2026/2/1 下午4:58:15 阅读次数:70
