# Lecture 1 迴圈與物件控制
>建國高中特色選修課程 - 物理現象的程式設計與模擬
>作者:曾靖夫、賴奕帆
>日期:2018/7/1
---
## 一、Vpython的物件插入
Vpython為Python程式的外掛套件之一,Vpython的優點是有很多視覺化套件可以使用簡單的指令插入,它的繪圖功能簡單,呈現的效果具體。很適合將物理中的方程式透過python的運算,然後用圖像的方式顯現出來,能幫助同學更具體理解物理觀念與現象。
### 1. sphere(球形物件):
```python
ball = sphere(pos=vector(1,2,1), radius=0.5, color=color.blue)
```
<img style="display: block; margin-left: auto; margin-right: auto"
src="https://i.imgur.com/chA1SQQ.png">
:::info
* 指令說明
ball:為這個球形物件的「名稱」。
pos:為ball這個物件的座標,Vpython的預設座標如上圖所示。
radius:為ball的半徑長度。
Color:為ball的顏色,以color.blue設為藍色。
:::
### 2. box(盒狀物件):
```python3
mybox = box(pos=vector(x0,y0,z0), length=L, height=H, width=W)
```
<img style="display: block; margin-left: auto; margin-right: auto"
src="https://i.imgur.com/hIjI0BD.png">
:::info
* 指令說明
length:沿著x軸的長度。
height:沿著y軸的長度。
width:沿著z軸的長度。
axis:為mybox的「軸方向」,預設為沿x方向。
:::
### 3. cylinder(柱狀物件):
```python
rod = cylinder(pos=vector(0,2,1), axis=vector(5,0,0), radius=1)
```
<img style="display: block; margin-left: auto; margin-right: auto"
src="https://i.imgur.com/vMjea4p.png">
:::info
* 指令說明
pos:為rod的尾端位置座標。
axis:為rod的軸方向,axis為由尾端指向頭端的向量。如右圖所示,rod的尾端座標相對於頭端座標即是axis,故其尾端座標為$\left ( x_0, y_0,z_0 \right )+\left ( L,0,0 \right )$。
:::
### 4. arrow(箭形物件):
```python
x = arrow(pos=vector(0,0,0), axis=vector(1,0,0), color=color.green)
y = arrow(pos=vector(0,0,0), axis=vector(0,1,0), color=color.red)
z = arrow(pos=vector(0,0,0), axis=vector(0,0,1), color=color.blue)
```
<img style="display: block; margin-left: auto; margin-right: auto"
src="https://i.imgur.com/tOkzp3m.png">
:::info
* 指令說明
這裡我們值些使用箭頭來表示圖像化向量的概念,指令中描述Vpython三維立體座標的x、y、z三個方向的單位向量。
:::
### 5. helix(螺線物件):
```python
spring = helix(pos=vector(0,2,1), axis=vector(5,0,0), radius=0.5)
```
:::info
* 指令說明
這也是一個長條形的物件,在物理中可以畫「彈簧」,基本上長條物件的指令與cylinder和arrow都差不多,僅差在一些圖形比例調整的指令。
:::
---
## 二、Vpython 7 官方網頁
有關 Vpython 7 的所有物件指令,這裡沒有足夠的篇幅一一介紹,請同學養成習慣查詢官方網頁:https://vpython.org/
---
## 三、向量的概念與應用
從前面的物件指令控制,同學們應該已經發現「空間向量」的慨念被廣泛的應用在python的程式運算上。在數學上,凡是有「大小」與「方向」的東西都可以用向量來表示,特別是在幾何學中的應用甚多。而在物理學中,同時需要清楚描述「大小」與「方向」的物理量更是不勝枚舉,比如位置、位移、速度、加速度、作用力、重力場、電場、磁場…等。
以下我們以二維向量為例,簡單介紹向量在物理中的應用:
### 1. 位置向量
用來描述物體在空間中相對於原點的位置,即是由原點指向物體的向量。圖中紅色箭頭為沿著x和y軸的單位向量。所有的向量都可以此為基本單位合成出來。
<img style="display: block; margin-left: auto; margin-right: auto" height="40%" width="40%"
src="https://i.imgur.com/VSuT2BD.png">
### 2. 向量的加法與減法(二維向量範例)
<img style="display: block; margin-left: auto; margin-right: auto" width="85%"
src="https://i.imgur.com/0sSiZZ8.png">
:::info
原則上物理學中的向量概念都是3D立體的空間向量,以上為方便繪製簡圖,因此僅以平面向量為例,但同學請注意在程式中都需要寫立體的向量!
:::
### 3. 位移向量
假設物體由A點運動到B點,則位移可以表示為$\Delta \vec{r}$
$$\Delta \vec{r} = \vec{r}_B - \vec{r}_A = \left ( B_x-A_x,B_y-A_y,B_z-A_z \right )$$
其中 $\vec{r}_B$ 為末位置、$\vec{r}_A$ 為初位置。
### 4. 速度向量
物體每單位時間的位移
$$\vec{v}=\dfrac{\Delta \vec{r}}{\Delta t}=\left ( v_x,v_y,v_z \right )$$
其中 $\Delta t$ 如果足夠小,即為瞬時速度。
### 5. 加速度向量
物體每單位時間的速度變化
$$\vec{a}=\dfrac{\Delta \vec{v}}{\Delta t}=\left ( a_x,a_y,a_z \right )$$
其中 $\Delta t$ 如果足夠小,即為瞬時加速度。
---
## 四、while loop - 以迴圈控制物件的運動
while為一種條件式的迴圈控制,當條件式判斷為True時,就反覆執行while迴圈中的內容,一直到條件式判斷為False則中止迴圈,流程概念可參考右圖,因此我們常用迴圈來控制物件的連續運動。以下用等速度運動為例簡單示範迴圈指令:
<img style="display: block; margin-left: auto; margin-right: auto" height="40%" width="40%"
src="https://i.imgur.com/FFVXWme.png">
<font size=2> <center>圖片來源:https://www.tutorialspoint.com/python/python_while_loop.htm </center></font>
### Example 1 : while loop簡介-等速度運動
```python=
from vpython import* #引用視覺畫套件Vpython
dt = 0.01 #每一次執行迴圈內容的時間間隔
t = 0.0 #第一次執行迴圈的初始時間
x = 0.0 #第一次執行迴圈的初始位置
v = 4.0 #物體的運動速度設為4m/s
while x < 1: #在x<1的判斷成立時,執行迴圈的內容
t = t + dt #計時器,每一次迴圈增加dt的時間間隔
x = x + v*dt #位置,每經過一個迴圈,物體位置改變v*dt的位移
print (t, x) #在執行視窗印出每一刻的時間和位置
```
這裡我們分解步驟來看每一次迴圈發生了什麼事情:
<style>
.markdown-body table{
display: unset;
}
</style>
<center>
| 迴圈計次 | 時間 t 的累加過程 | 位置 x 的累加過程|
|:--------:|:------------------------:|:----------------------------:|
| loop 1 | t = 0 + 0.01 = 0.01 | x = 0 + 4 * 0.01 = 0.04 |
| loop 2 | t = 0.01 + 0.01 = 0.02 | x = 0.04 + 4 * 0.01 = 0.08 |
| loop 3 | t = 0.02 + 0.01 = 0.03 | x = 0.08 + 4 * 0.01 = 0.12 |
| loop 4 | t = 0.03 + 0.01 = 0.04 | x = 0.12 + 4 * 0.01 = 0.16 |
| loop 5 | t = 0.04 + 0.01 = 0.05 | x = 0.16 + 4 * 0.01 = 0.20 |
| ... | ... | ... |
>
</center>
這裡我們發現,每經過一個迴圈時間累加0.01秒,而位置的改變為0.04公尺,這即是標準的等速度運動模擬。雖然這裡只處理純量,但是在向量也是完全一模一樣的概念,現在我們可以試試將前面學到的物件插入,然後用迴圈連續改變位置向量,使其產生動態效果。範例程式如下:
### Example 2 : 圖形化的等速度運動
```python=
from vpython import* #引用視覺畫套件Vpython
size = 0.05 #設定球的大小為0.05公尺
x = arrow(pos=vector(0,0,0), axis=vector(1,0,0), shaftwidth=0.02, color=color.green)
y = arrow(pos=vector(0,0,0), axis=vector(0,1,0), shaftwidth=0.02, color=color.red)
z = arrow(pos=vector(0,0,0), axis=vector(0,0,1), shaftwidth=0.02, color=color.blue)
#畫出3D直角座標沿x,y,z方向的單位向量
ball = sphere(radius=size, color=color.yellow, pos=vector(0,0,0), v=vector(1.0,0,0))
#畫球,球的半徑為size,顏色為黃色,位置在(0,0,0),速度為(1,0,0)
dt = 0.001 #模擬的時間間隔
t = 0.0 #設定模擬的初始時間
while t<2: #條件判斷t<2成立時執行迴圈內容
rate(1/dt) #設定迴圈的執行速度,每秒執行1/dt次
t = t+dt #計時器
ball.pos = ball.pos + ball.v*dt #球的每一時刻位置,每次迴圈改變ball.v *dt的位移
print (t) #在執行視窗印出每一時刻的時間
```
:::info
* 「.」**的用法(物件導向語法):例如ball.pos、ball.v**
在python中「.」的用法可以把它理解為中文「的」的意思,如ball.pos就是ball的pos,即ball的座標位置,又ball.pos.x為ball的位置向量的x方向分量。但如果使用ball.v(球的速度)就得留意,因為sphere的內建指令中並沒有v,所以電腦認不出來v是什麼。因此若要使用這樣的寫法,必須在sphere插入的時候就先定義v,例如:
sphere(radius=size, color=color.yellow, pos=vector(0,0,0), <font color = "red">**v=vector(1.0,0,0)**</font>)。
:::
---
## 五、運動學 - 位置、速度、加速度與時間的關係
在運動學中我們很常用 $x-t$、$v-t$、$a-t$ 圖來描述物體隨著時間的運動狀態,並從中看出規律以及運動的變化和趨勢。在python中我們已經學會用迴圈模擬出每一時刻的時間和位置,現在我們將加入vpython中繪製函數圖形的指令graph來檢視物件的運動。請參考以下範例程式:
### Example 3 : 圖形化的等速度運動與函數圖
```python=
from vpython import*
size = 0.1
scene = canvas(width=600, height=400, center=vector(2.5,0,0), background=vector(0,0,0))
#設定物件視窗的顯示畫面與背景,寬為600畫素、高為400畫素
#center為畫面中心,background為背景顏色
x = arrow(pos=vector(0,0,0), axis=vector(1,0,0), shaftwidth=0.02, color=color.green)
y = arrow(pos=vector(0,0,0), axis=vector(0,1,0), shaftwidth=0.02, color=color.red)
z = arrow(pos=vector(0,0,0), axis=vector(0,0,1), shaftwidth=0.02, color=color.blue)
ball = sphere(radius=size, color=color.yellow, pos=vector(0,0,0), v=vector(1.0,0,0))
gd = graph(title = "x-t plot", width=600, height=400, xtitle="t", ytitle="x")
#設定函數圖的畫面
f1 = gcurve(color=color.blue) #設定函數圖中線條的特性,這裡只設定顏色
dt = 0.001
t = 0.0
while t<5:
rate(1/dt)
t = t+dt
ball.pos = ball.pos + ball.v*dt
f1.plot(pos=(t,ball.pos.x)) #每一個迴圈畫一個點描出線條,x軸為時間,y軸為位置
print (t)
```
## 六、條件判斷結構
接著我們介紹極為常見的條件判斷結構(if-elif-else),指令架構圖如下:
<img style="display: block; margin-left: auto; margin-right: auto" width="60%"
src="https://i.imgur.com/veAYWn8.png">
<font size=2> <center>圖片來源:https://www.codecademy.com/en/forum_questions/51684a3d4ce76309b4001b9c </center></font>
上圖中的 a 和 b 稱為條件式,和前面學過得 while 裡面寫的條件式是一樣的。如上圖,這裡只要 a 是成立的就執行「do this」內容,若 a 不成立則程式往下判斷 b 是否成立,如果 b 成立了就執行「do that」內容。若 a、b 都不成立的話,程式將執行「whatever」內容。最後請記得條件判斷結構和迴圈結構都有「一層一層」的附屬概念,撰寫時請務必記得縮排!
以下我們簡單列出幾個常用的條件式算符:
<style>
.markdown-body table{
display: unset;
}
</style>
<center>
| operator | function |
|:--------:|:------------------------:|
| < | less than |
| <= | less than or equal to |
| > | greater than |
| >= | greater than or equal to |
| == | equal |
| != | not equal |
>
</center>
以下我們試著使用這種結構來挑出物理模擬過程中的特定時機點。例如程式執行中我們想把 t = 2.0 秒的那瞬間抓出來,我們從 Example 3 進行示範。同學想想可以這樣寫嗎?
```python
if t == 2.0:
print(t)
```
還是應該要這樣寫:
```python
if t+dt >= 2.0 and t < 2.0:
print(t)
```
實際執行之後你會發現只有第二種成功了!
<img style="display: block; margin-left: auto; margin-right: auto" width="95%"
src="https://i.imgur.com/1fBR7kA.png">
你會發現++等於++「==」要成立的條件判斷極其嚴苛,必須到小數點以下十幾位都要一樣,判斷才會成立。因此請同學養成習慣,用給定「範圍」的方式來寫條件判斷,才不會因為模擬過程中產生的誤差而錯過判斷點。
在 if 裡面結合兩個條件是的寫法,如 and 和 or ... 等更多用法,請參閱python官網 - 3.1.7. Compound Boolean Expressions:http://anh.cs.luc.edu/handsonPythonTutorial/ifstatements.html#compound-boolean-expressions
### 檢核作業 1
如果你已知一球沿 $x$ 軸作等加速度運動,加速度為 $3\ \rm m/s^2$,初速為 $-2\ \rm m/s$,由座標原點出發。請利用Vpython模擬此運動:
1. 在視窗中畫出球與 $x$、$y$、$z$ 三個座標軸,畫出 $x-t$、$v-t$、$a-t$ 圖,並算出球在3秒瞬間的位置。
2. 在程式中計算此物體的運動何時發生折返,並記錄物體在該折返點的時間、位置與速度。
:::success
* 如何挑出折返點:
1. 什麼是折返點:直線運動的折返點一般發生在速度歸零的那瞬間,因此在這個時間點之前和之後速度的方向是相反的。
2. 條件判斷寫法:在某時刻如果發生以下現象,代表折返點到了
```python
if ball.v.x > 0 and ball.v.x + ball.a.x*dt < 0:
print (時間...)
print (位置...)
print (速度...)
```
這個條件判斷的意思是,在某時刻沿 x 方向的速度是正的,但是加上速度變化(ball.a.x*dt)推算下一時刻的速度會變成負的。速度沿某方向由正轉負的現象,一般只有在折返的時候才會發生。
:::
---
### 指定作業 1-1
一人自靜止開始運動,其 $a-t$ 圖如圖所示,則 6 秒內此人離出發點最遠的距離為何?
1. 使物體沿 $+x$ 方向出發,畫出 $t=0$ 至 $t=6$ 的 $x-t$、$v-t$、$a-t$ 圖。
2. 請在物體達到離出發點最遠距離瞬間,在執行視窗印出時間、球位置、球速度。
<img style="display: block; margin-left: auto; margin-right: auto" height="40%" width="40%"
src="https://i.imgur.com/0kPTneo.png">
執行畫面如下:
<img style="display: block; margin-left: auto; margin-right: auto" width="98%"
src="https://i.imgur.com/bCIDc4E.png">
:::success
* 加速度的設定:用 if-else 在迴圈中將 t=2 秒以前和以後切開,分別設定成不同數值。
```python
if t <= 2:
ball.a = ...
else:
ball.a = ...
```
:::
### 指定作業 1-2
一質點以初速度 $\vec{v} = 3\hat{i}\ \rm m/s$,自原點出發,其加速度為 $\vec{a} = -\hat{i}-0.5\hat{j}\ \rm m/s^2$:
1. 當它達到 $x$ 座標的極大值時,其速度為何?位於何處?此時距出發時間多少秒?
2. 在畫面上每隔0.4秒在畫面上留下球與描述速度與加速度的箭頭,速度請用綠色、加速度請用紅色箭頭。
執行畫面如下圖所示:
<img style="display: block; margin-left: auto; margin-right: auto" height="40%" width="90%"
src="https://i.imgur.com/G6aVJlG.png">
:::success
* 提示:
1. 折返現象:當物體位置在 $x$ 方向產生極大值時,代表物體沿 $x$ 方向正要發生折返現象,請沿用++課堂作業1++挑出「折返點」的方法處理此問題。
2. 餘數除法 %:取出餘數,你可以在執行視窗輸入以下算式練習
```python
x = 10 % 3 # 輸出結果為 1
y = 87 % 10 # 輸出結果為 7
z = 12 % 8.5 # 輸出結果為 3.5
print ('x =',x, 'y =', y, 'z =', z)
```
3. 利用餘數除法切出等時距的時間點:此畫面效果會非常像3D的打點計時器
假設我們要每隔 T 秒畫一組物件,可以在迴圈中做如下設定:
```python
t = t + dt #計時器
plot_t = t%T #用餘數除法設定畫圖計時器,t累加至超過T後歸零
if plot_t + dt >= T and plot_t < T: #用條件判斷設定畫圖時間點
arrow(color=..., pos=..., axis=..., shaftwidth=0.05) #畫速度箭頭
arrow(color=..., pos=..., axis=..., shaftwidth=0.05) #畫加速度箭頭
sphere(color=..., pos=..., radius=...) #畫球
```
:::