Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

set_weapon_zero does not not compute correct weapon zero for bigger ranges and throws RangeError for even bigger ranges #155

Open
serhiy-yevtushenko opened this issue Jan 27, 2025 · 3 comments
Labels
bug Something isn't working

Comments

@serhiy-yevtushenko
Copy link
Contributor

Describe the bug
Calculator,set_weapon_zero currently does not handle ranges, which exceed a little bit half of maximum range, due to not handling RangeError

As well, the computed angle will not be correct for some ranges.

To Reproduce

Script to reproduce

import py_ballisticcalc

from py_ballisticcalc import (
    RangeError,
    Distance,
    Calculator,
    InterfaceConfigDict,
    Angular,
)


def min_zero_velocity_calc():
    config = InterfaceConfigDict(
        cMinimumVelocity=0,
    )
    return Calculator(_config=config)


def create_shot():
    drag_model = py_ballisticcalc.DragModel(
        bc=0.759,
        drag_table=py_ballisticcalc.TableG1,
        weight=py_ballisticcalc.Weight.Gram(108),
        diameter=py_ballisticcalc.Distance.Millimeter(23),
        length=py_ballisticcalc.Distance.Millimeter(108.2),
    )
    ammo = py_ballisticcalc.Ammo(drag_model, py_ballisticcalc.Velocity.MPS(930))
    gun = py_ballisticcalc.Weapon()
    shot = py_ballisticcalc.Shot(
        weapon=gun,
        ammo=ammo,
    )
    return shot

if __name__ == "__main__":
    TEST_DISTANCES = [
        50,
        100,
        1000,
        2000,
        3000,
        3500,
        3600,
        3700,
        3800,
        3900,
        4000,
        5000,
        6000,
        7000,
        7126.0478000569165,
    ]

    print(f'Max range shot')
    calc = min_zero_velocity_calc()
    shot = create_shot()
    shot.relative_angle = Angular.Degree(38.58299087491584)
    hit_result = calc.fire(shot, Distance.Meter(TEST_DISTANCES[-1]))
    print(f"Max distance shot {hit_result[-1].distance>>Distance.Meter=} {hit_result[-1].height>>Distance.Meter=}")


    for distance in TEST_DISTANCES:
        shot = create_shot()
        calc = min_zero_velocity_calc()
        range = Distance.Meter(distance)
        print(f"\nDistance: {distance:.2f}")
        try:
            elevation = calc.set_weapon_zero(shot, range)
            print(f"{elevation}")
        except RangeError as e:
            print(f"{distance=} get RangeError {e=} {e.reason=}")
        try:
            hit_result = calc.fire(shot, Distance.Meter(distance))
            print(f"{hit_result[-1].distance>>Distance.Meter=} {hit_result[-1].height>>Distance.Meter=}")
        except RangeError as e:
            print(f'Got range error as {e=} {e.reason=}')

The script produced following output:

Max range shot
Max distance shot hit_result[-1].distance>>Distance.Meter=7126.054548838994 hit_result[-1].height>>Distance.Meter=0.004317301927737416

Distance: 50.00
0.000289rad
hit_result[-1].distance>>Distance.Meter=50.06158904016097 hit_result[-1].height>>Distance.Meter=2.2214590588071558e-05

Distance: 100.00
0.000587rad
hit_result[-1].distance>>Distance.Meter=100.04696342544833 hit_result[-1].height>>Distance.Meter=4.597497519789639e-05

Distance: 1000.00
0.008129rad
hit_result[-1].distance>>Distance.Meter=1000.0695439537527 hit_result[-1].height>>Distance.Meter=0.0008765523480418931

Distance: 2000.00
0.026235rad
hit_result[-1].distance>>Distance.Meter=2000.0569700649191 hit_result[-1].height>>Distance.Meter=0.0040720861129738785

Distance: 3000.00
0.063313rad
hit_result[-1].distance>>Distance.Meter=3000.0292293643865 hit_result[-1].height>>Distance.Meter=0.010736849989238495

Distance: 3500.00
0.089645rad
hit_result[-1].distance>>Distance.Meter=3500.033867196157 hit_result[-1].height>>Distance.Meter=0.015142911688960977

Distance: 3600.00
0.095554rad
hit_result[-1].distance>>Distance.Meter=3600.0313658063183 hit_result[-1].height>>Distance.Meter=0.016112028286484944

Distance: 3700.00
0.101686rad
hit_result[-1].distance>>Distance.Meter=3330.0533201090852 hit_result[-1].height>>Distance.Meter=71.80853534522028

Distance: 3800.00
0.108042rad
hit_result[-1].distance>>Distance.Meter=3420.0231792026857 hit_result[-1].height>>Distance.Meter=78.42252996330228

Distance: 3900.00
distance=3900 get RangeError e=RangeError('Max range not reached: (Minimum altitude reached)') e.reason='Minimum altitude reached'
Got range error as e=RangeError('Max range not reached: (Minimum altitude reached), last distance: 12613.14ft') e.reason='Minimum altitude reached'

Distance: 4000.00
distance=4000 get RangeError e=RangeError('Max range not reached: (Minimum altitude reached)') e.reason='Minimum altitude reached'
Got range error as e=RangeError('Max range not reached: (Minimum altitude reached), last distance: 12613.14ft') e.reason='Minimum altitude reached'

Distance: 5000.00
distance=5000 get RangeError e=RangeError('Max range not reached: (Minimum altitude reached)') e.reason='Minimum altitude reached'
Got range error as e=RangeError('Max range not reached: (Minimum altitude reached), last distance: 12613.14ft') e.reason='Minimum altitude reached'

Distance: 6000.00
distance=6000 get RangeError e=RangeError('Max range not reached: (Minimum altitude reached)') e.reason='Minimum altitude reached'
Got range error as e=RangeError('Max range not reached: (Minimum altitude reached), last distance: 12613.14ft') e.reason='Minimum altitude reached'

Distance: 7000.00
distance=7000 get RangeError e=RangeError('Max range not reached: (Minimum altitude reached)') e.reason='Minimum altitude reached'
Got range error as e=RangeError('Max range not reached: (Minimum altitude reached), last distance: 12613.14ft') e.reason='Minimum altitude reached'

Distance: 7126.05
distance=7126.0478000569165 get RangeError e=RangeError('Max range not reached: (Minimum altitude reached)') e.reason='Minimum altitude reached'
Got range error as e=RangeError('Max range not reached: (Minimum altitude reached), last distance: 12613.14ft') e.reason='Minimum altitude reached'

As one could see, there are two breakdowns of behaviour:
1). Starting from 3600 meters, the computed angle does not allow to hit target
2). Starting from 3900 meters, one is getting range error

Expected behavior

To be discussed.

Reason for not computing the correct angle is so called Steady State Error in the Control Theory - starting from certain distance, the feedback driven correction does not allow to compensate for gravity influence. It could be partially compensated by summarazing erros from previous steps, checking whether final predicted angle has as a result of hit a deviation from target, and if that's the case, taking once it into account/or doing bracking search after getting overshoot over target/or search, which tries to find minimum from quadratic deviation from target

Reasons for Range Errors is the change in behaviour in the new version - we should discuss, whether we want to handle it in set_weapon_zero/set_barrel_elevation

Screenshots
If applicable, add screenshots to help explain your problem.

**Environment: **

  • OS: [e.g. iOS]
  • Python3 version: [e.g. 3.9, 3.11]
  • Release [e.g. 1.0.12]

Additional context
Add any other context about the problem here.

@serhiy-yevtushenko serhiy-yevtushenko added the bug Something isn't working label Jan 27, 2025
@dbookstaber
Copy link
Contributor

dbookstaber commented Jan 27, 2025

There may be multiple problems here. Two immediately visible:

  1. zero_angle() asks integrate() for height at zero_distance range 3700m but is given TrajectoryData at range 3330m. This is a recording bug.
  2. zero_angle() can't even begin to look beyond a certain distance because of the cMaximumDrop and/or cMinimumAltitude constraints applied in integrate(). Two possible solutions to this one:
    • Disable minimum height constraints when calling integrate from zero_angle. However we still need some check to prevent unlimited search when user asks for zero_angle at a range that is beyond reach of the shot. One decent solution is to throw RangeError here when horizontal velocity drops below some cMinHorizontalVelocity.
    • Estimate an initial barrel_elevation that will reach zero_distance without violating those height constraints.

@dbookstaber
Copy link
Contributor

Another possibility for resolving the more general problem of providing a reliable way of ensuring the integrator will halt in all scenarios (which has come up also in the course of addressing #150) is to establish a MaxTimeOfFlight parameter.

@dbookstaber
Copy link
Contributor

We are noticing that, as we approach a weapon's max range, we will have to handle RangeError because all but the near-perfect launch angles will not be able to reach the desired zero distance.

Also, we have to realize (and detect) that user could ask for a zero distance that is outside the max range of the weapon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants