用Python拖动的物理子弹立即低于零

时间:2017-11-02 23:50:13

标签: python physics

我正在编写一个程序来查找一个子弹以20度的角度射击多远,各种参数有无阻力。出于某种原因,我的程序立即计算出子弹的y值低于零,我认为这可能与我使用的物理方程有关。我没有最强大的物理背景,所以在努力弄清楚我哪里出错之后,我想我会寻求帮助。在下图中,我试图显示与不同时间步长相关的不同距离。

    import math
    import matplotlib.pyplot as plt
    rho = 1.2754
    Af = math.pi*(16*0.0254)**2/4
    g = -9.8 #m/s^2
    V = 250.0 #m/s
    #equation of motion
    def update(r,V,a,dt):
        return r+V*dt +.5*a*dt*dt, V + a*dt
    #drag force from velocity vector return x and y 
    def drag(Vx,Vy):
        Vmag = math.sqrt(Vx**2+Vy**2)
        Ff = .5*Cd*rho*Af*Vmag**2
        return -Ff * Vx/Vmag, -Ff *Vy/Vmag

    def getTrajectory(dt, th):
        #initialize problem [time,x,y,Vx,Vy]
        state = [[0.0,0.0,0.0, V*math.cos(th), V*math.sin(th)]]

        while state[-1][2] >= 0 : # while y > 0 
            time = state[-1][0] + dt
            Fd = drag(state[-1][3],state[-1][4]) # Vx,Vy
            ax = Fd[0]/m # new x acceleration
            ay = (Fd[1]/m) +g # new y acceleration

            nextX, nextVx = update(state[-1][1], state[-1][3],ax,dt)                                         #x,Vx,acceleration x, dt
            nextY, nextVy = update(state[-1][2], state[-1][4],ay,dt) #y,Vy, acceleration y, dt
            state.append([time,nextX,nextY,nextVx,nextVy])
            # linear interpolation 
            dtf = -state[-1][2]*(state[-2][0]-state[-1][0])/(state[-2][2]-state[-1][2])

            xf,vxf = update(state[-1][1],state[-1][3], ax, dtf)
            print(xf,vxf)
            yf,vyf = update(state[-1][2],state[-1][4], ay, dtf)
            print(yf,vyf)
            state[-1] = [time+dtf,xf,yf,vxf,vyf]
            return state

    delt = 0.01 #timestep
    th = 20.0 * math.pi/180.0 #changing to radians
    m = 2400 #kg

    Cd = 1.0
    tsteps = [0.001,0.01,0.1,1.0,3.0] # trying different timesteps to find the optimal one
    xdistance = [getTrajectory(tstep,th)[-1][1] for tstep in tsteps]
    plt.plot(tsteps,xdistance)
    plt.show()

状态变量的打印,包含一个时间步后的所有时间值x,y,Vx和Vy,得到:         [[0.0,0.0,0.0,234.9231551964771,85.50503583141717]        ,[0.0,0.0,-9.540979117872439e-18,234.9231551964771,85.50503583141717]] 第一个数组是初始条件,Vx和Vy分解为由20度角计算的矢量。第二个阵列的子弹应该以正x和y飞行,但由于某种原因,y值被计算为-9.54e-18,它退出了getTrajectory方法,因为它只能继续,而y> 0

为了简化我的问题,我认为专门研究我的更新功能可能会有所帮助。

    def update(initial,V,a,dt): #current x or y, Velocity in the x or y         direction, acceleration in x or y, timestep
        return initial+V*dt +.5*a*dt*dt, V + a*dt

此函数应该返回更新的x,Vx或更新的y,Vy,具体取决于传递的内容。我认为这可能是物理方程中的问题,但我并不完全确定。

2 个答案:

答案 0 :(得分:0)

我想我知道发生了什么:在你的while循环中,你首先做一个前进时间步骤来计算t = 0.001的{​​{1}}的运动变量,然后你将t = 0设置为负值,然后设置一个向后时间步,以便根据您在dtf(或其他)计算的值计算t = 0处的新值。我不确定你为什么这样做,但无论如何你的t = 0.001函数正在使用数字不稳定的Euler method - 当你采取越来越多的步骤时,它往往越来越偏离以某种不可预测的方式提供真正的解决方案。在这种情况下,它会变为负y位置,而不是像你期望的那样将其设置为0。

没有任何数值积分方法可以为您提供完美的结果,因此您总是可以期待一点点不准确,这可能是正面的或负面的。只是因为某些事情有点消极并不是必然引起关注。 (但这可能是,取决于具体情况。)话虽如此,通过使用更强大的整合方法,如Runge-Kutta 4阶(a.k.a. RK4)或辛积分器,您可以获得更好的结果。但这些都是一些先进的技术,所以我现在不会太担心它们。

至于手头的问题,我想知道你的方程中某处是否有符号错误,可能在设置update()的行中。我不能肯定地说,因为我真的不明白dtf应该如何运作。

答案 1 :(得分:0)

这似乎是一个缩进错误。从线性插值开始确定y零交叉位置的部分肯定不是集成循环的一部分,尤其不是return语句。修复此缩进级别会产生输出

(3745.3646817336303, 205.84399509886356)
(6.278677479133594e-07, -81.7511764639779)

(3745.2091465034314, 205.8432621147464)
(8.637877372419503e-05, -81.75094436152747)

(3743.6311931495325, 205.83605594288176)
(0.01056407140434586, -81.74756057157798)

(3727.977248738945, 205.75827166721402)
(0.1316764390634169, -81.72155620161116)

(3669.3437231150106, 205.73704583954634)
(10.273469073526238, -80.52193274789204)