[关闭]
@zy-0815 2017-12-20T13:46:15.000000Z 字数 6936 阅读 1312

计算物理第九次作业

计算物理


摘要

我们将探究碰撞反射问题,研究小球在方形界面、球形界面中的运动轨迹,及其影响因素,同时本次作业就3.30题进行探究和解答

背景

反射是在日常生活中较为常见的一种现象,无论是光的反射亦或是台球碰撞后的反弹,其遵循的基本规律都是反射定律,即反射角等于入射角。则对于速度,有如下的关系式:


同时我们知道,不同的边界条件将对反射的运动轨迹造成不同的影响,若为直线边界,则如图:
image_1b1u2knbr9k01qhb1cbufnu1dfp9.png-21.4kB
若为弧形边界,则类似Figure 3.19,初射角的分析将比之前略复杂:
image_1b1u2qa1f1fdalf7hrgqe21482m.png-83.9kB
当我们将圆形边界沿直径切开,并拉开一段距离(称之为 Stadium Billiard),情况会复杂很多:
image_1b1u2uso9re8q5a1mdeecf4al13.png-17.4kB

这里我们将研究不同边界条件对小球运动的影响


正文

1. 小球在方形边界中的运动

  1. import pylab as pl
  2. import math
  3. class Billiard_Program :
  4. def __init__(self,i=0,initial_theta=math.pi/6,initial_velocity=1,total_time=500,\
  5. initial_x=0.2,initial_y=0,time_step=0.01):
  6. self.theta=initial_theta
  7. self.v=initial_velocity
  8. self.v_x=[self.v*math.cos(self.theta)]
  9. self.v_y=[self.v*math.sin(self.theta)]
  10. self.x=[initial_x]
  11. self.y=[initial_y]
  12. self.time=total_time
  13. self.dt=time_step
  14. self.t=[0]
  15. def run(self):
  16. _time=0
  17. while(_time<self.time):
  18. self.x.append(self.x[-1]+self.v_x[-1]*self.dt)
  19. self.y.append(self.y[-1]+self.v_y[-1]*self.dt)
  20. if(self.x[-1]>1):
  21. self.x[-1]=self.x[-2]
  22. self.y[-1]=self.y[-2]
  23. while(1):
  24. self.x.append(self.x[-1]+self.v_x[-1]*self.dt*0.01)
  25. self.y.append(self.y[-1]+self.v_y[-1]*self.dt*0.01)
  26. if(self.x[-1]>1):
  27. self.v_x.append(-self.v_x[-1])
  28. break
  29. if(self.x[-1]<-1):
  30. self.x[-1]=self.x[-2]
  31. self.y[-1]=self.y[-2]
  32. while(1):
  33. self.x.append(self.x[-1]+self.v_x[-1]*self.dt*0.01)
  34. self.y.append(self.y[-1]+self.v_y[-1]*self.dt*0.01)
  35. if(self.x[-1]<-1):
  36. self.v_x.append(-self.v_x[-1])
  37. break
  38. if(self.y[-1]>1):
  39. self.x[-1]=self.x[-2]
  40. self.y[-1]=self.y[-2]
  41. while(1):
  42. self.x.append(self.x[-1]+self.v_x[-1]*self.dt*0.01)
  43. self.y.append(self.y[-1]+self.v_y[-1]*self.dt*0.01)
  44. if(self.y[-1]>1):
  45. self.v_y.append(-self.v_y[-1])
  46. break
  47. if(self.y[-1]<-1):
  48. self.x[-1]=self.x[-2]
  49. self.y[-1]=self.y[-2]
  50. while(1):
  51. self.x.append(self.x[-1]+self.v_x[-1]*self.dt*0.01)
  52. self.y.append(self.y[-1]+self.v_y[-1]*self.dt*0.01)
  53. if(self.y[-1]<-1):
  54. self.v_y.append(-self.v_y[-1])
  55. break
  56. self.t.append(_time)
  57. _time += self.dt
  58. def show_results(self):
  59. pl.plot(self.x,self.y)
  60. pl.title('Billiard Program with $\\theta$=$\pi$/6')
  61. pl.xlabel('x')
  62. pl.ylabel('y')
  63. pl.xlim(-1,1)
  64. pl.ylim(-1,1)
  65. pl.legend()
  66. pl.show()
  67. a = Billiard_Program()
  68. a.run()
  69. a.show_results()

2. 小球在圆形界面中的运动

  1. import pylab as pl
  2. import math
  3. class Billiard_Program :
  4. def __init__(self,i=0,initial_theta=math.pi/6,initial_velocity=1,total_time=80,\
  5. initial_x=0.2,initial_y=0,time_step=0.01):
  6. self.theta=[initial_theta]
  7. self.v=[initial_velocity]
  8. self.x=[initial_x]
  9. self.y=[initial_y]
  10. self.time=total_time
  11. self.dt=time_step
  12. self.t=[0]
  13. self.phi=[]
  14. self.v_x=[self.v[-1]*math.cos(self.theta[-1])]
  15. self.v_y=[self.v[-1]*math.sin(self.theta[-1])]
  16. def run(self):
  17. _time=0
  18. a=0.1
  19. r=1
  20. while(_time<self.time):
  21. self.x.append(self.x[-1]+self.v_x[-1]*self.dt)
  22. self.y.append(self.y[-1]+self.v_y[-1]*self.dt)
  23. if(self.y[-1]<-a*r and (pow(self.x[-1],2)+pow(self.y[-1]+a*r,2))>pow(r,2)):
  24. self.x[-1]=self.x[-2]
  25. self.y[-1]=self.y[-2]
  26. while(1):
  27. self.x.append(self.x[-1]+self.v_x[-1]*self.dt*0.01)
  28. self.y.append(self.y[-1]+self.v_y[-1]*self.dt*0.01)
  29. if(pow(self.x[-1],2)+pow(self.y[-1]+a*r,2)>pow(r,2)):
  30. cos_theta=self.x[-1]/r
  31. sin_theta=(self.y[-1]+a*r)/r
  32. vi_prependicular_x=abs(self.v_x[-1]*cos_theta+self.v_y[-1]*sin_theta)*cos_theta
  33. vi_prependicular_y=abs(self.v_x[-1]*cos_theta+self.v_y[-1]*sin_theta)*sin_theta
  34. vi_parallel_x=self.v_x[-1]-abs(self.v_x[-1]*cos_theta+self.v_y[-1]*sin_theta)*cos_theta
  35. vi_parallel_y=self.v_y[-1]-abs(self.v_x[-1]*cos_theta+self.v_y[-1]*sin_theta)*sin_theta
  36. vf_parallel_x=vi_parallel_x
  37. vf_parallel_y=vi_parallel_y
  38. vf_prependicular_x=-vi_prependicular_x
  39. vf_prependicular_y=-vi_prependicular_y
  40. vf_x=vf_parallel_x+vf_prependicular_x
  41. vf_y=vf_parallel_y+vf_prependicular_y
  42. self.v_x.append(vf_x)
  43. self.v_y.append(vf_y)
  44. break
  45. if(self.y[-1]>a*r and (pow(self.x[-1],2)+pow(self.y[-1]-a*r,2))>pow(r,2)):
  46. self.x[-1]=self.x[-2]
  47. self.y[-1]=self.y[-2]
  48. while(1):
  49. self.x.append(self.x[-1]+self.v_x[-1]*self.dt*0.01)
  50. self.y.append(self.y[-1]+self.v_y[-1]*self.dt*0.01)
  51. if(pow(self.x[-1],2)+pow(self.y[-1]-a*r,2)>pow(r,2)):
  52. cos_theta=self.x[-1]/r
  53. sin_theta=(self.y[-1]-a*r)/r
  54. vi_prependicular_x=abs(self.v_x[-1]*cos_theta+self.v_y[-1]*sin_theta)*cos_theta
  55. vi_prependicular_y=abs(self.v_x[-1]*cos_theta+self.v_y[-1]*sin_theta)*sin_theta
  56. vi_parallel_x=self.v_x[-1]-abs(self.v_x[-1]*cos_theta+self.v_y[-1]*sin_theta)*cos_theta
  57. vi_parallel_y=self.v_y[-1]-abs(self.v_x[-1]*cos_theta+self.v_y[-1]*sin_theta)*sin_theta
  58. vf_parallel_x=vi_parallel_x
  59. vf_parallel_y=vi_parallel_y
  60. vf_prependicular_x=-vi_prependicular_x
  61. vf_prependicular_y=-vi_prependicular_y
  62. vf_x=vf_parallel_x+vf_prependicular_x
  63. vf_y=vf_parallel_y+vf_prependicular_y
  64. self.v_x.append(vf_x)
  65. self.v_y.append(vf_y)
  66. break
  67. if(-a<self.y[-1]<a and self.x[-1]>1):
  68. self.x[-1]=self.x[-2]
  69. self.y[-1]=self.y[-2]
  70. while(1):
  71. self.x.append(self.x[-1]+self.v_x[-1]*self.dt*0.01)
  72. self.y.append(self.y[-1]+self.v_y[-1]*self.dt*0.01)
  73. if(self.x[-1]>1):
  74. self.v_x.append(-self.v_x[-1])
  75. break
  76. if(-a<self.y[-1]<a and self.x[-1]<-1):
  77. self.x[-1]=self.x[-2]
  78. self.y[-1]=self.y[-2]
  79. while(1):
  80. self.x.append(self.x[-1]+self.v_x[-1]*self.dt*0.01)
  81. self.y.append(self.y[-1]+self.v_y[-1]*self.dt*0.01)
  82. if(self.x[-1]<-1):
  83. self.v_x.append(-self.v_x[-1])
  84. break
  85. self.t.append(_time)
  86. _time += self.dt
  87. def show_results(self):
  88. pl.plot(self.x,self.y)
  89. pl.title('Circular stadium with $\\theta$=$\pi$/6')
  90. pl.xlabel('x')
  91. pl.ylabel('y')
  92. pl.xlim(-1.2,1.2)
  93. pl.ylim(-1.2,1.2)
  94. pl.legend()
  95. pl.show()
  96. a = Billiard_Program()
  97. a.run()
  98. a.show_results()

结论

1. 小球在方形界面中的运动

1.1 初始角度的影响
figure_1.png-36.9kB
figure_1-2.png-24.9kB
figure_1-1.png-30.6kB

1.2  以 为基础,增长程序运行时间
figure_1-3.png-104.4kB
figure_1-4.png-300.6kB
可见若时间足够长,轨迹将铺满整个平面

1.3 相空间
image_1b1u3si2n8377321o61c331njn4b.png-30kB
可见小球的速度在两确定值间变化

2. 圆形边界

2.1 正圆边界
figure_2-1.png-141.6kB

2.2 Stadium Billiard
figure_2.png-105.7kB
改变的取值
figure_1-6.png-127.1kB
figure_1-4.png-120.8kB
figure_1-5.png-126.3kB

可见时整个运动轨迹已发生了巨大改变,若我们将改至足够大,使之完全成为“体育场形”则有:
figure_1-7.png-95.8kB

2.3  相空间
figure_1-8.png-22.1kB
figure_1-9.png-19.1kB
figure_1-10.png-18.7kB
figure_1-11.png-17.1kB
时,轨迹已布满整个相空间,标志着运动以完全混乱

3 Problem 3.30

我们同时释放两个小球,他们有微小的初始位置差别,研究他们的运动,则有如下图像,此处设初始位置x相差0.001
figure_1-14.png-41kB
figure_1-12.png-45.1kB
figure_1-13.png-47.1kB

反思

1. 精度问题
为了提高小球在遇到边界时对边界的判断精度,我们采取如下算法,即超过边界时后退一步,再以更小步长前进,这一部分在程序中的表现如下:

  1. if(self.x[-1]>1):
  2. self.x[-1]=self.x[-2]
  3. self.y[-1]=self.y[-2]
  4. while(1):
  5. self.x.append(self.x[-1]+self.v_x[-1]*self.dt*0.01)
  6. self.y.append(self.y[-1]+self.v_y[-1]*self.dt*0.01)
  7. if(self.x[-1]>1):
  8. self.v_x.append(-self.v_x[-1])
  9. break

当然,对于该问题同样可以一开始就采用小步长,但这样无疑会加大计算量,当程序越来越长时会严重拖慢计算速度,在本次作业的最终程序面前,我的计算机已经出现了卡顿,不得不缩减步长,若一开始就采用高精度,则结果一定是大大拖慢程序进程,因此对这种算法不予考虑
同时,我们可以检验程序的精度,即将出射点改为(0,0),出射角为,若精度较高,则仅有一条直线,如图:
image_1b1u5i2m31mgd13mfcnfovs1r2a1d.png-42.7kB
亦或进行局部放大,以球形边界为例(注意由于放大后出现失真,表现的似乎不满足反射定律):
figure_1-15.png-37.3kB
综上可见我们的精度还是比较高的

2. 程序报错
在编写过程中常会弹出此类错误:
image_1b1u5rqj810t11d0gac48221su71h.png-1.6kB
此类错误非常容易出现,而产生的原因也很简单,是由于两变量字符串内所含元素的数量不相等,因此当给一个元素添加新的元素时,要注意另一坐标轴变量元素的添加

3. 进一步的探讨
其实我们还可以使用Vpython进行编写,从而更直观的看到小球的运动情况,
程序如下:

  1. from visual import *
  2. side = 4.0
  3. thk = 0.3
  4. s2 = 2*side - thk
  5. s3 = 2*side + thk
  6. wallR = box (pos=( side, 0, 0), size=(thk, s2, s3), color = color.red)
  7. wallL = box (pos=(-side, 0, 0), size=(thk, s2, s3), color = color.red)
  8. wallB = box (pos=(0, -side, 0), size=(s3, thk, s3), color = color.blue)
  9. wallT = box (pos=(0, side, 0), size=(s3, thk, s3), color = color.blue)
  10. ball = sphere(pos=(0.2,0,0), color=color.red, radius = 0.4, make_trail=True, retain=200)
  11. ball.trail_object.radius = 0.05
  12. ball.v = vector(0.5,0.3,0)
  13. side = side - thk*0.5 - ball.radius
  14. dt = 0.5
  15. t=0.0
  16. while True:
  17. rate(100)
  18. t = t + dt
  19. ball.pos = ball.pos + ball.v*dt
  20. if not (side > ball.x > -side):
  21. ball.v.x = -ball.v.x
  22. if not (side > ball.y > -side):
  23. ball.v.y = -ball.v.y

结果如下图所示:
捕获 09.gif-592.8kB
当然,我们也可让小球在三面上碰撞
捕获 10~1.gif-508kB

鸣谢

张梓桐同学帮助纠正了程序在反射运动部分的小bug

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注