53 """Along a vertical rail: dv/dt = F/m - g - D/m, dm/dt = -mdot, to s = rail length."""
55 t_c, F, mO, mF = header_curve()
56 m = shipped_flight[
"flight_report"][
"wet_mass_kg"]
57 A, rho = math.pi * cfg.rocket.radius**2, 1.1175
60 while s < cfg.environment.rail_length_m:
61 Fk = np.interp(t, t_c, F)
62 a = Fk / m - G0 - 0.5 * rho * v * v * 0.85 * A / m
65 m -= np.interp(t, t_c, mO + mF) * dt
67 rep = shipped_flight[
"flight_report"][
"launch"]
68 assert rep[
"rail_exit_velocity_m_s"] == pytest.approx(v, rel=0.01)
69 assert rep[
"rail_exit_velocity_m_s"] == pytest.approx(21.7, abs=0.2)
70 assert rep[
"rail_buttons_declared"]
is False and rep[
"effective_rail_length_m"] == 3.35
74 """Barrowman (TIR-33): nose CN_a = 2 at L - V/A_base from the tip (L/2 for von Karman);
75 trapezoidal fins with body interference 1 + R/(s + R)."""
76 R, fins = cfg.rocket.radius, cfg.rocket.fins
78 cr, ct, s, n = fins.root_chord, fins.tip_chord, fins.fin_span, fins.no_fins
80 l_f = math.hypot(s, sweep + ct / 2 - cr / 2)
81 cn_f = (1 + R / (s + R)) * 4 * n * (s / d) ** 2 / (1 + math.sqrt(1 + (2 * l_f / (cr + ct)) ** 2))
82 x_f_from_le = sweep * (cr + 2 * ct) / (3 * (cr + ct)) + (cr + ct - cr * ct / (cr + ct)) / 6
83 x_fins = fins.fin_position - x_f_from_le
84 x_nose = nose_tip - nose_len / 2
85 return (2.0 * x_nose + cn_f * x_fins) / (2.0 + cn_f)
113 """Point-mass 2-DOF: along the rail at incl_deg to its end, then thrust along the velocity
114 (a gravity turn, what an overstable vehicle does in still air). Returns h(90) - h(incl)."""
115 from fluids.atmosphere
import ATMOSPHERE_1976
116 from scipy.integrate
import solve_ivp
118 t_c, F, mO, mF = header_curve()
120 A = math.pi * cfg.rocket.radius**2
122 elev, rail = cfg.environment.elevation, cfg.environment.rail_length_m
125 th0 = math.radians(incl)
127 def forces(t, h, V, m):
128 burning = t < t_c[-1]
129 atm = ATMOSPHERE_1976(elev +
max(h, 0.0))
130 T = np.interp(t, t_c, F)
if burning
else 0.0
131 D = 0.5 * atm.rho * V * V * drag.at(V / atm.v_sonic, burning) * A
132 return T - D, (np.interp(t, t_c, md)
if burning
else 0.0)
136 f, mdot = forces(t, s_ * math.sin(th0), v, m)
137 return [v, f / m - G0 * math.sin(th0), -mdot]
139 off =
lambda t, y: y[0] - rail
141 r = solve_ivp(on_rail, (0, 5), [0, 0, m0], events=off, max_step=1e-3, rtol=1e-9)
142 t1, (s1, v1, m1) = r.t_events[0][0], r.y_events[0][0]
146 V = math.hypot(vx, vh)
147 f, mdot = forces(t, h, V, m)
148 return [vx, vh, f * vx / V / m, f * vh / V / m - G0, -mdot]
150 top =
lambda t, y: y[3]
151 top.terminal, top.direction =
True, -1
152 y0 = [s1 * math.cos(th0), s1 * math.sin(th0), v1 * math.cos(th0), v1 * math.sin(th0), m1]
153 sol = solve_ivp(flight, (t1, 80), y0, events=top, max_step=0.05, rtol=1e-8)
154 return sol.y_events[0][0][1]
156 return apogee(90.0) - apogee(incl_deg)
177 """The time-varying solver computes the curve at the pad's ISA 1976 pressure (test_ambient_isa.py)."""
180 elev = shipped().environment.elevation
181 p_ref = compute_ambient_pressure_from_elevation(elev)
182 motor = shipped_flight[
"flight"].rocket.motor
183 assert motor.reference_pressure == pytest.approx(p_ref, rel=1e-9)
184 assert shipped_flight[
"flight_report"][
"reference_pressure_pa"] == pytest.approx(p_ref, rel=1e-9)
188 """F(z) = F_curve + (p_ref - p(z)) A_exit, Sutton & Biblarz eq. 3-21: ~55 N at 1.2 km MSL."""
192 fl = shipped_flight[
"flight"]
193 A_e = ensure_chamber_geometry(cfg).A_exit
194 p = fl.env.pressure(1200.0)
195 dF = fl.rocket.motor.pressure_thrust(p)
196 assert dF == pytest.approx((fl.rocket.motor.reference_pressure - p) * A_e, abs=0.01)
197 assert dF == pytest.approx(54.6, abs=1.0)