[关闭]
@wudawufanfan 2016-10-23T04:33:25.000000Z 字数 12835 阅读 512

Precise striking problem

Introduction

Generalize the program developed for the trajectory of our cannon shell including both air drag and the reduced air density under adiabatic approximation with different firing angles.The target is higher or lower than the cannon.We can also investigate how the minimum firing velocity required to hit the target varies.


Text

The first problem is how to use a constant velocity to hit target at different height.We can still use V=700m/s to test. The principle mentality is to use Euler method.

If we add other forces like drog force,then



We can use the method of scattering the angle to find the most suitable point which is closest to the target.The smaller the angle is changed each time,the better the result is.
The folowing is the code.

  1. import math # import packages
  2. import pylab as pl
  3. import numpy as np
  4. # class PROJECTILE solves for projectile motion with air resistance
  5. # where :
  6. # x0, y0 : the connon's coordinates
  7. # v0, theta0 : shell's initial velocity and angle
  8. # B_m, a, alpha, T0 : coefficient of air resistance
  9. # g, dt: gravity acceleration and compute step size
  10. class PROJECTILE(object):
  11. def __init__(self,_x0,_y0,_v0,_theta0,_B_m,_a,_alpha,_T0,_g,_dt):
  12. self.x= [float(_x0)]
  13. self.y= [float(_y0)]
  14. self.vx= _v0*math.cos(_theta0)
  15. self.vy= _v0*math.sin(_theta0)
  16. self.v0, self.theta0= _v0, _theta0
  17. self.v= _v0
  18. self.B= float(_B_m)
  19. self.a, self.alpha, self.T0= float(_a), float(_alpha), float(_T0)
  20. self.g=_g
  21. self.dt= float(_dt)
  22. def calculate(self):
  23. while True :
  24. if self.y[-1]<-1E-4 :
  25. self.yi= self.y[-1]+self.vy*self.dt
  26. self.xi= self.x[-1]+self.vx*self.dt
  27. self.gama= -self.y[-1]/self.yi
  28. self.x.append((self.x[-1]+self.gama*self.xi)/(self.gama+1.))
  29. self.y.append(0.)
  30. break
  31. self.x.append(self.vx*self.dt+self.x[-1])
  32. self.y.append(self.vy*self.dt+self.y[-1])
  33. self.vx= -self.B*((1-self.a*self.y[-2]/self.T0)**self.alpha)\
  34. *self.vx*self.v*self.dt+self.vx
  35. self.vy= -self.B*((1-self.a*self.y[-2]/self.T0)**self.alpha)\
  36. *self.vy*self.v*self.dt+self.vy-self.g*self.dt
  37. self.v= math.sqrt(self.vx**2+self.vy**2)
  38. def store_max(self,x,v,theta): # store the max range and theta and v0
  39. x.append(self.x[-1])
  40. v.append(self.v0)
  41. theta.append(self.theta0)
  42. def plot(self): # plot the trace of the projectile
  43. pl.plot(self.x,self.y,'--')
  44. pl.annotate(r'$\theta$'+'= '+'%.2f'%(self.theta0*180./np.pi)+r'$^{o}$',
  45. xy=(7000,18000),fontsize=18)
  46. pl.annotate(r'$v_{0}$'+'= '+'%.2f'%self.v0+r'm/s',xy=(7000,16000),fontsize=18)
  47. pl.annotate('start y= %.2f m'%self.y[0],xy=(7000,14000),fontsize=18)
  48. # class TARGET give the minimun seperation of a given orbit
  49. # where :
  50. # x_target, y_target : the target's coordinates
  51. class TARGET(PROJECTILE):
  52. def reinit(self,_x_target,_y_target):
  53. self.x_target= _x_target
  54. self.y_target= _y_target
  55. def deviation(self):
  56. self.devi= np.sqrt((np.array(self.x)-self.x_target)**2+(np.array(self.y)-self.y_target)**2)
  57. self.devi= [min(self.devi),self.v0,self.theta0,self.x[0],self.y[0],\
  58. self.x_target,self.y_target]
  59. return self.devi
  60. # class TARGET_PLUS re-solves for the orbit of a given initial state and target
  61. # it will stop once it attack the target
  62. # where :
  63. # x_target, y_target : the target's coordinates
  64. class TARGET_PLUS(PROJECTILE):
  65. def reinit(self,_x_target,_y_target,_len):
  66. self.x_target= _x_target
  67. self.y_target= _y_target
  68. self.len= _len
  69. def calculate(self):
  70. while True :
  71. if math.sqrt((self.x[-1]-self.x_target)**2+(self.y[-1]-self.y_target)**2)<2*self.len \
  72. or self.y[-1]<-1E-4 :
  73. break
  74. self.x.append(self.vx*self.dt+self.x[-1])
  75. self.y.append(self.vy*self.dt+self.y[-1])
  76. self.vx= -self.B*((1-self.a*self.y[-2]/self.T0)**self.alpha)\
  77. *self.vx*self.v*self.dt+self.vx
  78. self.vy= -self.B*((1-self.a*self.y[-2]/self.T0)**self.alpha)\
  79. *self.vy*self.v*self.dt+self.vy-self.g*self.dt
  80. self.v= math.sqrt(self.vx**2+self.vy**2)
  81. def findextreme(to_find) : # to find the maximum and minimum of a table
  82. maxvalue, maxposition= 0, 0
  83. minvalue, minposition= 10**9, 0
  84. for i in range(len(to_find)):
  85. if to_find[i]>maxvalue:
  86. maxvalue= to_find[i]
  87. maxposition= i
  88. if to_find[i]<minvalue:
  89. minvalue= to_find[i]
  90. minposition= i
  91. return minposition
  92. # class PROPER_ANGEL give the proper initial angle to attack the target
  93. # initial velocity should be given
  94. # where :
  95. # x_target, y_target : the target's coordinates
  96. # x0, y0 : the connon's coordinates
  97. # v0, theta0 : shell's initial velocity and angle
  98. # B_m, a, alpha, T0 : coefficient of air resistance
  99. # g, dt, eps: gravity acceleration, compute step size, compute tolerant error
  100. class PROPER_ANGLE(object):
  101. def __init__(self,_up,_low,_n,_v0,_eps):
  102. self.up= _up
  103. self.low= _low
  104. self.n= float(_n)
  105. self.v0= _v0
  106. self.minlen= []
  107. self.theta= []
  108. self.eps =float(_eps)
  109. def calculate(self,_x0,_y0,_v0,_B_m,_a,_alpha,_T0,_g,_dt,_x_target,_y_target) :
  110. j = 1
  111. while True: # use iteration to give the angle that will attack the target
  112. print ('loop j= ',j)
  113. self.set_range= np.linspace(self.low, self.up, self.n)
  114. for i in range(len(self.set_range)):
  115. self.comp= TARGET(_x0,_y0,_v0,self.set_range[i],_B_m,_a,_alpha,_T0,_g,_dt)
  116. self.comp.calculate()
  117. self.comp.reinit(_x_target,_y_target)
  118. self.devi= self.comp.deviation()
  119. self.minlen.append(self.devi[0])
  120. self.theta.append(self.devi[2])
  121. self.minposi= findextreme(self.minlen)
  122. if (abs(max(self.minlen)-min(self.minlen))< self.eps and min(self.minlen)<10.*eps) \
  123. or (j>=15): # once it is near enough to the target, loop will be stop
  124. break
  125. self.up, self.low= self.set_range[self.minposi]+(self.up-self.set_range[self.minposi])/5, \
  126. self.set_range[self.minposi]-(self.set_range[self.minposi]-self.low)/5
  127. j = j+1
  128. self.minlen, self.theta=[], []
  129. return self.minlen[self.minposi],self.theta[self.minposi],max(self.minlen)-min(self.minlen)
  130. # initialize var. & para.
  131. # where :
  132. # x0, y0 : the connon's coordinates
  133. # v0, theta0 : shell's initial velocity and angle
  134. # B_m, a, alpha, T0 : coefficient of air resistance
  135. # g, dt, eps: gravity acceleration, compute step size, computational tolerant error
  136. # xtar, ytar: target's coordinates
  137. x0, y0= 0., [1000,2000,5000]
  138. v0= 700.
  139. B_m, a, alpha, T0, g= 4E-5, 6.5E-3, 2.5, 25.+273.5, 9.8
  140. dt= 0.5
  141. up, low= np.pi*44/90, np.pi/90
  142. n= 30
  143. eps= 0.1
  144. xtar= [10000,10000,10000]
  145. ytar= [5000,5000,5000]
  146. # give the figure with different initialization :
  147. # velocity: fixed
  148. # connon's height, target's position: variable
  149. figure= pl.figure(figsize=(15,5))
  150. pl.subplot(1,3,1)
  151. pl.ylabel('y (m)',fontsize=18)
  152. for i in range(3):
  153. minlen,v,theta=0,v0,0
  154. pro = PROPER_ANGLE(up, low, n, v0, eps)
  155. minlen,theta,delta= pro.calculate(x0,y0[i],v0,B_m,a,alpha,T0,g,dt,xtar[i],ytar[i])
  156. print( minlen,'m ',theta*180/np.pi,'degree ',delta,'m ')
  157. pro= TARGET_PLUS(x0,y0[i],v,theta,B_m,a,alpha,T0,g,dt)
  158. pro.reinit(xtar[i],ytar[i],minlen)
  159. pro.calculate()
  160. pl.subplot(1,3,i+1)
  161. pro.plot()
  162. pl.annotate(r'target',xy=(xtar[i],ytar[i]),xytext=(+5, +15),
  163. textcoords='offset points',fontsize=25)
  164. pl.scatter([xtar[i]],[ytar[i]],100,color= 'red')
  165. pl.xlim(0,32000)
  166. pl.ylim(0,23000)
  167. pl.xlabel('x (m)',fontsize=18)
  168. pl.show(figure)

QQ截图20161022184253.jpg
起始点分别在y轴1000米、2000米、5000米,打击点在(10000 5000)的三条曲线
We can also let the target is lower than the firing point.
QQ截图20161022202058.jpg
(The target is 2000m below the firing point)
Now we tend to find the smallest velocity.
As we know,the target is changed by x-coordinate and y-coordinate.Correspondingly,we should scatter the angle and the velocity to let cannon shell hit the target.

  1. import math # import packages
  2. import pylab as pl
  3. import numpy as np
  4. # class PROJECTILE solves for projectile motion with air resistance
  5. # where :
  6. # x0, y0 : the connon's coordinates
  7. # v0, theta0 : shell's initial velocity and angle
  8. # B_m, a, alpha, T0 : coefficient of air resistance
  9. # g, dt: gravity acceleration and compute step size
  10. class PROJECTILE(object):
  11. def __init__(self,_x0,_y0,_v0,_theta0,_B_m,_a,_alpha,_T0,_g,_dt):
  12. self.x= [float(_x0)]
  13. self.y= [float(_y0)]
  14. self.vx= _v0*math.cos(_theta0)
  15. self.vy= _v0*math.sin(_theta0)
  16. self.v0, self.theta0= _v0, _theta0
  17. self.v= _v0
  18. self.B= float(_B_m)
  19. self.a, self.alpha, self.T0= float(_a), float(_alpha), float(_T0)
  20. self.g=_g
  21. self.dt= float(_dt)
  22. def calculate(self):
  23. while True :
  24. if self.y[-1]<-1E-4 :
  25. self.yi= self.y[-1]+self.vy*self.dt
  26. self.xi= self.x[-1]+self.vx*self.dt
  27. self.gama= -self.y[-1]/self.yi
  28. self.x.append((self.x[-1]+self.gama*self.xi)/(self.gama+1.))
  29. self.y.append(0.)
  30. break
  31. self.x.append(self.vx*self.dt+self.x[-1])
  32. self.y.append(self.vy*self.dt+self.y[-1])
  33. self.vx= -self.B*((1-self.a*self.y[-2]/self.T0)**self.alpha)\
  34. *self.vx*self.v*self.dt+self.vx
  35. self.vy= -self.B*((1-self.a*self.y[-2]/self.T0)**self.alpha)\
  36. *self.vy*self.v*self.dt+self.vy-self.g*self.dt
  37. self.v= math.sqrt(self.vx**2+self.vy**2)
  38. def store_max(self,x,v,theta): # store the max range and theta and v0
  39. x.append(self.x[-1])
  40. v.append(self.v0)
  41. theta.append(self.theta0)
  42. def plot(self): # plot the trace of the projectile
  43. pl.plot(self.x,self.y,'--')
  44. pl.annotate(r'$\theta$'+'= '+'%.2f'%(self.theta0*180./np.pi)+r'$^{o}$',
  45. xy=(5000,18000),fontsize=15)
  46. pl.annotate(r'$v_{0}$'+'= '+'%.2f'%self.v0+r'm/s',xy=(5000,16000),fontsize=15)
  47. pl.annotate('with radii error 40m',xy=(5000,14000),fontsize=15)
  48. # class TARGET give the minimun seperation of a given orbit
  49. # where :
  50. # x_target, y_target : the target's coordinates
  51. class TARGET(PROJECTILE):
  52. def reinit(self,_x_target,_y_target):
  53. self.x_target= _x_target
  54. self.y_target= _y_target
  55. def deviation(self):
  56. self.devi= np.sqrt((np.array(self.x)-self.x_target)**2+(np.array(self.y)-self.y_target)**2)
  57. self.devi= [min(self.devi),self.v0,self.theta0,self.x[0],self.y[0],\
  58. self.x_target,self.y_target]
  59. return self.devi
  60. # class TARGET_PLUS re-solves for the orbit of a given initial state and target
  61. # it will stop once it attack the target
  62. # where :
  63. # x_target, y_target : the target's coordinates
  64. class TARGET_PLUS(PROJECTILE):
  65. def reinit(self,_x_target,_y_target,_len):
  66. self.x_target= _x_target
  67. self.y_target= _y_target
  68. self.len= _len
  69. def calculate(self):
  70. while True :
  71. if math.sqrt((self.x[-1]-self.x_target)**2+(self.y[-1]-self.y_target)**2)<2*self.len \
  72. or self.y[-1]<-1E-4 :
  73. break
  74. self.x.append(self.vx*self.dt+self.x[-1])
  75. self.y.append(self.vy*self.dt+self.y[-1])
  76. self.vx= -self.B*((1-self.a*self.y[-2]/self.T0)**self.alpha)\
  77. *self.vx*self.v*self.dt+self.vx
  78. self.vy= -self.B*((1-self.a*self.y[-2]/self.T0)**self.alpha)\
  79. *self.vy*self.v*self.dt+self.vy-self.g*self.dt
  80. self.v= math.sqrt(self.vx**2+self.vy**2)
  81. def findextreme(to_find) : # to find the maximum and minimum of a table
  82. maxvalue, maxposition= 0, 0
  83. minvalue, minposition= 10**9, 0
  84. for i in range(len(to_find)):
  85. if to_find[i]>maxvalue:
  86. maxvalue= to_find[i]
  87. maxposition= i
  88. if to_find[i]<minvalue:
  89. minvalue= to_find[i]
  90. minposition= i
  91. return minposition
  92. # class PROPER_ANGEL give the proper initial angle to attack the target
  93. # initial velocity should be given
  94. # where :
  95. # x_target, y_target : the target's coordinates
  96. # x0, y0 : the connon's coordinates
  97. # v0, theta0 : shell's initial velocity and angle
  98. # B_m, a, alpha, T0 : coefficient of air resistance
  99. # g, dt, eps: gravity acceleration, compute step size, compute tolerant error
  100. class PROPER_ANGLE(object):
  101. def __init__(self,_up,_low,_n,_v0,_eps):
  102. self.up= _up
  103. self.low= _low
  104. self.n= float(_n)
  105. self.v0= _v0
  106. self.minlen= []
  107. self.theta= []
  108. self.eps =float(_eps)
  109. def calculate(self,_x0,_y0,_v0,_B_m,_a,_alpha,_T0,_g,_dt,_x_target,_y_target) :
  110. j = 1
  111. while True: # use iteration to give the angle that will attack the target
  112. self.set_range= np.linspace(self.low, self.up, self.n)
  113. for i in range(len(self.set_range)):
  114. self.comp= TARGET(_x0,_y0,_v0,self.set_range[i],_B_m,_a,_alpha,_T0,_g,_dt)
  115. self.comp.calculate()
  116. self.comp.reinit(_x_target,_y_target)
  117. self.devi= self.comp.deviation()
  118. self.minlen.append(self.devi[0])
  119. self.theta.append(self.devi[2])
  120. self.minposi= findextreme(self.minlen)
  121. if (abs(max(self.minlen)-min(self.minlen))< self.eps and min(self.minlen)<10.*eps) \
  122. or (j>=15): # once it is near enough to the target, loop will be stop
  123. break
  124. self.up, self.low= self.set_range[self.minposi]+(self.up-self.set_range[self.minposi])/5, \
  125. self.set_range[self.minposi]-(self.set_range[self.minposi]-self.low)/5
  126. j = j+1
  127. self.minlen, self.theta=[], []
  128. return self.minlen[self.minposi],self.theta[self.minposi],max(self.minlen)-min(self.minlen)
  129. # initialize var. & para.
  130. # where :
  131. # x0, y0 : the connon's coordinates
  132. # v0, theta0 : shell's initial velocity and angle
  133. # B_m, a, alpha, T0 : coefficient of air resistance
  134. # g, dt, eps: gravity acceleration, compute step size, computational tolerant error
  135. # xtar, ytar: target's coordinates
  136. x0, y0= 0., 1.
  137. v0= 100.
  138. B_m, a, alpha, T0, g= 4E-5, 6.5E-3, 2.5, 25.+273.5, 9.8
  139. dt= 0.5
  140. up, low= np.pi*44/90, np.pi/90
  141. n= 30
  142. eps= 0.1
  143. xtar= 20000
  144. ytar= 5000
  145. # give the figure that plot the shell to attack the target
  146. figure= pl.figure(figsize=(7,5))
  147. pl.ylabel('y (m)',fontsize=15)
  148. pl.xlabel('x (m)',fontsize=15)
  149. pl.xlim(0,30000)
  150. pl.ylim(0,20000)
  151. minlen_t= []
  152. v_t= []
  153. theta_t= []
  154. for i in range(0,1000,10):
  155. minlen,v,theta=0,v0+i*1.,0
  156. print( 'v = ','%.2f'%v)
  157. pro = PROPER_ANGLE(up, low, n, v, eps)
  158. minlen,theta,delta= pro.calculate(x0,y0,v,B_m,a,alpha,T0,g,dt,xtar,ytar)
  159. minlen_t.append(minlen)
  160. v_t.append(v)
  161. theta_t.append(theta)
  162. minlen = 10**9
  163. v = 10**9
  164. theta=0
  165. for i in range(len(v_t)):
  166. if minlen_t[i]<40 and v_t[i]<v :
  167. minlen, v, theta= minlen_t[i], v_t[i], theta_t[i]
  168. print ('v= %.2f'%v,' theta= %.2f degree'%(theta*180/np.pi))
  169. pro= TARGET_PLUS(x0,y0,v,theta,B_m,a,alpha,T0,g,dt)
  170. pro.reinit(xtar,ytar,minlen)
  171. pro.calculate()
  172. pro.plot()
  173. pl.scatter([xtar],[ytar],50)
  174. pl.annotate(r'target',xy=(xtar,ytar),xytext=(+5, +15),
  175. textcoords='offset points',fontsize=15)
  176. pl.show(figure)

QQ截图20161022195431.jpg the initial angle and velocity associated with the position of target
Input different initial place of target,we can get different angles to meet the need of minimum firing velocity.
QQ截图20161022205917.jpg         the target is at(15000,15000)

Further discussion

add the head-on resistance.
This problem is changed into a systerm with different initial velocity along the x-coordinate.Different velocity may have a different result.

Conclusion

We can use this method to solve the practical problems about projectile problem.

Thanks

Cheng Yy's code with my debug and his suggestion.

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