def run_tests(cd0 = 0.0221, e = 0.825): """ Run all test cases to compare drag polar model against CAFE results. """ sum_sq = 0 wt_value_tot = 0 wing_area = 110 prop = PM.Prop('7666-4RV') for n, test in enumerate(level_test_cases): tas = test[0] dalt = test[1] wt = test[2] rpm = test[3] mp = test[4] wt_value = test[5] eas = A.tas2eas(tas, dalt, speed_units = 'mph') tas_fts = U.speed_conv(tas, from_units = 'mph', to_units = 'ft/s') cl = FT.eas2cl(eas, wt, wing_area, speed_units = 'mph') cd = FT.cl2cd_test(cl, cd0, e, flap = 0) drag = FT.cd2drag(cd, eas, wing_area, speed_units = 'mph') drag_power = drag * tas_fts / 550. power = IO.pwr(rpm, mp, dalt) prop_eff = PM.prop_eff(prop, power, rpm, tas, dalt, speed_units = 'mph') thrust_power = power * prop_eff excess_power = thrust_power - drag_power print 'Case', n, 'Altitude =', dalt, 'TAS =', tas, 'EAS =', eas, 'Excess power =', excess_power sum_sq += wt_value * excess_power ** 2 wt_value_tot += wt_value print 'Average sum of squares of excess power =', \ (sum_sq / wt_value_tot) ** 0.5
def aoca(prop, altitude, weight = 1800, press_drop = 1.2, temp = 'std', \ climb = True): """ Returns speed for best climb or descent gradient and the gradient at that speed. """ MP = SA.alt2press(altitude) - press_drop pwr = IO.pwr(2700, MP, altitude, temp=temp) if climb == True: eass = list(range(550, 800, 1)) else: eass = list(range(700, 1200, 1)) aocs = [] if climb == True: for eas in eass: aocs.append((aoc(prop, altitude, eas / 10., weight, pwr, 2700, temp=temp), eas)) else: for eas in eass: aocs.append((aoc(prop, altitude, eas / 10., weight, 0, 2700, temp=temp), eas)) maoc, meas = max(aocs) return meas / 10., maoc
def roca(prop, altitude, weight = 1800, press_drop = 1.2, temp = 'std', \ load_factor =1, prop_factor=1): """ Returns speed for best rate of climb and the rate of climb at that speed. """ MP = SA.alt2press(altitude) - press_drop pwr = IO.pwr(2700, MP, altitude, temp = temp) roc_max = -100000 eass = range(600, 1500, 1) rocs = [] for eas in eass: rocs.append((roc(prop, altitude, eas/10., weight, pwr, 2700, temp = temp, \ load_factor = load_factor, prop_factor=prop_factor),eas/10.)) mroc, meas = max(rocs) return meas, mroc
def roca(prop, altitude, weight = 1800, press_drop = 1.2, temp = 'std', \ load_factor =1, prop_factor=1): """ Returns speed for best rate of climb and the rate of climb at that speed. """ MP = SA.alt2press(altitude) - press_drop pwr = IO.pwr(2700, MP, altitude, temp=temp) roc_max = -100000 eass = list(range(600, 1500, 1)) rocs = [] for eas in eass: rocs.append((roc(prop, altitude, eas/10., weight, pwr, 2700, temp = temp, \ load_factor = load_factor, prop_factor=prop_factor),eas/10.)) mroc, meas = max(rocs) return meas, mroc
def cafe_speed(): """ Check the calculated speeds against the data from the CAFE tests for the RV-8A """ prop = PM.Prop('7666-4RV') for n, test in enumerate(level_test_cases): tas = test[0] dalt = test[1] wt = test[2] rpm = test[3] mp = test[4] wt_value = test[5] eas = A.tas2eas(tas, dalt, speed_units = 'mph') calc_tas = speed(prop, dalt, wt, IO.pwr(rpm, mp, dalt), rpm, \ speed_units = 'mph') print 'Actual TAS =', tas, 'Calc TAS =', calc_tas
def cafe_speed(): """ Check the calculated speeds against the data from the CAFE tests for the RV-8A """ prop = PM.Prop('7666-4RV') for n, test in enumerate(level_test_cases): tas = test[0] dalt = test[1] wt = test[2] rpm = test[3] mp = test[4] wt_value = test[5] eas = A.tas2eas(tas, dalt, speed_units='mph') calc_tas = speed(prop, dalt, wt, IO.pwr(rpm, mp, dalt), rpm, \ speed_units = 'mph') print('Actual TAS =', tas, 'Calc TAS =', calc_tas)
def p(tas, dalt, wt, rpm, mp, prop): """ test function for RV-8A drag, to compare against CAFE foundation level flt data. prop is a prop_map.Prop instance. """ eas = A.tas2eas(tas, dalt, speed_units='mph') # tas = A.cas2tas(cas, dalt, speed_units = 'mph') tas_fts = U.speed_conv(tas, from_units='mph', to_units='ft/s') drag = FT.eas2drag(eas, wt, 110, rv='8a', speed_units='mph') drag_power = drag * tas_fts / 550. power = IO.pwr(rpm, mp, dalt) prop_eff = PM.prop_eff(prop, power, rpm, tas, dalt, speed_units='mph') thrust_power = power * prop_eff excess_power = thrust_power - drag_power return excess_power
def p(tas, dalt, wt, rpm, mp, prop): """ test function for RV-8A drag, to compare against CAFE foundation level flt data. prop is a prop_map.Prop instance. """ eas = A.tas2eas(tas, dalt, speed_units = 'mph') # tas = A.cas2tas(cas, dalt, speed_units = 'mph') tas_fts = U.speed_conv(tas, from_units = 'mph', to_units = 'ft/s') drag = FT.eas2drag(eas, wt, 110, rv = '8a', speed_units = 'mph') drag_power = drag * tas_fts / 550. power = IO.pwr(rpm, mp, dalt) prop_eff = PM.prop_eff(prop, power, rpm, tas, dalt, speed_units = 'mph') thrust_power = power * prop_eff excess_power = thrust_power - drag_power return excess_power
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 aoca(prop, altitude, weight = 1800, press_drop = 1.2, temp = 'std', \ climb = True): """ Returns speed for best climb or descent gradient and the gradient at that speed. """ MP = SA.alt2press(altitude) - press_drop pwr = IO.pwr(2700, MP, altitude, temp = temp) if climb == True: eass = range(550, 800, 1) else: eass = range(700, 1200, 1) aocs = [] if climb == True: for eas in eass: aocs.append((aoc(prop, altitude, eas/10., weight, pwr, 2700, temp = temp),eas)) else: for eas in eass: aocs.append((aoc(prop, altitude, eas/10., weight, 0, 2700, temp = temp),eas)) maoc, meas = max(aocs) return meas/10., maoc
def alt2pwr(alt, rpm = 2700, MP_max = 30, temp = 'std', alt_units = 'ft', \ temp_units = 'C'): """ Returns power at a given altitude. Default rpm is 2700. The maximum MP may be specified, if for example, one wanted to use 25 inches MP until full throttle was reached. """ # MP loss at full throttle at 2700 rpm at sea level. # From Lycoming power chart MP_loss_base = 29.9213 - 28.6 press = SA.alt2press(alt, alt_units = alt_units) # assume pressure drop is proportional to square of velocity MP_loss = MP_loss_base * (rpm / 2700.) ** 2 MP = min(press - MP_loss, MP_max) # from climb testing, get MP of 0.5 above ambient # get 2650 rpm during climb MP = SA.alt2press(alt) + 0.5 * (2650./rpm) ** 2 pwr = IO.pwr(rpm, MP, alt, temp = temp, alt_units = alt_units, \ temp_units = temp_units) # decrement power as a function of altitude to make predicted climb perf match flight test resutls # this decrement is optimized for the MT prop pwr = pwr * (0.8525 - 4.35E-10 * alt**2) return pwr
def alt2pwr(alt, rpm = 2700, MP_max = 30, temp = 'std', alt_units = 'ft', \ temp_units = 'C'): """ Returns power at a given altitude. Default rpm is 2700. The maximum MP may be specified, if for example, one wanted to use 25 inches MP until full throttle was reached. """ # MP loss at full throttle at 2700 rpm at sea level. # From Lycoming power chart MP_loss_base = 29.9213 - 28.6 press = SA.alt2press(alt, alt_units=alt_units) # assume pressure drop is proportional to square of velocity MP_loss = MP_loss_base * (rpm / 2700.)**2 MP = min(press - MP_loss, MP_max) # from climb testing, get MP of 0.5 above ambient # get 2650 rpm during climb MP = SA.alt2press(alt) + 0.5 * (2650. / rpm)**2 pwr = IO.pwr(rpm, MP, alt, temp = temp, alt_units = alt_units, \ temp_units = temp_units) # decrement power as a function of altitude to make predicted climb perf match flight test resutls # this decrement is optimized for the MT prop pwr = pwr * (0.8525 - 4.35E-10 * alt**2) return pwr
def run_tests(cd0=0.0221, e=0.825): """ Run all test cases to compare drag polar model against CAFE results. """ sum_sq = 0 wt_value_tot = 0 wing_area = 110 prop = PM.Prop('7666-4RV') for n, test in enumerate(level_test_cases): tas = test[0] dalt = test[1] wt = test[2] rpm = test[3] mp = test[4] wt_value = test[5] eas = A.tas2eas(tas, dalt, speed_units='mph') tas_fts = U.speed_conv(tas, from_units='mph', to_units='ft/s') cl = FT.eas2cl(eas, wt, wing_area, speed_units='mph') cd = FT.cl2cd_test(cl, cd0, e, flap=0) drag = FT.cd2drag(cd, eas, wing_area, speed_units='mph') drag_power = drag * tas_fts / 550. power = IO.pwr(rpm, mp, dalt) prop_eff = PM.prop_eff(prop, power, rpm, tas, dalt, speed_units='mph') thrust_power = power * prop_eff excess_power = thrust_power - drag_power print('Case', n, 'Altitude =', dalt, 'TAS =', tas, 'EAS =', eas, 'Excess power =', excess_power) sum_sq += wt_value * excess_power**2 wt_value_tot += wt_value print('Average sum of squares of excess power =', \ (sum_sq / wt_value_tot) ** 0.5)
def pwr_vs_alt_temp(temps): """ Returns a series of powers at full throttle and 2700 rpm at various temps 0 ft -20 0 20 40 ISA 213.4 205.4 198.3 191.9 200.0 2000 ft -20 0 20 40 ISA 197.3 189.9 183.3 177.4 186.2 4000 ft -20 0 20 40 ISA 182.4 175.6 169.5 164.0 173.4 6000 ft -20 0 20 40 ISA 167.8 161.5 155.9 150.9 160.6 8000 ft -20 0 20 40 ISA 154.1 148.3 143.2 138.6 148.6 10000 ft -20 0 20 40 ISA 141.3 136.1 131.3 127.1 137.3 12000 ft -20 0 20 40 ISA 129.3 124.5 120.2 116.3 126.6 14000 ft -20 0 20 40 ISA 118.2 113.8 109.8 106.2 116.5 16000 ft -20 0 20 40 ISA 107.4 103.4 99.8 96.6 106.7 18000 ft -20 0 20 40 ISA 97.3 93.7 90.4 87.5 97.4 20000 ft -20 0 20 40 ISA 87.7 84.4 81.5 78.9 88.5 """ alts = range(0,22000, 2000) for alt in alts: print alt, 'ft' for temp in temps: print temp, '\t', print 'ISA' for temp in temps: power = alt2pwr(alt, temp = temp) print '%.1f' % (power), '\t', press = SA.alt2press(alt) MP = press - (29.9213 - 28.6) isa_pwr = IO.pwr(2700, MP, alt) print '%.1f' % (isa_pwr), '\n'
def pwr_vs_alt_temp(temps): """ Returns a series of powers at full throttle and 2700 rpm at various temps 0 ft -20 0 20 40 ISA 213.4 205.4 198.3 191.9 200.0 2000 ft -20 0 20 40 ISA 197.3 189.9 183.3 177.4 186.2 4000 ft -20 0 20 40 ISA 182.4 175.6 169.5 164.0 173.4 6000 ft -20 0 20 40 ISA 167.8 161.5 155.9 150.9 160.6 8000 ft -20 0 20 40 ISA 154.1 148.3 143.2 138.6 148.6 10000 ft -20 0 20 40 ISA 141.3 136.1 131.3 127.1 137.3 12000 ft -20 0 20 40 ISA 129.3 124.5 120.2 116.3 126.6 14000 ft -20 0 20 40 ISA 118.2 113.8 109.8 106.2 116.5 16000 ft -20 0 20 40 ISA 107.4 103.4 99.8 96.6 106.7 18000 ft -20 0 20 40 ISA 97.3 93.7 90.4 87.5 97.4 20000 ft -20 0 20 40 ISA 87.7 84.4 81.5 78.9 88.5 """ alts = list(range(0, 22000, 2000)) for alt in alts: print(alt, 'ft') for temp in temps: print(temp, '\t', end=' ') print('ISA') for temp in temps: power = alt2pwr(alt, temp=temp) print('%.1f' % (power), '\t', end=' ') press = SA.alt2press(alt) MP = press - (29.9213 - 28.6) isa_pwr = IO.pwr(2700, MP, alt) print('%.1f' % (isa_pwr), '\n')