Skip to content

DragModel

Drag model of projectile

DragDataPoint dataclass

DragDataPoint(Mach: float, CD: float)

Drag coefficient at Mach number

BCPoint dataclass

BCPoint(BC: float, Mach: Optional[float] = None, V: Optional[Union[float, Velocity]] = None)

For multi-bc drag models, designed to sort by Mach ascending

Source code in py_ballisticcalc\drag_model.py
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
def __init__(self,
             BC: float,
             Mach: Optional[float] = None,
             V: Optional[Union[float, Velocity]] = None):

    if BC <= 0:
        raise ValueError('Ballistic coefficient must be positive')

    if Mach and V:
        raise ValueError("You cannot specify both 'Mach' and 'V' at the same time")

    if not Mach and not V:
        raise ValueError("One of 'Mach' and 'V' must be specified")

    self.BC = BC
    self.V = PreferredUnits.velocity(V or 0)
    if V:
        self.Mach = (self.V >> Velocity.MPS) / self._machC()
    elif Mach:
        self.Mach = Mach

DragModel

DragModel(bc: float, drag_table: DragTableDataType, weight: Union[float, Weight] = 0, diameter: Union[float, Distance] = 0, length: Union[float, Distance] = 0)

:param bc: Ballistic Coefficient of bullet = weight / diameter^2 / i, where weight is in pounds, diameter is in inches, and is the bullet's form factor relative to the selected drag model. :param drag_table: If passed as List of {Mach, CD} dictionaries, this will be converted to a List of DragDataPoints. :param weight: Bullet weight in grains :param diameter: Bullet diameter in inches :param length: Bullet length in inches NOTE: .weight, .diameter, .length are only relevant for computing spin drift

Source code in py_ballisticcalc\drag_model.py
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
def __init__(self, bc: float,
             drag_table: DragTableDataType,
             weight: Union[float, Weight] = 0,
             diameter: Union[float, Distance] = 0,
             length: Union[float, Distance] = 0):

    if len(drag_table) <= 0:
        # TODO: maybe have to require minimum items count, cause few values don't give a valid result
        raise ValueError('Received empty drag table')
    if bc <= 0:
        raise ValueError('Ballistic coefficient must be positive')

    self.drag_table = make_data_points(drag_table)

    self.BC = bc
    self.length = PreferredUnits.length(length)
    self.weight = PreferredUnits.weight(weight)
    self.diameter = PreferredUnits.diameter(diameter)
    if weight > 0 and diameter > 0:
        self.sectional_density = self._get_sectional_density()
        self.form_factor = self._get_form_factor(self.BC)

DragModelMultiBC

DragModelMultiBC(bc_points: List[BCPoint], drag_table: DragTableDataType, weight: Union[float, Weight] = 0, diameter: Union[float, Distance] = 0, length: Union[float, Distance] = 0) -> DragModel

Compute a drag model based on multiple BCs. If weight and diameter are provided then we set bc=sectional density. Otherwise, we set bc=1 and the drag_table contains final drag terms. :param bc_points: :param drag_table: list of dicts containing drag table data :param weight: Bullet weight in grains :param diameter: Bullet diameter in inches :param length: Bullet length in inches

Source code in py_ballisticcalc\drag_model.py
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
def DragModelMultiBC(bc_points: List[BCPoint],
                     drag_table: DragTableDataType,
                     weight: Union[float, Weight] = 0,
                     diameter: Union[float, Distance] = 0,
                     length: Union[float, Distance] = 0) -> DragModel:
    """
    Compute a drag model based on multiple BCs.
    If weight and diameter are provided then we set bc=sectional density.
    Otherwise, we set bc=1 and the drag_table contains final drag terms.
    :param bc_points:
    :param drag_table: list of dicts containing drag table data
    :param weight: Bullet weight in grains
    :param diameter: Bullet diameter in inches
    :param length: Bullet length in inches
    """
    weight = PreferredUnits.weight(weight)
    diameter = PreferredUnits.diameter(diameter)
    if weight > 0 and diameter > 0:
        bc = sectional_density(weight >> Weight.Grain, diameter >> Distance.Inch)
    else:
        bc = 1.0

    drag_table = make_data_points(drag_table)  # Convert from list of dicts to list of DragDataPoints

    bc_points.sort(key=lambda p: p.Mach)  # Make sure bc_points are sorted for linear interpolation
    bc_interp = linear_interpolation([x.Mach for x in drag_table],
                                     [x.Mach for x in bc_points],
                                     [x.BC / bc for x in bc_points])

    for i, point in enumerate(drag_table):
        point.CD = point.CD / bc_interp[i]
    return DragModel(bc, drag_table, weight, diameter, length)