def pwr2ff(pwr, rpm, mixture='pwr', ff_units='gph'): """ Returns fuel flow. Defaults to mixture for best power ("pwr"), but may also be used with mixture for best economy ("econ"). Fuel flow units default to USG/hr, but pounds per hour ("lb/hr") and litres per hour ("l/hr") may also be selected. """ if mixture == 'pwr': if rpm >= 2600: rpm1 = 2600 rpm2 = 2700 elif rpm >= 2400: rpm1 = 2400 rpm2 = 2600 elif rpm >= 2200: rpm1 = 2200 rpm2 = 2400 else: rpm1 = 2000 rpm2 = 2200 ff1 = _pwr_ff_best_power(rpm1, pwr) ff2 = _pwr_ff_best_power(rpm2, pwr) elif mixture == 'econ': if rpm >= 2600: rpm1 = 2600 rpm2 = 2700 elif rpm >= 2400: rpm1 = 2400 rpm2 = 2600 elif rpm >= 2200: rpm1 = 2200 rpm2 = 2400 elif rpm >= 2000: rpm1 = 2000 rpm2 = 2200 else: rpm1 = 1800 rpm2 = 2000 ff1 = _pwr_ff_econ(rpm1, pwr) ff2 = _pwr_ff_econ(rpm2, pwr) else: raise ValueError('mixture must be one of "econ" or "pwr"') # else: # raise ValueError, 'Invalid value for mixture.' ff = ff1 + (ff2 - ff1) * (rpm - rpm1) / (rpm2 - rpm1) if ff_units == 'lb/hr': pass elif ff_units == 'gph': ff = U.avgas_conv(ff, to_units='USG') elif ff_units == 'l/hr': ff = U.avgas_conv(ff, to_units='l') else: raise ValueError('Invalid fuel flow units') return ff
def pwr2ff(pwr, rpm, mixture = 'pwr', ff_units = 'gph'): """ Returns fuel flow. Defaults to mixture for best power ("pwr"), but may also be used with mixture for best economy ("econ"). Fuel flow units default to USG/hr, but pounds per hour ("lb/hr") and litres per hour ("l/hr") may also be selected. """ if mixture == 'pwr': if rpm >= 2600: rpm1 = 2600 rpm2 = 2700 elif rpm >= 2400: rpm1 = 2400 rpm2 = 2600 elif rpm >= 2200: rpm1 = 2200 rpm2 = 2400 else: rpm1 = 2000 rpm2 = 2200 ff1 = _pwr_ff_best_power(rpm1, pwr) ff2 = _pwr_ff_best_power(rpm2, pwr) elif mixture == 'econ': if rpm >= 2600: rpm1 = 2600 rpm2 = 2700 elif rpm >= 2400: rpm1 = 2400 rpm2 = 2600 elif rpm >= 2200: rpm1 = 2200 rpm2 = 2400 elif rpm >= 2000: rpm1 = 2000 rpm2 = 2200 else: rpm1 = 1800 rpm2 = 2000 ff1 = _pwr_ff_econ(rpm1, pwr) ff2 = _pwr_ff_econ(rpm2, pwr) else: raise ValueError, 'mixture must be one of "econ" or "pwr"' # else: # raise ValueError, 'Invalid value for mixture.' ff = ff1 + (ff2 - ff1) * (rpm - rpm1) / (rpm2 - rpm1) if ff_units == 'lb/hr': pass elif ff_units == 'gph': ff = U.avgas_conv(ff, to_units = 'USG') elif ff_units == 'l/hr': ff = U.avgas_conv(ff, to_units = 'l') else: raise ValueError, 'Invalid fuel flow units' return ff
def power(ff, ff_at_pk_EGT, rpm, CR=8.7, displacement=360, ff_units='USG/h', fric_power_factor=1): """ Returns engine power, based on fuel flow data. Based on an internal Lycoming document, apparently for use during flight test programs. ff = fuel flow ff_at_pk_EGT = fuel flow at peak EGT rpm = engine speed CR = compression ratio. Allowable values are 6.75, 7, 7.2, 7.3, 8, 8.5, 8.7 or 9 (10 to be implemented later). displacement = engine displacement in cubic inches. Allowable values are 235, 320, 360, 480, 480S, 540, 540S, 541 or 720. The suffix S denotes GSO or IGSO engines. # type = type of fuel delivery system. Allowable values are # 'port_injection', 'carb', and 'single_point' (i.e fuel # injected at a single point, prior to the intake tubes). # This input is not yet implemented, as it is only needed # for an alternate method, for high power conditions where # it is not safe to lean to peak EGT. ff_units = fuel flow units. Allowable values are 'USG/h', 'ImpGal/h', 'l/h', 'lb/h', and 'kg/h' """ ff_units = ff_units[:-2] ff = U.avgas_conv(ff, from_units=ff_units, to_units='lb') ff_at_pk_EGT = U.avgas_conv(ff_at_pk_EGT, from_units=ff_units, to_units='lb') ff_best_mixture = ff_at_pk_EGT / .849 SFC_best_mixture = iSFC(CR) best_mixture_pwr = ff_best_mixture / SFC_best_mixture ihp = best_mixture_pwr * pwr_ratio_vs_ff_ratio(ff / ff_best_mixture) try: imep = P.BMEP(best_mixture_pwr, rpm, displacement, power_units='hp', vol_units='in**3') disp_numeric = displacement except TypeError: disp_numeric = int(displacement[:3]) imep = P.BMEP(best_mixture_pwr, rpm, disp_numeric, power_units='hp', vol_units='in**3') if imep < 140: imep_best_pwr = imep for n in range(10): SFC_best_mixture = iSFC(CR, imep_best_pwr) best_mixture_pwr = ff_best_mixture / SFC_best_mixture imep_best_pwr = P.BMEP(best_mixture_pwr, rpm, disp_numeric, power_units='hp', vol_units='in**3') # print 'iSFC = %.4f' % SFC_best_mixture ihp = best_mixture_pwr * pwr_ratio_vs_ff_ratio(ff / ff_best_mixture) bhp = ihp - friction_hp(displacement, rpm) * fric_power_factor return bhp
def test_02(self): # 200 lb of nominal fuel at -40 deg C to USG # truth value from Canada Flight Supplement Value = U.avgas_conv(200., from_units='lb', to_units='USG', temp=-40) Truth = 200. / 6.41 self.failUnless(RE(Value, Truth) <= 5e-4)
def test_01(self): # 10 USG of nominal fuel at nominal temperature to lbs # truth value from Canada Flight Supplement Value = U.avgas_conv(10, from_units='USG', to_units='lb') Truth = 60.1 self.failUnless(RE(Value, Truth) <= 5e-4)
def test_03(self): # 200 lb of 100LL grade fuel at 15 deg C to Imperial Gallons # truth value from Air BP Handbook of Products - 715 kg/m**3 Value = U.avgas_conv(200., from_units='lb', to_units='ImpGal', grade='100LL') Truth = (((200. / 2.204622622) / 715) * 1000) / 4.54609 self.failUnless(RE(Value, Truth) <= 5e-4)
def test_05(self): # 200 l of 80 grade fuel at -40 deg C to kg # truth value from Air BP Handbook of Products - 690 kg/m**3 at 15 deg C Value = U.avgas_conv(200., from_units='l', to_units='kg', grade='80', temp=-40) Truth = (200. / 1000) * 690 # correct for temperature, using ratio given in Canada Flight Supplement Truth *= 6.41 / 6.01 self.failUnless(RE(Value, Truth) <= 5e-4)
def test_04(self): # 200 kg of 100 grade fuel at 30 deg C to l # truth value from Air BP Handbook of Products - 695 kg/m**3 at 15 deg C Value = U.avgas_conv(200., from_units='kg', to_units='l', grade='100', temp=30) Truth = (200. / 695) * 1000 # correct for temperature, using ratio given in Canada Flight Supplement Truth *= 6.01 / 5.9 self.failUnless(RE(Value, Truth) <= 5e-4)
def power_lop(ff, n, ff_units='USG/h'): """ Alternate, very simplified and approximate method to determine power, for lean of peak operations. Optimized for operations at 50 deg F lean of peak on Lycoming IO-360A series engines. This was a trial, and initial testing suggests this function is not adequately accurate. """ ff_units = ff_units[:-2] ff = U.avgas_conv(ff, from_units=ff_units, to_units='USG') a, b, c, d, e, f, g, h, i = [4.61824610e+00, -7.90382136e-01, -4.09623195e-03, 7.58928066e-04, -3.51093492e-05, -1.87325980e-07, 8.64253036e-09, 3.65001722e-02, 1.02174312e-06] sfc = a + b * ff + c * n + d * ff * n + e * ff**2 * n + f * ff * n**2 + g * ff**2 * n**2 + h * ff**2 + i * n**2 pwr = ff * 6.01 / sfc return pwr
def power_lop(ff, n, ff_units='USG/h'): """ Alternate, very simplified and approximate method to determine power, for lean of peak operations. Optimized for operations at 50 deg F lean of peak on Lycoming IO-360A series engines. This was a trial, and initial testing suggests this function is not adequately accurate. """ ff_units = ff_units[:-2] ff = U.avgas_conv(ff, from_units=ff_units, to_units='USG') a, b, c, d, e, f, g, h, i = [ 4.61824610e+00, -7.90382136e-01, -4.09623195e-03, 7.58928066e-04, -3.51093492e-05, -1.87325980e-07, 8.64253036e-09, 3.65001722e-02, 1.02174312e-06 ] sfc = a + b * ff + c * n + d * ff * n + e * ff**2 * n + f * ff * n**2 + g * ff**2 * n**2 + h * ff**2 + i * n**2 pwr = ff * 6.01 / sfc return pwr
def test_01(self): Value = U.avgas_conv(100, from_units='lb', to_units='kg') Truth = 45.359 self.failUnless(RE(Value, Truth) <= 1e-5)
def climb_data(prop, weight = 1800., alt_max = 20000., TO_fuel = 0, TO_dist = 0, \ fuel_units = 'USG', alt_interval = 500., isa_dev = 0, temp_units = 'C', \ rv = '8', wing_area = 110., pwr = 'max', pwr_factor=1.0, \ climb_speed = 'max', output = 'raw'): """ Returns a table of climb 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. pwr may be 'max', 'cc' (cruise climb = 2500 rpm and 25") or 2500 (2500 rpm and full throttle) climb_speed may be 'max' (Vy), 'cc' (120 kt to 10,000 ft, then reducing by 4 kt/1000 ft) or 'norm' (100 kt to 10,000 ft, then reducing by 2 kt/1000 ft) Note: compared cruise range for all climb speed and power. The predicted results are all within 1.5 nm of range. Thus there is no advantage to using anything but Vy and max power. """ def _alt2ROC(prop, alt): """ calculate ROC for an altitude """ temp = SA.isa2temp(isa_dev, alt) calc_pwr = alt2pwr(alt, rpm=rpm, MP_max=MP_max, temp=temp) * pwr_factor cas = alt2roc_speed(alt, climb_speed=climb_speed) eas = A.cas2eas(cas, alt) ROC = roc(prop, alt, eas, weight, calc_pwr, rpm, rv = rv, \ wing_area = wing_area) return ROC alt = 0 time = 0 fuel_used = U.avgas_conv(TO_fuel, from_units=fuel_units, to_units='lb') weight = weight - fuel_used dist = TO_dist if pwr == 'max': # rpm = 2700 rpm = 2650 MP_max = 30 elif pwr == 'cc': rpm = 2500 MP_max = 25 elif pwr == 2500: rpm = 2500 MP_max = 30 else: raise ValueError("pwr must be one of 'max', 'cc', or 2500") if output == 'raw': print(S.center('Altitude', 10), end=' ') print(S.center('ROC', 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 MSL print(S.rjust(locale.format('%.0f', 0, True), 7), end=' ') # calculate ROC at MSL print(S.rjust(locale.format('%.0f', round(_alt2ROC(prop, 0) / 10.) * 10, \ True), 10), end=' ') print(S.rjust('%.1f' % (0), 10), end=' ') print(S.rjust('%.1f' % (TO_fuel), 10), end=' ') print(S.rjust('%.1f' % (TO_dist), 10), end=' ') print(S.rjust('%3d' % (alt2roc_speed(0, climb_speed=climb_speed)), 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', alt2roc_speed(0, \ climb_speed = climb_speed)))) MSL_line.append(str(locale.format('%.0f', round(_alt2ROC(prop, 0) / 10.)\ * 10, True))) MSL_line.append('0') MSL_line.append(str(TO_fuel)) MSL_line.append(str(TO_dist)) print('&'.join(MSL_line) + '\\\\') print('\\hline') elif output == 'array': # no header rows, but make blank array array = [[0, 0, TO_fuel, 0]] calc_alt = alt_interval / 2. while calc_alt < alt_max: temp = SA.isa2temp(isa_dev, calc_alt) pwr = alt2pwr(calc_alt, rpm=rpm, MP_max=MP_max, temp=temp) calc_pwr = pwr * pwr_factor cas = alt2roc_speed(calc_alt, climb_speed=climb_speed) eas = A.cas2eas(cas, calc_alt) tas = A.cas2tas(cas, calc_alt, temp=temp, temp_units=temp_units) tas_fts = U.speed_conv(tas, from_units='kt', to_units='ft/s') ROC = roc(prop, calc_alt, eas, weight, calc_pwr, rpm, rv = rv, \ wing_area = wing_area) roc_fts = ROC / 60 fuel_flow = IO.pwr2ff(pwr, rpm, ff_units='lb/hr') slice_time = alt_interval / roc_fts 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 = alt2roc_speed(alt, climb_speed=climb_speed) temp_out = SA.isa2temp(isa_dev, alt) ROC = _alt2ROC(prop, alt) time += slice_time / 60 dist += slice_dist / 6076.115 if output == 'raw': print(S.rjust(locale.format('%.0f', alt, True), 7), end=' ') # calculate ROC at the displayed altitude print(S.rjust(locale.format('%.0f', ROC, True), 10), end=' ') print(S.rjust('%.1f' % (time), 10), end=' ') print(S.rjust('%.1f' % (fuel_out), 10), end=' ') print(S.rjust('%.1f' % (dist), 10), end=' ') print(S.rjust('%3d' % (int(cas_out)), 10)) elif output == 'latex': line = [] line.append(str(locale.format('%.0f', alt, True))) line.append(str(locale.format('%.0f', round(temp_out)))) line.append(str(locale.format('%.0f', cas_out))) line.append(str(locale.format('%.0f', round(ROC / 10.) * 10, True))) line.append(str(locale.format('%.0f', time))) line.append(str(locale.format('%.1f', fuel_out))) line.append(str(locale.format('%.0f', dist))) print('&' + '&'.join(line) + '\\\\') print('\\hline') elif output == 'array': array.append([alt, time, fuel_out, dist]) calc_alt += alt_interval if output == 'array': 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
def climb_data(prop, weight = 1800., alt_max = 20000., TO_fuel = 0, TO_dist = 0, \ fuel_units = 'USG', alt_interval = 500., isa_dev = 0, temp_units = 'C', \ rv = '8', wing_area = 110., pwr = 'max', pwr_factor=1.0, \ climb_speed = 'max', output = 'raw'): """ Returns a table of climb 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. pwr may be 'max', 'cc' (cruise climb = 2500 rpm and 25") or 2500 (2500 rpm and full throttle) climb_speed may be 'max' (Vy), 'cc' (120 kt to 10,000 ft, then reducing by 4 kt/1000 ft) or 'norm' (100 kt to 10,000 ft, then reducing by 2 kt/1000 ft) Note: compared cruise range for all climb speed and power. The predicted results are all within 1.5 nm of range. Thus there is no advantage to using anything but Vy and max power. """ def _alt2ROC(prop, alt): """ calculate ROC for an altitude """ temp = SA.isa2temp(isa_dev, alt) calc_pwr = alt2pwr(alt, rpm = rpm, MP_max = MP_max, temp = temp) * pwr_factor cas = alt2roc_speed(alt, climb_speed = climb_speed) eas = A.cas2eas(cas, alt) ROC = roc(prop, alt, eas, weight, calc_pwr, rpm, rv = rv, \ wing_area = wing_area) return ROC alt = 0 time = 0 fuel_used = U.avgas_conv(TO_fuel, from_units = fuel_units, to_units = 'lb') weight = weight - fuel_used dist = TO_dist if pwr == 'max': # rpm = 2700 rpm = 2650 MP_max = 30 elif pwr == 'cc': rpm = 2500 MP_max = 25 elif pwr == 2500: rpm = 2500 MP_max = 30 else: raise ValueError, "pwr must be one of 'max', 'cc', or 2500" if output == 'raw': print S.center('Altitude', 10), print S.center('ROC', 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 MSL print S.rjust(locale.format('%.0f', 0, True), 7), # calculate ROC at MSL print S.rjust(locale.format('%.0f', round(_alt2ROC(prop, 0) / 10.) * 10, \ True), 10), print S.rjust('%.1f' % (0), 10), print S.rjust('%.1f' % (TO_fuel), 10), print S.rjust('%.1f' % (TO_dist), 10), print S.rjust('%3d' % (alt2roc_speed(0, climb_speed = climb_speed)), 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', alt2roc_speed(0, \ climb_speed = climb_speed)))) MSL_line.append(str(locale.format('%.0f', round(_alt2ROC(prop, 0) / 10.)\ * 10, True))) MSL_line.append('0') MSL_line.append(str(TO_fuel)) MSL_line.append(str(TO_dist)) print '&'.join(MSL_line) + '\\\\' print '\\hline' elif output == 'array': # no header rows, but make blank array array = [[0,0,TO_fuel,0]] calc_alt = alt_interval / 2. while calc_alt < alt_max: temp = SA.isa2temp(isa_dev, calc_alt) pwr = alt2pwr(calc_alt, rpm = rpm, MP_max = MP_max, temp = temp) calc_pwr = pwr * pwr_factor cas = alt2roc_speed(calc_alt, climb_speed = climb_speed) eas = A.cas2eas(cas, calc_alt) tas = A.cas2tas(cas, calc_alt, temp = temp, temp_units = temp_units) tas_fts = U.speed_conv(tas, from_units = 'kt', to_units = 'ft/s') ROC = roc(prop, calc_alt, eas, weight, calc_pwr, rpm, rv = rv, \ wing_area = wing_area) roc_fts = ROC / 60 fuel_flow = IO.pwr2ff(pwr, rpm, ff_units = 'lb/hr') slice_time = alt_interval / roc_fts 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 = alt2roc_speed(alt, climb_speed = climb_speed) temp_out = SA.isa2temp(isa_dev, alt) ROC = _alt2ROC(prop, alt) time += slice_time / 60 dist += slice_dist / 6076.115 if output == 'raw': print S.rjust(locale.format('%.0f', alt, True), 7), # calculate ROC at the displayed altitude print S.rjust(locale.format('%.0f', ROC, True), 10), print S.rjust('%.1f' % (time), 10), print S.rjust('%.1f' % (fuel_out), 10), print S.rjust('%.1f' % (dist), 10), print S.rjust('%3d' % (int(cas_out)), 10) elif output == 'latex': line = [] line.append(str(locale.format('%.0f', alt, True))) line.append(str(locale.format('%.0f', round(temp_out)))) line.append(str(locale.format('%.0f', cas_out))) line.append(str(locale.format('%.0f', round(ROC / 10.) * 10, True))) line.append(str(locale.format('%.0f', time))) line.append(str(locale.format('%.1f', fuel_out))) line.append(str(locale.format('%.0f', dist))) print '&' + '&'.join(line) + '\\\\' print '\\hline' elif output == 'array': array.append([alt, time, fuel_out, dist]) calc_alt += alt_interval if output == 'array': 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), 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 test_03(self): Value = U.avgas_conv(100, from_units='lb', to_units='lb') Truth = 100 self.failUnless(RE(Value, Truth) <= 1e-5)
def test_02(self): Value = U.avgas_conv(45.359, from_units='kg', to_units='lb') Truth = 100 self.failUnless(RE(Value, Truth) <= 1e-5)