2018年3月19日 星期一

自由落下

作者:王一哲
日期: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

當條件成立時繼續執行。接下來逐行說明程式碼的用途。

  1. rate(1000) 是指每秒更新動畫1000次。
  2. ball.v += ball.a*dt 用來更新小球的速度,用 ball.v 讀取小球的速度,將讀取到的值加上加速度乘以一小段時間,再重新指定給小球的速度。由於所取的時間長度 dt 很短,可以當成是一小段等加速度運動,因此本式就是 $$v = v_0 + at$$
  3. ball.pos += ball.v*dt 用來更新小球的位置,用 ball.pos 讀取小球的位置,將讀取到的值加上速度乘以一小段時間,再重新指定給小球的位置。由於所取的時間長度 dt 很短,可以當成是一小段等速度運動,因此本式就是 $$s = v \times dt $$
  4. yt.plot(pos = (t, ball.pos.y)) 用來畫小球的 y-t 圖。
  5. vt.plot(pos = (t, ball.v.y)) 用來畫小球的 v-t 圖。
  6. t += dt 用來更新時間。
  7. 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 幾乎一模一樣,以下只說明不同之處。

  1. 由於小球與地板間不是彈性碰撞,因此定義恢復係數 ,其中為撞前速度量值、為撞後速度量值。發生碰撞時執行的程式碼改為
  2. ball.v.y = -ball.v.y*e
  3. 為了計算小球、地板撞擊次數,並在撞擊20次時停止程式,新增變數 i = 0 (小球撞地板次數,預設值為0)、N = 20(小球撞地板次數上限, 到達上限後停止運作),while 迴圈的條件改為 i < N,每次發生碰撞時將 i 的數值 +1。




  4. 為了使小球撞擊地板時的條件更精準需要考慮地板的厚度,因此 if 的條件改為下式,式中 floor.height 是用來讀取物件 floor 的高度值。
    ball.pos.y - floor.pos.y <= size + 0.5*floor.height and ball.v.y < 0

結語

其實程式 4-1、4-2 是為了寫出 4-3 的前置作業,先寫出最簡單程式再慢慢把條件加上去,不需要一口氣就寫出很複雜的程式,那樣難度太高了。在程式 4-3 中,可以試著將 e 改成不同的值,觀察反彈高度及運動時間的變化。也可以拿一顆球實際測試看看,如果想要增加實驗的精準度,可以將小球的運動過程錄影,再用影像分析軟體 Tracker 找出小球的 y-t、v-t 圖,同時也把測得的 e 值代入程式 4-3 中,看看理論與實驗值有何差異。

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. graph: http://www.glowscript.org/docs/VPythonDocs/graph.html

HackMD 版本連結:https://hackmd.io/@yizhewang/S1e8LxzGQ

沒有留言:

張貼留言