# 質譜儀
> 作者:王一哲
> 日期:2018/5/13
<br />
有5種粒子以相同之速度垂直進入均勻磁場B,其軌跡如下圖所示。設此5種粒子為:碳原子(<sup>12</sup>C)、氧離子(<sup>16</sup>O<sup>2-</sup>)、鈉離子(<sup>23</sup>Na<sup>+</sup>)、鎂離子(<sup>24</sup>Mg<sup>2+</sup>)及氯離子(<sup>35</sup>Cl<sup>-</sup>)。若不考慮重力因素,則圖中1、2、3、4及5之示意軌跡分別代表何者?
<img style="display: block; margin-left: auto; margin-right: auto" height="60%" width="60%" src="https://i.imgur.com/oX3Xckp.png">
<div style="text-align:center">粒子在質譜儀中運動軌跡示意圖</div>
<br />
這是84年日大聯招的題目,雖然年代已經很久遠,但在坊間各家的參考書中仍然可以找到這個題目。當粒子向上進入磁場時,帶正電粒子所受的磁力向左,帶負電粒子所受的磁力向右,電中性的粒子沒有受到磁力。若以磁力當作向心力,在磁場中做等速率圓周運動,則
$$ qvB = m \cdot \frac{v^2}{R} ~\Rightarrow~ R = \frac{mv}{qB} \propto \frac{m}{q} $$
因此本題的答案為<sup>23</sup>Na<sup>+</sup>、<sup>24</sup>Mg<sup>2+</sup>、12<sup>C</sup>、<sup>16</sup>O<sup>2-</sup>、<sup>35</sup>Cl<sup>-</sup>。這次我們要試著用 VPython 將粒子在質譜儀中的運動過程畫出來。
<br />
## 程式 23-1.質譜儀 ([取得程式碼](https://github.com/YiZheWangTw/VPythonTutorial/blob/master/23.%E8%B3%AA%E8%AD%9C%E5%84%80/23-1.mass_spectrometer.py)) ([GlowScript 網站動畫連結](http://www.glowscript.org/#/user/yizhe/folder/Public/program/23-1.massspectrometer))
```python=
"""
VPython教學: 23-1.質譜儀
Ver. 1: 2018/4/8
Ver. 2: 2019/9/19
作者: 王一哲
"""
from vpython import *
"""
1. 參數設定, 設定變數及初始值
"""
size, m, q = 0.01, 1E-10, 2E-8 # 粒子半徑, 質量, 電量
v0 = vec(0, 10, 0) # 粒子初速度
# 用 dictionary 儲存的粒子資料, 用 list 儲存的粒子名稱
masses = {"C": 12*m, "O": 16*m, "Na": 23*m, "Mg": 24*m, "Cl": 35*m}
charges = {"C": 0, "O": -2*q, "Na": q, "Mg": 2*q, "Cl": -q}
colors = {"C": color.red, "O": color.yellow, "Na": color.orange, "Mg": color.white, "Cl": color.green}
particles = ["C", "O", "Na", "Mg", "Cl"]
L = 0.4 # 金屬板長度
B_field = vec(0, 0, -10) # 磁場
t, dt = 0, 1E-5 # 時間, 時間間隔
"""
2. 畫面設定
"""
# 產生動畫視窗、金屬板
scene = canvas(title="Mass Spectrometer", width=800, height=600, x=0, y=0,
center=vec(0, 0, 0), background=color.black)
p1 = box(pos=vec(-0.55*L, 0, 0), size=vec(L, 0.01*L, 0.1*L), color=color.blue)
p2 = box(pos=vec(0.55*L, 0, 0), size=vec(L, 0.01*L, 0.1*L), color=color.blue)
# 產生帶電粒子
name = particles[0]
particle = sphere(pos=vec(0, -L/3, 0), v=v0, radius=size, m=masses[name],
q=charges[name], color=colors[name], make_trail=True)
# 產生表示磁場的箭頭及標籤
arrow_B = arrow(pos=vec(-0.5*L, 0.5*L, 0), axis=vec(0, 0, -0.1), shaftwidth=size, color=color.green)
label_B = label(pos=vec(-0.5*L, 0.5*L, 0), text="B", xoffset=25, yoffset=25, color=color.green, font="sans")
# 產生表示速度、加速度的箭頭
arrow_v = arrow(pos=particle.pos, shaftwidth=0.5*size, color=color.cyan)
arrow_a = arrow(pos=particle.pos, shaftwidth=0.5*size, color=color.magenta)
"""
3. 物體運動部分
"""
while((abs(particle.pos.x) < 0.1*size and particle.pos.y < L/2) or \
(abs(particle.pos.x) > 0 and particle.pos.y > p1.height/2 + size)):
rate(1000)
# 計算帶電粒子所受合力, 更新帶電粒子加速度、速度、位置
if(particle.pos.y > p1.height/2 + size): F = particle.q*cross(particle.v, B_field)
else: F = vec(0, 0, 0)
particle.a = F/particle.m
particle.v += particle.a*dt
particle.pos += particle.v*dt
# 更新表示速度、加速度的箭頭, 只畫出方向以避免動畫自動縮小
arrow_v.pos = particle.pos
arrow_a.pos = particle.pos
arrow_v.axis = particle.v.norm()*0.1
arrow_a.axis = particle.a.norm()*0.1
# 更新時間
t += dt
```
<br />
### 參數設定
在此設定變數為size、m、q、masses、charges、colors、particles、v0、L、B_field、t、dt,用途已寫在該行的註解當中。為了使動畫較為順暢,刻意將粒子的電量、質量調大很多。
<br />
### 畫面設定
1. 產生動畫視窗、金屬板。
2. 產生帶電粒子,可以選擇粒子的名稱,程式會從masses、charges、colors讀取粒子的資料。
3. 產生表示磁場的箭頭及標籤。
4. 產生表示速度、加速度的箭頭。
<br />
### 物體運動
1. while 迴圈當中的條件設定為 **(abs(particle.pos.x) < 0.1*size and particle.pos.y < L/2) or (abs(particle.pos.x) > 0 and particle.pos.y > p1.height/2 + size)**
(a) 第1個條件:當粒子沒有偏轉(-0.1*size < x < 0.1*size)而且還沒有到達畫面最上方時(particle.pos.y < L/2),動畫繼續執行。
(b) 第2個條件:當粒子向左或向右偏轉(abs(particle.pos.x) > 0)而且還沒有撞到金屬板時(particle.pos.y > p1.height/2 + size),動畫繼續執行。
2. 計算帶電粒子所受合力,更新帶電粒子加速度、速度、位置。
3. 更新表示速度、加速度的箭頭,只畫出方向以避免動畫自動縮小。
4. 更新時間。
<br />
### 模擬結果
以下是3種不同粒子的執行結果。程式 23-1 是測試用的,一次輸入一個粒子的資料並觀察執行的結果,接下來要用 for 迴圈一口氣將 5 個粒子的軌跡畫出來。
<img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://i.imgur.com/9DBNutT.png">
<div style="text-align:center">程式 23-1:<sup>12</sup>C 畫面截圖</div>
<br />
<img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://i.imgur.com/YmrsGYH.png">
<div style="text-align:center">程式 23-1:<sup>16</sup>O<sup>2-</sup> 畫面截圖</div>
<br />
<img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://i.imgur.com/IMl6PH1.png">
<div style="text-align:center">程式 23-1:<sup>23</sup>Na<sup>+</sup> 畫面截圖</div>
<br />
## 程式 23-2.質譜儀, 用 for 迴圈自動跑完 5 種粒子 ([取得程式碼](https://github.com/YiZheWangTw/VPythonTutorial/blob/master/23.%E8%B3%AA%E8%AD%9C%E5%84%80/23-2.mass_spectrometer_for.py)) ([GlowScript 網站動畫連結](http://www.glowscript.org/#/user/yizhe/folder/Public/program/23-2.massspectrometerfor))
```python=
"""
VPython教學: 23-2.質譜儀, 用 for 迴圈自動跑完 5 種粒子
Ver. 1: 2018/4/8
Ver. 2: 2019/9/19
作者: 王一哲
"""
from vpython import *
"""
1. 參數設定, 設定變數及初始值
"""
size, m, q = 0.01, 1E-10, 2E-8 # 粒子半徑, 質量, 電量
v0 = vec(0, 10, 0) # 粒子初速度
# 用 dictionary 儲存的粒子資料, 用 list 儲存的粒子名稱
masses = {"C": 12*m, "O": 16*m, "Na": 23*m, "Mg": 24*m, "Cl": 35*m}
charges = {"C": 0, "O": -2*q, "Na": q, "Mg": 2*q, "Cl": -q}
colors = {"C": color.red, "O": color.yellow, "Na": color.orange, "Mg": color.white, "Cl": color.green}
labels = {"C": "C", "O": "<sup>16</sup>O<sup>2-</sup>", "Na": "<sup>23</sup>Na<sup>+</sup>",
"Mg": "<sup>24</sup>Mg<sup>2+</sup>", "Cl": "<sup>35</sup>Cl<sup>-</sup>"}
particles = ["C", "O", "Na", "Mg", "Cl"]
L = 0.4 # 金屬板長度
B_field = vec(0, 0, -10) # 磁場
t, dt = 0, 1E-5 # 時間, 時間間隔
"""
2. 畫面設定
"""
# 產生動畫視窗、金屬板
scene = canvas(title="Mass Spectrometer", width=800, height=600, x=0, y=0,
center=vec(0, 0, 0), background=color.black)
p1 = box(pos=vec(-0.55*L, 0, 0), size=vec(L, 0.01*L, 0.1*L), color=color.blue)
p2 = box(pos=vec(0.55*L, 0, 0), size=vec(L, 0.01*L, 0.1*L), color=color.blue)
# 產生表示磁場的箭頭及標籤
arrow_B = arrow(pos=vec(-0.5*L, 0.5*L, 0), axis=vec(0, 0, -0.1), shaftwidth=size, color=color.green)
label_B = label(pos=vec(-0.5*L, 0.5*L, 0), text="B", xoffset=25, yoffset=25, color=color.green, font="sans")
"""
3. 用 for 迴圈自動跑完 5 種粒子
"""
for name in particles:
# 產生帶電粒子
particle = sphere(pos=vec(0, -L/3, 0), v=v0, radius=size, m=masses[name], q=charges[name],
color=colors[name], make_trail=True, retain=1000)
# 物體運動部分
while((abs(particle.pos.x) < 0.1*size and particle.pos.y < L/2) or \
(abs(particle.pos.x) > 0 and particle.pos.y > p1.height/2 + size)):
rate(1000)
# 計算帶電粒子所受合力, 更新帶電粒子加速度、速度、位置
if(particle.pos.y > p1.height/2 + size): F = particle.q*cross(particle.v, B_field)
else: F = vec(0, 0, 0)
particle.a = F/particle.m
particle.v += particle.a*dt
particle.pos += particle.v*dt
# 更新時間
t += dt
# 粒子標籤
particle_label = label(pos=particle.pos, text=labels[name], xoffset=25, yoffset=25,
color=colors[name], font = "sans")
```
<br />
### 程式設計部分
程式 23-2 和 23-1 很像,以下只說明修改之處。
1. 加上粒子標籤資料 labels,由於 VPython 的標籤支援 html 語法,可以做出上標、下標的效果。<sup> </sup> 之間的文字為上標, <sub> </sub> 之間的文字為下標。
2. 用 for 迴圈讀取粒子的名稱,並將產生粒子及粒子運動部分的 while 迴圈放到 for 迴圈當中,當 while 迴圈執行完畢時加上粒子的標籤。
<br />
### 模擬結果
以下是程式 23-2 的執行結果,可以看到粒子的迴轉半徑與 m/q 成正比。
<img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://i.imgur.com/EEFDrf9.png">
<div style="text-align:center">程式 23-2 畫面截圖</div>
<br />
## 結語
以前遇到這類的題目時,總是根據計算得到的結果畫示意圖,用 VPython 計算粒子在每個時刻的受力,再將整個運動過程畫出來,感覺上比較真實。也可以試著改變粒子的質量和電量,看看會有什麼變化。
<br />
## VPython官方說明書
1. **canvas**: http://www.glowscript.org/docs/VPythonDocs/canvas.html
2. **box**: http://www.glowscript.org/docs/VPythonDocs/box.html
3. **sphere**: http://www.glowscript.org/docs/VPythonDocs/sphere.html
4. **arrow**: http://www.glowscript.org/docs/VPythonDocs/arrow.html
5. **label**: http://www.glowscript.org/docs/VPythonDocs/label.html
---
###### tags:`VPython`