<font color=#008000>
>作者: 吳姿瑩
>更新:2022.12.29
</font>[color=#008000]
# Lesson15: 彈簧運動(簡諧運動)
###### tags: `運動科學模擬` `多元選修` `vpython` `簡諧運動` `彈簧`
## :memo:什麼是簡諧運動Simple Harmonic Motion?
簡諧運動即是簡單又和諧的運動,位置對時間的函數圖,可用簡單的數學正弦$sin(t)$函數來表達的運動,皆是簡諧運動,簡稱為S.H.M.其中位置、速度、加速度的時間函數可表示為
- $x(t)=A\times sin(\omega t) ,其中A表示振幅,\omega 表示角速率(轉動的快慢)$
- $v(t)=A\omega \times cos(\omega t)$
- $a(t)=-A\omega^2 \times sin(\omega t)$
其函數圖如下:
<a href="https://imgur.com/La4KJfz"><img src="https://i.imgur.com/La4KJfz.png?2" title="source: imgur.com" /></a>
其中彈簧運動亦是簡諧運動其中一種,彈簧運動符合虎克定律$F=-kx$,其中$k$為彈力常數,$x$為形變量($x = 總長度-原長$),彈簧運動如下:
<a href="https://imgur.com/ych64gG"><img src="https://i.imgur.com/ych64gG.gif" title="source: imgur.com" /></a>
<a href="https://imgur.com/McZKDXB"><img src="https://i.imgur.com/McZKDXB.gif" title="source: imgur.com" /></a>
## :memo:簡諧運動物理觀念
我們考慮較簡單的水平光滑面的彈簧運動,木塊受到3個力,即重力、正向力、彈力,其中合力即為彈力。將木塊向右拉一段距離振幅$R$ 且靜止釋放,所受合力為
$F=ma=-kx$
根據數學、簡諧運動的概念可解出
- $x(t)=R\times sin(\omega t) ,其中A表示振幅,\omega 表示角速率(轉動的快慢)$
- $v(t)=R\omega \times cos(\omega t)$
- $a(t)=-R\omega^2 \times sin(\omega t)$
其中角速率$\omega =\sqrt\frac{k}{m}$
根據週期$T =\frac{2\pi}{\omega} = 2\pi \sqrt\frac{m}{k}$
## :memo:設置一個物體box彈簧運動
### 1.參數設定
|**意涵** |**設定**|
|-----|--------|
|木塊質量 1kg|m = 4 |
|木塊邊長 0.8m |size = 0.8 |
|振幅 5 m|R = 5|
|彈性力常數 k |k = 1|
|彈簧原長 L0 |L0 = R + size|
|木塊回到初位置的次數|i = 0|
|時間間隔|dt = 0.01|
|地板厚度 0.01 m| thin = 0.01|
並在執行程式時,先輸出木塊簡諧運動的週期理論值
```javascript
print("週期理論值為 {:.6f} s".format(2*pi*sqrt(m/k)))
```
其中==f==代表可結合==字串==輸出一同輸出,亦即結合運算式陳述(expression statements)與print()函式的運用,運用字串的 str.format()寫法可給予更詳細的輸出格式指令。
在==f前方加上6==表示,輸出的數字以小數點後6位來呈現。
### 2.畫面設定
- 有關畫布==canvas==的設定,請設定title="Simple Harmonic Motion", caption='spring motion'的畫布
畫面的 ***正中央為起點(0, 0, 0)*** 的位置
- 利用==box設定一個地板==,為了讓木塊可以平放在地板上(木塊的起始高度位置為0),調整地板高度下降一個木塊高及地板的一半高
- 利用==box設定一個牆壁==,牆壁的起始點在最左方,故須退縮一個彈簧長度,讓彈簧可連接至牆壁
- 利用==box設定一個木塊==,木塊的起始位置在畫面做右方,故木塊中央位置拉至一個振幅R 加上木塊寬度之一半
其中這次使用到的顏色不再是單一顏色,使用vpython中的材質顏色textures。
```javascript
# 畫面設定,視窗、地板、木塊
scene = canvas(title="Simple Harmonic Motion", caption='spring motion',
width=640, height=400, x=0, y=0,center=vec(0, 0.3, 0),
background=vec(204/255,204/255,255/255))
floor = box(pos=vec(0, -(size+thin)/2, 0),
size=vec(2*L0, thin, R), texture=textures.wood)
wall = box(pos=vec(-L0, 0, 0),
size=vec(0.1, size, R), texture=textures.metal)
block = box(pos=vec(R+size/2, 0, 0),
size=vec(size, size, size), texture=textures.rough,
v=vec(0, 0, 0))
```
- 設置==彈簧資訊,helix表螺線館之意==,其中螺線管的位置由左端開始,亦即牆面的位置(-L0, 0, 0),radius半徑即是螺線管旋轉半徑大小,thickness厚度即是螺線管粗細
- 特別注意彈簧需連接至木塊上,其中==axis軸的資訊即是連接至何方==,而axis指向某物體(木塊)時,是連接至木塊中心,故將彈簧指向axis長度設置為,==$木塊位置 - 木塊一半寬 - 彈簧左端位置$==
```javascript
#彈簧相關資訊
spring = helix(pos=vec(-L0, 0, 0), radius=0.2*size,
thickness=0.05*size, color=color.green)
spring.axis = block.pos - vec(size/2, 0, 0) - spring.pos
```
- 根據前一堂課的箭頭練習,==箭頭視覺化,將速度、加速度大小畫在木塊正上方==,故箭頭的位置即是木塊位置再加上高度為size的向量大小,讓箭頭隨著木塊一同移動,黑色表速度大小、藍色表加速度大小。
```javascript
# 產生表示速度、加速度的箭頭
arrow_v = arrow(pos=block.pos + vec(0, size, 0),
axis=vec(0, 0, 0), shaftwidth=0.3*size, color=color.black)
arrow_a = arrow(pos=block.pos + vec(0, 2*size, 0),
axis=vec(0, 0, 0), shaftwidth=0.3*size, color=color.blue)
```
- 繪圖部分總共畫了4張圖,分別為==x-t圖、v-t圖、a-t圖、以及將位置、速度、加速度一同畫在同一張圖中==做比較
```javascript
# 繪圖部分
gd = graph(title="x-t plot", width=600, height=450, x=0, y=850,
xtitle="<i>t</i>(s)", ytitle="<i>x</i>(m)")
gd_v = graph(title="v-t plot", width=600, height=450, x=0, y=1300,
xtitle="<i>t</i>(s)", ytitle="<i>v</i>(m/s)")
gd_a = graph(title="a-t plot", width=600, height=450, x=0, y=1750,
xtitle="<i>t</i>(s)", ytitle="<i>a</i>(m/s<sup>2</sup>)")
gd_tot = graph(title="plot", width=600, height=450, x=0, y=2200,
xtitle="<i>t</i>(s)",
ytitle="red: <i>x</i>(m), black: <i>v</i>(m/s), blue: <i>a</i>(m/s<sup>2</sup>)")
xt = gcurve(graph=gd, color=color.red)
vt = gcurve(graph=gd_v, color=color.black)
at = gcurve(graph=gd_a, color=color.blue)
xt_tot = gcurve(graph=gd_tot, color=color.red, label="red x-t plot")
vt_tot = gcurve(graph=gd_tot, color=color.black, label="black v-t plot")
at_tot = gcurve(graph=gd_tot, color=color.blue, label="blue a-t plot")
```
### 3.物體的運動
- 前一堂課使用了click以後才開始執行程式運動的部分
```javascript
#等待click才會開始執行
T = text(text='Please click to run! ',pos=vec(-3, 5, 0), align='left', height = 0.5, color=color.black)
scene.waitfor('click')
```
- 利用==變數i來計算木塊歷經多少週期==,當達到3個週期的時候則結束迴圈
- 在以下程式第29行,將計算木塊完成的次數,並==印出完成第i次週期的時間==,可與週期理論值做比較
- 木塊的運動須考量虎克定律($F=-kx$),在進行加速度、速度、位置的計算,可由以下程式第5~7行,在計算虎克定律所產生的彈力大小,==spring.axis為彈簧的總長向量,扣除彈簧原長即是彈簧伸長量==,特別注意當彈簧比原長長(spring.axis - vec(L0, 0, 0)>0)時,所受的力為負,即是回復力,反之彈簧長度比原長短時,彈力向右。
- 最後更新箭頭的位置、大小資訊,==箭頭位置隨著木塊的位置移動(以下程式第15~16行)== ,==箭頭大小分別為速度、加速度大小(以下程式第17~18行)==
- 更新畫圖資訊,將木塊位置、速度、加速度資訊畫出,==特別注意我們習慣畫彈簧伸長量的圖來表示簡諧運動,故在木塊位置顯示中,我們需要扣除木塊的一半寬==,才是真正彈簧伸長量對時間的圖。
```javascript=
while i < 3:
rate(1000)
# 計算彈簧長度、伸長量、回復力
spring.axis = block.pos - spring.pos - vec(0.5*size, 0, 0)
# 虎克定律 F = -kx
F = -k * (spring.axis - vec(L0, 0, 0))
# 計算木塊加速度, 更新速度、位置
block.a = F/m
block.v += block.a*dt
block.pos += block.v*dt
# 更新代表速度、加速度的箭頭位置、方向、長度
arrow_v.pos = block.pos + vec(0, size, 0)
arrow_a.pos = block.pos + vec(0, 2*size, 0)
arrow_v.axis = block.v
arrow_a.axis = block.a
# 畫出 x-t, v-t, a-t 圖
xt.plot(pos=(t, block.pos.x - size/2))
vt.plot(pos=(t, block.v.x))
at.plot(pos=(t, block.a.x))
xt_tot.plot(pos=(t, block.pos.x - size/2))
vt_tot.plot(pos=(t, block.v.x))
at_tot.plot(pos=(t, block.a.x))
# 判斷木塊是否回到出發點, 計算回到出發點的次數
if block.pos.x > R + size/2 and block.v.x > 0:
i += 1
print("第 {:d} 次回到右端點,經過時間為 {:6f} s".format(i, t))
# 更新時間
t += dt
```
:::spoiler **簡諧運動(一組彈簧組) 完整程式碼**
```javascript=
"""
Auther :吳姿瑩
Date :2022/12/29
version :python3.10.6 vpython7
chapter :spring彈簧
"""
from vpython import *
"""
1. 參數設定, 設定變數及初始值
"""
thin = 0.1 # 地板厚度
m = 4 # 木塊質量 4 kg
size = 0.8 # 木塊邊長 0.8 m
R = 5 # 振幅 5 m
k = 1 # 彈性常數 1 N/m
L0 = R + size # 彈簧原長
i = 0 # 木塊回到初位置的次數
t = 0 # 時間
dt = 0.001 # 時間間隔
print("週期理論值為 {:.6f} s".format(2*pi*sqrt(m/k)))
"""
2. 畫面設定
"""
# 畫面設定,視窗、地板、木塊
scene = canvas(title="Simple Harmonic Motion", caption='spring motion', width=640, height=400, x=0, y=0,center=vec(0, 0.3, 0), background=vec(204/255,204/255,255/255))
floor = box(pos=vec(0, -(size+thin)/2, 0), size=vec(2*L0, thin, R), texture=textures.wood)
wall = box(pos=vec(-L0, 0, 0), size=vec(0.1, size, R), texture=textures.metal)
block = box(pos=vec(R+size/2, 0, 0), size=vec(size, size, size), texture=textures.rough, v=vec(0, 0, 0))
#彈簧相關資訊
spring = helix(pos=vec(-L0, 0, 0), radius=0.2*size, thickness=0.05*size, color=color.green)
spring.axis = block.pos - vec(size/2, 0, 0) - spring.pos
# 產生表示速度、加速度的箭頭
arrow_v = arrow(pos=block.pos + vec(0, size, 0), axis=vec(0, 0, 0), shaftwidth=0.3*size, color=color.black)
arrow_a = arrow(pos=block.pos + vec(0, 2*size, 0), axis=vec(0, 0, 0), shaftwidth=0.3*size, color=color.blue)
# 繪圖部分
gd = graph(title="x-t plot", width=600, height=450, x=0, y=850, xtitle="<i>t</i>(s)", ytitle="<i>x</i>(m)")
gd_v = graph(title="v-t plot", width=600, height=450, x=0, y=1300, xtitle="<i>t</i>(s)", ytitle="<i>v</i>(m/s)")
gd_a = graph(title="a-t plot", width=600, height=450, x=0, y=1750, xtitle="<i>t</i>(s)", ytitle="<i>a</i>(m/s<sup>2</sup>)")
gd_tot = graph(title="plot", width=600, height=450, x=0, y=2200, xtitle="<i>t</i>(s)", ytitle="red: <i>x</i>(m), black: <i>v</i>(m/s), blue: <i>a</i>(m/s<sup>2</sup>)")
xt = gcurve(graph=gd, color=color.red)
vt = gcurve(graph=gd_v, color=color.black)
at = gcurve(graph=gd_a, color=color.blue)
xt_tot = gcurve(graph=gd_tot, color=color.red, label="red x-t plot")
vt_tot = gcurve(graph=gd_tot, color=color.black, label="black v-t plot")
at_tot = gcurve(graph=gd_tot, color=color.blue, label="blue a-t plot")
"""
3. 物體運動部分, 重複3個週期
"""
#等待click才會開始執行
T = text(text='Please click to run! ',pos=vec(-3, 5, 0), align='left', height = 0.5, color=color.black)
scene.waitfor('click')
while i < 3:
rate(1000)
# 計算彈簧長度、伸長量、回復力
spring.axis = block.pos - spring.pos - vec(0.5*size, 0, 0)
# 虎克定律 F = -kx
F = -k * (spring.axis - vec(L0, 0, 0))
# 計算木塊加速度, 更新速度、位置
block.a = F/m
block.v += block.a*dt
block.pos += block.v*dt
# 更新代表速度、加速度的箭頭位置、方向、長度
arrow_v.pos = block.pos + vec(0, size, 0)
arrow_a.pos = block.pos + vec(0, 2*size, 0)
arrow_v.axis = block.v
arrow_a.axis = block.a
# 畫出 x-t, v-t, a-t 圖
xt.plot(pos=(t, block.pos.x - size/2))
vt.plot(pos=(t, block.v.x))
at.plot(pos=(t, block.a.x))
xt_tot.plot(pos=(t, block.pos.x - size/2))
vt_tot.plot(pos=(t, block.v.x))
at_tot.plot(pos=(t, block.a.x))
# 判斷木塊是否回到出發點, 計算回到出發點的次數
if block.pos.x > R + size/2 and block.v.x > 0:
i += 1
print("第 {:d} 次回到右端點,經過時間為 {:f} s".format(i, t))
# 更新時間
t += dt
```
:::
:::spoiler **學生活動**
1. 試求m=1 kg,k=1 N/m的週期理論值?
2. 試求程式中完成一週期的時間為何?
3. 試問,當木塊在左右端點時,速度、加速度何者最大?
4. 試問,當木塊在平衡點時(彈簧原長處),速度、加速度何者最大?
:::
:::spoiler **學生作業**
1. 1. Homework:設置==兩個不同顏色的彈簧分別繫在4kg 木塊上,彈簧力常數分別為k=1, 0.25 N/m==,並畫出 ==$v$和$a$,速度、加速度箭頭視覺化==
Requirements要求:
(1)需畫出木塊不重疊的移動
(2)需畫出兩個彈簧搭配顏色的(1)x-t圖 (2)v-t圖 (3)a-t圖
(3)需畫出各自木塊的速度、加速度視覺化箭頭
2. 請將==程式code以及瀏覽器結果截圖== 至google classroom繳交作業。
3. 完成今日協作平台更新
4. 將code上傳至雲端硬碟中(Lesson15 vpython彈簧運動(簡諧運動))
:::
## :memo:參考網址
1. python 輸入和輸出: https://docs.python.org/zh-tw/3/tutorial/inputoutput.html
2. vpython 的textures材質顏色:https://www.glowscript.org/docs/VPythonDocs/textures.html
3. vpython textures 列表:https://www.glowscript.org/#/user/GlowScriptDemos/folder/Examples/program/Textures-VPython
4. vpython 彈簧螺線管使用:https://www.glowscript.org/docs/VPythonDocs/helix.html
5. vpython 箭頭arrow:https://www.glowscript.org/docs/VPythonDocs/arrow.html