Этот класс представляет распространяемый снаряд.
Код: Выделить всё
import numpy as np
import matplotlib.pyplot as plt
class Projectile:
def __init__(self,
m: float = None,
cal: float = None,
S: float = None,
CD0subsonic: float = None,
CD0max: float = None,
k: float = None,
) -> None:
self._m: float = m
self._cal: float = cal
self._CD0subsonic: float = CD0subsonic
self._CD0max: float = CD0max
self._k: float = k
if S is None:
self._S: float = .25 * np.pi * self._cal**2
else:
self._S: float = S
self._x: list[float] = []
self._y: list[float] = []
self._z: list[float] = []
self._pos: list[tuple[float, float, float]] = list(zip(self._x, self._y, self._z))
self._vx: list[float] = []
self._vy: list[float] = []
self._vz: list[float] = []
self._v: list[tuple[float, float, float]] = list(zip(self._vx, self._vy, self._vz))
@property
def m(self) -> float:
return self._m
@property
def cal(self) -> float:
return self._cal
@property
def CD0subsonic(self) -> float:
return self._CD0subsonic
@property
def CD0max(self) -> float:
return self._CD0max
@property
def k(self) -> float:
return self._k
@property
def S(self) -> float:
return self._S
@property
def x(self) -> list[float]:
return self._x
@x.setter
def x(self, x: float) -> None:
self._x.append(x)
@property
def y(self) -> list[float]:
return self._y
@y.setter
def y(self, y: float) -> None:
self._y.append(y)
@property
def z(self) -> list[float]:
return self._z
@z.setter
def z(self, z: float) -> None:
self._z.append(z)
def get_zidx(self, i: int) -> float:
return self.z[i]
@property
def pos(self) -> list[tuple[float, float, float]]:
return list(zip(self._x, self._y, self._z))
@pos.setter
def pos(self, pos: tuple[float, float, float]) -> None:
self._pos.append(pos)
def get_posidx(self, i: int) -> tuple[float, float, float]:
return self.pos[i]
@property
def vx(self) -> list[float]:
return self._vx
@vx.setter
def vx(self, vx: float) -> None:
self._vx.append(vx)
def get_vxidx(self, i: int) -> float:
return self.vx[i]
@property
def vy(self) -> list[float]:
return self._vy
@vy.setter
def vy(self, vy: float) -> None:
self._vy.append(vy)
def get_vyidx(self, i: int) -> float:
return self.vy[i]
@property
def vz(self) -> list[float]:
return self._vz
@vz.setter
def vz(self, vz: float) -> None:
self._vz.append(vz)
def get_vzidx(self, i: int) -> float:
return self.vz[i]
@property
def v(self) -> list[tuple[float, float, float]]:
return list(zip(self._vx, self._vy, self._vz))
@v.setter
def v(self, v: tuple[float, float, float]) -> None:
self._v.append(v)
def get_vidx(self, i: int) -> tuple[float, float, float]:
return self.v[i]
Код: Выделить всё
class PMM:
def __init__(self,
projectile: Projectile = None,
tFinal: float = None,
dt: float = None,
nIterMax: int = None,
) -> None:
self._projectile: Projectile = projectile
self._tFinal: float = tFinal
self._dt: float = dt
self._nIterMax: int = nIterMax
@property
def projectile(self) -> Projectile:
return self._projectile
@property
def tFinal(self) -> float:
return self._tFinal
@property
def dt(self) -> float:
return self._dt
@dt.setter
def dt(self, dt: float) -> None:
self._dt: float = dt
@property
def nIterMax(self) -> int:
return self._nIterMax
def drag_force(self,
v: tuple[float, float, float]
) -> tuple[float, float, float]:
return tuple(
-0.5
* 1.22
* self.projectile.S
* self.CD0(v = v)
* np.linalg.norm(v)
* vval for vval in v
)
def CD0(self, v: tuple[float, float, float]) -> float:
vMa: float = np.linalg.norm(v) / 340.0
if vMa < 1.0:
return self.projectile.CD0subsonic
elif vMa == 1.0:
return self.projectile.CD0max
else:
return (self.projectile.CD0max / (vMa ** self.projectile.k))
def init_proj_pos(self, pos: tuple[float, float, float]) -> None:
self.projectile.x = pos[0]
self.projectile.y = pos[1]
self.projectile.z = pos[2]
def init_proj_vel(self, v0: float, az: float, el: float) -> None:
self.projectile.vx = v0 * np.cos(az) * np.cos(el)
self.projectile.vy = v0 * np.sin(az) * np.cos(el)
self.projectile.vz = v0 * np.sin(el)
def run_bare(self,
posTarget: tuple[float, float, float] = None,
pos: tuple[float, float, float] = None,
tolDist: float = None,
v0: float = None,
az: float = None,
el: float = None,
) -> float:
dt: float = self.dt
t: float = dt
self.projectile.x.clear()
self.projectile.y.clear()
self.projectile.z.clear()
self.init_proj_pos(pos = pos)
self.projectile.v.clear()
self.init_proj_vel(v0 = v0, az = az, el = el)
gForce: tuple[float, float, float] = tuple([0.0, 0.0, -9.81 * self.projectile.m])
i: int = 1
nIterMax: int = self.nIterMax
while (t None:
self.projectile.x.clear()
self.projectile.y.clear()
self.projectile.z.clear()
self.projectile.v.clear()
t: float = self.dt
self.init_proj_pos(pos = pos)
self.init_proj_vel(v0 = v0, az = az, el = el)
gForce: tuple[float, float, float] = tuple([0.0, 0.0, -9.81 * self.projectile.m])
i: int = 1
while (t tuple[float, float]:
pos_proj: tuple[float, float, float] = self.projectile.get_posidx(i = 0)
az: float = np.arctan2((posTarget[1] - pos_proj[1]), (posTarget[0] - pos_proj[0]))
el: float = np.arctan2((posTarget[2] - pos_proj[2]), (posTarget[1] - pos_proj[1]))
el_min, el_max = 0.3 * el, 1.5 * el
el = .5 * (el_min + el_max)
nIter: int = 0
distZ = self.run_bare(posTarget = posTarget,
pos = pos,
tolDist = tolDist,
v0 = v0,
az = az,
el = el,
)
while (abs(distZ) > tolDist) and (abs(el - el_min) > tolAng):
if distZ < 0.0:
el_min = el
el = .5 * (el_min + el_max)
else:
el_max = el
el = .5 * (el_min + el_max)
distZ = self.run_bare(posTarget = posTarget,
pos = pos,
tolDist = tolDist,
v0 = v0,
az = az,
el = el,
)
nIter += 1
return (az, el)
Код: Выделить всё
if __name__ == "__main__":
posTarget: tuple[float, float, float] = (50.0, 50.0, 50.0)
p: Projectile = Projectile(m = 4.04e-3,
cal = 5.56e-3,
CD0subsonic = .15,
CD0max = .85,
k = 1.0,
)
pInit: tuple[float, float, float] = (0.0, 0.0, 0.0)
p.x = pInit[0]
p.y = pInit[1]
p.z = pInit[2]
vec_LOS = tuple([posTargetVal - posProjVal for posTargetVal, posProjVal in zip(posTarget, p.get_posidx(i = 0))])
dist_LOS: float = np.linalg.norm(vec_LOS)
dt: float = 1e-3
v0: float = 750.0
tFinal: float = 1.5 * (dist_LOS / v0)
nIterMax: int = int(tFinal / dt)
pmm: PMM = PMM(projectile = p,
tFinal = tFinal,
dt = dt,
nIterMax = nIterMax,
)
tolDist: float = 1.0e-3
tolAngle: float = 1.0e-3
az, el = pmm.get_init_orientation(posTarget = posTarget,
pos = pInit,
tolAng = tolAngle,
tolDist = tolDist,
v0 = v0,
)
pmm.run(v0 = v0, az = az, el = el, pos = pInit)
fig = plt.figure()
ax = plt.axes(projection = '3d')
ax.scatter(pmm.projectile.x, pmm.projectile.y, pmm.projectile.z)
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("z")
ax.scatter(posTarget[0], posTarget[1], posTarget[2], label = "Target")
plt.legend()
plt.show()
Подробнее здесь: https://stackoverflow.com/questions/788 ... to-account