# 斜向抛射 > 作者:王一哲 > 日期:2018/3/29 <br /> 將一個小球由地面以初速 v<sub>0</sub>、仰角 𝜃 抛出,小球受到重力作用向下加速,計算小球的飛行時間及水平射程。分為以下3種不同的狀況: 1. 只考慮重力的作用,小球撞到地板時停止運動。 ([GlowScript 網站動畫連結](http://www.glowscript.org/#/user/yizhe/folder/Public/program/6-1projection)) 2. 同時考慮重力及空氣阻力 \\( f = -bv \\),同時畫出考慮空氣阻力與不考慮空氣阻力的小球。 ([GlowScript 網站動畫連結](http://www.glowscript.org/#/user/yizhe/folder/Public/program/6-2projectiona)) 3. 使用 for 迴圈,分別計算不同仰角 𝜃、不同的空氣阻力係數 b 對應的飛行時間和水平射程。 ([GlowScript 網站動畫連結](http://www.glowscript.org/#/user/yizhe/folder/Public/program/6-3projectionloop)) 成果如下: <img style="display: block; margin-left: auto; margin-right: auto" height="100%" width="100%" src="https://i.imgur.com/Xcz900w.png"> <div style="text-align:center">只考慮重力的作用,小球撞到地板時停止運動</div> <br /> <img style="display: block; margin-left: auto; margin-right: auto" height="100%" width="100%" src="https://i.imgur.com/8QiHVSk.png"> <div style="text-align:center">同時考慮重力及空氣阻力,b = 0.1</div> <br /> <img style="display: block; margin-left: auto; margin-right: auto" height="100%" width="100%" src="https://i.imgur.com/kudsA9l.png"> <div style="text-align:center">使用 for 迴圈改變仰角 𝜃 = 15º ~ 90º</div> <br /> <img style="display: block; margin-left: auto; margin-right: auto" height="100%" width="100%" src="https://i.imgur.com/Jt67aCO.png"> <div style="text-align:center">使用 for 迴圈改變空氣阻力係數 b = 0 ~ 0.9</div> <br /> ## 程式 6-1:斜向抛射, 球落地停止運作 ([取得程式碼](https://github.com/YiZheWangTw/VPythonTutorial/blob/master/06.%E6%96%9C%E5%90%91%E6%8A%9B%E5%B0%84/6-1_projection.py)) ```python= """ VPython教學: 6-1.斜向抛射, 球落地停止運作 Ver. 1: 2018/2/21 Ver. 2: 2019/9/7 作者: 王一哲 """ from vpython import * """ 1. 參數設定, 設定變數及初始值 """ size = 1 # 小球半徑 v0 = 30 # 小球初速 theta = radians(30) # 小球抛射仰角, 用 radians 將單位轉為弧度 L = 100 # 地板長度 g = 9.8 # 重力加速度 9.8 m/s^2 t = 0 # 時間 dt = 0.001 # 時間間隔 """ 2. 畫面設定 """ scene = canvas(title="Projection", width=800, height=400, x=0, y=0, center=vec(0, 5, 0), background=vec(0, 0.6, 0.6)) floor = box(pos=vec(0, -size, 0), size=vec(L, 0.01, 10), texture=textures.metal) ball = sphere(pos=vec(-L/2, 0, 0), radius=size, color=color.red, make_trail=True, v=vec(v0*cos(theta), v0*sin(theta), 0), a=vec(0, -g, 0)) """ 3. 物體運動部分 """ while ball.pos.y - floor.pos.y >= size: rate(1000) ball.v += ball.a*dt ball.pos += ball.v*dt t += dt print(t, ball.pos.x + L/2) ``` <br /> ### 參數設定 在此定義的變數有 size、v0、theta、L、g、t、dt,用途都已經寫在該行的註解中。這裡出現了一個新的函式 ```python radians(x) ``` 這個函式可以將 x 的單位由角度轉換為弧度(rad),radians 包含於 math 函式庫中,使用前需要引入函式庫,但是 vpython 已經包含了 math,不需要額外再引入 math。需要這樣做是因為 python 的三角函數輸入值皆以 rad 為單位。另一個類似的函式為 ```python degrees(x) ``` 這個函式可以將 x 的單位由 rad 轉換為角度。 <br /> ### 畫面設定 畫面設定部分與程式 5-1 非常類以,不同之處在於小球的初位置及初速 ```python ball = sphere(pos=vec(-L/2, 0, 0), radius=size, color=color.red, make_trail=True, v=vec(v0*cos(theta), v0*sin(theta), 0), a=vec(0, -g, 0)) ``` 小球出發時高度為0,初速度 \\( v_x = v_0 \cos \theta \\)、\\( v_y = v_0 \sin \theta \\)。 <br /> ### 物體運動 物體運動部分與程式 5-1 非常類以,不同之處在於小球碰到地板時停止動畫,因此 while 迴圈中設定的條件為 ```python ball.pos.y - floor.pos.y >= size ``` 在 while 迴圈結束之後,印出飛行時間 t 及水平射程 R。可以手動修改 v0 或 theta 的數值,觀察 t 和 R 的變化。 <br /> ## 程式 6-2.斜向抛射, 球落地停止運作, 有空氣阻力 ([取得程式碼](https://github.com/YiZheWangTw/VPythonTutorial/blob/master/06.%E6%96%9C%E5%90%91%E6%8A%9B%E5%B0%84/6-2_projection_a.py)) ```python= """ VPython教學: 6-2.斜向抛射, 球落地停止運作, 有空氣阻力 Ver. 1: 2018/2/21 Ver. 2: 2019/11/13 改變儲存球落地時間的方法 作者: 王一哲 """ from vpython import * """ 1. 參數設定, 設定變數及初始值 """ size = 1 # 小球半徑 m = 1 # 小球質量 v0 = 30 # 小球初速 theta = radians(30) # 小球抛射仰角, 用 radians 將單位轉為弧度 L = 100 # 地板長度 b = 0.1 # 空氣阻力 f=-bv g = 9.8 # 重力加速度 9.8 m/s^2 t = 0 # 時間 dt = 0.001 # 時間間隔 t1, t2 = 0, 0 # 小球落地時間 s1, s2 = False, False # 小球是否落地 """ 2. 畫面設定 """ scene = canvas(title="Projection with Air Resistance", width=800, height=400, x=0, y=0, center=vec(0, 5, 0), background=vec(0, 0.6, 0.6)) floor = box(pos=vec(0, -size, 0), size=vec(L, 0.01, 10), texture=textures.metal) # ball: 有空氣阻力; ball2: 沒有空氣阻力 ball = sphere(pos=vec(-L/2, 0, 0), radius=size, color=color.blue, make_trail=True, v=vec(v0*cos(theta), v0*sin(theta), 0)) ball2 = sphere(pos=vec(-L/2, 0, 0), radius=size, color=color.red, make_trail=True, v=vec(v0*cos(theta), v0*sin(theta), 0), a=vec(0, -g, 0)) """ 3. 物體運動部分, 小球觸地停止運動, 記錄落地時間, 畫出兩者軌跡 印出落地時間及水平射程 """ while ball.pos.y - floor.pos.y >= size or ball2.pos.y - floor.pos.y >= size: rate(1000) # ball 還沒有落地才更新加速度、速度、位置 if s1 == False: f = -b*ball.v ball.a = vec(0, -g, 0) + f/m ball.v += ball.a*dt ball.pos += ball.v*dt # ball2 還沒有落地才更新加速度、速度、位置 if s2 == False: ball2.v += ball2.a*dt ball2.pos += ball2.v*dt # ball 第一次碰到地板時將狀態改成 True 並記錄時間 if ball.pos.y - floor.pos.y <= size and s1 == False: ball.v = vec(0, 0, 0) s1, t1 = True, t # ball2 第一次碰到地板時將狀態改成 True 並記錄時間 if ball2.pos.y - floor.pos.y <= size and s2 == False: ball2.v = vec(0, 0, 0) s2, t2 = True, t # 更新時間 t += dt print("t1, r1, t2, r2") print("{:f}, {:f}, {:f}, {:f}".format(t1, ball.pos.x + L/2, t2, ball2.pos.x + L/2)) ``` <br /> ### 參數設定 程式 6-2 與 6-1 很像,但是增加了小球質量 m 及空氣阻力係數 b。為了記錄小球飛行時間,新增了 s1、s2、t1、t2 等4個變數。如果對於加上空氣阻力的寫法已經很熟悉,其實可以跳過 6-1 直接寫 6-2。 <br /> ### 畫面設定 為了與不考慮空氣阻力的理想狀況對照,需要畫出兩個球,ball 是考慮空氣阻力的狀況、ball2 是理想狀況。由於 ball 的加速度與速度有關,放在 while 迴圈裡再設定即可。 <br /> ### 物體運動 1. 為了讓兩個小球都碰到地板後才停止動畫,因此 while 迴圈中設定的條件為 ```python ball.pos.y - floor.pos.y >= size or ball2.pos.y - floor.pos.y >= size ``` 2. 由於 ball 需要考慮空氣阻力,需要加上 ```python f = -b*ball.v ball.a = vector(0, -g, 0) + f/m ``` 用原來的速度計算空氣阻力,再代入 \\( F = ma \\) 更新加速度。 3. 為了記錄飛行時間,先將狀態 s1、s2 設定成 False,當小球第一次碰到地板時將狀態改為 True 並將時間 t 儲存到 t1 及 t2。 <br /> ## 程式 6-3.斜向抛射, 使用for 迴圈改變仰角 theta, 空氣阻力係數 b ([取得程式碼](https://github.com/YiZheWangTw/VPythonTutorial/blob/master/06.%E6%96%9C%E5%90%91%E6%8A%9B%E5%B0%84/6-3_projection_loop.py)) ```python= """ VPython教學: 6-3.斜向抛射, 使用 for 迴圈改變仰角 theta, 空氣阻力係數 b Ver. 3: 2019/10/11 改用 with 及 def 簡化程式 作者: 王一哲 """ from vpython import * """ 1. 參數設定, 設定變數及初始值 """ size = 1 # 小球半徑 m = 1 # 小球質量 L = 100 # 地板長度 g = 9.8 # 重力加速度 9.8 m/s^2 dt = 0.001 # 時間間隔 """ 2. 畫面設定 """ scene = canvas(title="Projection with for loop", width=800, height=400, x=0, y=0, center=vec(0, 5, 0), background=vec(0, 0.6, 0.6)) floor = box(pos=vec(0, -size, 0), size=vec(L, 0.01, 10), texture=textures.metal) # 開啟檔案 data.csv, 屬性為寫入, 先寫入欄位的標題 with open("data.csv", "w", encoding="UTF-8") as file: file.write("theta(degree), b, t(s), R(m)\n") """ 3. 物體運動部分 """ def main(i=0, n=16, v0=30, degree=30, b=0.0): t = 0 theta = radians(degree) ball = sphere(pos=vec(-L/2, 0, 0), radius=size, color=vec((n-i)/n, 0, i/n), make_trail=True, v=vec(v0*cos(theta), v0*sin(theta), 0)) while ball.pos.y - floor.pos.y >= size: rate(1000) f = -b*ball.v ball.a = vec(0, -g, 0) + f/m ball.v += ball.a*dt ball.pos += ball.v*dt t += dt return degree, b, t, ball.pos.x + L/2 for i in range(0, 10): # 改變 theta 時設為16, 改變 b 時設為10 #degree = 15 + 5*i # 改變 theta #degree, b, t, r = main(i=i, degree=degree) b = 0.1*i # 改變 b degree, b, t, r = main(i=i, n=10, b=b) print("{:f}, {:f}, {:f}, {:f}".format(degree, b, t, r)) with open("data.csv", "a", encoding="UTF-8") as file: file.write(str(degree) + "," + str(b) + "," + str(t) + "," + str(r) + "\n") ``` <br /> ### 程式設計部分 程式 6-3 是將 5-5、6-1、6-2 合為一體的產物,有兩個使用方法: 1. 主程式 main 中需要輸入的參數有 i、n、v0、degree、b,如果引用 main 時不輸入數值則採用等號後的預設值。 ```pthon main(i=0, n=16, v0=30, degree=30, b=0.0) ``` 2. 改變仰角 theta,範圍為 15º ~ 90º,每次增加 5º,總共執行 16 次。為了記錄代入的角度數值,需要增加變數 degree,將 i 及 degree 代入主程式 main 並回傳計算結果。 ```python degree = 15 + 5 * i degree, b, t, r = main(i=i, degree=degree) ``` 3. 改變空氣阻力係數 b,範圍為 0 ~ 0.9,每次增加 0.1,總共執行 10 次,將 i、n 及 degree 代入主程式 main 並回傳計算結果。 ```python b = 0.1 * i degree, b, t, r = main(i=i, n=10, b=b) ``` 4. 為了方便使用者從圖中看出執行的順序,我將小球的顏色加上一點變化 ```python color = vec((n-i)/n, 0, i/n) ``` 一開始小球是紅色的,隨著執行次數增加會慢慢變為藍色。 <br /> ### 數據處理部分 若以 v0 = 30 m/s、b = 0、改變 theta 產生的數據如下 ```csv v0(m/s), theta(degree), b, t(s), R(m) 30,15,0.0,1.5839999999999363,45.900795265255965 30,20,0.0,3.677999999999706,59.03149043776981 30,25,0.0,6.265000000000427,70.3385473519133 30,30,0.0,9.32600000000027,79.5271128295263 30,35,0.0,12.836999999998325,86.28128482496055 30,40,0.0,16.771999999997515,90.43154651019775 30,45,0.0,21.101000000002806,91.83195767269348 30,50,0.0,25.791000000008538,90.44021668289648 30,55,0.0,30.806000000014667,86.29457484901386 30,60,0.0,36.10800000000655,79.53000000000226 30,65,0.0,41.65599999999362,70.34058348411925 30,70,0.0,47.40899999998021,59.02925653658275 30,75,0.0,53.32199999996643,45.9119104107409 30,80,0.0,59.35099999995238,31.407745894621137 30,85,0.0,65.44999999994846,15.946886250519292 30,90,0.0,71.57199999997769,0.0 ``` <br /> 將數據匯入 SciDAVis 作圖得到的成果如下 <img style="display: block; margin-left: auto; margin-right: auto" height="100%" width="100%" src="https://i.imgur.com/vr2mkSL.jpg"> <div style="text-align:center">t - 𝛳 關係圖</div> <br /> <img style="display: block; margin-left: auto; margin-right: auto" height="100%" width="100%" src="https://i.imgur.com/dQwYDnj.jpg"> <div style="text-align:center">R - 𝛳 關係圖</div> <br /> 若以 v0 = 30 m/s、theta = 30、改變 b 產生的數據如下 ```csv theta(degree), b, t(s), R(m) 30,0.0,3.060999999999774,79.5271128295263 30,0.1,2.9189999999997895,65.7683163073318 30,0.2,2.7999999999998026,55.694591159308345 30,0.30000000000000004,2.6989999999998138,48.05540251489901 30,0.4,2.6129999999998232,42.10134734984786 30,0.5,2.5369999999998316,37.33313950127536 30,0.6000000000000001,2.469999999999839,33.44825688170242 30,0.7000000000000001,2.4109999999998455,30.2339703048744 30,0.8,2.3579999999998513,27.533728914252674 30,0.9,2.3099999999998566,25.238123689064427 ``` <br /> 將數據匯入 SciDAVis 作圖得到的成果如下 <img style="display: block; margin-left: auto; margin-right: auto" height="100%" width="100%" src="https://imgur.com/xxQHhCi.jpg"> <div style="text-align:center">t - b 關係圖</div> <br /> <img style="display: block; margin-left: auto; margin-right: auto" height="100%" width="100%" src="https://imgur.com/iwq4UcB.jpg"> <div style="text-align:center">R - b 關係圖</div> <br /> ## 結語 使用 VPython 可以避開很多不容易用手算的數學,例如在空氣阻力不可忽略的前提下,計算斜向抛射的飛行時間和水平射程。雖然是一次將一小段時間代入程式中運動,難免會有一點誤差,但只要將代入的時間縮短一點,計算結果就不致於偏差太多。 <br /> ## 官方說明書 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. **math.radians**: https://docs.python.org/3/library/math.html --- ###### tags:`VPython`