diff --git a/.coverage b/.coverage deleted file mode 100644 index 11cf65d..0000000 Binary files a/.coverage and /dev/null differ diff --git a/README.md b/README.md index f2f7ae5..4e21a9e 100644 --- a/README.md +++ b/README.md @@ -62,19 +62,20 @@ The following is the format you'll have to use in your `.json` input files: ```json { "Engine" : { - "Specific Impulse (s)" : 318, - "Thrust (N)" : 500 + "Type" : "Liquid", + "Specific impulse (s)" : 318, + "Thrust (N)" : 500 }, "Fuel" : { - "Oxidizer/Fuel Mixture Ratio" : 15, - "Fuel Reserve (%)" : 5 + "Oxidizer/fuel mixture ratio" : 15, + "Fuel reserve (%)" : 5 }, "Mass" : { - "Dry Mass (kg)" : 10 + "Dry Mass (kg)" : 10 }, "Aerodynamics" : { - "Drag Coefficient" : 0.0556, - "Cross-section (m2)" : 0.0255364 + "Drag coefficient" : 0.0556, + "Cross-section (m2)" : 0.0255364 }, "Environment" : { "Elevation (m)" : 113, @@ -83,11 +84,11 @@ The following is the format you'll have to use in your `.json` input files: "Air molar mass (kg/mol)" : 0.02896968, "Gas constant (J/(K.mol))" : 8.314462618, "Air heat capacity ratio" : 1.4, - "Standard Atmospheric pressure @SL (Pa)" : 101325 + "Standard atmospheric pressure @SL (Pa)" : 101325 }, "Output" : { - "Log File Path" : "path/to/Flight.log", - "CSV File Path" : "path/to/Flight.csv" + ".log file" : "Flight.log", + ".csv file" : "Flight.csv" } } ``` diff --git a/REQUIREMENTS.txt b/REQUIREMENTS.txt index 2738fcc..3e5489f 100644 --- a/REQUIREMENTS.txt +++ b/REQUIREMENTS.txt @@ -1,4 +1,5 @@ matplotlib +numpy coverage pytest pytest-cov diff --git a/preflightpy/env.py b/preflightpy/env.py index a6d2aa5..8e849d5 100644 --- a/preflightpy/env.py +++ b/preflightpy/env.py @@ -26,7 +26,7 @@ class Environment: def __init__(self, vars): # Environmental Constants - self.elev, self.t, self.g, self.M_air, self.R, self.gamma, self.Pstatic = vars # noqa + self.elev, self.t, self.g, self.M_air, self.R, self.gamma, self.P_zero = vars # noqa self.g_zero = self.g self.Re = 6356766 self.hb = [ # Layer base altitudes diff --git a/preflightpy/params.py b/preflightpy/params.py index a5060e8..91f4441 100644 --- a/preflightpy/params.py +++ b/preflightpy/params.py @@ -58,7 +58,3 @@ def cast(self, x): return float(x) except Exception: return str(x) - -# TEMP: for testing purposes -# p = Params() -# print(p.package, len(str(p.package)), type(p.package[0][1])) diff --git a/preflightpy/system.py b/preflightpy/system.py index 37f1b26..1693d4a 100644 --- a/preflightpy/system.py +++ b/preflightpy/system.py @@ -29,24 +29,51 @@ def __init__(self, params, env, burn_time: float): p = params # Environment self.env = env + # Burn time - self.num_steps = int(burn_time/self.env.t) + self.num_steps = int(burn_time // self.env.t) self.burn_time = self.num_steps * self.env.t + # Engine specs - self.isp, self.Fthrust = p.package[0] + self.etype = p.package[0][0] + p.package[0].pop(0) + if self.etype == "Liquid": + self.isp, self.thrust = p.package[0] + elif self.etype == "Solid": + self.isp, self.avg_thrust, path = p.package[0] # noqa + with(open(path)) as f: + csv_reader = csv.reader(f) + self.thrust_curve = {} + for row in csv_reader: + self.thrust_curve.update({ + float(row[0]): float(row[1]) + }) + f.close() + # Fuel Specs - self.OFratio, self.Reserve = p.package[1] + if self.etype == "Liquid": + self.OFratio, self.Reserve = p.package[1] + elif self.etype == "Solid": + self.OFratio = 0 + self.Reserve = p.package[1][0] # Flow Rate - self.w = (self.Fthrust/self.env.g_zero)/self.isp - self.dF = self.w * (1/(self.OFratio+1)) + if self.etype == "Liquid": + self.w = (self.thrust/self.env.g_zero)/self.isp + elif self.etype == "Solid": + self.w = (self.avg_thrust/self.env.g_zero)/self.isp + self.dF = self.w * (1 / (self.OFratio + 1)) self.dOx = (self.w - self.dF) + # Fuel & Oxidizer self.F = (self.dF * self.burn_time)/(1 - self.Reserve/100) self.Ox = (self.dOx * self.burn_time)/(1 - self.Reserve/100) + # Mass - self.frameM = p.package[2][0] + self.dry_mass = p.package[2][0] + # Aerodynamics - self.Cd, self.Aproj = p.package[3] + self.Cd, self.cross_section = p.package[3] + # Output self.logout, self.csvout = p.package[4] @@ -54,21 +81,21 @@ def __init__(self, params, env, burn_time: float): self.field_names = [ "t", - "Fthrust", - "Fdrag", + "thrust", + "drag", "m", "v", - "Mach", + "mach", "a", "altitude", "asl", "twr", - "maxV", - "maxMach", - "maxAcc", - "minAcc", - "maxG", - "minG" + "max_v", + "max_mach", + "max_acc", + "min_acc", + "max_g", + "min_g" ] with open(self.csvout, "w", newline="") as f: csv_writer = csv.writer(f) @@ -78,25 +105,26 @@ def __init__(self, params, env, burn_time: float): # Flight def launch(self): """Runs a simulation within the given parameters.""" - # Variable setup + # Variables setup + self.t = 0 self.altitude = 0 self.asl = self.altitude + self.env.elev self.calc_mass() self.env.get_status(self.asl) + self.calc_thrust() self.calc_twr() - self.Fdrag = 0 + self.drag = 0 self.v = 0 - self.maxV = 0 - self.Mach = 0 - self.maxMach = 0 - self.maxAcc = 0 - self.maxG = 0 - self.minAcc = 0 - self.minG = 0 + self.max_v = 0 + self.mach = 0 + self.max_mach = 0 + self.max_acc = 0 + self.max_g = 0 + self.min_acc = 0 + self.min_g = 0 self.a = 0 self.j = 0 self.s = 0 - self.t = 0 # Used by matplotlib self.plot_data = [ @@ -119,6 +147,8 @@ def launch(self): self.add_data() # Environment-related self.update_env() + # Thrust-related + self.calc_thrust() # Accelaration/derivative-related self.calc_acc() self.calc_additional_derivatives() @@ -130,23 +160,20 @@ def launch(self): self.calc_drag() self.calc_twr() # Mass-related - self.remove_fuel() + self.calc_propellant() self.calc_mass() # Time-related self.t += self.env.t - if self.twr < 1: - raise RuntimeError("TWR below 1 : {}".format(self.twr)) + if self.a > self.max_acc: + self.max_acc = self.a + self.max_g = self.max_acc/self.env.g - if self.a > self.maxAcc: - self.maxAcc = self.a - self.maxG = self.maxAcc/self.env.g + if self.v > self.max_v: + self.max_v = self.v + self.max_mach = self.mach - if self.v > self.maxV: - self.maxV = self.v - self.maxMach = self.Mach - - self.Fthrust = 0 + self.thrust = 0 # Deceleration phase while self.v > 0: @@ -169,29 +196,35 @@ def launch(self): # Time-related self.t += self.env.t - if self.a < self.minAcc: - self.minAcc = self.a - self.minG = self.minAcc/self.env.g + if self.a < self.min_acc: + self.min_acc = self.a + self.min_g = self.min_acc/self.env.g self.output( - "maxV", - "maxMach", - "maxAcc", - "minAcc", - "maxG", - "minG" + "max_v", + "max_mach", + "max_acc", + "min_acc", + "max_g", + "min_g" ) def suicide_burn(self): """Run a suicide burn simulation, will affct ascent simulation.""" - self.Vt = math.sqrt((2 * self.m * self.env.g) / (self.env.Rho * self.Aproj * self.Cd)) # noqa + self.Vt = math.sqrt((2 * self.m * self.env.g) / (self.env.Rho * self.cross_section * self.Cd)) # noqa # Mass def calc_mass(self): - self.fuelM = (self.Ox + self.F) - self.m = self.fuelM + self.frameM - - def remove_fuel(self): + self.propellant_mass = (self.Ox + self.F) + self.m = self.propellant_mass + self.dry_mass + + def calc_propellant(self): + if self.etype == "Liquid": + self.w = (self.thrust/self.env.g_zero)/self.isp + elif self.etype == "Solid": + self.w = (self.avg_thrust/self.env.g_zero)/self.isp + self.dF = self.w * (1/(self.OFratio+1)) + self.dOx = (self.w - self.dF) self.Ox -= self.dOx * self.env.t self.F -= self.dF * self.env.t @@ -203,21 +236,27 @@ def set_altitude(self): # Derivatives of position def calc_velocity(self): self.v += self.a * self.env.t - self.Mach = self.v/self.env.c + self.mach = self.v/self.env.c def calc_acc(self): - self.a = (self.Fthrust - (self.m * self.env.g + self.Fdrag)) / self.m + self.a = (self.thrust - (self.m * self.env.g + self.drag)) / self.m def calc_additional_derivatives(self): self.j = (self.a - self.plot_data[4][-1]) / self.env.t self.s = (self.j - self.plot_data[5][-1]) / self.env.t # Forces + def calc_thrust(self): + if self.etype == "Liquid": + pass + elif self.etype == "Solid": + self.thrust = self.thrust_curve[round(self.t, 3)] + def calc_drag(self): - self.Fdrag = 0.5 * (self.env.Rho * self.v**2 * self.Cd * self.Aproj) + self.drag = 0.5 * (self.env.Rho * self.v**2 * self.Cd * self.cross_section) # noqa def calc_twr(self): - self.twr = self.Fthrust / (self.m * self.env.g) + self.twr = self.thrust / (self.m * self.env.g) # Environment def update_env(self): @@ -250,14 +289,14 @@ def add_data(self): self.plot_data[4].append(self.a) self.plot_data[5].append(self.j) self.plot_data[6].append(self.s) - self.plot_data[7].append(self.Fdrag) + self.plot_data[7].append(self.drag) self.output( "t", - "Fthrust", - "Fdrag", + "thrust", + "drag", "m", "v", - "Mach", + "mach", "a", "altitude", "asl", diff --git a/tests/input/case.json b/tests/input/case.json index 733cc79..389c9a8 100644 --- a/tests/input/case.json +++ b/tests/input/case.json @@ -1,17 +1,18 @@ { "Engine" : { - "Specific Impulse (s)" : 318, + "Type" : "Liquid", + "Specific impulse (s)" : 318, "Thrust (N)" : 500 }, "Fuel" : { - "Oxidizer/Fuel Mixture Ratio" : 15, - "Fuel Reserve (%)" : 5 + "Oxidizer/fuel mixture ratio" : 15, + "Fuel reserve (%)" : 5 }, "Mass" : { "Dry Mass (kg)" : 10 }, "Aerodynamics" : { - "Drag Coefficient" : 0.0556, + "Drag coefficient" : 0.0556, "Cross-section (m2)" : 0.0255364 }, "Environment" : { @@ -21,10 +22,10 @@ "Air molar mass (kg/mol)" : 0.02896968, "Gas constant (J/(K.mol))" : 8.314462618, "Air heat capacity ratio" : 1.4, - "Standard Atmospheric pressure @SL (Pa)" : 101325 + "Standard atmospheric pressure @SL (Pa)" : 101325 }, "Output" : { - "Log File Path" : "Flight.log", - "CSV File Path" : "Flight.csv" + ".log file" : "Flight.log", + ".csv file" : "Flight.csv" } } diff --git a/tests/input/case.params b/tests/input/case.params index 31f7b16..0c5eed1 100644 --- a/tests/input/case.params +++ b/tests/input/case.params @@ -1,7 +1,8 @@ +Type : Solid Specific impulse (s) : 318 -Thrust (N) : 500 +Average thrust (N) : 500 +Thrust curve file path : tests/input/thrust.csv ================== ▲ Engine ▲ ================= -Oxidizer/Fuel mixture ratio : 15 Fuel reserve (%) : 5 =================== ▲ Fuel ▲ ================== Dry mass (kg) : 10 diff --git a/tests/input/gofast.json b/tests/input/gofast.json index d164ae7..0dc0325 100644 --- a/tests/input/gofast.json +++ b/tests/input/gofast.json @@ -1,18 +1,19 @@ { "Engine" : { - "Specific Impulse (s)" : 212.5, - "Thrust (N)" : 39419 + "Type" : "Solid", + "Specific impulse (s)" : 212.5, + "Average thrust (N)" : 39419, + "Thrust curve file path" : "Preflight/tests/input/S-50000.csv" }, "Fuel" : { - "Oxidizer/Fuel Mixture Ratio" : 1, - "Fuel Reserve (%)" : 0 + "Fuel reserve (%)" : 0 }, "Mass" : { - "Dry Mass (kg)" : 131.36 + "Dry mass (kg)" : 131.36 }, "Aerodynamics" : { - "Drag Coefficient" : 0.0555, - "Frontal Area (m2)" : 0.21 + "Drag coefficient" : 0.1, + "Cross-section (m2)" : 0.05 }, "Environment" : { "Elevation (m)" : 1190, @@ -21,10 +22,10 @@ "Air molar mass (kg/mol)" : 0.02896968, "Gas constant (J/(K.mol))" : 8.314462618, "Air heat capacity ratio" : 1.4, - "Standard Atmospheric pressure @SL (Pa)" : 101325 + "Standard atmospheric pressure @SL (Pa)" : 101325 }, "Output" : { - "Log File Path" : "tests/output/gofast.log", - "CSV File Path" : "tests/output/gofast.csv" + ".log file" : "Preflight/tests/output/gofast.log", + ".csv file" : "Preflight/tests/output/gofast.csv" } } diff --git a/tests/params_test.py b/tests/params_test.py index 6898dde..ee3b9d1 100644 --- a/tests/params_test.py +++ b/tests/params_test.py @@ -71,8 +71,8 @@ def test_params_extension(self): p = pre.Parameters("tests/input/case.params") assert p.package == [ - [318, 500], - [15, 5], + ["Solid", 318, 500, "tests/input/thrust.csv"], + [5], [10], [0.0556, 0.0255364], ["Flight.log", "Flight.csv"] @@ -91,7 +91,7 @@ def test_json_extension(self): p = pre.Parameters("tests/input/case.json") assert p.package == [ - [318, 500], + ["Liquid", 318, 500], [15, 5], [10], [0.0556, 0.0255364],