Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
弹丸直线运动的Python动画_Python_Matplotlib_Animation_Physics_Projectile - Fatal编程技术网

弹丸直线运动的Python动画

弹丸直线运动的Python动画,python,matplotlib,animation,physics,projectile,Python,Matplotlib,Animation,Physics,Projectile,目标是设置/模拟喷水装置的动画。基本思想是在一个实例中创建多个液滴,每个液滴以不同的角度离开喷水装置。 然而,我得到的不是一个移动的点,而是一条直线,静态的线。我试过同样的代码,只有一个或两个滴/点,但我仍然得到相同的直线。起初我认为这是因为我在动画中加入了阻力(在以前的试验中,当我加入阻力时,我得到了奇怪/意外的结果,所以我希望这是相同的问题) 下面是我写的代码 编辑:dragx和dragy不再设置为相同的值。初始速度是在更新函数之外计算的 由于阻力取决于速度,因此每次索引增加时都会重新计算阻

目标是设置/模拟喷水装置的动画。基本思想是在一个实例中创建多个液滴,每个液滴以不同的角度离开喷水装置。 然而,我得到的不是一个移动的点,而是一条直线,静态的线。我试过同样的代码,只有一个或两个滴/点,但我仍然得到相同的直线。起初我认为这是因为我在动画中加入了阻力(在以前的试验中,当我加入阻力时,我得到了奇怪/意外的结果,所以我希望这是相同的问题)

下面是我写的代码

编辑:dragx和dragy不再设置为相同的值。初始速度是在更新函数之外计算的

由于阻力取决于速度,因此每次索引增加时都会重新计算阻力

进口品现在也包括在内

我现在也尝试使用散点图而不是直线,它在原点给了我一个点。从那时起,我又回到了台词上

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from mpl_toolkits.mplot3d import Axes3D 
import matplotlib.animation as animation
from math import sin, cos
import matplotlib.axes as axess

#pressure in system
def pressure(pump):
    return 10.197*pump*10**5/998.2

#Initial velocity based on the pressure of the system
def vinit(init_head):
    return (2*9.81*init_head)**0.5
# Number of droplets per iteration
n = 2
v0 = vinit(pressure(5.8))
cd = 0.5                                             #drag coefficient of a sphere;   
rho = 1.225                                          #density of air;                 kg/m^3

fps = 20
runtime = 1*20
numframes = fps*runtime
time = np.linspace(0,runtime,numframes)

#Initialize droplets

droplets = np.zeros(numframes, dtype = [('position', float, 2),
                                ('velocity', float, 2),
                                ('force', float, 2),
                                ('angle',float, 1),
                                ('radius', float, 1)])

droplets['radius'] = np.random.normal(0.0045, 0.001, numframes)
A = 4*np.pi*droplets['radius']**2
mass = ((4*np.pi*droplets['radius']**3)/3)*1000     #mass of waterdroplet
drag = np.zeros(numframes,dtype = [('dragx', float, 1),('dragy', float, 1)])

rads = np.radians(np.random.normal(37,1,numframes))
droplets['angle'] = rads
droplets['force'][:,1] = -9.8*mass

#Initialize velocity
for i in range(0, numframes):
    droplets['velocity'][i,0] = v0*cos(droplets['angle'][i])
    droplets['velocity'][i,1] = v0*sin(droplets['angle'][i])    

#Initialize the drag
drag['dragx'] = -0.5*rho*cd*A*droplets['velocity'][:,0]
drag['dragy'] = -0.5*rho*cd*A*droplets['velocity'][:,1]


droplets['position'][:,0] = 0


#Initialize the figure
fig,ax = plt.subplots()
axess.Axes.set_frame_on(ax,True)
ax.autoscale(True)
ax.set_xlim(0)
ax.set_ylim(0)

line = ax.plot(droplets['position'][0, 0], droplets['position'][0, 1],'b.')[0]
line = ax.plot(droplets['position'][:, 0], droplets['position'][:, 1],'b.')[0]
xdata = [droplets['position'][0, 0]]
ydata = [droplets['position'][0, 1]]
ln = plt.plot([],[],'b')[0]

def initfunc():
    droplets['position'][0,:] = 0
    ln.set_data(droplets['position'][0, 0], droplets['position'][0, 1])
    return ln

def update(framenum):
    index = framenum
    cd = 0.5                                          #drag coefficient of a sphere;   
    rho = 1.225                                       #density of air;                 kg/m^3
    A = 4*np.pi*droplets['radius']**2                 #surface area of droplet;        m^2
    mass = ((4*np.pi*droplets['radius']**3)/3)*1000   #mass of waterdroplet

    #Update the drag force on the droplet
    drag['dragx'] = -0.5*rho*cd*A*droplets['velocity'][:,0]
    drag['dragy'] = -0.5*rho*cd*A*droplets['velocity'][:,1]

    droplets['force'][index,0] += drag['dragx'][index]
    droplets['force'][index,1] += drag['dragy'][index]
    #droplets['position'][0] = [0,0]
    droplets['velocity'][index,0] = droplets['velocity'][index,0] + (droplets['force'][index,0]/mass[index])*index
    droplets['velocity'][index,1] = droplets['velocity'][index,1] + (droplets['force'][index,1]/mass[index])*index
    droplets['position'][index,0] = droplets['position'][index,0] + (droplets['velocity'][index,0])*index  
    droplets['position'][index,1] = droplets['position'][index,1] + (droplets['velocity'][index,1])*index  

    xdata.append(droplets['position'][index,0])
    ydata.append(droplets['position'][index,1])
    ln.set_data(xdata,ydata)

    line.set_data(droplets['position'][:,0], droplets['position'][:,1])

    return ln



sprink = animation.FuncAnimation(fig, update,init_func = initfunc,interval= 200,  frames = numframes)
plt.show()

sprink.save('Sprinkler.mp4', fps = fps)

除了所指出的错误,您使用的是水滴(近似为球体)的表面积(
4*pi*r^2
)而不是横截面积(
pi*r^2
)。此外,你们似乎在尝试使用假设真空的运动方程,当空气阻力或其他非恒定力增加时,这些方程就失效了

我建议你们阅读关于计算空气阻力下弹道弹丸运动的更完整解释,但这里是一个简化版本

计算粒子在介质中运动的位置实质上就是求解一个方程,数值求解这样一个方程的方法有很多种。最简单(尽管最不可靠)的方法是将问题分成几个小部分,并将当前点到下一点的变化进行近似。对于这个问题,假设您使用足够小的时间步长,那么这种方法工作得相当好

在你的情况下,我们可以这样做

import matplotlib
import matplotlib.pyplot as plt
from matplotlib import animation
import numpy as np
from math import sin, cos

g = 9.81
rho = 1.225
v0 = 50.0    # This can be initialized as desired, I chose 50 m/s for demonstration
C = 0.5

nframes = 100
ndrops = 10
tend = 8.0
time = np.linspace(0.1, tend, nframes)   # Runtime of 4s chosen arbitrarily
dt = time[1] - time[0]                    # change in time between steps
maxs = [0.0, 0.0]
r = [0.001, 0.0045]                       # This stores the range of radii to be used

# I have implemented a class to store the drops for brevity
class drop:

    def __init__(self, pos, vel, r):
        self.pos = pos
        self.vel = vel
        self.r = r

class sprinkler:
# I implemented this as a class to simplify updating the scatter plot
    def __init__(self):
        self.fig, self.ax = plt.subplots()
        self.drops = [None]*ndrops
        self.maxt = 0.0
        ## This step is simply to figure out how far the water drops can travel
        ## in order to set the bounds of the plot accordingly
        angles = np.linspace(0, np.pi/2, 90)    # We only need to sample from 0 to pi/2
        for angle in angles:
            m = [drop([0.0, 0.1], [v0*cos(angle), v0*sin(angle)], 0.001),
                 drop([0.0, 0.1], [v0*cos(angle), v0*sin(angle)], 0.0045)]
            for d in m:
                t = 0.0
                coef = - 0.5*C*np.pi*d.r**2*rho
                mass = 4/3*np.pi*d.r**3*1000
                while d.pos[1] > 0:
                    a = np.power(d.vel, 2) * coef * np.sign(d.vel)/mass
                    a[1] -= g
                    d.pos += (d.vel + a * dt) * dt
                    d.vel += a * dt
                    t += dt
                    if d.pos[1] > maxs[1]:
                        maxs[1] = d.pos[1]
                    if d.pos[0] > maxs[0]:
                        maxs[0] = d.pos[0]
                    if d.pos[1] < 0.0:
                        if t > self.maxt:
                            self.maxt = t
                        break
        for ii in range(ndrops):    # Make some randomly distributed water drops
            self.drops[ii] = drop([0.0, 0.0], [cos(np.random.random()*np.pi)*v0,
                             sin(np.random.random()*np.pi)*v0],
                             np.random.random()*(r[1]-r[0]) + r[0])

        anim = animation.FuncAnimation(self.fig, self.update, init_func=self.setup,
                                       interval=200, frames=nframes)
        anim.save('Sprinkler.gif', fps = 20, writer='imagemagick')

    def setup(self):
        self.scat = self.ax.scatter([d.pos[0] for d in self.drops],
                               [d.pos[1] for d in self.drops], marker='.', color='k')
        self.ax.set_xlim([-maxs[0]*1.15, maxs[0]*1.15])
        self.ax.set_ylim([0, maxs[1]*1.15])

        return self.scat,

    def update(self,frame):  # Use set_offsets to move the water drops
        self.step()          # Advance to the next 'step'
        self.scat.set_offsets(np.stack([[d.pos[0] for d in self.drops],
                                       [d.pos[1] for d in self.drops]], 1))

        return self.scat,

    def step(self):
        for ii in range(ndrops):
            coef = - 0.5*C*np.pi*self.drops[ii].r**2*rho    # Aggregated coefficient
            mass = 4/3*np.pi*self.drops[ii].r**3*1000
            a = np.power(self.drops[ii].vel, 2)*coef * np.sign(self.drops[ii].vel)/mass
            a[1] -= g
            # Approximate how much the position and velocity would change if we assume
            # a(t) does not change between t and t+dt
            self.drops[ii].pos += np.array(self.drops[ii].vel) * dt + 0.5 * a * dt**2
            self.drops[ii].vel += a * dt
            if self.drops[ii].pos[1] < 0.0:     # Check if the drop has hit the ground
                self.drops[ii].pos[1] = 0.0
                self.drops[ii].vel = [0.0, 0.0]

sprinkler()

编辑-生成第二个动画的整个代码
导入matplotlib
将matplotlib.pyplot作为plt导入
从matplotlib导入动画
将numpy作为np导入
从数学输入罪恶,因为
g=9.81
rho=1.225
v0=50.0#这可以根据需要进行初始化,我选择50 m/s进行演示
C=0.5
n帧=100
ndrops=10
倾向=8.0
时间=np.linspace(0.1,趋势,n帧)#任意选择的4s运行时
dt=时间[1]-时间[0]#步骤之间的时间变化
最大值=[0.0,0.0]
r=[0.001,0.0045]#存储要使用的半径范围
#为了简洁起见,我实现了一个类来存储滴水
下课:
定义初始值(自身、位置、级别、r):
self.pos=pos
self.vel=vel
self.r=r
洒水车等级:
#我将其实现为一个类,以简化散点图的更新
定义初始化(自):
self.fig,self.ax=plt.subplot()
self.drops=[None]*ndrops
self.maxt=0.0
##这一步只是为了计算水滴可以移动多远
##以便相应地设置绘图的边界
角度=np.linspace(0,np.pi/2,90)#我们只需要从0到pi/2进行采样
对于角度中的角度:
m=[压降([0.0,0.1],[v0*cos(角度),v0*sin(角度)],0.001),
下降([0.0,0.1],[v0*cos(角度),v0*sin(角度)],0.0045)]
以m表示的d:
t=0.0
系数=-0.5*C*np.pi*d.r**2*rho
质量=4/3*np.pi*d.r**3*1000
当d.pos[1]>0时:
a=净功率(d级,2)*系数*净符号(d级)/质量
a[1]=g
d、 位置+=(d.vel+a*dt)*dt
d、 vel+=a*dt
t+=dt
如果d.pos[1]>maxs[1]:
maxs[1]=d.pos[1]
如果d.pos[0]>maxs[0]:
maxs[0]=d.pos[0]
如果d.pos[1]<0.0:
如果t>self.maxt:
self.maxt=t
打破
对于射程内的ii(ndrops):#制造一些随机分布的水滴
自下降[ii]=下降([0.0,0.0],[cos(np.random.random()*np.pi)*v0,
sin(np.random.random()*np.pi)*v0],
np.random.random()*(r[1]-r[0])+r[0])
anim=animation.FuncAnimation(self.fig、self.update、init_func=self.setup、,
间隔=200,帧=n帧)
动画保存('sprayer.gif',fps=20,writer='imagemagick')
def设置(自):
self.scat=self.ax.scatt([d.pos[0]表示自降中的d],
[d.pos[1]表示自投中的d],标记='',颜色='k')
self.ax.set_xlim([-maxs[0]*1.15,maxs[0]*1.15])
self.ax.set_ylim([0,maxs[1]*1.15])
返回self.scat,
def更新(自身,帧):#使用设置偏移移动水滴
#创建介于0和ndrops之间的新放置,但仅在tend maxt之前创建
如果时间[帧]    def update(self,frame):  # Use set_offsets to move the water drops
        # Create between 0 and ndrops new drops, but only until tend-maxt
        if time[frame] < tend - self.maxt*1.1:
            self.create(np.random.randint(0, ndrops))
        self.step()          # Advance to the next 'step'
        self.scat.set_offsets(np.stack([[d.pos[0] for d in self.drops],
                                        [d.pos[1] for d in self.drops]], 1))

        return self.scat,

    def create(self, i):
        for ii in range(i):
            self.drops.append(drop([0.0, 0.0], [cos(np.random.random()*np.pi)*v0,
                             sin(np.random.random()*np.pi)*v0],
                             np.random.random()*(r[1]-r[0]) + r[0]))