日期:2018/3/19
這次讓物體加上重力的作用,目標是畫出小球從某個高度往下加速落到地板上,並畫出小球的 y-t 圖、 v-t 圖,分為3個不同的狀況:
1. 小球觸地時停止 (GlowScript 網站動畫連結)
2. 小球觸地時反彈 (GlowScript 網站動畫連結)
3. 小球觸地時反彈, 恢復係數為e (GlowScript 網站動畫連結)
成果如下:
自由落下畫面截圖
小球觸地時停止: y-t 圖及 v-t 圖
小球觸地時反彈: y-t 圖及 v-t 圖
小球觸地時反彈,e = 0.9: y-t 圖及 v-t 圖
小球觸地時反彈,e = 0.8: y-t 圖及 v-t 圖
程式 4-1:自由落下
取得程式碼
"""
VPython教學: 4-1.自由落下
Ver. 1: 2018/2/18
Ver. 2: 2019/9/6
作者: 王一哲
"""
from vpython import *
"""
1. 參數設定, 設定變數及初始值
"""
size = 1 # 小球半徑
h = 15 # 小球離地高度
g = 9.8 # 重力加速度 9.8 m/s^2
t = 0 # 時間
dt = 0.001 # 時間間隔
"""
2. 畫面設定
"""
scene = canvas(title="Free Fall", width=600, height=600, x=0, y=0, center=vec(0, h/2, 0), background=vec(0, 0.6, 0.6))
floor = box(pos=vec(0, 0, 0), size=vec(40, 0.01, 10), color=color.blue)
ball = sphere(pos=vec(0, h, 0), radius=size, color=color.red, v=vec(0, 0, 0), a=vec(0, -g, 0))
gd = graph(title="plot", width=600, height=450, x=0, y=600, xtitle="t(s)", ytitle="blue: y(m), red: v(m/s)")
yt = gcurve(graph=gd, color=color.blue)
vt = gcurve(graph=gd, color=color.red)
"""
3. 物體運動部分, 小球觸地時停止
"""
while(ball.pos.y - floor.pos.y > size + 0.5*floor.height):
rate(1000)
ball.v += ball.a*dt
ball.pos += ball.v*dt
yt.plot(pos=(t, ball.pos.y))
vt.plot(pos=(t, ball.v.y))
t += dt
print("t = ", t)
參數設定
在此定義的變數有 size、h、g、t、dt,用途都已經寫在該行的註解中。
畫面設定
sphere
與前一個例子相比,這次新增的函式為 sphere,功能是用來畫出球體。sphere 是英文的球、球體,在 VPython 中用來產生球體,在這個程式中用來產生小球 ball。[3] 在產生物件時通常會調整的選項為:
- pos: 球心位置,數值為向量,vector(x, y, z),vector 也可以簡化為 vec。
- radius: 半徑,數值為純量。
- color: 顏色。
也可以在產生物件後,用
[物件名稱].[選項] =
來調整物件的屬性,例如質量 m、位置 pos、速度 v、加速度 a、動量 p……等等。因此以下兩行程式碼的功能,是將名稱為 ball 的 sphere 物件速度設為 (0, 0, 0)、加速度設為 (0, -g, 0)。
ball.v = vec(0, 0, 0)
ball.a = vec(0, -g, 0)
graph
graph是英文的圖,在 VPython 中用來產生繪圖視窗。[4],在這個程式中我將繪圖視窗命名為 gd,並將小球的 y-t 圖和 v-t 圖畫在同一個視窗當中。
物體運動
利用一個 while 迴圈每隔一小段時間 dt 更新一次物體的狀態,由於我希望當小球接觸到地板時程式停止運作,因此在 while 裡設定的條件為
ball.pos.y - floor.pos.y > size + 0.5*floor.height
當條件成立時繼續執行。接下來逐行說明程式碼的用途。
- rate(1000) 是指每秒更新動畫1000次。
- ball.v += ball.a*dt 用來更新小球的速度,用 ball.v 讀取小球的速度,將讀取到的值加上加速度乘以一小段時間,再重新指定給小球的速度。由於所取的時間長度 dt 很短,可以當成是一小段等加速度運動,因此本式就是 $$v = v_0 + at$$
- ball.pos += ball.v*dt 用來更新小球的位置,用 ball.pos 讀取小球的位置,將讀取到的值加上速度乘以一小段時間,再重新指定給小球的位置。由於所取的時間長度 dt 很短,可以當成是一小段等速度運動,因此本式就是 $$s = v \times dt $$
- yt.plot(pos = (t, ball.pos.y)) 用來畫小球的 y-t 圖。
- vt.plot(pos = (t, ball.v.y)) 用來畫小球的 v-t 圖。
- t += dt 用來更新時間。
- print("t = ", t) 印出整個運動經過的時間。
程式 4-2:自由落下,小球觸地時反彈
取得程式碼
"""
VPython教學: 4-2.自由落下, 小球觸地時反彈
Ver. 1: 2018/2/18
Ver. 2: 2019/9/6
作者: 王一哲
"""
from vpython import *
"""
1. 參數設定, 設定變數及初始值
"""
size = 1 # 小球半徑
h = 15 # 小球離地高度
g = 9.8 # 重力加速度 9.8 m/s^2
t = 0 # 時間
dt = 0.001 # 時間間隔
"""
2. 畫面設定
"""
scene = canvas(title="Free Fall", width=600, height=600, x=0, y=0, center=vec(0, h/2, 0), background=vec(0, 0.6, 0.6))
floor = box(pos=vec(0, 0, 0), size=vec(40, 0.01, 10), color=color.blue)
ball = sphere(pos=vec(0, h, 0), radius=size, color=color.red, v=vec(0, 0, 0), a=vec(0, -g, 0))
gd = graph(title="plot", width=600, height=450, x=0, y=600, xtitle="t(s)", ytitle="blue: y(m), red: v(m/s)")
yt = gcurve(graph=gd, color=color.blue)
vt = gcurve(graph=gd, color=color.red)
"""
3. 物體運動部分, 小球觸地時反彈
"""
while(t < 20):
rate(1000)
ball.v += ball.a*dt
ball.pos += ball.v*dt
yt.plot(pos=(t, ball.pos.y))
vt.plot(pos=(t, ball.v.y))
if(ball.pos.y - floor.pos.y <= size + 0.5*floor.height and ball.v.y < 0):
ball.v.y = -ball.v.y
t += dt
print("t = ", t)
程式 4-2 與 4-1 幾乎一模一樣,只是為了使小球在接觸地板時反彈,在物體運動部分增加了
if(ball.pos.y - floor.pos.y <= size + 0.5*floor.height and ball.v.y < 0):
ball.v.y = -ball.v.y
若 ball.pos.y - floor.pos.y <= size + 0.5*floor.height 代表小球碰到地板,若 ball.v.y < 0 代表小球速度向下,當兩個條件同時成立時,代表小球正在向下運動並撞到地板,小球反彈後速度由負變為正,因此將 ball.v.y 的乘上負號後再指定回 ball.v.y。
程式 4-3:自由落下,小球觸地時反彈,恢復係數為e
取得程式碼
"""
VPython教學: 4-3.自由落下, 小球觸地時反彈, 恢復係數為e
Ver. 1: 2018/2/19
Ver. 2: 2019/9/6
作者: 王一哲
"""
from vpython import *
"""
1. 參數設定, 設定變數及初始值
"""
size = 1 # 小球半徑
e = 0.9 # 恢復係數
i = 0 # 小球撞地板次數
N = 20 # 小球撞地板次數上限, 到達上限後停止運作
h = 15 # 小球離地高度
g = 9.8 # 重力加速度 9.8 m/s^2
t = 0 # 時間
dt = 0.001 # 時間間隔
"""
2. 畫面設定
"""
scene = canvas(title="Free Fall", width=600, height=600, x=0, y=0, center=vec(0, h/2, 0), background=vec(0, 0.6, 0.6))
floor = box(pos=vec(0, 0, 0), size=vec(40, 0.01, 10), color=color.blue)
ball = sphere(pos=vec(0, h, 0), radius=size, color=color.red, v=vec(0, 0, 0), a=vec(0, -g, 0))
gd = graph(title="plot", width=600, height=450, x=0, y=600, xtitle="t(s)", ytitle="blue: y(m), red: v(m/s)")
yt = gcurve(graph=gd, color=color.blue)
vt = gcurve(graph=gd, color=color.red)
"""
3. 物體運動部分, 小球觸地時反彈
"""
while(i < N):
rate(1000)
ball.v += ball.a*dt
ball.pos += ball.v*dt
yt.plot(pos=(t, ball.pos.y))
vt.plot(pos=(t, ball.v.y))
if(ball.pos.y - floor.pos.y <= size + 0.5*floor.height and ball.v.y < 0):
ball.v.y = -ball.v.y*e
i += 1
t += dt
print("i = ", i)
print("t = ", t)
程式 4-3 與 4-2 幾乎一模一樣,以下只說明不同之處。
- 由於小球與地板間不是彈性碰撞,因此定義恢復係數 ,其中為撞前速度量值、為撞後速度量值。發生碰撞時執行的程式碼改為
- 為了計算小球、地板撞擊次數,並在撞擊20次時停止程式,新增變數 i = 0 (小球撞地板次數,預設值為0)、N = 20(小球撞地板次數上限, 到達上限後停止運作),while 迴圈的條件改為 i < N,每次發生碰撞時將 i 的數值 +1。
- 為了使小球撞擊地板時的條件更精準需要考慮地板的厚度,因此 if 的條件改為下式,式中 floor.height 是用來讀取物件 floor 的高度值。
ball.pos.y - floor.pos.y <= size + 0.5*floor.height and ball.v.y < 0
ball.v.y = -ball.v.y*e
結語
其實程式 4-1、4-2 是為了寫出 4-3 的前置作業,先寫出最簡單程式再慢慢把條件加上去,不需要一口氣就寫出很複雜的程式,那樣難度太高了。在程式 4-3 中,可以試著將 e 改成不同的值,觀察反彈高度及運動時間的變化。也可以拿一顆球實際測試看看,如果想要增加實驗的精準度,可以將小球的運動過程錄影,再用影像分析軟體 Tracker 找出小球的 y-t、v-t 圖,同時也把測得的 e 值代入程式 4-3 中,看看理論與實驗值有何差異。VPython官方說明書
- canvas: http://www.glowscript.org/docs/VPythonDocs/canvas.html
- box: http://www.glowscript.org/docs/VPythonDocs/box.html
- sphere: http://www.glowscript.org/docs/VPythonDocs/sphere.html
- graph: http://www.glowscript.org/docs/VPythonDocs/graph.html
HackMD 版本連結:https://hackmd.io/@yizhewang/S1e8LxzGQ
沒有留言:
張貼留言