def WOT_speed(altitude, weight = 2100, rpm = 2700, temp = 'std', \ temp_units = 'C', rv = 'F1', wing_area = 102, speed_units = 'kt', \ prop_eff = 0.78, MP_loss = 1.322, ram = 0.5, rated_power=275): """ Returns the predicted speed at full throttle. The MP_loss is the MP lost in the induction tract at full throttle at 2700 rpm at MSL. The default value is from the Lycoming power charts. The ram is the percentage of available ram recovery pressure that is achieved in the MP. """ press = SA.alt2press(altitude, press_units = 'in HG') MP_loss = MP_loss * (rpm / 2700.) ** 2 cas_guess = 300 error = 1 while error > 0.0001: dp = A.cas2dp(cas_guess, press_units = 'in HG') # print 'dp =', dp ram_press = ram * dp # print 'Ram rise =', ram_press MP = press - MP_loss + ram_press pwr = O.pwr(rpm, MP, altitude, temp = temp, temp_units = temp_units) * rated_power/180 print 'MP =', MP, 'Power =', pwr tas = speed(altitude, weight, pwr, rpm, temp = temp, \ temp_units = temp_units, rv = rv, wing_area = wing_area, \ speed_units = speed_units, prop_eff = prop_eff) cas = A.tas2cas(tas, altitude, temp = temp, temp_units = temp_units) error = M.fabs((cas - cas_guess) / cas) cas_guess = cas # print 'CAS =', cas, 'TAS =', tas return tas
def tas2ssec(tas, alt, oat, ias, speed_units=default_speed_units, alt_units=default_alt_units, temp_units=default_temp_units, press_units = default_press_units): """ Return static source position error as speed error, pressure error and altitude error at sea level. Returns delta_Vpc, delta_Ps, delta_Hpc and Vc delta_Vpc = error in airspeed = calibrated airspeed - indicated airspeed corrected for instrument error delta_Ps = error in the pressure sensed by the static system = pressure sensed in the static system - ambient pressure delta_Hpc = altitude error at sea level = actual altitude - altitude sensed by the static system Vc = calibrated airspeed at the test point """ P0 = U.press_conv(constants.P0, from_units = 'pa', to_units = press_units) cas = A.tas2cas(tas, alt, oat, speed_units=speed_units, alt_units=alt_units, temp_units=temp_units) delta_Vpc = cas - ias qcic = A.cas2dp(ias, speed_units=speed_units, press_units =press_units) qc = A.cas2dp(cas, speed_units=speed_units, press_units = press_units) delta_Ps = qc - qcic delta_Hpc = SA.press2alt(P0 - delta_Ps, press_units = press_units) # print 'Vc = %.1f, delta_vpc = %.1f, delta_ps = %.1f, delta_hpc = %.0f' % (cas, delta_Vpc, delta_Ps, delta_Hpc) return delta_Vpc, delta_Ps, delta_Hpc, cas
def WOT_speed(altitude, weight = 2100, rpm = 2700, temp = 'std', \ temp_units = 'C', rv = 'F1', wing_area = 102, speed_units = 'kt', \ prop_eff = 0.78, MP_loss = 1.322, ram = 0.5, rated_power=275): """ Returns the predicted speed at full throttle. The MP_loss is the MP lost in the induction tract at full throttle at 2700 rpm at MSL. The default value is from the Lycoming power charts. The ram is the percentage of available ram recovery pressure that is achieved in the MP. """ press = SA.alt2press(altitude, press_units='in HG') MP_loss = MP_loss * (rpm / 2700.)**2 cas_guess = 300 error = 1 while error > 0.0001: dp = A.cas2dp(cas_guess, press_units='in HG') # print 'dp =', dp ram_press = ram * dp # print 'Ram rise =', ram_press MP = press - MP_loss + ram_press pwr = O.pwr(rpm, MP, altitude, temp=temp, temp_units=temp_units) * rated_power / 180 print('MP =', MP, 'Power =', pwr) tas = speed(altitude, weight, pwr, rpm, temp = temp, \ temp_units = temp_units, rv = rv, wing_area = wing_area, \ speed_units = speed_units, prop_eff = prop_eff) cas = A.tas2cas(tas, altitude, temp=temp, temp_units=temp_units) error = M.fabs((cas - cas_guess) / cas) cas_guess = cas # print 'CAS =', cas, 'TAS =', tas return tas
def test_02(self): # 400 kt at 30000, temp -70 deg F # truth value from NASA RP 1046 + correction for non-standard temp Value = A.tas2cas(586.266, 30000, -70, temp_units='F') Truth = 400 self.assertTrue(RE(Value, Truth) <= 3e-5)
def test_01(self): # 400 kt at 30000, std temp # truth value from NASA RP 1046 Value = A.tas2cas(602.6, 30000) Truth = 400 self.assertTrue(RE(Value, Truth) <= 3e-5)
def test_02(self): # 400 kt at 30000, temp -70 deg F # truth value from NASA RP 1046 + correction for non-standard temp Value = A.tas2cas(586.266, 30000, -70, temp_units='F') Truth = 400 self.failUnless(RE(Value, Truth) <= 3e-5)
def test_01(self): # 400 kt at 30000, std temp # truth value from NASA RP 1046 Value = A.tas2cas(602.6, 30000) Truth = 400 self.failUnless(RE(Value, Truth) <= 3e-5)
def gps2stall(GS, TK, Hp, T, temp_units='C', alt_units=default_alt_units, speed_units=default_speed_units, GPS_units=default_speed_units): """ Return the CAS at the stall, given four GPS ground speeds, GPS tracks, altitude and temperature. speed_units = CAS units. May be 'kt', 'mph', 'km/h', 'm/s' and 'ft/s'. GS_units = GPS ground speed units. 'kt', 'mph', 'km/h', 'm/s' and 'ft/s'. HP = pressure altitude. May be feet ('ft'), metres ('m'), kilometres ('km'), statute miles, ('sm') or nautical miles ('nm'). The temperature may be in deg C, F, K or R. If the units are not specified, the units in default_units.py are used. Conduct four stalls, in a four sided box pattern, with all stalls at the same pressure altitude. The data reduction algorithm calculates the TAS using Doug Gray's GPS to TAS method, using four different combinations of three legs. If the data quality is high, all four TAS values will be similar, with a low standard deviation. The TAS at the stall is converted to CAS, using pressure altitude and temperature. Returns CAS and standard deviation of the CAS value. Examples: >>> gps2stall([44, 104, 157, 131], [258, 29, 91, 150], 7000, 14, temp_units='F', GPS_units='km/h') (50.322235245211225, 0.6583323098888626) """ tas, std_dev = SSEC.gps2tas(GS, TK, verbose=1) tas = U.speed_conv(tas, from_units=GPS_units, to_units=speed_units) std_dev = U.speed_conv(std_dev, from_units=GPS_units, to_units=speed_units) cas = A.tas2cas(tas, Hp, T, temp_units=temp_units, alt_units=alt_units, speed_units=speed_units) std_dev = std_dev * cas / tas # factor standard deviation to reference CAS vs TAS return cas, std_dev
def WOT_speed_orig(prop, altitude, weight = 1800, rpm = 2700, temp = 'std', \ temp_units = 'C', rv = '8', wing_area = 110, speed_units = 'kt' , \ MP_loss = 1.322, ram = 0.5, pwr_factor=1, mixture='pwr', \ wheel_pants=1): """ Returns the predicted speed at full throttle. The MP_loss is the MP lost in the induction tract at full throttle at 2700 rpm at MSL. The default value is from the Lycoming power charts. The ram is the percentage of available ram recovery pressure that is achieved in the MP. """ press = SA.alt2press(altitude, press_units='in HG') MP_loss = MP_loss * (rpm / 2700.)**2 cas_guess = 300 error = 1 if mixture == 'econ': pwr_factor *= .86 # average power ratio to max power when at 50 deg LOP mixture elif mixture == 'pwr': pass else: raise ValueError('mixture must be one of "pwr" or "econ"') while error > 0.0001: dp = A.cas2dp(cas_guess, press_units='in HG') # print 'dp =', dp ram_press = ram * dp # print 'Ram rise =', ram_press MP = press - MP_loss + ram_press pwr = IO.pwr(rpm, MP, altitude, temp=temp, temp_units=temp_units) * pwr_factor # print 'MP =', MP, 'Power =', pwr tas = speed(prop, altitude, weight, pwr, rpm, temp = temp, \ temp_units = temp_units, rv = rv, wing_area = wing_area, \ speed_units = speed_units, wheel_pants = wheel_pants) cas = A.tas2cas(tas, altitude, temp=temp, temp_units=temp_units) error = M.fabs((cas - cas_guess) / cas) cas_guess = cas # print 'CAS =', cas, 'TAS =', tas # print "MP = %.3f" % MP # print "Pwr = %.2f" % pwr return tas
def WOT_speed_orig(prop, altitude, weight = 1800, rpm = 2700, temp = 'std', \ temp_units = 'C', rv = '8', wing_area = 110, speed_units = 'kt' , \ MP_loss = 1.322, ram = 0.5, pwr_factor=1, mixture='pwr', \ wheel_pants=1): """ Returns the predicted speed at full throttle. The MP_loss is the MP lost in the induction tract at full throttle at 2700 rpm at MSL. The default value is from the Lycoming power charts. The ram is the percentage of available ram recovery pressure that is achieved in the MP. """ press = SA.alt2press(altitude, press_units = 'in HG') MP_loss = MP_loss * (rpm / 2700.) ** 2 cas_guess = 300 error = 1 if mixture == 'econ': pwr_factor *= .86 # average power ratio to max power when at 50 deg LOP mixture elif mixture == 'pwr': pass else: raise ValueError, 'mixture must be one of "pwr" or "econ"' while error > 0.0001: dp = A.cas2dp(cas_guess, press_units = 'in HG') # print 'dp =', dp ram_press = ram * dp # print 'Ram rise =', ram_press MP = press - MP_loss + ram_press pwr = IO.pwr(rpm, MP, altitude, temp = temp, temp_units = temp_units) * pwr_factor # print 'MP =', MP, 'Power =', pwr tas = speed(prop, altitude, weight, pwr, rpm, temp = temp, \ temp_units = temp_units, rv = rv, wing_area = wing_area, \ speed_units = speed_units, wheel_pants = wheel_pants) cas = A.tas2cas(tas, altitude, temp = temp, temp_units = temp_units) error = M.fabs((cas - cas_guess) / cas) cas_guess = cas # print 'CAS =', cas, 'TAS =', tas # print "MP = %.3f" % MP # print "Pwr = %.2f" % pwr return tas
def tas2ssec(tas, alt, oat, ias, speed_units=default_speed_units, alt_units=default_alt_units, temp_units=default_temp_units, press_units=default_press_units): """ Return static source position error as speed error, pressure error and altitude error at sea level. Returns delta_Vpc, delta_Ps, delta_Hpc and Vc delta_Vpc = error in airspeed = calibrated airspeed - indicated airspeed corrected for instrument error delta_Ps = error in the pressure sensed by the static system = pressure sensed in the static system - ambient pressure delta_Hpc = altitude error at sea level = actual altitude - altitude sensed by the static system Vc = calibrated airspeed at the test point """ P0 = U.press_conv(constants.P0, from_units='pa', to_units=press_units) cas = A.tas2cas(tas, alt, oat, speed_units=speed_units, alt_units=alt_units, temp_units=temp_units) delta_Vpc = cas - ias qcic = A.cas2dp(ias, speed_units=speed_units, press_units=press_units) qc = A.cas2dp(cas, speed_units=speed_units, press_units=press_units) delta_Ps = qc - qcic delta_Hpc = SA.press2alt(P0 - delta_Ps, press_units=press_units) # print 'Vc = %.1f, delta_vpc = %.1f, delta_ps = %.1f, delta_hpc = %.0f' % (cas, delta_Vpc, delta_Ps, delta_Hpc) return delta_Vpc, delta_Ps, delta_Hpc, cas
def tas2ssec2(tas, ind_alt, oat, ias, std_alt=0, speed_units=default_speed_units, alt_units=default_alt_units, temp_units=default_temp_units, press_units=default_press_units): """ Return static source position error as speed error, pressure error and altitude error at sea level using speed course method. Returns delta_Vpc, delta_Ps and delta_Hpc tas = true airspeed determined by speed course method, or GPS ind_alt = pressure altitude, corrected for instrument error oat = outside air temperature, corrected for instrument error and ram temperature rise ias = indicated airspeed, corrected for instrument error std_alt = altitude to provide delta_Hpc for delta_Vpc = error in airspeed = calibrated airspeed - indicated airspeed corrected for instrument error delta_Ps = error in the pressure sensed by the static system = pressure sensed in the static system - ambient pressure delta_Hpc = altitude error at std_alt = actual altitude - altitude sensed by the static system Uses analysis method from USAF Test Pilot School. Unlike some other methods (e.g.. that in FAA AC 23-8B, or NTPS GPS_PEC.xls), this method provides an exact conversion from TAS to CAS (some other methods assume CAS = EAS), and it accounts for the effect of position error of altitude on the conversion from TAS to CAS (some other methods assume pressure altitude = indicated pressure altitude). """ tas = U.speed_conv(tas, speed_units, 'kt') ind_alt = U.length_conv(ind_alt, alt_units, 'ft') oat = U.temp_conv(oat, temp_units, 'C') M = A.tas2mach(tas, oat, temp_units='C', speed_units='kt') if M > 1: raise ValueError('This method only works for Mach < 1') delta_ic = SA.alt2press_ratio(ind_alt, alt_units='ft') qcic_over_Psl = A.cas2dp(ias, speed_units='kt', press_units=press_units) / U.press_conv( constants.P0, 'pa', to_units=press_units) qcic_over_Ps = qcic_over_Psl / delta_ic Mic = A.dp_over_p2mach(qcic_over_Ps) delta_mach_pc = M - Mic if Mic > 1: raise ValueError('This method only works for Mach < 1') deltaPp_over_Ps = (1.4 * delta_mach_pc * (Mic + delta_mach_pc / 2)) / ( 1 + 0.2 * (Mic + delta_mach_pc / 2)**2) deltaPp_over_qcic = deltaPp_over_Ps / qcic_over_Ps delta_Hpc = SA.alt2temp_ratio( std_alt, alt_units='ft') * deltaPp_over_Ps / 3.61382e-5 # experimental - alternate way to calculate delta_Hpc that gives same answer Ps = SA.alt2press(ind_alt, alt_units='ft', press_units=press_units) delta_Ps = deltaPp_over_Ps * Ps P_std = SA.alt2press(std_alt, alt_units='ft', press_units=press_units) deltaPs_std = deltaPp_over_Ps * P_std delta_Hpc2 = SA.press2alt(P_std - deltaPs_std, press_units=press_units) - std_alt delta_std_alt = SA.alt2press_ratio(std_alt, alt_units='ft') asl = U.speed_conv(constants.A0, 'm/s', 'kt') delta_Vpc_std_alt = deltaPp_over_Ps * delta_std_alt * asl**2 / ( 1.4 * ias * (1 + 0.2 * (ias / asl)**2)**2.5) actual_alt = SA.press2alt(Ps + delta_Ps, press_units=press_units, alt_units='ft') cas = A.tas2cas(tas, actual_alt, oat, speed_units='kt', alt_units='ft', temp_units='C') return delta_Vpc, delta_Ps, delta_Hpc, cas
def tas2ssec2(tas, ind_alt, oat, ias, std_alt = 0, speed_units=default_speed_units, alt_units=default_alt_units, temp_units=default_temp_units, press_units = default_press_units): """ Return static source position error as speed error, pressure error and altitude error at sea level using speed course method. Returns delta_Vpc, delta_Ps and delta_Hpc tas = true airspeed determined by speed course method, or GPS ind_alt = pressure altitude, corrected for instrument error oat = outside air temperature, corrected for instrument error and ram temperature rise ias = indicated airspeed, corrected for instrument error std_alt = altitude to provide delta_Hpc for delta_Vpc = error in airspeed = calibrated airspeed - indicated airspeed corrected for instrument error delta_Ps = error in the pressure sensed by the static system = pressure sensed in the static system - ambient pressure delta_Hpc = altitude error at std_alt = actual altitude - altitude sensed by the static system Uses analysis method from USAF Test Pilot School. Unlike some other methods (e.g.. that in FAA AC 23-8B, or NTPS GPS_PEC.xls), this method provides an exact conversion from TAS to CAS (some other methods assume CAS = EAS), and it accounts for the effect of position error of altitude on the conversion from TAS to CAS (some other methods assume pressure altitude = indicated pressure altitude). """ tas = U.speed_conv(tas, speed_units, 'kt') ind_alt = U.length_conv(ind_alt, alt_units, 'ft') oat = U.temp_conv(oat, temp_units, 'C') M = A.tas2mach(tas, oat, temp_units='C', speed_units='kt') if M > 1: raise ValueError, 'This method only works for Mach < 1' delta_ic = SA.alt2press_ratio(ind_alt, alt_units='ft') qcic_over_Psl = A.cas2dp(ias, speed_units='kt', press_units=press_units) / U.press_conv(constants.P0, 'pa', to_units=press_units) qcic_over_Ps = qcic_over_Psl / delta_ic Mic = A.dp_over_p2mach(qcic_over_Ps) delta_mach_pc = M - Mic if Mic > 1: raise ValueError, 'This method only works for Mach < 1' deltaPp_over_Ps = (1.4 * delta_mach_pc * (Mic + delta_mach_pc / 2)) / (1 + 0.2 * (Mic + delta_mach_pc / 2 )**2) deltaPp_over_qcic = deltaPp_over_Ps / qcic_over_Ps delta_Hpc = SA.alt2temp_ratio(std_alt, alt_units='ft') * deltaPp_over_Ps / 3.61382e-5 # experimental - alternate way to calculate delta_Hpc that gives same answer Ps = SA.alt2press(ind_alt, alt_units='ft', press_units=press_units) delta_Ps = deltaPp_over_Ps * Ps P_std = SA.alt2press(std_alt, alt_units='ft', press_units=press_units) deltaPs_std = deltaPp_over_Ps * P_std delta_Hpc2 = SA.press2alt(P_std - deltaPs_std, press_units = press_units) - std_alt delta_std_alt = SA.alt2press_ratio(std_alt, alt_units='ft') asl = U.speed_conv(constants.A0, 'm/s', 'kt') delta_Vpc_std_alt = deltaPp_over_Ps * delta_std_alt * asl**2 / (1.4 * ias * (1 + 0.2 * (ias / asl)**2)**2.5) actual_alt = SA.press2alt(Ps + delta_Ps, press_units = press_units, alt_units = 'ft') cas = A.tas2cas(tas, actual_alt, oat, speed_units='kt', alt_units='ft', temp_units='C') return delta_Vpc, delta_Ps, delta_Hpc, cas
def descent_data(prop, weight=1600., alt_max=20000., fuel_units='USG', \ alt_interval=500., isa_dev=0, temp_units='C', rv='8', wing_area=110., \ tas=180., ROD=-500., angle='', speed_units='kt', rpm=2100., sfc=0.45, output='raw'): """ Returns a table of descent performance vs altitude. The items in each row of the table are altitude, time, fuel burned and distance. Time is in units of minutes, rounded to the nearest half minute. Fuel units are selectable, with a default of USG. Distances are in nm. The output may be specified as raw, latex (a LaTeX table for the POH), or array. tas is the TAS in descent (overridden by the angle, if the angle is provided). angle is the flight path angle in degrees. """ tas_fts = U.speed_conv(tas, speed_units, 'ft/s') if angle: ROD = tas_fts * 60 * M.sin(angle * M.pi / 180) rod_fts = ROD / 60 tas = U.speed_conv(tas, speed_units, 'kt') alt = alt_max + alt_interval temp = SA.isa2temp(isa_dev, alt, temp_units=temp_units) time = 0 fuel_used = 0 dist = 0 if output == 'raw': print S.center('Altitude', 10), print S.center('ROD', 10), print S.center('Time', 10), print S.center('Fuel Used', 10), print S.center('Dist', 10), print S.center('Speed', 10) print S.center('(ft)', 10), print S.center('(ft/mn)', 10), print S.center('(mn)', 10), f_units = '(' + fuel_units + ')' print S.center(f_units, 10), print S.center('(nm)', 10), print S.center('(KCAS)', 10) # # data for max altitude # print S.rjust(locale.format('%.0f', alt_max, True), 7), # print S.rjust(locale.format('%.0f', round(ROD / 10.) * 10, True), 10), # print S.rjust('%.1f' % (0), 10), # print S.rjust('%.1f' % (fuel_used), 10), # print S.rjust('%.1f' % (dist), 10), # print S.rjust('%3d' % (A.tas2cas(tas, alt_max, temp, temp_units=temp_units)), 10) # elif output == 'latex': # # temp = 15 + isa_dev # MSL_line = [] # MSL_line.append(str(locale.format('%.0f', weight, True))) # MSL_line.append('0') # MSL_line.append(str(locale.format('%.0f', temp))) # MSL_line.append(str(locale.format('%.0f', A.tas2cas(tas, alt, temp, temp_units=temp_units)))) # MSL_line.append(str(locale.format('%.0f', round(ROD / 10.) * 10, True))) # MSL_line.append('0') # MSL_line.append(str(fuel_used)) # MSL_line.append(str(dist)) # # print '&'.join(MSL_line) + '\\\\' # print '\\hline' # elif output == 'array': # # no header rows, but make blank array # array = [[alt_max,0,0,0]] alts = [] RODs = [] times_temp = [] CASs = [] dists_temp = [] fuel_useds_temp = [] temps = [] calc_alt = alt_max - alt_interval / 2. while alt > 0: temp = SA.isa2temp(isa_dev, alt, temp_units = temp_units) eas = A.tas2eas(tas, alt) drag = FT.eas2drag(eas, weight) pwr_level_flt = tas_fts * drag / 550 thrust_power = pwr_level_flt + FT.Pexcess_vs_roc(weight, ROD) prop_eff = PM.prop_eff(prop, thrust_power, rpm, tas, alt, temp, temp_units=temp_units) calc_pwr = thrust_power / prop_eff #fuel_flow = IO.pwr2ff(calc_pwr, rpm, ff_units = 'lb/hr') fuel_flow = calc_pwr * sfc # print "Level flt pwr = %.1f, thrust power = %.1f, prop eff = %.3f, fuel flow = %.3f" % (pwr_level_flt, thrust_power, prop_eff, fuel_flow) slice_time = alt_interval / rod_fts * -1. slice_dist = tas_fts * slice_time slice_fuel = fuel_flow * slice_time / 3600 fuel_used += slice_fuel fuel_out = (U.avgas_conv(fuel_used, from_units = 'lb', \ to_units = fuel_units)) weight -= slice_fuel alt -= alt_interval cas_out = A.tas2cas(tas, alt, temp, temp_units=temp_units) temp_out = SA.isa2temp(isa_dev, alt) time += slice_time / 60. dist += slice_dist / 6076.115 alts.append(alt) CASs.append(cas_out) RODs.append(ROD) times_temp.append(time) fuel_useds_temp.append(fuel_out) dists_temp.append(dist) temps.append(temp_out) calc_alt += alt_interval alts.reverse() CASs.reverse() RODs.reverse() temps.reverse() times = [] fuel_useds = [] dists = [] for n, time in enumerate(times_temp): times.append(times_temp[-1] - time) fuel_useds.append(fuel_useds_temp[-1] - fuel_useds_temp[n]) dists.append(dists_temp[-1] - dists_temp[n]) times.reverse() fuel_useds.reverse() dists.reverse() if output == 'raw': for n, alt in enumerate(alts): print S.rjust(locale.format('%.0f', alt, True), 7), # calculate ROC at the displayed altitude print S.rjust(locale.format('%.0f', RODs[n], True), 10), print S.rjust('%.1f' % (times[n]), 10), print S.rjust('%.1f' % (fuel_useds[n]), 10), print S.rjust('%.1f' % (dists[n]), 10), print S.rjust('%3d' % (int(CASs[n])), 10) elif output == 'latex': for n, alt in enumerate(alts): line = [] line.append(str(locale.format('%.0f', alt, True))) line.append(str(locale.format('%.0f', round(temps[n])))) line.append(str(locale.format('%.0f', CASs[n]))) line.append(str(locale.format('%.0f', round(RODs[n] / 10.) * 10, True))) line.append(str(locale.format('%.0f', times[n]))) line.append(str(locale.format('%.1f', fuel_useds[n]))) line.append(str(locale.format('%.0f', dists[n]))) print '&' + '&'.join(line) + '\\\\' print '\\hline' elif output == 'array': array = [] for n, alt in enumerate(alts): array.append([alt, times[n], fuel_useds[n], dists[n]]) return array
def descent_data(prop, weight=1600., alt_max=20000., fuel_units='USG', \ alt_interval=500., isa_dev=0, temp_units='C', rv='8', wing_area=110., \ tas=180., ROD=-500., angle='', speed_units='kt', rpm=2100., sfc=0.45, output='raw'): """ Returns a table of descent performance vs altitude. The items in each row of the table are altitude, time, fuel burned and distance. Time is in units of minutes, rounded to the nearest half minute. Fuel units are selectable, with a default of USG. Distances are in nm. The output may be specified as raw, latex (a LaTeX table for the POH), or array. tas is the TAS in descent (overridden by the angle, if the angle is provided). angle is the flight path angle in degrees. """ tas_fts = U.speed_conv(tas, speed_units, 'ft/s') if angle: ROD = tas_fts * 60 * M.sin(angle * M.pi / 180) rod_fts = ROD / 60 tas = U.speed_conv(tas, speed_units, 'kt') alt = alt_max + alt_interval temp = SA.isa2temp(isa_dev, alt, temp_units=temp_units) time = 0 fuel_used = 0 dist = 0 if output == 'raw': print(S.center('Altitude', 10), end=' ') print(S.center('ROD', 10), end=' ') print(S.center('Time', 10), end=' ') print(S.center('Fuel Used', 10), end=' ') print(S.center('Dist', 10), end=' ') print(S.center('Speed', 10)) print(S.center('(ft)', 10), end=' ') print(S.center('(ft/mn)', 10), end=' ') print(S.center('(mn)', 10), end=' ') f_units = '(' + fuel_units + ')' print(S.center(f_units, 10), end=' ') print(S.center('(nm)', 10), end=' ') print(S.center('(KCAS)', 10)) # # data for max altitude # print S.rjust(locale.format('%.0f', alt_max, True), 7), # print S.rjust(locale.format('%.0f', round(ROD / 10.) * 10, True), 10), # print S.rjust('%.1f' % (0), 10), # print S.rjust('%.1f' % (fuel_used), 10), # print S.rjust('%.1f' % (dist), 10), # print S.rjust('%3d' % (A.tas2cas(tas, alt_max, temp, temp_units=temp_units)), 10) # elif output == 'latex': # # temp = 15 + isa_dev # MSL_line = [] # MSL_line.append(str(locale.format('%.0f', weight, True))) # MSL_line.append('0') # MSL_line.append(str(locale.format('%.0f', temp))) # MSL_line.append(str(locale.format('%.0f', A.tas2cas(tas, alt, temp, temp_units=temp_units)))) # MSL_line.append(str(locale.format('%.0f', round(ROD / 10.) * 10, True))) # MSL_line.append('0') # MSL_line.append(str(fuel_used)) # MSL_line.append(str(dist)) # # print '&'.join(MSL_line) + '\\\\' # print '\\hline' # elif output == 'array': # # no header rows, but make blank array # array = [[alt_max,0,0,0]] alts = [] RODs = [] times_temp = [] CASs = [] dists_temp = [] fuel_useds_temp = [] temps = [] calc_alt = alt_max - alt_interval / 2. while alt > 0: temp = SA.isa2temp(isa_dev, alt, temp_units=temp_units) eas = A.tas2eas(tas, alt) drag = FT.eas2drag(eas, weight) pwr_level_flt = tas_fts * drag / 550 thrust_power = pwr_level_flt + FT.Pexcess_vs_roc(weight, ROD) prop_eff = PM.prop_eff(prop, thrust_power, rpm, tas, alt, temp, temp_units=temp_units) calc_pwr = thrust_power / prop_eff #fuel_flow = IO.pwr2ff(calc_pwr, rpm, ff_units = 'lb/hr') fuel_flow = calc_pwr * sfc # print "Level flt pwr = %.1f, thrust power = %.1f, prop eff = %.3f, fuel flow = %.3f" % (pwr_level_flt, thrust_power, prop_eff, fuel_flow) slice_time = alt_interval / rod_fts * -1. slice_dist = tas_fts * slice_time slice_fuel = fuel_flow * slice_time / 3600 fuel_used += slice_fuel fuel_out = (U.avgas_conv(fuel_used, from_units = 'lb', \ to_units = fuel_units)) weight -= slice_fuel alt -= alt_interval cas_out = A.tas2cas(tas, alt, temp, temp_units=temp_units) temp_out = SA.isa2temp(isa_dev, alt) time += slice_time / 60. dist += slice_dist / 6076.115 alts.append(alt) CASs.append(cas_out) RODs.append(ROD) times_temp.append(time) fuel_useds_temp.append(fuel_out) dists_temp.append(dist) temps.append(temp_out) calc_alt += alt_interval alts.reverse() CASs.reverse() RODs.reverse() temps.reverse() times = [] fuel_useds = [] dists = [] for n, time in enumerate(times_temp): times.append(times_temp[-1] - time) fuel_useds.append(fuel_useds_temp[-1] - fuel_useds_temp[n]) dists.append(dists_temp[-1] - dists_temp[n]) times.reverse() fuel_useds.reverse() dists.reverse() if output == 'raw': for n, alt in enumerate(alts): print(S.rjust(locale.format('%.0f', alt, True), 7), end=' ') # calculate ROC at the displayed altitude print(S.rjust(locale.format('%.0f', RODs[n], True), 10), end=' ') print(S.rjust('%.1f' % (times[n]), 10), end=' ') print(S.rjust('%.1f' % (fuel_useds[n]), 10), end=' ') print(S.rjust('%.1f' % (dists[n]), 10), end=' ') print(S.rjust('%3d' % (int(CASs[n])), 10)) elif output == 'latex': for n, alt in enumerate(alts): line = [] line.append(str(locale.format('%.0f', alt, True))) line.append(str(locale.format('%.0f', round(temps[n])))) line.append(str(locale.format('%.0f', CASs[n]))) line.append( str(locale.format('%.0f', round(RODs[n] / 10.) * 10, True))) line.append(str(locale.format('%.0f', times[n]))) line.append(str(locale.format('%.1f', fuel_useds[n]))) line.append(str(locale.format('%.0f', dists[n]))) print('&' + '&'.join(line) + '\\\\') print('\\hline') elif output == 'array': array = [] for n, alt in enumerate(alts): array.append([alt, times[n], fuel_useds[n], dists[n]]) return array