41 eng =
check(to_eng(r, run_id=
"abc"))
42 assert eng[
"increasing"]
43 assert eng[
"time"][0] == 0.0
and eng[
"thrust"][0] == 0.0
44 assert eng[
"thrust"][-1] == 0.0
45 assert eng[
"time"][1] == pytest.approx(EDGE_S)
46 assert eng[
"time"][-2] == pytest.approx(N * DT)
and eng[
"time"][-1] == pytest.approx(N * DT + EDGE_S)
47 assert eng[
"impulse"] == pytest.approx(impulse, rel=2e-4)
49 t, f = r[
"timeseries"][
"data"][
"time"], [v * 1e3
for v
in r[
"timeseries"][
"data"][
"thrust_kN"]]
50 curve = sum(0.5 * (f[i] + f[i + 1]) * (t[i + 1] - t[i])
for i
in range(len(t) - 1))
51 assert abs(eng[
"impulse"] - curve) < 0.5
52 assert eng[
"delays"] ==
"P"
53 assert eng[
"propellant_kg"] == pytest.approx(10.75)
54 assert eng[
"total_kg"] == pytest.approx(10.75 + 14.54)
55 assert (eng[
"diameter_mm"], eng[
"length_mm"]) == (165.1, 309.9)
56 assert eng[
"name"].startswith(
"STAR-")
and " " not in eng[
"name"]
76 """The file's name and the motor's name in it carry the same mean thrust, the run's (step-held).
77 The header moved to the run's mean on 2026-11-02 while the download kept the trapezoid's: this
78 falling curve (6800 N less 20 N a step) read STAR-5070N on the file and STAR-5060N inside it.
79 By hand: 0.02 s x (175 x 6800 - 20 x 15225) N = 17710 N s over 3.5 s = 5060 N."""
82 r, impulse =
_result(thrust=
lambda k: 6800.0 - 20.0 * k)
83 mean = impulse / (N * DT)
84 t, f = [0.0] + [DT * (k + 1)
for k
in range(N)], [6800.0] + [6800.0 - 20.0 * k
for k
in range(N)]
85 trapezoid = sum(0.5 * (f[i] + f[i + 1]) * (t[i + 1] - t[i])
for i
in range(N)) / (N * DT)
86 assert round(trapezoid) != round(mean)
87 motor =
check(to_eng(r))[
"name"]
88 assert motor == f
"STAR-{round(mean)}N"
89 assert filename(r,
"abc") == f
"{motor}-abc.eng"
106 cfg = load_config(os.path.join(ROOT,
"configs",
"ethalox_6800N.yaml"))
107 m = motor_header(cfg)
110 assert m[
"chamber_od_mm"] == pytest.approx(6.5 * 25.4, abs=0.05)
111 assert m[
"diameter_mm"] == pytest.approx(2.0 * cfg.rocket.radius * 1e3, abs=0.05)
112 cg = cfg.chamber_geometry
113 R_t = math.sqrt(cg.A_throat / math.pi)
114 theta = math.radians(cfg.design_requirements.layer1_contraction_half_angle_deg
or 45.0)
116 r_c, r_tan = cg.chamber_diameter / 2.0, R_t * (1.0 + 1.5 * (1.0 - math.cos(theta)))
117 L_cone = (r_c - r_tan) / math.tan(theta)
118 V_cone = math.pi * L_cone / 3.0 * (r_c ** 2 + r_c * r_tan + r_tan ** 2)
119 L_cyl = (cg.Lstar * cg.A_throat - V_cone) / (math.pi * r_c ** 2)
120 bell = 0.8 * (math.sqrt(cg.expansion_ratio) - 1.0) * R_t / math.tan(math.radians(15.0))
121 expected = (L_cyl + L_cone + 1.5 * R_t * math.sin(theta) + bell) * 1e3
122 assert m[
"length_mm"] == pytest.approx(expected, rel=0.02)
123 assert m[
"dry_kg"] == pytest.approx(cfg.rocket.engine_mass)