Почему обновленный аргумент не принимается во внимание?Python

Программы на Python
Anonymous
Почему обновленный аргумент не принимается во внимание?

Сообщение Anonymous »

Я пытаюсь решить обратную задачу баллистики, где необходимо найти начальную ориентацию запуска (az, el), учитывая точку достижения posTarget и начальную скорость выброса v0 . Для этого у меня есть несколько классов:
Этот класс представляет распространяемый снаряд.

Код: Выделить всё

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()
Функция run_bare вычисляет распространение для заданного (az, el) и, если снаряд находится в пределах определенного допуска до точки достижения (вдоль оси Y), он возвращает соответствующую разницу высот между целью и снарядом. Это значение используется в get_init_orientation для поиска правильного адреса. При проверке оказывается, что значение el, переданное в run_bare в методе get_init_orientation, меняется, но начальная скорость, т.е. self.projectile.get_vidx(i = 0) всегда один и тот же, даже несмотря на то, что метод init_proj_vel получает новый el в каждом цикле get_init_elevation. Следовательно, код не может найти правильный адрес. Как получается, что обновляется el, но не соответствующая начальная скорость выброса?


Подробнее здесь: https://stackoverflow.com/questions/788 ... to-account

Вернуться в «Python»