# 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=...) #畫球 ``` :::