def power_required(self): thrust_required_dict = {} power_required_dict = {} alpha_dict = {} for velocity in self.velocity_range: total_lift = 0 alpha = self.plane.stall_min while total_lift < self.plane.mtow * 9.81: alpha += 0.1 total_lift = self.wing1.lift(self.rho, velocity, alpha) - self.hs.lift( self.rho, velocity, alpha) if self.plane.plane_type == "biplane": total_lift += self.wing2.lift(self.rho, velocity, alpha) if alpha >= self.plane.stall_max: alpha_nivel = None break else: alpha_nivel = alpha thrust_required = ( drag(self.rho, velocity, self.plane.S_tp, self.plane.CD_tp) + drag(self.rho, velocity, self.plane.S_fus, self.plane.CD_fus) + self.wing1.drag(self.rho, velocity, alpha_nivel) + self.wing2.drag(self.rho, velocity, alpha_nivel) + self.hs.drag(self.rho, velocity, alpha_nivel)) alpha_dict[velocity] = alpha_nivel thrust_required_dict[velocity] = thrust_required for velocity in thrust_required_dict: power_required_dict[ velocity] = thrust_required_dict[velocity] * velocity self.thrust_required_dict = thrust_required_dict self.power_required_dict = power_required_dict self.alpha_dict = alpha_dict self.alpha_df = dict_to_dataframe(alpha_dict, "Alpha", "Velocity") self.thrust_required_df = dict_to_dataframe(thrust_required_dict, "Thrust required", "Velocity") self.power_required_df = dict_to_dataframe(power_required_dict, "Power required", "Velocity") return self.alpha_df, self.thrust_required_df, self.power_required_df
def power_excess(self): power_excess_dict = {} for velocity in self.power_available_dict: power_required = self.power_required_dict[velocity] power_available = self.power_available_dict[velocity] power_excess_dict[velocity] = power_available - power_required self.power_excess_dict = power_excess_dict self.power_excess_df = dict_to_dataframe(power_excess_dict, "Power excess", "Velocity")
def get_CD_alpha_plane(self): CD_alpha_plane = {} for alpha in np.arange(-10, 21, 1.0): numerator = (self.wing1.get_CD(alpha) * self.wing1.area - self.hs.get_CD(alpha) * self.hs.area) if self.plane_type == "biplane": numerator += self.wing2.get_CD(alpha) * self.wing2.area CD_alpha_plane[alpha] = numerator / self.wing1.area self.CD_alpha = dict_to_dataframe(CD_alpha_plane, "CD", "alpha") return self.CD_alpha
def power_available(self): thrust_available_dict = {} power_available_dict = {} for velocity in self.velocity_range: thrust_available = self.plane.motor.thrust(velocity) thrust_available_dict[velocity] = thrust_available for velocity in thrust_available_dict: power_available_dict[ velocity] = thrust_available_dict[velocity] * velocity self.thrust_available_dict = thrust_available_dict self.power_available_dict = power_available_dict self.thrust_available_df = dict_to_dataframe(thrust_available_dict, "Thrust available", "Velocity") self.power_available_df = dict_to_dataframe(power_available_dict, "Power available", "Velocity") return self.thrust_available_df, self.power_available_df
def trimm(self): tail_trimm = {} for hs_incidence in self.hs.incidence_range: root = find_df_roots( self.CM_alpha_CG_plane_each_hs_incidence[hs_incidence], "CM") if len(root) != 0: alpha_trimm = root[0] tail_trimm[alpha_trimm] = hs_incidence self.tail_trimm = tail_trimm self.tail_trimm_df = dict_to_dataframe(tail_trimm, "hs_incidence", "alpha") self.plane.tail_trimm = self.tail_trimm_df if tail_trimm: self.plane.alpha_trimm_min = min(tail_trimm, key=tail_trimm.get) self.plane.alpha_trimm_max = max(tail_trimm, key=tail_trimm.get) else: self.plane.alpha_trimm_min = 0 self.plane.alpha_trimm_max = 0 return self.tail_trimm_df
def test_get_CL_alpha_plane(plane): cl = { -10.0: 0.8961720610687022, -9.0: 1.0828123664122136, -8.0: 1.2690087022900762, -7.0: 1.4544367938931297, -6.0: 1.6393807633587787, -5.0: 1.8236004580152672, -4.0: 2.00718, -3.0: 2.1898352671755723, -2.0: 2.3712140458015263, -1.0: 2.5516685496183205, 0.0: 2.7310867175572517, 1.0: 2.9091882442748087, 2.0: 3.085813282442748, 3.0: 3.260721679389313, 4.0: 3.4343535877862594, 5.0: 3.606312824427481, 6.0: 3.7766433587786263, 7.0: 3.945017099236641, 8.0: 4.111562137404579, 9.0: 4.276278473282442, 10.0: 4.438685801526717, 11.0: 4.59902427480916, 12.0: 4.75733786259542, 13.0: 4.836142442748091, 14.0: 4.913922137404579, 15.0: 4.99043679389313, 16.0: 4.977114045801526, 17.0: 4.9639671755725185, 18.0: 4.950996183206107, 19.0: 4.938289007633587, 20.0: 4.925757709923665 } df_cl_alpha = dict_to_dataframe(cl, "CL", "alpha") pd.testing.assert_frame_equal(plane.get_CL_alpha_plane(), df_cl_alpha, check_less_precise=3)
def test_get_CD_alpha_plane(plane): cd = { -10.0: 0.005704, -9.0: 0.011138, -8.0: 0.017323, -7.0: 0.024453, -6.0: 0.032331, -5.0: 0.040958, -4.0: 0.050333, -3.0: 0.060700, -2.0: 0.072012, -1.0: 0.083633, 0.0: 0.096442, 1.0: 0.109715, 2.0: 0.123580, 3.0: 0.138194, 4.0: 0.153556, 5.0: 0.169427, 6.0: 0.185846, 7.0: 0.203057, 8.0: 0.220337, 9.0: 0.238164, 10.0: 0.256300, 11.0: 0.274833, 12.0: 0.293873, 13.0: 0.303226, 14.0: 0.312970, 15.0: 0.322387, 16.0: 0.320189, 17.0: 0.317946, 18.0: 0.315616, 19.0: 0.313242, 20.0: 0.31082 } df_cd_alpha = dict_to_dataframe(cd, "CD", "alpha") pd.testing.assert_frame_equal(plane.get_CD_alpha_plane(), df_cd_alpha, check_less_precise=3)
def static_margin(self): SM_alpha = {} self.hs.incidence = 0 for alpha_plane in self.plane.alpha_range: self.wing1.update_alpha(float(alpha_plane)) self.wing2.update_alpha(float(alpha_plane)) self.hs.update_alpha(float(alpha_plane)) if self.hs.attack_angle in self.hs.get_alpha_range(): # Calculating Static Margin for each alpha self.sm = SM( self.plane.plane_type, self.wing1, self.wing2, self.hs, alpha_plane, self.plane.dCM_dalpha.at[alpha_plane, "CM"], ) # TODO: We should pass the entire plane into SM analysys SM_alpha[alpha_plane] = self.sm.SM self.SM_alpha_df = dict_to_dataframe(SM_alpha, "SM", "alpha") self.plane.SM_alpha = self.SM_alpha_df return self.SM_alpha_df
def CM_plane_CG(self, cg): CM_alpha_CG_tail = {} CM_alpha_CG_wing1 = {} CM_alpha_CG_wing2 = {} CM_alpha_CG_wings = {} CM_alpha_CG_plane = {} self.CM_alpha_CG_plane_each_hs_incidence = {} for alpha_plane in self.plane.alpha_range: self.wing1.update_alpha(float(alpha_plane)) self.wing2.update_alpha(float(alpha_plane)) # Getting CM_alpha of wing1 CM_alpha_CG_wing1[alpha_plane] = self.wing1.moment_on_CG( self.wing1, self.plane.cg, alpha_plane) CM_alpha_CG_wings[alpha_plane] = CM_alpha_CG_wing1[alpha_plane] if self.plane.plane_type == "biplane": CM_alpha_CG_wing2[alpha_plane] = self.wing2.moment_on_CG( self.wing1, self.plane.cg, alpha_plane) CM_alpha_CG_wings[alpha_plane] += CM_alpha_CG_wing2[ alpha_plane] for hs_incidence in self.hs.incidence_range: self.hs.incidence = hs_incidence for alpha_plane in self.plane.alpha_range: self.hs.update_alpha(float(alpha_plane)) if self.hs.attack_angle in self.hs.get_alpha_range(): # Getting CM_alpha of tail CM_alpha_CG_tail[alpha_plane] = self.hs.moment_on_CG( self.wing1, self.plane.cg, alpha_plane) # Summing CM of tail with CM of wing per each alpha # Getting CM_alpha of plane CM_alpha_CG_plane[alpha_plane] = ( CM_alpha_CG_wings[alpha_plane] + CM_alpha_CG_tail[alpha_plane]) else: CM_alpha_CG_tail[alpha_plane] = None CM_alpha_CG_plane[alpha_plane] = None CM_alpha_CG_plane_df = dict_to_dataframe(CM_alpha_CG_plane, "CM", "alpha") self.CM_alpha_CG_plane_each_hs_incidence[ hs_incidence] = CM_alpha_CG_plane_df self.trimm() dCM_dalpha_plane_df = self.CM_alpha_CG_plane_each_hs_incidence[0].diff( ) dCM_dalpha_plane_df.fillna(method="bfill", inplace=True) self.plane.dCM_dalpha = dCM_dalpha_plane_df self.wing1.CM_alpha_CG = dict_to_dataframe(CM_alpha_CG_wing1, "CM", "alpha") self.wing2.CM_alpha_CG = dict_to_dataframe(CM_alpha_CG_wing2, "CM", "alpha") self.hs.CM_alpha_CG = dict_to_dataframe(CM_alpha_CG_tail, "CM", "alpha") return self.CM_alpha_CG_plane_each_hs_incidence
def test_power_required(power): power_required_check = { 3.693459: 55.925256, 3.793459: 60.549268, 3.893459: 65.434352, 3.993459: 70.606824, 4.093459: 76.044941, 4.193459: 81.755353, 4.293459: 87.744713, 4.393459: 94.019673, 4.493459: 100.586884, 4.593459: 107.452999, 4.693459: 114.624669, 4.793459: 122.108547, 4.893459: 129.911284, 4.993459: 138.039533, 5.093459: 146.499945, 5.193459: 155.299173, 5.293459: 164.443868, 5.393459: 173.940683, 5.493459: 183.796268, 5.593459: 194.017277, 5.693459: 204.610362, 5.793459: 215.582173, 5.893459: 226.939364, 5.993459: 238.688586, 6.093459: 250.836491, 6.193459: 263.389731, 6.293459: 276.354958, 6.393459: 289.738825, 6.493459: 303.547982, 6.593459: 317.789082, 6.693459: 332.468778, 6.793459: 347.593720, 6.893459: 363.170561, 6.993459: 379.205954, 7.093459: 395.706549, 7.193459: 412.678999, 7.293459: 430.129955, 7.393459: 448.066071, 7.493459: 466.493997, 7.593459: 485.420386, 7.693459: 504.851889, 7.793459: 524.795160, 7.893459: 545.256849, 7.993459: 566.243608, 8.093459: 587.762090, 8.193459: 609.818947, 8.293459: 632.420830, 8.393459: 655.574392, 8.493459: 679.286284, 8.593459: 703.563159, 8.693459: 728.411668, } df_power_required_check = dict_to_dataframe(power_required_check, "Power required", "Velocity") alpha_velocity_check = { 3.693459: -9.4, 3.793459: -9.7, 3.893459: -9.9, 3.993459: -9.9, 4.093459: -9.9, 4.193459: -9.9, 4.293459: -9.9, 4.393459: -9.9, 4.493459: -9.9, 4.593459: -9.9, 4.693459: -9.9, 4.793459: -9.9, 4.893459: -9.9, 4.993459: -9.9, 5.093459: -9.9, 5.193459: -9.9, 5.293459: -9.9, 5.393459: -9.9, 5.493459: -9.9, 5.593459: -9.9, 5.693459: -9.9, 5.793459: -9.9, 5.893459: -9.9, 5.993459: -9.9, 6.093459: -9.9, 6.193459: -9.9, 6.293459: -9.9, 6.393459: -9.9, 6.493459: -9.9, 6.593459: -9.9, 6.693459: -9.9, 6.793459: -9.9, 6.893459: -9.9, 6.993459: -9.9, 7.093459: -9.9, 7.193459: -9.9, 7.293459: -9.9, 7.393459: -9.9, 7.493459: -9.9, 7.593459: -9.9, 7.693459: -9.9, 7.793459: -9.9, 7.893459: -9.9, 7.993459: -9.9, 8.093459: -9.9, 8.193459: -9.9, 8.293459: -9.9, 8.393459: -9.9, 8.493459: -9.9, 8.593459: -9.9, 8.693459: -9.9, } df_alpha_velocity_check = dict_to_dataframe(alpha_velocity_check, "Alpha", "Velocity") thrust_velocity_check = { 3.693459: 15.141704, 3.793459: 15.961495, 3.893459: 16.806228, 3.993459: 17.680620, 4.093459: 18.577186, 4.193459: 19.495925, 4.293459: 20.436837, 4.393459: 21.399922, 4.493459: 22.385181, 4.593459: 23.392613, 4.693459: 24.422218, 4.793459: 25.473996, 4.893459: 26.547948, 4.993459: 27.644073, 5.093459: 28.762371, 5.193459: 29.902842, 5.293459: 31.065487, 5.393459: 32.250305, 5.493459: 33.457296, 5.593459: 34.686460, 5.693459: 35.937797, 5.793459: 37.211308, 5.893459: 38.506992, 5.993459: 39.824849, 6.093459: 41.164880, 6.193459: 42.527084, 6.293459: 43.911461, 6.393459: 45.318011, 6.493459: 46.746734, 6.593459: 48.197631, 6.693459: 49.670701, 6.793459: 51.165944, 6.893459: 52.683360, 6.993459: 54.222950, 7.093459: 55.784713, 7.193459: 57.368649, 7.293459: 58.974758, 7.393459: 60.603041, 7.493459: 62.253496, 7.593459: 63.926125, 7.693459: 65.620928, 7.793459: 67.337903, 7.893459: 69.077052, 7.993459: 70.838374, 8.093459: 72.621869, 8.193459: 74.427538, 8.293459: 76.255379, 8.393459: 78.105394, 8.493459: 79.977582, 8.593459: 81.871944, 8.693459: 83.788479, } df_thrust_velocity_check = dict_to_dataframe(thrust_velocity_check, "Thrust required", "Velocity") pd.testing.assert_frame_equal(power.power_required_df, df_power_required_check, check_less_precise=3) pd.testing.assert_frame_equal(power.alpha_df, df_alpha_velocity_check, check_less_precise=3) pd.testing.assert_frame_equal(power.thrust_required_df, df_thrust_velocity_check, check_less_precise=3)
def test_power_excess(power): power_excess_check = { 3.693458584650559: -53.87901072296934, 3.7934585846505593: -58.39071923177715, 3.8934585846505594: -63.16049866668177, 3.9934585846505595: -68.21466776637739, 4.093458584650559: -73.53148059043242, 4.19345858465056: -79.11758911028298, 4.29345858465056: -84.97964529736497, 4.39345858465056: -91.12430112311439, 4.4934585846505595: -97.55820855896721, 4.59345858465056: -104.28801957635953, 4.6934585846505605: -111.32038614672733, 4.79345858465056: -118.66196024150648, 4.89345858465056: -126.31939383213309, 4.99345858465056: -134.2993388900432, 5.093458584650561: -142.60844738667276, 5.1934585846505605: -151.2533712934577, 5.29345858465056: -160.24076258183413, 5.393458584650561: -169.57727322323802, 5.493458584650561: -179.26955518910538, 5.593458584650561: -189.3242604508721, 5.6934585846505605: -199.74804097997426, 5.793458584650561: -210.54754874784794, 5.893458584650562: -221.72943572592908, 5.993458584650561: -233.30035388565358, 6.093458584650561: -245.26695519845754, 6.193458584650561: -257.6358916357771, 6.293458584650562: -270.4138151690479, 6.393458584650562: -283.60737776970626, 6.493458584650561: -297.22323140918803, 6.593458584650562: -311.26802805892925, 6.693458584650562: -325.74841969036595, 6.793458584650562: -340.671058274934, 6.893458584650562: -356.04259578406953, 6.993458584650562: -371.8696841892086, 7.093458584650563: -388.15897546178707, 7.193458584650562: -404.917121573241, 7.293458584650562: -422.1507744950062, 7.3934585846505625: -439.86658619851903, 7.493458584650563: -458.0712086552154, 7.593458584650563: -476.77129383653096, 7.693458584650562: -495.9734937139021, 7.793458584650562: -515.6844602587644, 7.893458584650563: -535.9108454425548, 7.993458584650563: -556.6593012367081, 8.093458584650563: -577.936479612661, 8.193458584650562: -599.7490325418494, 8.293458584650564: -622.1036119957093, 8.393458584650563: -645.0068699456767, 8.493458584650563: -668.465458363187, 8.593458584650563: -692.4860292196771, 8.693458584650564: -717.0752344865831, } df_power_excess_check = dict_to_dataframe(power_excess_check, "Power excess", "Velocity") pd.testing.assert_frame_equal(power.power_excess_df, df_power_excess_check, check_less_precise=3)
def test_power_available(power): thrust_available_check = { 3.693459: 0.554019, 3.793459: 0.569019, 3.893459: 0.584019, 3.993459: 0.599019, 4.093459: 0.614019, 4.193459: 0.629019, 4.293459: 0.644019, 4.393459: 0.659019, 4.493459: 0.674019, 4.593459: 0.689019, 4.693459: 0.704019, 4.793459: 0.719019, 4.893459: 0.734019, 4.993459: 0.749019, 5.093459: 0.764019, 5.193459: 0.779019, 5.293459: 0.794019, 5.393459: 0.809019, 5.493459: 0.824019, 5.593459: 0.839019, 5.693459: 0.854019, 5.793459: 0.869019, 5.893459: 0.884019, 5.993459: 0.899019, 6.093459: 0.914019, 6.193459: 0.929019, 6.293459: 0.944019, 6.393459: 0.959019, 6.493459: 0.974019, 6.593459: 0.989019, 6.693459: 1.004019, 6.793459: 1.019019, 6.893459: 1.034019, 6.993459: 1.049019, 7.093459: 1.064019, 7.193459: 1.079019, 7.293459: 1.094019, 7.393459: 1.109019, 7.493459: 1.124019, 7.593459: 1.139019, 7.693459: 1.154019, 7.793459: 1.169019, 7.893459: 1.184019, 7.993459: 1.199019, 8.093459: 1.214019, 8.193459: 1.229019, 8.293459: 1.244019, 8.393459: 1.259019, 8.493459: 1.274019, 8.593459: 1.289019, 8.693459: 1.304019, } df_thrust_available_check = dict_to_dataframe(thrust_available_check, "Thrust available", "Velocity") power_available_check = { 3.693459: 2.046245, 3.793459: 2.158549, 3.893459: 2.273853, 3.993459: 2.392157, 4.093459: 2.513460, 4.193459: 2.637764, 4.293459: 2.765068, 4.393459: 2.895372, 4.493459: 3.028676, 4.593459: 3.164979, 4.693459: 3.304283, 4.793459: 3.446587, 4.893459: 3.591891, 4.993459: 3.740194, 5.093459: 3.891498, 5.193459: 4.045802, 5.293459: 4.203106, 5.393459: 4.363409, 5.493459: 4.526713, 5.593459: 4.693017, 5.693459: 4.862321, 5.793459: 5.034624, 5.893459: 5.209928, 5.993459: 5.388232, 6.093459: 5.569536, 6.193459: 5.753839, 6.293459: 5.941143, 6.393459: 6.131447, 6.493459: 6.324751, 6.593459: 6.521054, 6.693459: 6.720358, 6.793459: 6.922662, 6.893459: 7.127966, 6.993459: 7.336269, 7.093459: 7.547573, 7.193459: 7.761877, 7.293459: 7.979181, 7.393459: 8.199484, 7.493459: 8.422788, 7.593459: 8.649092, 7.693459: 8.878396, 7.793459: 9.110700, 7.893459: 9.346003, 7.993459: 9.584307, 8.093459: 9.825611, 8.193459: 10.069915, 8.293459: 10.317218, 8.393459: 10.567522, 8.493459: 10.820826, 8.593459: 11.077130, 8.693459: 11.336433, } df_power_available_check = dict_to_dataframe(power_available_check, "Power available", "Velocity") pd.testing.assert_frame_equal(power.thrust_available_df, df_thrust_available_check, check_less_precise=3) pd.testing.assert_frame_equal(power.power_available_df, df_power_available_check, check_less_precise=3)