<style> .markdown-body table{ display: unset; } </style> # 一維彈性碰撞次數與圓周率 > 作者:王一哲 > 日期:2019/8/14 ## 前言 如下圖所示,假設在水平光滑桌面上有兩個木塊,右側紅色木塊的質量為$m_1$、初速度方向向左,左側綠色木塊的質量為$m_2$、原為靜止,且$m_1 = 100^n m_2$,最左側有固定的牆壁。若木塊之間、木塊與牆壁之間的碰撞皆為一維彈性碰撞,則碰撞次數與$n$的關係如下。 <img height="100%" width="100%" src="https://imgur.com/c2WGmKV.png" style="display: block; margin-left: auto; margin-right: auto;"/> <div style="text-align:center">裝置示意圖</div><br /> <div style="text-align:center"> | n | 碰撞次數 | |---|---------| | 1 | 31 | | 2 | 314 | | 3 | 3141 | | 4 | 31415 | | 5 | 314159 | </div> <br /> 如果想要了解背後的原理請看這部影片 **So why do colliding blocks compute pi?** [[1](https://youtu.be/jsYwFizhncE)],影片作者是**3Blue1Brown**。接下來我們拿之前寫過的〈[一維彈性碰撞](https://hackmd.io/@yizhewang/SkYXPWrfm?type=view)〉程式碼來修改,試著畫出這個現象。 <br /> ## 程式及模擬結果 ```python= from vpython import * """ 1. 參數設定, 設定變數及初始值 """ n = 4 # m1 = 100^n m2 num = 0 # 撞擊次數 d2, m2, v2, c2 = 0.2, 1.0, 0.0, color.green # 左側被撞的木塊寬度, 質量, 初速, 顏色 d1, m1, v1, c1 = 0.4, m2*100**n, -1.0, color.red # 右側撞人的木塊寬度, 質量, 初速, 顏色 d3, c3 = 0.2, color.blue # 左側牆壁的寬度, 地板及牆壁, 顏色 xmax, xmin = 2.0, -2.0 # x 軸範圍 xrange = xmax - xmin # 畫面寬度 t, dt = 0.0, 0.0001 # 時間, 時間間隔, 單位為s """ 2. 畫面設定 """ # 產生動畫視窗 scene = canvas(title="1 Dimension Collisions and &pi;", width=800, height=400, center=vec(0, 0.2*xmax, 0), background=color.black, range=0.8*xmax, autoscale=False) # 產生地板 floor = box(size=vec(1.6, 0.04, 0.2)*xrange, pos=vec(0.3*xrange, -0.02*xrange, 0), color=c3) # 產生牆壁 wall = box(size=vec(d3, 5*d3, 0.2*xrange), pos=vec(xmin + 0.5*d3, 2.5*d3, 0), color=c3) # 產生左側木塊 b2 並設定初速度 b2 = box(size=vec(d2, d2, d2), pos=vec(0, 0.5*d2, 0), color=c2, m=m2, v=vec(v2, 0, 0)) # 產生右側木塊 b1 並設定初速度 b1 = box(size=vec(d1, d1, d1), pos=vec(xmax - 0.5*d1, 0.5*d1, 0), color=c1, m=m1, v=vec(v1, 0, 0)) # 產生顯示撞擊次數用的標籤 counter = label(pos=vec(0.5*xmax, 0.8*xmax, 0), text="Collisions: 0", space=50, height=24, border=4, box=False, font="monospace") # 產生顯示質量用的標籤 mass = label(pos=vec(-0.5*xmax, 0.8*xmax, 0), text="<i>m</i><sub>1</sub> = 100<sup>%d</sup> <i>m</i><sub>2</sub>" % int(n), space=50, height=24, border=4, box=False, font="monospace") # 自訂函式,一維彈性碰撞速度公式 def collision(m1, m2, v1, v2): v1_prime = (m1-m2)/(m1+m2)*v1 + (2*m2)/(m1+m2)*v2 v2_prime = (2*m1)/(m1+m2)*v1 + (m2-m1)/(m1+m2)*v2 return v1_prime, v2_prime """ 3. 物體運動部分, 重複執行直到不再發生碰撞為止 """ while True: if(abs(b1.pos.x - b2.pos.x) <= 0.51*(d1 + d2)): rate(2000) dt = 0.000005 else: rate(1000) dt = 0.0005 # 計算木塊間的距離, 若發生碰撞則計算撞後速度 if(abs(b1.pos.x - b2.pos.x) <= 0.5*(d1 + d2) and b1.v.x < b2.v.x): b1.v.x, b2.v.x = collision(b1.m, b2.m, b1.v.x, b2.v.x) num += 1 counter.text = "Collisions: %d" % int(num) # 計算左側木塊與牆壁的距離, 若發生碰撞則撞後速度反向 if(abs(b2.pos.x - wall.pos.x) <= 0.5*(d2 + d3) and b2.v.x < 0): b2.v.x = -b2.v.x num += 1 counter.text = "Collisions: %d" % int(num) # 條件成立時停止迴圈 if(b1.v.x > 0 and b2.v.x > 0 and b1.v.x > b2.v.x): break # 更新木塊的位置 b1.pos += b1.v * dt b2.pos += b2.v * dt # 更新時間 t += dt ``` <br /> ### 程式設計部分 沒有安裝 VPython 的同學可以使用線上版:[GlowScript 網站動畫連結](https://www.glowscript.org/#/user/yizhe/folder/Public/program/collisonpi)。我們可以看到,這支程式和[程式 15-1.一維彈性碰撞公式](https://github.com/YiZheWangTw/VPythonTutorial/blob/master/15.%E4%B8%80%E7%B6%AD%E5%BD%88%E6%80%A7%E7%A2%B0%E6%92%9E/15-1_1D_collision.py)幾乎一樣,以下說明不同之處。 1. 第 6 行和第 9 行:設定質量$m_1 = 100^n m_2$。 2. 第 24 行:畫面左側增加一面牆壁。 3. 第 30 ~ 31 行:畫面右上方增加標示撞擊次數用的標籤counter。 4. 第 33 ~ 35 行:畫面左上方增加標示質量用的標籤mass。 5. 第 47 ~ 52 行:當木塊很接近時降低時間間隔 dt,避免木塊一次移動太多。 6. 第 57 行和第 62 行:更新標籤 counter 顯示的數值。 7. 第 64 行:當兩個木塊的速度皆向右,且右側木塊速度較大時,代表不會再發生碰撞,用 break 停止迴圈。 <br /> ### 模擬結果 按照目前的設定只能畫到$n=4$,當$n \geq 5$時右側的木塊會穿過左側的木塊和牆壁,也許將 dt 再調小一點可以解決這個問題,有興趣的同學可以試著修改程試碼。 <img height="100%" width="100%" src="https://imgur.com/XkmVHJZ.png" style="display: block; margin-left: auto; margin-right: auto;"/> <div style="text-align:center">n = 1,撞擊 31 次</div><br /> <img height="100%" width="100%" src="https://imgur.com/7s6JFPr.png" style="display: block; margin-left: auto; margin-right: auto;"/> <div style="text-align:center">n = 2,撞擊 314 次</div><br /> <img height="100%" width="100%" src="https://imgur.com/RVIf1jn.png" style="display: block; margin-left: auto; margin-right: auto;"/> <div style="text-align:center">n = 3,撞擊 3141 次</div><br /> <img height="100%" width="100%" src="https://imgur.com/PShVkCL.png" style="display: block; margin-left: auto; margin-right: auto;"/> <div style="text-align:center">n = 4,撞擊 31415 次</div><br /> ## 參考資料 1. [So why do colliding blocks compute pi?](https://youtu.be/jsYwFizhncE) 2. [VPython 官方說明書 canvas](http://www.glowscript.org/docs/VPythonDocs/canvas.html) 3. [VPython 官方說明書 box](http://www.glowscript.org/docs/VPythonDocs/box.html) 4. [VPython 官方說明書 label](https://www.glowscript.org/docs/VPythonDocs/label.html) --- ###### tags:`VPython`