Skip to content

Commit

Permalink
Fixed #2 and cleaned up time-step logic.
Browse files Browse the repository at this point in the history
  • Loading branch information
dbookstaber committed Mar 7, 2024
1 parent b0cb39b commit 41025d0
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 47 deletions.
2 changes: 1 addition & 1 deletion py_ballisticcalc/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class Units(metaclass=Metadataclass): # pylint: disable=too-many-instance-attri
target_height: Unit = Unit.INCH
twist: Unit = Unit.INCH

_MAX_CALC_STEP_SIZE: float = 1
_MAX_CALC_STEP_SIZE: float = 0.5
USE_POWDER_SENSITIVITY: bool = False

@classmethod
Expand Down
35 changes: 19 additions & 16 deletions py_ballisticcalc/trajectory_calc.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,16 +100,20 @@ def __init__(self, ammo: Ammo):
self._table_data = ammo.dm.drag_table
self._curve = calculate_curve(self._table_data)

def get_calc_step(self, step: float):
maximum_step = Settings.get_max_calc_step_size()
step /= 2
if step > maximum_step:
step_order = int(math.floor(math.log10(step)))
maximum_order = int(math.floor(math.log10(maximum_step)))
step /= math.pow(10, step_order - maximum_order + 1)
return step
def get_calc_step(self, step: float = 0):
"""Keep step under max_calc_step_size
:param step: proposed step size
:return: step size for calculations (in feet)
"""
if step == 0:
return Settings.get_max_calc_step_size() / 2.0
return min(step, Settings.get_max_calc_step_size()) / 2.0

def zero_angle(self, shot_info: Shot, distance: Distance):
"""Find barrel elevation to hit zero
:param shot_info: Shot conditions
:param distance: Zero distance
"""
return self._zero_angle(shot_info, distance)

def trajectory(self, shot_info: Shot, max_range: Distance, dist_step: Distance,
Expand All @@ -125,7 +129,7 @@ def trajectory(self, shot_info: Shot, max_range: Distance, dist_step: Distance,
return self._trajectory(self.ammo, atmo, shot_info, winds, max_range, dist_step, filter_flags)

def _zero_angle(self, shot_info: Shot, distance: Distance):
calc_step = self.get_calc_step(distance.units(10) >> Distance.Foot)
calc_step = self.get_calc_step()
zero_distance = math.cos(shot_info.look_angle >> Angular.Radian) * (distance >> Distance.Foot)
height_at_zero = math.sin(shot_info.look_angle >> Angular.Radian) * (distance >> Distance.Foot)
maximum_range = zero_distance + calc_step
Expand Down Expand Up @@ -160,10 +164,9 @@ def _zero_angle(self, shot_info: Shot, distance: Distance):
if velocity < cMinimumVelocity or range_vector.y < cMaximumDrop:
break

delta_time = calc_step / velocity_vector.x
delta_time = calc_step / velocity

drag = density_factor * velocity * self.drag_by_mach(velocity / mach)

velocity_vector -= (velocity_vector * drag - gravity_vector) * delta_time
delta_range_vector = Vector(calc_step, velocity_vector.y * delta_time,
velocity_vector.z * delta_time)
Expand All @@ -186,14 +189,16 @@ def _zero_angle(self, shot_info: Shot, distance: Distance):
def _trajectory(self, ammo: Ammo, atmo: Atmo,
shot_info: Shot, winds: list[Wind],
max_range: Distance, dist_step: Distance, filter_flags: TrajFlag):
"""Calculate trajectory for specified shot
:return: list of TrajectoryData, one for each dist_step, out to max_range
"""
time = 0
look_angle = shot_info.look_angle >> Angular.Radian
twist = shot_info.weapon.twist >> Distance.Inch
length = ammo.dm.length >> Distance.Inch
diameter = ammo.dm.diameter >> Distance.Inch
weight = ammo.dm.weight >> Weight.Grain

# step = shot_info.step >> Distance.Foot
step = dist_step >> Distance.Foot
calc_step = self.get_calc_step(step)

Expand Down Expand Up @@ -310,13 +315,11 @@ def _trajectory(self, ammo: Ammo, atmo: Atmo,

previous_mach = velocity / mach

velocity_adjusted = velocity_vector - wind_vector
delta_time = calc_step / velocity

delta_time = calc_step / velocity_vector.x
velocity_adjusted = velocity_vector - wind_vector
velocity = velocity_adjusted.magnitude()

drag = density_factor * velocity * self.drag_by_mach(velocity / mach)

velocity_vector -= (velocity_adjusted * drag - gravity_vector) * delta_time
delta_range_vector = Vector(calc_step,
velocity_vector.y * delta_time,
Expand Down
29 changes: 10 additions & 19 deletions py_ballisticcalc_exts/py_ballisticcalc_exts/trajectory_calc.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -110,16 +110,10 @@ cdef class TrajectoryCalc:
self._table_data = ammo.dm.drag_table
self._curve = calculate_curve(self._table_data)

cdef double get_calc_step(self, double step):
cdef:
int step_order, maximum_order
double maximum_step = Settings.get_max_calc_step_size()
step /= 2
if step > maximum_step:
step_order = int(floor(log10(step)))
maximum_order = int(floor(log10(maximum_step)))
step /= pow(10, step_order - maximum_order + 1)
return step
cdef double get_calc_step(self, double step = 0):
if step == 0:
return Settings.get_max_calc_step_size() / 2.0
return min(step, Settings.get_max_calc_step_size()) / 2.0

def zero_angle(self, shot_info: Shot, distance: Distance):
return self._zero_angle(shot_info, distance)
Expand All @@ -140,7 +134,7 @@ cdef class TrajectoryCalc:

cdef _zero_angle(TrajectoryCalc self, object shot_info, object distance):
cdef:
double calc_step = self.get_calc_step(distance.units(10) >> Distance.Foot)
double calc_step = self.get_calc_step()
double zero_distance = cos(shot_info.look_angle >> Angular.Radian) * (distance >> Distance.Foot)
double height_at_zero = sin(shot_info.look_angle >> Angular.Radian) * (distance >> Distance.Foot)
double maximum_range = zero_distance + calc_step
Expand Down Expand Up @@ -178,7 +172,7 @@ cdef class TrajectoryCalc:
if velocity < cMinimumVelocity or range_vector.y < cMaximumDrop:
break

delta_time = calc_step / velocity_vector.x
delta_time = calc_step / velocity

drag = density_factor * velocity * self.drag_by_mach(velocity / mach)

Expand All @@ -204,16 +198,15 @@ cdef class TrajectoryCalc:
cdef _trajectory(TrajectoryCalc self, object ammo, object atmo, object shot_info,
list[object] winds, object max_range, object dist_step, CTrajFlag filter_flags):
cdef:
double density_factor, mach
double time, velocity, windage, delta_time, drag
double time = 0
double density_factor, mach, velocity, windage, delta_time, drag

double look_angle = shot_info.look_angle >> Angular.Radian
double twist = shot_info.weapon.twist >> Distance.Inch
double length = ammo.dm.length >> Distance.Inch
double diameter = ammo.dm.diameter >> Distance.Inch
double weight = ammo.dm.weight >> Weight.Grain

# double step = shot_info.step >> Distance.Foot
double step = dist_step >> Distance.Foot
double calc_step = self.get_calc_step(step)

Expand Down Expand Up @@ -329,13 +322,11 @@ cdef class TrajectoryCalc:

previous_mach = velocity / mach

velocity_adjusted = velocity_vector - wind_vector
delta_time = calc_step / velocity

delta_time = calc_step / velocity_vector.x
velocity_adjusted = velocity_vector - wind_vector
velocity = velocity_adjusted.magnitude()

drag = density_factor * velocity * self.drag_by_mach(velocity / mach)

velocity_vector -= (velocity_adjusted * drag - gravity_vector) * delta_time
delta_range_vector = Vector(calc_step,
velocity_vector.y * delta_time,
Expand Down
22 changes: 11 additions & 11 deletions tests/test_trajectory.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def test_zero1(self):
zero_angle = calc.barrel_elevation_for_target(Shot(weapon=weapon, ammo=ammo, atmo=atmosphere),
Distance(100, Distance.Yard))

self.assertAlmostEqual(zero_angle >> Angular.Radian, 0.001651, 6,
self.assertAlmostEqual(zero_angle >> Angular.Radian, 0.001652, 6,
f'TestZero1 failed {zero_angle >> Angular.Radian:.10f}')

def test_zero2(self):
Expand All @@ -33,7 +33,7 @@ def test_zero2(self):

def custom_assert_equal(self, a, b, accuracy, name):
with self.subTest(name=name):
self.assertLess(fabs(a - b), accuracy, f'Assertion {name} failed ({a}/{b}, {accuracy})')
self.assertLess(fabs(a - b), accuracy, f'Equality {name} failed (|{a} - {b}|, {accuracy} digits)')

def validate_one(self, data: TrajectoryData, distance: float, velocity: float,
mach: float, energy: float, path: float, hold: float,
Expand Down Expand Up @@ -73,13 +73,14 @@ def test_path_g1(self):
ammo = Ammo(dm, Velocity(2750, Velocity.FPS))
weapon = Weapon(Distance(2, Distance.Inch), zero_elevation=Angular(0.001228, Angular.Radian))
atmosphere = Atmo.icao()
calc = TrajectoryCalc(ammo)
shot_info = Shot(weapon=weapon, atmo=atmosphere,
shot_info = Shot(weapon=weapon, ammo=ammo, atmo=atmosphere,
winds=[Wind(Velocity(5, Velocity.MPH), Angular(10.5, Angular.OClock))])
data = calc.trajectory(shot_info, Distance.Yard(1000), Distance.Yard(100))

self.custom_assert_equal(len(data), 11, 0.1, "Length")
calc = Calculator()
data = calc.fire(shot_info, Distance.Yard(1000), Distance.Yard(100)).trajectory
self.assertEqual(len(data), 11, "Trajectory Row Count")

# Dist(yd), vel(fps), Mach, energy(ft-lb), drop(in), drop(mil), wind(in), wind(mil), time, ogw
test_data = [
[data[0], 0, 2750, 2.463, 2820.6, -2, 0, 0, 0, 0, 880, Angular.MOA],
[data[1], 100, 2351.2, 2.106, 2061, 0, 0, -0.6, -0.6, 0.118, 550, Angular.MOA],
Expand All @@ -95,12 +96,11 @@ def test_path_g7(self):
dm = DragModel(0.223, TableG7, 168, 0.308, 1.282)
ammo = Ammo(dm, Velocity(2750, Velocity.FPS))
weapon = Weapon(2, 12, zero_elevation=Angular.MOA(4.221))
shot_info = Shot(weapon=weapon, ammo=ammo, winds=[Wind(Velocity(5, Velocity.MPH), -45)])
shot_info = Shot(weapon=weapon, ammo=ammo, winds=[Wind(Velocity(5, Velocity.MPH), Angular.Degree(-45))])

calc = TrajectoryCalc(ammo)
data = calc.trajectory(shot_info, Distance.Yard(1000), Distance.Yard(100))

self.custom_assert_equal(len(data), 11, 0.1, "Length")
calc = Calculator()
data = calc.fire(shot_info, Distance.Yard(1000), Distance.Yard(100)).trajectory
self.assertEqual(len(data), 11, "Trajectory Row Count")

# Dist(yd), vel(fps), Mach, energy(ft-lb), drop(in), drop(mil), wind(in), wind(mil), time, ogw
test_data = [
Expand Down

0 comments on commit 41025d0

Please sign in to comment.