作者:王一哲
日期:2018/7/14
最近看到建國中學曾靖夫老師的 VPython 講義〈Lecture 7 多物件控制(list) - 波動現象模擬〉,其中一項作業就是要學生做出蛇擺的動畫。蛇擺的英文為 pendulum wave,如果照字面翻譯應該譯為擺波,由一組數個的單擺構成的波,假設整組蛇擺的週期為
這是我用 VPython 在 Glowscript 網站製作的動畫,連結為 https://www.glowscript.org/#/user/yizhe/folder/Public/program/PendulumWave。
這個程式是進階教材,我們要善用類別(class)的特性,使程式在使用上更加方便。程式的目標:
"""
VPython教學進階內容: 蛇擺 pendulum wave, 使用 class
Ver. 1: 2018/7/12
Ver. 2: 2018/7/14 加上計時器
作者: 王一哲
"""
from vpython import *
"""
1. 參數設定, 設定變數及初始值
"""
g = 9.8 # 重力加速度
Tpw = 30 # 蛇擺的週期
N = 15 # 週期最長的單擺在蛇擺的1個週期內擺動的次數
Tmax = Tpw / N # 週期最長的單擺擺動週期
Lmax = Tmax**2 * g / (4 * pi**2) # 週期最長的單擺擺長
num = 20 # 單擺的個數
width = Lmax # 將畫面邊長設定為最長的單擺擺長
m = 1 # 小球質量
size = width / (2 * num) # 小球半徑
theta0 = radians(30)# 起始擺角, 用 radians 將單位換成 rad
i = 0 # 小球經過週期次數
t = 0 # 時間
dt = 0.001 # 時間間隔
"""
2. 畫面設定
"""
# 產生動畫視窗、天花板
scene = canvas(title="Pendulum Wave", width=600, height=600, x=0, y=0, background=color.black)
scene.camera.pos = vec(-1.5*width, 0.5*width, width)
scene.camera.axis = vec(1.5*width, -0.5*width, -width)
roof = box(pos=vec(0, (width + size)/2, 0), size=vec(width, size, 0.5*width), color=color.cyan)
timer = label(pos=vec(0.9*width, 0.9*width, 0), text="t = s", space=50, height=24,
border=4, font="monospace")
# 新增類別 Pendulum, 輸入週期T, 懸掛位置loc, 編號idx, 自動產生小球及對應的繩子
# 設定方法 update, 輸入經過的時間dt, 更新單擺狀態
class Pendulum:
def __init__(self, T, loc, idx):
self.T = T
self.loc = loc
self.idx = idx
self.L = self.T**2 * g / (4 * pi**2)
self.I = m * self.L**2
self.alpha = 0
self.omega = 0
self.theta = theta0
self.ball = sphere(pos=vec(self.loc, width/2 - self.L*cos(theta0), self.L*sin(theta0)),
radius=size, color=vec(1 - self.idx/num, 0, self.idx/num))
self.rope = cylinder(pos=vec(self.loc, width/2, 0), axis=self.ball.pos - vec(self.loc, width/2, 0),
radius=0.1*size, color=color.yellow)
def update(self, dt):
self.dt = dt
self.alpha = -m*g*self.ball.pos.z/self.I
self.omega += self.alpha*self.dt
self.theta += self.omega*self.dt
self.ball.pos = vec(self.loc, 0.5*width - self.L*cos(self.theta), self.L*sin(self.theta))
self.rope.axis = self.ball.pos - vec(self.loc, 0.5*width, 0)
# 利用自訂類別 Pendulum 產生 num 個單擺
pendulums = []
for i in range(num):
T = Tpw / (N + i)
loc = width*(-0.5+(i/(num-1)))
pendulum = Pendulum(T, loc, i)
pendulums.append(pendulum)
"""
3. 物體運動部分
"""
while True:
rate(500)
for pendulum in pendulums:
pendulum.update(dt)
timer.text = "t = {:.1f} s".format(t)
t += dt
timer.text = "t = {:.1f} s".format(t)
timer.text = "t = " + str('%.1f' % t) + " s"
print("{:.6f}".format(a))
print('%.6f' % a)
我將程式碼上傳到 GlowScript 網站,請按以下連結觀看動畫 http://www.glowscript.org/#/user/yizhe/folder/Public/program/PendulumWave
GlowScript 網站在指定浮點數顯示位數的部分,只支援第1種語法。
我們在這個動畫裡利用自訂的 Class 產生單擺,在使用上比較方便但在程式設計上比較麻煩,如果只是想做出同樣的動畫,可以使用 list 儲存單擺的週期、擺長等資料,再用 for 迴圈讀取、執行。Python 裡有許多好用但有點難懂的工具,例如這次用到的Class,還有科學計算套件Numpy、繪圖套件Matplotlib、讀取資料套件Pandas……等等,如果之後的動畫中需要用到會再寫講義,敬請期待。
VPython