[关闭]
@wudawufanfan 2016-11-20T14:15:57.000000Z 字数 10457 阅读 741

The billiard problem

未分类


Introduction

A ball moving without friction on a horizontal table and imagine that there are walls at the edges of the table that reflect the ball perfectly and that there is no frictional force between the ball and the table.The ball is given some initial velocity,and we are to calculate and understand the resulting trajectory.This is konwn as the stadium billiard problem.

Text

1、

Except for the collisions with the walls,the motion of the billiard is quite simple.Between collisions the velocity is constant so we have


and the Euler solution gives an exact description of the motion across the table.Now we tend to the calculation for the the collisions


Once we have the components of we can reflect the billiard.A mirrorlike reflection reverses the perpendicular component of velocity,but leaves the parallel component unchanged.Hence,the velocity after reflection from the wall is

2、The trajectory of a billiard on a square table and the corresponding phase-space plots of versus x.

Firstly,consider a square table with a circular interior wall located in the center and a elliptical-bounded boundary.

  1. from numpy import *
  2. import matplotlib.pyplot as plt
  3. # class: BILLIARD solves for a stadium-shaped boundary
  4. # where:
  5. # x0, y0, vx0, vy0: initial position of billiard
  6. # dt, time : time step and total time
  7. # alpha: the length cube region
  8. class BILLIARD(object):
  9. def __init__(self,_alpha=0.,_r=1.,_x0=0.2,_y0=0.,_vx0=0.6,_vy0=0.8,_dt=0.001,_time=300):
  10. self.alpha, self.r, self.dt, self.time, self.n = _alpha, _r, _dt, _time, int(_time/_dt)
  11. self.x, self.y, self.vx, self.vy = [_x0], [_y0], [_vx0], [_vy0]
  12. def cal(self): # use Euler method to solve billiard motion
  13. for i in range(self.n):
  14. self.nextx = self.x[-1]+self.vx[-1]*self.dt
  15. self.nexty = self.y[-1]+self.vy[-1]*self.dt
  16. self.nextvx, self.nextvy = self.vx[-1], self.vy[-1]
  17. if (self.nexty>self.alpha*self.r and self.nextx**2+(self.nexty-self.alpha*self.r)**2>self.r**2) \
  18. or (self.nexty<-self.alpha*self.r and self.nextx**2+(self.nexty+self.alpha*self.r)**2>self.r**2) \
  19. or (self.nextx>self.r) \
  20. or (self.nextx<-self.r):
  21. self.nextx=self.x[-1]
  22. self.nexty=self.y[-1]
  23. while not( \
  24. (self.nexty>self.alpha*self.r and self.nextx**2+(self.nexty-self.alpha*self.r)**2>self.r**2) \
  25. or (self.nexty<-self.alpha*self.r and self.nextx**2+(self.nexty+self.alpha*self.r)**2>self.r**2) \
  26. or (self.nextx>self.r) \
  27. or (self.nextx<-self.r)):
  28. self.nextx=self.nextx+self.nextvx*self.dt/100
  29. self.nexty=self.nexty+self.nextvy*self.dt/100
  30. if self.nexty>self.alpha*self.r:
  31. self.v = array([self.nextvx,self.nextvy])
  32. self.norm = 1/self.r*array([self.nextx, self.nexty-self.alpha*self.r])
  33. self.v_perpendicular = dot(self.v, self.norm)*self.norm
  34. self.v_parrallel = self.v-self.v_perpendicular
  35. self.v_perpendicular= -self.v_perpendicular
  36. self.nextvx, self.nextvy= (self.v_parrallel+self.v_perpendicular)[0],(self.v_parrallel+self.v_perpendicular)[1]
  37. elif self.nexty<-self.alpha*self.r:
  38. self.v = array([self.nextvx,self.nextvy])
  39. self.norm = 1/self.r*array([self.nextx, self.nexty+self.alpha*self.r])
  40. self.v_perpendicular = dot(self.v, self.norm)*self.norm
  41. self.v_parrallel = self.v-self.v_perpendicular
  42. self.v_perpendicular= -self.v_perpendicular
  43. self.nextvx, self.nextvy= (self.v_parrallel+self.v_perpendicular)[0],(self.v_parrallel+self.v_perpendicular)[1]
  44. else:
  45. self.nextvx, self.nextvy= -self.nextvx, self.nextvy
  46. self.x.append(self.nextx)
  47. self.y.append(self.nexty)
  48. self.vx.append(self.nextvx)
  49. self.vy.append(self.nextvy)
  50. def plot_position(self,_ax): # give trajectory plot
  51. _ax.plot(self.x,self.y,'-b',label=r'$\alpha=$'+' %.2f'%self.alpha)
  52. _ax.plot([self.r]*10,linspace(-self.alpha*self.r,self.alpha*self.r,10),'-k',lw=5)
  53. _ax.plot([-self.r]*10,linspace(-self.alpha*self.r,self.alpha*self.r,10),'-k',lw=5)
  54. _ax.plot(self.r*cos(linspace(0,pi,100)),self.r*sin(linspace(0,pi,100))+self.alpha*self.r,'-k',lw=5)
  55. _ax.plot(self.r*cos(linspace(pi,2*pi,100)),self.r*sin(linspace(pi,2*pi,100))-self.alpha*self.r,'-k',lw=5)
  56. def plot_phase(self,_ax,_secy=0): # give phase-space plot
  57. self.secy=_secy
  58. self.phase_x, self.phase_vx = [], []
  59. for i in range(len(self.x)):
  60. if abs(self.y[i]-self.secy)<1E-3 :
  61. self.phase_x.append(self.x[i])
  62. self.phase_vx.append(self.vx[i])
  63. _ax.plot(self.phase_x,self.phase_vx,'ob',markersize=2,label=r'$\alpha=$'+' %.2f'%self.alpha)
  64. # give a trajectory and phase space plot
  65. fig= plt.figure(figsize=(10,10))
  66. ax1=plt.axes([0.1,0.55,0.35,0.35])
  67. ax2=plt.axes([0.6,0.55,0.35,0.35])
  68. ax3=plt.axes([0.1,0.1,0.35,0.35])
  69. ax4=plt.axes([0.6,0.1,0.35,0.35])
  70. ax1.set_xlim(-1.1,1.1)
  71. ax2.set_xlim(-1.1,1.1)
  72. ax3.set_xlim(-1.1,1.1)
  73. ax4.set_xlim(-1.1,1.1)
  74. ax1.set_ylim(-1.1,1.1)
  75. ax2.set_ylim(-1.1,1.1)
  76. ax3.set_ylim(-1.1,1.1)
  77. ax4.set_ylim(-1.1,1.1)
  78. ax1.set_xlabel(r'$x (m)$',fontsize=18)
  79. ax1.set_ylabel(r'$y (m)$',fontsize=18)
  80. ax1.set_title('Circular stadium: trajectory',fontsize=18)
  81. ax2.set_xlabel(r'$x (m)$',fontsize=18)
  82. ax2.set_ylabel(r'$v_x (m/s)$',fontsize=18)
  83. ax2.set_title('Circular stadium: phase-space',fontsize=18)
  84. ax3.set_xlabel(r'$x (m)$',fontsize=18)
  85. ax3.set_ylabel(r'$y (m)$',fontsize=18)
  86. ax3.set_title('Billiard'+r'$\alpha=0.05$'+': trajectory',fontsize=18)
  87. ax4.set_xlabel(r'$x (m)$',fontsize=18)
  88. ax4.set_ylabel(r'$v_x (m/s)$',fontsize=18)
  89. ax4.set_title('Billiard '+r'$\alpha=0.05$'+': phase-space',fontsize=18)
  90. cmp=BILLIARD()
  91. cmp.cal()
  92. cmp.plot_position(ax1)
  93. cmp.plot_phase(ax2)
  94. cmp=BILLIARD(0.05)
  95. cmp.cal()
  96. cmp.plot_position(ax3)
  97. cmp.plot_phase(ax4)
  98. plt.show()

QQ截图20161119192920.jpg
QQ截图20161119192936.jpg

  1. from numpy import *
  2. import matplotlib.pyplot as plt
  3. # class: BILLIARD solves for a elliptical-bounded boundary
  4. # where:
  5. # x0, y0, vx0, vy0: initial position of billiard
  6. # dt, time : time step and total time
  7. class BILLIARD(object):
  8. def __init__(self,_x0=sqrt(2),_y0=0.,_vx0=0,_vy0=1,_dt=0.001,_time=500):
  9. self.dt, self.time, self.n = _dt, _time, int(_time/_dt)
  10. self.x, self.y, self.vx, self.vy = [_x0], [_y0], [_vx0], [_vy0]
  11. def cal(self): # use Euler method to solve billiard motion
  12. for i in range(self.n):
  13. self.nextx = self.x[-1]+self.vx[-1]*self.dt
  14. self.nexty = self.y[-1]+self.vy[-1]*self.dt
  15. self.nextvx, self.nextvy = self.vx[-1], self.vy[-1]
  16. if self.nextx**2/3+self.nexty**2>1:
  17. self.nextx=self.x[-1]
  18. self.nexty=self.y[-1]
  19. while not(self.nextx**2/3+self.nexty**2>1):
  20. self.nextx=self.nextx+self.nextvx*self.dt/100
  21. self.nexty=self.nexty+self.nextvy*self.dt/100
  22. self.norm=array([self.nextx,3*self.nexty])
  23. self.norm=self.norm/sqrt(dot(self.norm,self.norm))
  24. self.v=array([self.nextvx,self.nextvy])
  25. self.v_perpendicular=dot(self.v,self.norm)*self.norm
  26. self.v_parrallel=self.v-self.v_perpendicular
  27. self.v_perpendicular=-self.v_perpendicular
  28. [self.nextvx,self.nextvy]=self.v_parrallel+self.v_perpendicular
  29. self.x.append(self.nextx)
  30. self.y.append(self.nexty)
  31. self.vx.append(self.nextvx)
  32. self.vy.append(self.nextvy)
  33. def plot_position(self,_ax): # give trajectory plot
  34. _ax.plot(self.x,self.y,'-b',label='Ellipse'+r'$a=2,b=1$')
  35. _ax.plot(sqrt(3)*cos(linspace(0,2*pi,200)),sin(linspace(0,2*pi,200)),'-k',lw=5)
  36. def plot_phase(self,_ax,_secy=0): # give phase-space plot
  37. self.secy=_secy
  38. self.phase_x, self.phase_vx = [], []
  39. for i in range(len(self.x)):
  40. if abs(self.y[i]-self.secy)<1E-3 and abs(self.vx[i])<0.95:
  41. self.phase_x.append(self.x[i])
  42. self.phase_vx.append(self.vx[i])
  43. _ax.plot(self.phase_x,self.phase_vx,'ob',markersize=2,label='Ellipse'+r'$a=2,b=1$')
  44. # give a trajectory and phase space plot
  45. fig= plt.figure(figsize=(10,4))
  46. ax1=plt.axes([0.1,0.15,0.35,0.7])
  47. ax2=plt.axes([0.6,0.15,0.35,0.7])
  48. ax1.set_xlim(-2,2)
  49. ax1.set_ylim(-1.1,1.1)
  50. ax2.set_xlim(-2,2)
  51. ax2.set_ylim(-1.1,1.1)
  52. ax1.set_title('Elliptical boundary: '+r'$a^2 =3,b^2 = 1$',fontsize=18)
  53. ax2.set_title('Phase-space: '+r'$a^2 =3,b^2 = 1$',fontsize=18)
  54. ax1.set_xlabel(r'$x(m)$',fontsize=18)
  55. ax1.set_ylabel(r'$y(m)$',fontsize=18)
  56. ax2.set_xlabel(r'$x(m)$',fontsize=18)
  57. ax2.set_ylabel(r'$v_x (m/s)$',fontsize=18)
  58. cmp=BILLIARD()
  59. cmp.cal()
  60. cmp.plot_position(ax1)
  61. cmp.plot_phase(ax2)
  62. plt.show()

QQ截图20161119193336.jpg
if the shape of boundary is line,the the code for python is easy without losing generalizability.The only one need to calculate is the tranformation of velocity.Here we set four boundaries are
y(x+3)
y-(x-3)
y2.5
y0。
When x0, we only need to use the boundaries y-(x-3) and y2.5
When the particle reach the boundary -(x-3),
line y=-(x-3)'s normal unit vector is =(cos,sin), while tan=
=i+j)•(cosi+sinj)(cos,sin)
The line's direction unit vector is (cos,sin), while tan=-
=(i+j)•(cosi+sinj)(cos,sin)
so the velocity after colision is
-

  1. import numpy as np
  2. from pylab import *
  3. x=[0]
  4. y=[1]
  5. vx,vy=2.3,3
  6. time,i,dt=0,0,0.001
  7. sdt=0.00001
  8. velocity=[4]
  9. while time<=300:
  10. X=x[i]+vx*dt
  11. Y=y[i]+vy*dt
  12. if Y>0 and Y<2.5:
  13. if X>=0:
  14. if Y<-X*4.0/3.0+4:
  15. x.append(X)
  16. y.append(Y)
  17. velocity.append(vx)
  18. else:
  19. x1=x[i]+vx*sdt
  20. y1=y[i]+vy*sdt
  21. if y1<-x1*4.0/3.0+4:
  22. x.append(x1)
  23. y.append(y1)
  24. velocity.append(vx)
  25. else:
  26. char1=-vx*(9.0/41.0)-vy*(40.0/41.0)
  27. char2=-vx*(40.0/41.0)+vy*(9.0/41.0)
  28. vx=char1
  29. vy=char2
  30. x.append(x[i]+vx*sdt)
  31. y.append(y[i]+vy*sdt)
  32. velocity.append(vx)
  33. if X<0:
  34. if Y<X*4.0/3.0+4:
  35. x.append(X)
  36. y.append(Y)
  37. velocity.append(vx)
  38. else:
  39. x2=x[i]+vx*sdt
  40. y2=y[i]+vy*sdt
  41. if y2<x2*4.0/3.0+4:
  42. x.append(x2)
  43. y.append(y2)
  44. velocity.append(vx)
  45. else:
  46. char3=-vx*(9/41)+vy*(40/41)
  47. char4=vx*(40/41)+vy*(9/41)
  48. vx=char3
  49. vy=char4
  50. x.append(x[i]+vx*sdt)
  51. y.append(y[i]+vy*sdt)
  52. velocity.append(vx)
  53. if Y>=2.5:
  54. x4=x[i]+vx*sdt
  55. y4=y[i]+vy*sdt
  56. if y4<2.5:
  57. x.append(x4)
  58. y.append(y4)
  59. velocity.append(vx)
  60. else:
  61. vy=-vy
  62. x.append(x[i]+vx*sdt)
  63. y.append(y[i]+vy*sdt)
  64. velocity.append(vx)
  65. if Y<=0:
  66. x3=x[i]+vx*sdt
  67. y3=y[i]+vy*sdt
  68. if y3>0:
  69. x.append(x3)
  70. y.append(y3)
  71. velocity.append(vx)
  72. else:
  73. vy=-vy
  74. x.append(x[i]+vx*sdt)
  75. y.append(y[i]+vy*sdt)
  76. velocity.append(vx)
  77. time=time+dt
  78. i=i+1
  79. plt.figure(figsize=(16,5.5))
  80. subplot(1,2,1)
  81. plt.title("vx0=2.3,vy0=3")
  82. plt.xlabel("x")
  83. plt.ylabel("y")
  84. plt.xticks([-3,-2,-1,0,1,2,3])
  85. plt.yticks([0,1,2,3,4])
  86. plt.xlim(-3,3)
  87. plt.ylim(0,4)
  88. plt.plot([1.125,3],[2.5,0],color="blue",label="isosceles triangle",linewidth=2)
  89. plt.plot([-1.125,1.125],[2.5,2.5],color="blue",linewidth=2)
  90. plt.plot([-3,-1.125],[0,2.5],color="blue",linewidth=2)
  91. plt.plot([-3,3],[0,0],color="blue",linewidth=2)
  92. plt.plot(x,y,label="trajectory",color="red")
  93. plt.scatter(0,1,color="black",alpha=1,linewidth=4,label="initial")
  94. plt.legend()
  95. subplot(1,2,2)
  96. plt.xlabel("x")
  97. plt.ylabel("vx")
  98. for i in range(1000):
  99. if 1000*i<=len(x):
  100. plt.scatter(x[1000*i],velocity[1000*i])
  101. plt.show()

We can change the velocity to get different trajectory in which some is chaoic
QQ截图20161119222241.jpg
the velocity is vx=0,vy=2
QQ截图20161119222537.jpg
the velocity is vx=0.01,vy=2
QQ截图20161119223212.jpg
the velocity is vx=1,vy=0
QQ截图20161119223403.jpg
the velocity is vx=5,vy=4
QQ截图20161119223526.jpg
the velocity is vx=5.01,vy=4
we can see a small change to initial condition may cause big difference to trajectory.

Conclusion

For any realistically shaped container,such motion is likely to be chaotic and thus unpredictable.

Thanks

cheng yaoyang's code.
wu yuqiao's vpython.

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