class Engine(Turbomachine): def __init__(self): self.compressor = Compressor() self.turbine = Turbine() self.initial_guess = self.__class__.DEFAULT_PARAMS.copy() self.cpc = 1004 # J/(kg K) self.cpt = 1225 # J/(kg K) self.T01 = 273.15 # K self.P01 = 101e3 # Pa self.R_c = (1 - 1 / self.compressor.gam) * self.cpc # from gam and cp self.R_t = (1 - 1 / self.turbine.gam) * self.cpt self.A8 = pi / 4 * 35e-3**2 # Measured: D8 = 45mm self.FHV = 43e6 #J/kg Fuel lower calorific value self.eta_combustion = 0.5 DEFAULT_PARAMS = { 'P0_ratio_c': 1.2347241010782356, 'Mb_t': 0.27072466251896482, 'MFP4': 0.15310678698124691, 'MFP3': 0.14924987675288623, 'M_flight': 0, 'mdotf': 0.0019637316313999187, 'P0_ratio_t': 0.92680225375718472, 'MFP5': 0.15451547834023707, 'Mb_c': 0.44527731422329964, 'MFP': 0.14801196525452109, 'T0_ratio_t': 0.98261102832775471, 'T0_ratio_c': 1.0669702796449636, 'T04': 840.63888888888891 } N_FREE_PARAMS = 2 def implicit_map( self, M_flight, # flight mach number MFP, MFP3, Mb_c, T0_ratio_c, P0_ratio_c, # compressor mdotf, T04, # burner MFP4, MFP5, Mb_t, T0_ratio_t, P0_ratio_t # turbine ): """ This function implements burner, nozzle and spool dynamics and integrates it with turbine and compressor maps Variable balance: 12 variables - 11 equations -------- 2 free choices (e.g. M_flight and mdotf) """ # Expose constants A8 = self.A8 FHV = self.FHV eta_combustion = self.eta_combustion A5 = self.turbine.geom['A2'] gam_c = self.compressor.gam gam_t = self.turbine.gam cpc = self.cpc cpt = self.cpt T01 = self.T01 P01 = self.P01 R_c = self.R_c R_t = self.R_t ### Dimensionalize everything ### dim_params = self.dimensionalize( M_flight, # flight mach number MFP, MFP3, Mb_c, T0_ratio_c, P0_ratio_c, # compressor mdotf, T04, # burner MFP4, MFP5, Mb_t, T0_ratio_t, P0_ratio_t # turbine ) T02 = dim_params.T02 T03 = dim_params.T03 T05 = dim_params.T05 P02 = dim_params.P02 P03 = dim_params.P03 P04 = dim_params.P04 P05 = dim_params.P05 omega_c = dim_params.omega_c omega_t = dim_params.omega_t mdot2 = dim_params.mdot2 mdot3 = dim_params.mdot3 mdot4 = dim_params.mdot4 mdot5 = dim_params.mdot5 ### CONSTRAINTS ### # * Energy addition in ther burner res_T04 = T03 + mdotf * FHV * eta_combustion / (mdot3 * cpc) - T04 # * Spool has constant speed res_omega = omega_c - omega_t # * Conservation of energy in the spool res_energy = mdot2 * cpc * (T03 - T02) - mdot4 * cpt * (T04 - T05) # * Consevation of mass in the combustor res_mdot = mdot3 + mdotf - mdot4 # * Nozzle exit is either choked or at ambient pressure Pa = P01 / (1 + (gam_c - 1) / 2 * M_flight**2)**(gam_c / (gam_c - 1)) MFP8 = MFP5 * A5 / A8 res_MFP_nozzle = (P05 / Pa - 1) * MFP8 - (P05 / Pa - 1) * mach2mfp( min(1, (2 / (gam_t - 1) * ((P05 / Pa)**( (gam_t - 1) / gam_t) - 1))**0.5) if P05 / Pa > 1 else 0, gam_t) ### remove dimensions of residuals ### # References for removing dimensions of residuals mdotref = (T01 * R_c)**0.5 / (P01 * gam_c**0.5 * self.compressor.geom['A1']) h_ref = cpc * T01 omega_ref = (gam_c * R_c * T01)**0.5 / self.compressor.geom['D2'] #remove dimensions res_omega /= omega_ref res_energy /= h_ref * mdotref res_mdot /= mdotref res_T04 /= T04 ### COMPRESSOR MAP ### res_MFP_c, res_T0_ratio_c, res_P0_ratio_c = self.compressor.implicit_map( MFP, MFP3, Mb_c, T0_ratio_c, P0_ratio_c, tol=1e-13) ### TURBINE MAP ### res_MFP_t, res_T0_ratio_t, res_P0_ratio_t = self.turbine.implicit_map( MFP4, MFP5, Mb_t, T0_ratio_t, P0_ratio_t, tol=1e-13) return (res_omega, res_energy, res_mdot, res_MFP_nozzle, res_T04, res_MFP_c, res_T0_ratio_c, res_P0_ratio_c, res_MFP_t, res_T0_ratio_t, res_P0_ratio_t) def dimensionalize( self, M_flight, # flight mach number MFP, MFP3, Mb_c, T0_ratio_c, P0_ratio_c, # compressor mdotf, T04, # burner MFP4, MFP5, Mb_t, T0_ratio_t, P0_ratio_t # turbine ): gam_c = self.compressor.gam gam_t = self.turbine.gam T01 = self.T01 P01 = self.P01 R_c = self.R_c R_t = self.R_t ### Dimensionalize everything ### a01 = (gam_c * R_c * T01)**0.5 a04 = (gam_t * R_t * T04)**0.5 T02 = T01 T03 = T02 * T0_ratio_c T04 = T04 T05 = T04 * T0_ratio_t P02 = P01 P03 = P02 * P0_ratio_c P04 = P03 P05 = P03 * P0_ratio_t omega_c = Mb_c * a01 / (self.compressor.geom['D2'] / 2) omega_t = Mb_t * a04 / (self.turbine.geom['D1t'] / 2) mdot2 = MFP * self.compressor.geom['A1'] * P01 * gam_c**0.5 / ( T01 * R_c)**0.5 mdot3 = MFP3 * self.compressor.geom['A2'] * P03 * gam_c**0.5 / ( T03 * R_c)**0.5 mdot4 = MFP4 * self.turbine.geom['A1'] * P04 * gam_t**0.5 / (T04 * R_t)**0.5 mdot5 = MFP5 * self.turbine.geom['A2'] * P05 * gam_t**0.5 / (T05 * R_t)**0.5 #Nozzle MFP8 = min(MFP5 * self.turbine.geom['A2'] / self.A8, mach2mfp(1, gam_t)) M8 = mfp2mach(MFP8, gam_t) P8 = P05 * (1 + (gam_t - 1) / 2 * M8**2)**(-gam_t / (gam_t - 1)) T8 = T05 * (1 + (gam_t - 1) / 2 * M8**2)**(-1) dim_params = DimensionalParameters(T02=T02, T03=T03, T04=T04, T05=T05, T8=T8, P02=P02, P03=P03, P04=P04, P05=P05, P8=P8, omega_c=omega_c, omega_t=omega_t, mdot2=mdot2, mdot3=mdot3, mdot4=mdot4, mdot5=mdot5) return dim_params def working_line(self, T04_grid): wline = [] params = self.initial_guess for T04 in T04_grid: sol = self.general_explicit_map({ 'M_flight': 0, 'T04': T04 }, params) params = sol.params wline.append(params) return wline def thrust(self, **params): gam_t = self.turbine.gam R_t = self.R_t MFP8 = min(params['MFP5'] * self.turbine.geom['A2'] / self.A8, mach2mfp(1, gam_t)) mdot = params['MFP5'] * self.turbine.geom['A2'] * params[ 'P05'] * gam_t**0.5 / (params['T05'] * R_t)**0.5 M8 = mfp2mach(MFP8, gam_t) P8 = params['P05'] * (1 + (gam_t - 1) / 2 * M8**2)**(-gam_t / (gam_t - 1)) mdot5 = params['MFP5'] * self.turbine.geom['A2'] * params[ 'P05'] * gam_t**0.5 / (params['T05'] * R_t)**0.5 T8 = params['T05'] * (1 + (gam_t - 1) / 2 * M8**2)**(-1) return mdot * M8 * (gam_t * R_t * T8)**0.5 + ( P8 - self.P01 / (1 + (gam_t - 1) * params['M_flight']**2)**0.5) * self.A8 def ode_fun(self, t, y): P4, mdot, omega = y self.compressor.explicit_map(mdot, omega) T04 = self.throtle(t, mdot, T03) self.turbine.explicit_map(P4, omega) P4_dot = a01**2 * (mdot - mdott) mdotdot = A1 / Lc * (P3 - P4) omega_dot = 1 / J * torque_t - torque_c return P4_dot, mdotdot, omega_dot