SageMath 示範:物理學的平面拋體運動(Projectile Motion)¶
本 notebook 用 SageMath(符號計算 + 數值 + 圖形)說明經典的「平面拋體運動」:
- 建立運動方程(含參數)
- 推導軌跡方程(消去時間)
- 計算飛行時間、射程、最高點
- 用圖形驗證並做參數掃描
假設:無空氣阻力、重力加速度恆定、發射點與落點在同一高度(除非另行設定)。
1. 物理模型與符號設定¶
1.1 參數與變數¶
- $t$:時間(秒)
- $x(t), y(t)$:位置(公尺)
- $v_0$:初速度大小(m/s)
- $\theta$:仰角(弧度)
- $g$:重力加速度(m/s²),地表常用 $g\approx 9.8$
1.2 初始條件(可改)¶
- 初始位置:$(x_0,y_0)$
- 初速度分量: $ v_{x0}=v_0\cos\theta,\quad v_{y0}=v_0\sin\theta $
1.3 運動方程(無阻力)¶
$ x(t)=x_0+v_{x0}t,\quad y(t)=y_0+v_{y0}t-\frac12gt^2 $
下面用 SageMath 建立符號式。
# 符號變數
var('t v0 theta g x0 y0')
# 速度分量
vx0 = v0*cos(theta)
vy0 = v0*sin(theta)
# 位置隨時間
x_t = x0 + vx0*t
y_t = y0 + vy0*t - (g/2)*t^2
x_t, y_t
2. 消去時間得到軌跡方程(拋物線)¶
由 $x(t)=x_0+v_0\cos\theta\,t$ 得 $ t=\frac{x-x_0}{v_0\cos\theta} $ 代入 $y(t)$ 得到 $y$ 與 $x$ 的關係(拋物線)。
用 Sage 直接做代入與化簡。
var('x y')
t_expr = (x - x0)/(v0*cos(theta))
y_of_x = y0 + vy0*t_expr - (g/2)*t_expr^2
y_of_x_simplified = simplify(y_of_x)
y_of_x_simplified
這就是常見的拋體軌跡: $ y = y_0 + (x-x_0)\tan\theta - \frac{g}{2v_0^2\cos^2\theta}(x-x_0)^2 $
你可以用 simplify(...) 驗算與課本公式一致。
3. 飛行時間、最高點、射程(同高度落地)¶
3.1 落地條件(同高度)¶
若 $y_0=0$ 且落地高度也是 0:令 $y(t)=0$ 解 t(非零解即飛行時間)
$ 0 = v_0\sin\theta\,t-\frac12gt^2 \Rightarrow t_f=\frac{2v_0\sin\theta}{g} $
3.2 射程(range)¶
$ R = x(t_f)-x_0 = v_0\cos\theta\cdot t_f = \frac{v_0^2\sin(2\theta)}{g} $
3.3 最高點¶
速度 y 分量: $ v_y(t)=v_0\sin\theta-gt $ 最高點 $v_y=0\Rightarrow t_{top}=v_0\sin\theta/g$
最高高度(相對 y0): $ H = \frac{v_0^2\sin^2\theta}{2g} $
下面用 Sage 解與驗算。
# 先設定常用條件:x0=0, y0=0
x0_val, y0_val = 0, 0
y_t0 = y_t.subs({x0:x0_val, y0:y0_val})
# 解 y(t)=0 的 t
sol_t = solve(y_t0 == 0, t)
sol_t
# 取非零解作為飛行時間 t_f
tf = [s.rhs() for s in sol_t if s.rhs() != 0][0]
tf_simplified = simplify(tf)
tf_simplified
# 射程 R = x(tf) - x0
x_t0 = x_t.subs({x0:x0_val})
R = simplify(x_t0.subs(t=tf_simplified) - x0_val)
R
# 最高點時間與高度
vy_t = diff(y_t0, t)
t_top = solve(vy_t == 0, t)[0].rhs()
H = simplify(y_t0.subs(t=t_top))
vy_t, t_top, H
4. 數值例子:畫出軌跡、標記最高點與落點¶
設定:
- $v_0=20$ m/s
- $\theta=45^\circ$
- $g=9.8$ m/s²
- $x_0=y_0=0$
我們同時用:
- 參數式:$(x(t),y(t))$
- 軌跡式:$y(x)$
並標出:最高點、落點。
# 數值參數
v0_num = 20
theta_num = pi/4
g_num = 9.8
# 代入
x_num = x_t.subs({x0:0, v0:v0_num, theta:theta_num})
y_num = y_t.subs({x0:0, y0:0, v0:v0_num, theta:theta_num, g:g_num})
# 飛行時間、射程、最高點(數值)
tf_num = N(tf_simplified.subs({v0:v0_num, theta:theta_num, g:g_num}))
R_num = N(R.subs({v0:v0_num, theta:theta_num, g:g_num}))
t_top_num = N(t_top.subs({v0:v0_num, theta:theta_num, g:g_num}))
H_num = N(H.subs({v0:v0_num, theta:theta_num, g:g_num}))
tf_num, R_num, t_top_num, H_num
# 參數式 2D 圖:t 從 0 到 tf
traj = parametric_plot((x_num, y_num), (t, 0, tf_num), thickness=2)
# 標記點:起點、最高點、落點
start = point((0, 0), size=40)
top_pt = point((N(x_num.subs(t=t_top_num)), H_num), size=50)
end_pt = point((R_num, 0), size=40)
traj + start + top_pt + end_pt
你也可以畫出 $y(x)$ 的顯式拋物線(在 x ∈ [0,R]):
y_x_num = y_of_x_simplified.subs({x0:0, y0:0, v0:v0_num, theta:theta_num, g:g_num})
plot(y_x_num, (x, 0, R_num), thickness=2)
5. 參數掃描:不同仰角的射程與軌跡疊圖¶
固定 $v_0$ 與 g,改變 $\theta$(例如 20°, 35°, 45°, 55°, 70°)。
你會看到:
- 仰角越大,最高點越高,但射程不一定更遠
- 在同高度落地且無阻力時,射程最大在 45°(課本結論)
下面用 Sage 直接疊圖。
v0_num = 20
g_num = 9.8
angles_deg = [20, 35, 45, 55, 70]
angles = [a*pi/180 for a in angles_deg]
plots = Graphics() # <-- key change
for th in angles:
tf_n = N((2*v0*sin(theta)/g).subs({v0:v0_num, theta:th, g:g_num}))
x_n = x_t.subs({x0:0, v0:v0_num, theta:th})
y_n = y_t.subs({x0:0, y0:0, v0:v0_num, theta:th, g:g_num})
plots += parametric_plot((x_n, y_n), (t, 0, tf_n))
plots
射程 vs 仰角(數值表)¶
rows = []
for a_deg, th in zip(angles_deg, angles):
Rn = N((v0^2*sin(2*theta)/g).subs({v0:v0_num, theta:th, g:g_num}))
rows.append([a_deg, Rn])
table(rows, header_row=["theta (deg)", "Range R (m)"])
| theta (deg) | Range R (m) |
|---|---|
6. 非同高度落地(延伸):給定初始高度 y0¶
若 $y_0>0$,落地條件:$y(t)=0$ 解 t(取正根),射程:$x(t_f)-x_0$。
例:
- $y_0=5$ m
- $v_0=20$ m/s
- $\theta=35^\circ$
- $g=9.8$
用 Sage 解出 $t_f$ 並畫軌跡。
# 參數
v0_num = 20
theta_num = 35*pi/180
g_num = 9.8
y0_num = 5
x_num = x_t.subs({x0:0, v0:v0_num, theta:theta_num})
y_num = y_t.subs({x0:0, y0:y0_num, v0:v0_num, theta:theta_num, g:g_num})
# 解 y(t)=0 的正根作飛行時間
sol_tf = solve(y_num == 0, t)
sol_tf
tf_candidates = [s.rhs() for s in sol_tf]
tf_candidates_n = [N(c) for c in tf_candidates]
tf_candidates_n
tf_num = max(tf_candidates_n) # 取較大的正根(落地時刻)
R_num = N(x_num.subs(t=tf_num))
traj = parametric_plot((x_num, y_num), (t, 0, tf_num), thickness=2)
traj + point((0, y0_num), size=40) + point((R_num, 0), size=40)