Last active
October 1, 2023 06:22
-
-
Save edt11x/52c69a6448f7a379ad19 to your computer and use it in GitHub Desktop.
Horsepower Python Script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from __future__ import print_function | |
import math | |
try: input = raw_input | |
except NameError: pass | |
# | |
# Next Steps | |
# * Compute HP loss or gain based on Barometric Pressure and Temperature | |
# * Can I make an estimate of manifold vacuum at wide open throttle | |
# based on a carb that is too small? | |
# | |
# Done | |
# * Manifold Pressure | |
# * Inches of Water | |
# | |
# https://gist.github.com/edt11x/52c69a6448f7a379ad19 | |
# | |
# NC50 | |
# Port Timing Table | |
# | |
# From http://hondaspree.net/wiki/index.php5?title=Cylinder_Port_Timing | |
# | |
# Variator Equipped Transmission | |
# 1987 SE 50 83-84 Aero 50 85-87 Aero 50 88-93 Elite SA50 94/2001 Elite SA50 Urban Express NU50 1982 Express Sr NX50 | |
# BBDC Exhaust Open 78 71 76 80 79 67.5 67 | |
# ABDC Exhaust Close 78 71 76 80 79 67.5 67 | |
# BBDC Scavenge Open 57 52 57 56 56 47.5 47 | |
# ABDC Scavenge Close 57 52 57 56 56 47.5 47 | |
# | |
# Fixed Ratio Transmission | |
# Spree 84/85 Spree 86/87 Iowa Spree 84/85 Iowa Spree 86/87 Elite SB50 Elite SB50P 1977-81 Express NC50 | |
# BBDC Exhaust Open 71 73 70 71 77 74 65 | |
# ABDC Exhaust Close 71 73 70 71 77 74 65 | |
# BBDC Scavenge Open 52 54 50 52 60 57 47 | |
# ABDC Scavenge Close 52 54 50 52 60 57 47 | |
# guard against dividing by zero | |
def too_small_guard(val): | |
if (val < 1.0e-9): | |
val = 1.0e-9 | |
return val | |
# Compression ratio should not be less than one in any normal circumstance I can | |
# think of. | |
def cr_guard(cr): | |
if (cr < 1.0): | |
cr = 1.0 | |
return cr | |
# | |
# Conversion routines | |
# | |
# Percentage | |
PERCENT_DIVISOR = 100 | |
def decimal_to_percent(decimal): | |
return decimal * PERCENT_DIVISOR | |
# Gravity | |
# http://hyperphysics.phy-astr.gsu.edu/hbase/work.html | |
STANDARD_GRAVITY = 9.80665 | |
# Temperature | |
FAHRENHEIT_OFFSET = 32.0 | |
KELVIN_OFFSET = 273.15 | |
RANKINE_OFFSET = 459.67 | |
CELSIUS_TO_FAHREN_RATIO = (9.0/5.0) | |
# Reynolds number, Universal gas constant | |
# R - Universal gas constant, 8.314510 J/(mol * K) | |
# R - 1545 ft lbf / degrees Rankin | |
CONST_R = 8.314510 # J/(mol * K) | |
# Kelvin exactly Celsius + 273.15 | |
# | |
# it establishes the difference between the two scales null | |
# points as being precisely 273.15 degrees Celsius (-273.15 | |
# C = 0 K and 0 C = 273.15 K). | |
# | |
# https://en.wikipedia.org/wiki/Celsius | |
def celsius_to_fahrenheit(temp): | |
return ((temp*CELSIUS_TO_FAHREN_RATIO) + FAHRENHEIT_OFFSET) | |
def fahrenheit_to_celsius(temp): | |
return ((temp - FAHRENHEIT_OFFSET) / CELSIUS_TO_FAHREN_RATIO) | |
def celsius_to_kelvin(temp): | |
return (temp + KELVIN_OFFSET) | |
def kelvin_to_celsius(temp): | |
return temp - KELVIN_OFFSET | |
def fahrenheit_to_kelvin(temp): | |
return celsius_to_kelvin(fahrenheit_to_celsius(temp)) | |
def fahrenheit_to_rankine(temp): | |
return temp + RANKINE_OFFSET | |
def celsius_to_rankine(temp): | |
return fahrenheit_to_rankine(celsius_to_fahrenheit(temp)) | |
def rankine_to_fahrenheit(temp): | |
return temp - RANKINE_OFFSET | |
def rankine_to_celsius(temp): | |
return fahrenheit_to_celsius(rankine_to_fahrenheit(temp)) | |
# Mass and Weight | |
# The modern definition of the avoirdupois pound is exactly 0.45359237 kilograms. | |
KG_PER_LB = 0.45359237 | |
# There are exactly 16 ounces in the avoirdupois pound | |
OUNCES_PER_LB = 16 | |
# https://en.wikipedia.org/wiki/Kilogram | |
# | |
# The avoirdupois (or international) pound, used in both the | |
# Imperial system and U.S. customary units, is defined as | |
# exactly 0.45359237 kg | |
# | |
def lbs_to_kg(lbs): | |
return lbs * KG_PER_LB | |
def kg_to_lbs(kg): | |
return kg / KG_PER_LB | |
def per_lb_to_per_kg(per_lb): | |
return per_lb / KG_PER_LB | |
def per_kg_to_per_lb(per_kg): | |
return per_kg * KG_PER_LB | |
# Distance | |
MM_PER_CM = 10 | |
MM_PER_M = 1000 | |
MM_PER_INCH = 25.4 | |
M_PER_KM = 1000 | |
CM_PER_INCH = MM_PER_INCH / MM_PER_CM | |
INCHES_PER_FOOT = 12 | |
FEET_PER_YARD = 3 | |
YARDS_PER_MILE = 1760 | |
def inches_to_mm(inches): | |
return inches * MM_PER_INCH | |
def inches_to_feet(inches): | |
return inches / INCHES_PER_FOOT | |
def inches_to_yards(inches): | |
return feet_to_yards(inches_to_feet(inches)) | |
def inches_to_miles(inches): | |
return yards_to_miles(inches_to_yards(inches)) | |
def feet_to_inches(feet): | |
return feet * INCHES_PER_FOOT | |
def feet_to_mm(feet): | |
return inches_to_mm(feet_to_inches(feet)) | |
def feet_to_yards(feet): | |
return feet / FEET_PER_YARD | |
def feet_to_miles(feet): | |
return yards_to_miles(feet_to_yards(feet)) | |
def miles_to_feet(miles): | |
return yards_to_feet(miles_to_yards(miles)) | |
def miles_to_inches(miles): | |
return feet_to_inches(miles_to_feet(miles)) | |
def miles_to_mm(miles): | |
return inches_to_mm(miles_to_inches(miles)) | |
def yards_to_feet(yards): | |
return yards * FEET_PER_YARD | |
def yards_to_miles(yards): | |
return yards / YARDS_PER_MILE | |
def miles_to_yards(miles): | |
return miles * YARDS_PER_MILE | |
def miles_to_feet(miles): | |
return yards_to_feet(miles_to_yards(miles)) | |
def miles_to_inches(miles): | |
return feet_to_inches(miles_to_feet(miles)) | |
def miles_to_mm(miles): | |
return inches_to_mm(miles_to_inches(miles)) | |
def miles_to_meters(miles): | |
return mm_to_meters(miles_to_mm(miles)) | |
def yards_to_inches(yards): | |
return feet_to_inches(yards_to_feet(yards)) | |
def yards_to_mm(yards): | |
return inches_to_mm(yards_to_inches(yards)) | |
def mm_to_inches(mm): | |
return mm / MM_PER_INCH | |
def mm_to_cm(mm): | |
return mm / MM_PER_CM | |
def mm_to_meters(mm): | |
return mm / MM_PER_M | |
def meters_to_km(meters): | |
return meters / M_PER_KM | |
def mm_to_km(mm): | |
return meters_to_km(mm_to_meters(mm)) | |
def meters_to_mm(meters): | |
return meters * MM_PER_M | |
def meters_to_inches(meters): | |
return mm_to_inches(meters_to_mm(meters)) | |
def meters_to_feet(meters): | |
return inches_to_feet(meters_to_inches(meters)) | |
def meters_to_yards(meters): | |
return feet_to_yards(meters_to_feet(meters)) | |
def meters_to_miles(meters): | |
return yards_to_miles(meters_to_yards(meters)) | |
def km_to_meters(km): | |
return km * M_PER_KM | |
def km_to_mm(km): | |
return meters_to_mm(km_to_meters(km)) | |
def feet_to_meters(feet): | |
return mm_to_meters(inches_to_mm(feet_to_inches(feet))) | |
def mm_to_feet(mm): | |
return inches_to_feet(mm_to_inches(mm)) | |
def mm_to_yards(mm): | |
return feet_to_yards(mm_to_feet(mm)) | |
def mm_to_miles(mm): | |
return yards_to_miles(mm_to_yards(mm)) | |
# Angle | |
FULL_ROT_DEGREES = 360 | |
HALF_ROT_DEGREES = FULL_ROT_DEGREES / 2 | |
def bbdc_to_atdc_deg(degrees): | |
return HALF_ROT_DEGREES - degrees | |
def bbdc_to_atdc_rad(rad): | |
return math.pi - rad | |
def atdc_to_bbdc_deg(degrees): | |
return HALF_ROT_DEGREES - degrees | |
def atdc_to_bbdc_rad(rad): | |
return math.pi - rad | |
# Time | |
SEC_PER_MIN = 60 | |
MIN_PER_HOUR = 60 | |
def sec_to_min(sec): | |
return sec / SEC_PER_MIN | |
def min_to_sec(minutes): | |
return minutes * SEC_PER_MIN | |
def per_sec_to_per_min(per_sec): | |
return per_sec * SEC_PER_MIN | |
def per_sec_to_per_hour(per_sec): | |
return per_sec_to_per_min(per_sec) * MIN_PER_HOUR | |
def per_min_to_per_sec(per_min): | |
return per_min / SEC_PER_MIN | |
def per_min_to_per_hour(per_min): | |
return per_min * MIN_PER_HOUR | |
def per_hour_to_per_min(per_hour): | |
return per_hour / MIN_PER_HOUR | |
def per_hour_to_per_sec(per_hour): | |
return per_min_to_per_sec(per_hour_to_per_min(per_hour)) | |
# Volume | |
ML_PER_LITER = 1000 | |
CC_PER_LITER = ML_PER_LITER | |
def cubic_mm_to_cc(cubic_mm): | |
return cubic_mm / (MM_PER_CM * MM_PER_CM * MM_PER_CM) | |
def cc_to_ml(cc): | |
return cc | |
def cc_to_liters(cc): | |
return cc_to_ml(cc) / ML_PER_LITER | |
def liters_to_cc(liters): | |
return liters * CC_PER_LITER | |
def liters_to_ci(liters): # cubic inches | |
return cc_to_ci(liters_to_cc(liters)) | |
def cc_to_ci(cc): # cubic centimeters to cubic inches | |
return cc / (CM_PER_INCH * CM_PER_INCH * CM_PER_INCH) | |
def ci_to_cc(ci): | |
return ci * (CM_PER_INCH * CM_PER_INCH * CM_PER_INCH) | |
def cc_to_cf(cc): # cubic centimeters to cubic feet | |
return cc_to_ci(cc) / (INCHES_PER_FOOT * INCHES_PER_FOOT * INCHES_PER_FOOT) | |
def cf_to_cc(cf): # cubic feet to cubic centimeters | |
return ci_to_cc(cf) * (INCHES_PER_FOOT * INCHES_PER_FOOT * INCHES_PER_FOOT) | |
# Volumetric Capacity | |
# Cubic Centimeters per second to Cubic Feet per Minute | |
def cc_sec_to_cfm(cc_sec): | |
return per_sec_to_per_min(cc_to_cf(cc_sec)) | |
def cc_sec_to_liters_sec(cc_sec): | |
return cc_to_liters(cc_sec) | |
def cc_sec_to_liters_min(cc_sec): | |
return per_sec_to_per_min(cc_sec_to_liters_sec(cc_sec)) | |
# Liquid Capacity | |
# The US gallon, which is equal to approximately 3.785 L, is | |
# legally defined as 231 cubic inches. | |
# | |
# https://en.wikipedia.org/wiki/Gallon | |
CI_PER_US_LIQUID_GALLON = 231 | |
QUARTS_PER_US_LIQUID_GALLON = 4 | |
PINTS_PER_QUART = 2 | |
FLUID_OUNCES_PER_PINT = 16 | |
def us_liquid_gallons_to_ci(gallons): | |
return gallons * CI_PER_US_LIQUID_GALLON | |
def ci_to_us_liquid_gallons(ci): | |
return ci / CI_PER_US_LIQUID_GALLON | |
def us_liquid_gallons_to_cc(gallons): | |
return ci_to_cc(us_liquid_gallons_to_ci(gallons)) | |
def cc_to_us_liquid_gallons(cc): | |
return ci_to_us_liquid_gallons(cc_to_ci(cc)) | |
def us_liquid_gallons_to_ml(gallons): | |
return cc_to_ml(us_liquid_gallons_to_cc(gallons)) | |
def ml_to_us_liquid_gallons(ml): | |
return cc_to_us_liquid_gallons(ml_to_cc(ml)) | |
def us_liquid_gallons_to_liters(gallons): | |
return cc_to_liters(us_liquid_gallons_to_cc(gallons)) | |
def liters_to_us_liquid_gallons(liters): | |
return cc_to_us_liquid_gallons(liters_to_cc(liters)) | |
def us_liquid_gallons_to_quarts(gallons): | |
return gallons * QUARTS_PER_US_LIQUID_GALLON | |
def quarts_to_us_liquid_gallons(quarts): | |
return quarts / QUARTS_PER_US_LIQUID_GALLON | |
def cc_to_quarts(cc): | |
return us_liquid_gallons_to_quarts(cc_to_us_liquid_gallons(cc)) | |
def quarts_to_cc(quarts): | |
return us_liquid_gallons_to_cc(quarts_to_us_liquid_gallons(quarts)) | |
def quarts_to_pints(quarts): | |
return quarts * PINTS_PER_QUART | |
def pints_to_quarts(pints): | |
return pints / PINTS_PER_QUART | |
def us_liquid_gallons_to_pints(gallons): | |
return quarts_to_pints(us_liquid_gallons_to_quarts(gallons)) | |
def pints_to_us_liquid_gallons(pints): | |
return quarts_to_us_liquid_gallons(pints_to_quarts(pints)) | |
def cc_to_pints(cc): | |
return quarts_to_pints(cc_to_quarts(cc)) | |
def pints_to_cc(pints): | |
return quarts_to_cc(pints_to_quarts(pints)) | |
def pints_to_fluid_ounces(pints): | |
return pints * FLUID_OUNCES_PER_PINT | |
def fluid_ounces_to_pints(fluid_ounces): | |
return fluid_ounces / FLUID_OUNCES_PER_PINT | |
def us_liquid_gallons_to_fluid_ounces(gallons): | |
return pints_to_fluid_ounces(us_liquid_gallons_to_pints(gallons)) | |
def fluid_ounces_to_us_liquid_gallons(fluid_ounces): | |
return pints_to_us_liquid_gallons(fluid_ounces_to_pints(fluid_ounces)) | |
def cc_to_fluid_ounces(cc): | |
return pints_to_fluid_ounces(cc_to_pints(cc)) | |
def fluid_ounces_to_cc(fluid_ounces): | |
return pints_to_cc(fluid_ounces_to_pints(fluid_ounces)) | |
# Velocity | |
def meters_sec_to_miles_hour(ms): | |
return per_sec_to_per_hour(meters_to_miles(ms)) | |
def meters_sec_to_feet_sec(ms): | |
return meters_to_feet(ms) | |
def meters_sec_to_feet_min(ms): | |
return per_sec_to_per_min(meters_sec_to_feet_sec(ms)) | |
def meters_sec_to_km_hour(ms): | |
return per_sec_to_per_hour(meters_to_km(ms)) | |
def miles_hour_to_meters_sec(mph): | |
return per_hour_to_per_sec(miles_to_meters(mph)) | |
def feet_sec_to_meters_sec(feet_sec): | |
return feet_to_meters(feet_sec) | |
def feet_min_to_meters_sec(feet_min): | |
return feet_sec_to_meters_sec(per_min_to_per_sec(feet_min)) | |
def km_hour_to_meters_sec(kmh): | |
return per_hour_to_per_sec(km_to_meters(kmh)) | |
# Pressure | |
# 1 pascal is 1 Newton per square meter | |
# 1 Newton is the force required to accelerate 1 kg 1 meter per sec | |
# https://en.wikipedia.org/wiki/Inch_of_water | |
# 1 inH2O is defined as 248.84 pascals at 60F | |
def kPa_to_Pa(kPa): | |
return kPa * 1000.0 | |
def Pa_to_kPa(pa): | |
return pa / 1000.0 | |
def inHg_to_psi(inHg): | |
return inHg * 0.49109778 | |
def inHg_to_Pa(inHg): | |
return inHg * 1000.0 / 0.295299830714 | |
def inHg_to_kPa(inHg): | |
return Pa_to_kPa(inHg_to_Pa(inHg)) | |
def inHg_to_mmHg(inHg): | |
return inches_to_mm(inHg) | |
def kPa_to_inHg(kPa): | |
return 0.295299830714 * kPa | |
def kPa_to_inH2O(kPa): | |
return kPa_to_Pa(kPa) / 248.84 | |
def kPa_to_MPa(kPa): | |
return kPa / 1000.0 | |
def kPa_to_bar(kPa): | |
return kPa * 0.01 | |
def kPa_to_psi(kPa): | |
return 0.145037738 * kPa | |
# Standard atmosphere is defined as 101.325 kilopascal (kPa) | |
# https://en.wikipedia.org/wiki/Atmosphere_(unit) | |
def kPa_to_std_atm(kPa): | |
return kPa / 101.325 | |
# One atmosphere is exactly 760 torr | |
# https://en.wikipedia.org/wiki/Atmosphere_(unit) | |
def std_atm_to_torr(atm): | |
return 760.0 * atm | |
def psi_to_kPa(psi): | |
return 6.89475729 * psi | |
# One Bar is exactly equal to 100,000 Pa | |
# https://en.wikipedia.org/wiki/Bar_(unit) | |
def bar_to_kPa(bar): | |
return bar * 100.0 | |
# Work, Energy or Torque | |
# | |
# Energy is the capacity for doing work. You must have | |
# energy to accomplish work - it is like the "currency" for | |
# performing work. To do 100 joules of work, you must | |
# expend 100 joules of energy. | |
# | |
# Work refers to an activity involving a force and movement | |
# in the directon of the force. A force of 20 newtons | |
# pushing an object 5 meters in the direction of the force | |
# does 100 joules of work. | |
# | |
# The rate of doing work is equal to the rate of using | |
# energy since the a force transfers one unit of energy when | |
# it does one unit of work. A horsepower is equal to 550 ft | |
# lb/s, and a kilowatt is 1000 watts. | |
# | |
# The British thermal unit (BTU or Btu) is a traditional unit of work equal to | |
# about 1055 joules. A BTU is the amount of heat required to rasie the | |
# temperature of 1 avoirdupois bound of liquid water by 1 degree Fahrenheit at | |
# a constant pressure of 1 atmosphere. | |
# ISO Standard Definition of BTU 1055.056 joules, but this is an approximation | |
# https://en.wikipedia.org/wiki/British_thermal_unit | |
JOULES_PER_BTU = 1055.056 | |
JOULES_PER_CALORIE = 4.184 | |
# A BTU is defined as 1054.3503 Joules | |
# https://en.wikipedia.org/wiki/British_thermal_unit | |
def joules_to_KJ(joules): | |
return joules / 1000 | |
def joules_to_MJ(joules): | |
return joules_to_KJ(joules) / 1000 | |
def KJ_to_joules(kj): | |
return kj * 1000 | |
def MJ_to_joules(mj): | |
return KJ_to_joules(mj * 1000) | |
def btus_to_joules(btus): | |
return btus * JOULES_PER_BTU | |
def joules_to_btus(j): | |
return j / JOULES_PER_BTU | |
def btus_per_lb_to_MJ_per_kg(btus_per_lb): | |
return per_lb_to_per_kg(joules_to_MJ(btus_to_joules(btus_per_lb))) | |
def MJ_per_kg_to_btus_per_lb(MJ_per_kg): | |
return per_kg_to_per_lb(joules_to_btus(MJ_to_joules(MJ_per_kg))) | |
def ft_lbs_to_inch_lbs(ft_lbs_force): | |
return feet_to_inches(ft_lbs_force) | |
def ft_lbs_to_kg_m(ft_lbs_force): | |
return lbs_to_kg(feet_to_meters(ft_lbs_force)) | |
# newton-meter is kg-m * gravity, kg-m * m/s^2, kg-m * 9.8 m/s^2 | |
# https://en.wikipedia.org/wiki/Newton_metre | |
def kg_m_to_newton_m(kg_m): | |
return kg_m * STANDARD_GRAVITY | |
def ft_lbs_to_newton_m(ft_lbs_force): | |
return kg_m_to_newton_m(ft_lbs_to_kg_m(ft_lbs_force)) | |
# newton-meters and joules are dimensionally equivalent | |
def ft_lbs_to_joules(ft_lbs_force): | |
return ft_lbs_to_newton_m(ft_lbs_force) | |
def ft_lbs_to_btus(ft_lbs_force): | |
return ft_lbs_to_joules(ft_lbs_force) / JOULES_PER_BTU | |
# Thermochemical calorie is defined as 4.184 joules | |
# https://en.wikipedia.org/wiki/Calorie | |
def ft_lbs_to_calories(ft_lbs_force): | |
return ft_lbs_to_joules(ft_lbs_force) / JOULES_PER_CALORIE | |
# Power | |
# | |
# Power is the rate of doing work or the rate of using | |
# energy, which are numerically the same. If you do 100 | |
# joules of work in one second (using 100 joules of energy), | |
# the power is 100 watts. | |
# | |
HP_TO_FT_LBS_PER_SEC = 550 | |
HP_TO_FT_LBS_PER_MIN = HP_TO_FT_LBS_PER_SEC * SEC_PER_MIN | |
WATTS_PER_KILOWATT = 1000 | |
# It is defined by standard as 9.80665 m/s^s | |
# https://en.wikipedia.org/wiki/Standard_gravity | |
KG_M_PER_SEC_PER_METRIC_HP = 75 | |
# 550 ft-lbs per second is exactly 33,000 ft-lbs per minute | |
def ft_lbs_per_sec_to_ft_lbs_per_min(ftLbsPerSec): | |
return per_sec_to_per_min(ftLbsPerSec) | |
# Imperial Horsepower is defined as exactly 550 ft-lbs (force) per second | |
# https://en.wikipedia.org/wiki/Horsepower | |
def ft_lbs_per_sec_to_imperial_hp(ftLbsPerSec): | |
return ftLbsPerSec / HP_TO_FT_LBS_PER_SEC | |
def ft_lbs_per_min_to_imperial_hp(ftLbsPerMin): | |
return ft_lbs_per_sec_to_imperial_hp(per_min_to_per_sec(ftLbsPerMin)) | |
# Imperial Horsepower is defined as exactly 550 ft-lbs/second | |
def imperial_hp_to_ft_lbs_per_sec(hp): | |
return hp * HP_TO_FT_LBS_PER_SEC | |
def imperial_hp_to_ft_lbs_per_min(hp): | |
return per_sec_to_per_min(imperial_hp_to_ft_lbs_per_sec(hp)) | |
# convert from ft-lbs/sec to m-kg/sec | |
def ft_lbs_per_sec_to_kg_m_per_sec(ftLbsPerSec): | |
return feet_to_meters(lbs_to_kg(ftLbsPerSec)) | |
def kg_m_per_sec_to_ft_lbs_per_sec(kg_m_per_sec): | |
return meters_to_feet(kg_to_lbs(kg_m_per_sec)) | |
def imperial_hp_to_kg_m_per_sec(hp): | |
return ft_lbs_per_sec_to_kg_m_per_sec(imperial_hp_to_ft_lbs_per_sec(hp)) | |
def kg_m_per_sec_to_imperial_hp(kg_m_per_sec): | |
return ft_lbs_per_sec_to_imperial_hp(kg_m_per_sec_to_ft_lbs_per_sec(kg_m_per_sec)) | |
# Mechanical horsepower | |
# https://en.wikipedia.org/wiki/Horsepower#Metric_horsepower_.28PS.2C_cv.2C_hk.2C_pk.2C_ks.2C_ch.29 | |
# | |
# Assuming the third CGPM (1901, CR 70) definition of | |
# standard gravity, gn=9.80665 m/s^2, is used to define the | |
# pound-force as well as the kilogram force, and the | |
# international avoirdupois pound (1959), one mechanical | |
# horsepower is: | |
# | |
# 1 hp = 33,000 ft-lbf/min by definition | |
# = 550 ft-lbf/s since 1 min = 60 s | |
# = 550x0.3048x0.45359237 m-kgf/s since 1 ft = 0.3048 m and | |
# = 76.0402249068 kgf-m/s 1 lb = 0.45359237 kg | |
# = 76.0402249068x9.80665 kg-m^2/s^3 g = 9.80665 m/s^2 | |
# = 745.69987158227 W since 1 W = 1 J/s = 1 N-m/s = 1 (kg-m/s2)-(m/s) | |
# Or given that 1 hp = 550 ft-lbf/s, 1 ft = 0.3048 m, | |
# 1 lbf is approx 4.448 N, 1 J = 1 N-m, 1 W = 1 J/s: 1 hp = 746 W | |
# Imperial Horsepower to Watts | |
def watts_to_kilowatts(watts): | |
return watts / WATTS_PER_KILOWATT | |
def kilowatts_to_watts(kilowatts): | |
return kilowatts * WATTS_PER_KILOWATT | |
def kg_m_per_sec_to_watts(kg_m_per_sec): | |
return kg_m_per_sec * STANDARD_GRAVITY | |
def watts_to_kg_m_per_sec(watts): | |
return watts / STANDARD_GRAVITY | |
def kilowatts_to_kg_m_per_sec(kilowatts): | |
return watts_to_kg_m_per_sec(kilowatts_to_watts(kilowatts)) | |
def imperial_hp_to_watts(hp): | |
return kg_m_per_sec_to_watts(imperial_hp_to_kg_m_per_sec(hp)) | |
def imperial_hp_to_kilowatts(hp): | |
return watts_to_kilowatts(imperial_hp_to_watts(hp)) | |
def watts_to_imperial_hp(watts): | |
return kg_m_per_sec_to_imperial_hp(watts_to_kg_m_per_sec(watts)) | |
def kilowatts_to_imperial_hp(kilowatts): | |
return kg_m_per_sec_to_imperial_hp(kilowatts_to_kg_m_per_sec(kilowatts)) | |
def hp_to_hp_uk(hp): | |
return hp / 746.0 * 745.7 | |
# DIN 66036 defines one metric horsepower as the power to | |
# raise a mass of 75 kg against the earth's gravitational | |
# force over a distance of one metre in one second; this is | |
# equivalent to 735.49875 W or 98.6% of an imperial | |
# mechanical horsepower. | |
def kg_m_per_sec_to_metric_hp(kg_m_per_sec): | |
return kg_m_per_sec / KG_M_PER_SEC_PER_METRIC_HP | |
def imperial_hp_to_metric_hp(hp): | |
return kg_m_per_sec_to_metric_hp( imperial_hp_to_kg_m_per_sec(hp) ) | |
def metric_hp_to_kg_m_per_sec(metric_hp): | |
return metric_hp * KG_M_PER_SEC_PER_METRIC_HP | |
def metric_hp_to_imperial_hp(metric_hp): | |
return kg_m_per_sec_to_imperial_hp(metric_hp_to_kg_m_per_sec(metric_hp)) | |
# Energy | |
# one watt is defined as one joule per second | |
# defined mostly for documentation | |
def watts_to_joules_per_sec(watts): | |
return watts | |
def joules_per_sec_to_watts(jps): | |
return jps | |
# we can internally self consistently go from hp to watts | |
# now we can go from watts to joules/sec | |
# now we can go from joules/sec to BTUs/sec | |
def imperial_hp_to_btus_per_sec(hp): | |
return joules_to_btus(watts_to_joules_per_sec(imperial_hp_to_watts(hp))) | |
def imperial_hp_to_btus_per_minute(hp): | |
return per_sec_to_per_min(imperial_hp_to_btus_per_sec(hp)) | |
def imperial_hp_to_btus_per_hour(hp): | |
return per_sec_to_per_hour(imperial_hp_to_btus_per_sec(hp)) | |
# Frequency of Rotation | |
# revolutions per minute to revolutions per second (hz) | |
def rpm_to_rps(rpm): | |
return per_min_to_per_sec(rpm) | |
def rps_to_rpm(rps): | |
return per_sec_to_per_min(rps) | |
def rps_to_rad_per_sec(rps): | |
return rps * 2 * math.pi | |
def rpm_to_rad_per_sec(rpm): | |
return rps_to_rad_per_sec(rpm_to_rps(rpm)) | |
def rpm_to_deg_per_sec(rpm): | |
return math.degrees(rpm_to_rad_per_sec(rpm)) | |
# | |
# Geometry routines | |
# | |
# http://www.ajdesigner.com/phpcircle/circle_arc_length_s.php | |
def calc_geom_radius_to_diameter(radius): | |
return 2 * radius | |
def calc_geom_diameter_to_radius(diameter): | |
return diameter / 2 | |
def calc_geom_circumference(diameter): | |
return diameter * math.pi | |
def calc_geom_radius_from_circumference(circum): | |
return calc_geom_diameter_to_radius(circum / math.pi) | |
# (pi * r^2) or ((pi * d^2) / 4) | |
def calc_geom_area_of_circle(diameter): | |
return (diameter * diameter * math.pi) / 4 | |
def calc_geom_volume_of_cylinder(diameter, height): | |
return calc_geom_area_of_circle(diameter) * height | |
# The length a of the arc is a fraction of the length of the | |
# circumference which is 2 * pi * r. So arc length = r * angle | |
def calc_geom_arc_length(radius, angle_rads): | |
return radius * angle_rads | |
# Just rearrange the equation l = r * angle, r = l / angle | |
def calc_geom_circ_radius_from_arc(arc_length, angle_rads): | |
return arc_length / angle_rads | |
# Again, rearrange the equation l = r * angle, angle = l / r | |
def calc_geom_arc_central_angle_rad(arc_length, radius): | |
return arc_length / radius | |
# https://en.wikipedia.org/wiki/Circular_segment | |
# c = chord length | |
# r = radius | |
# A = angle | |
# chord length is c = 2 * r * sin(A / 2) | |
def calc_geom_chord_from_angle_radius(angle_rads, radius): | |
return 2 * radius * math.sin(angle_rads / 2) | |
def calc_geom_chord_from_arc_length(arc_length, radius): | |
angle_rads = calc_geom_arc_central_angle_rad(arc_length, radius) | |
chord = calc_geom_chord_from_angle_radius(angle_rads, radius) | |
return chord | |
# | |
# Calculation routines | |
# | |
# duration is the time to the bottom and then back up | |
def calc_epo_duration_rad(epo_rad_ATDC): | |
return 2 * atdc_to_bbdc_rad(epo_rad_ATDC) | |
def calc_epo_duration_deg(epo_deg_ATDC): | |
return 2 * atdc_to_bbdc_deg(epo_deg_ATDC) | |
# Crank radius is half the stroke | |
def calc_crank_radius(stroke): | |
return stroke / 2 | |
# https://en.wikipedia.org/wiki/Piston_motion_equations | |
# Distance from the center of the crank, x, is given by | |
# l = connecting rod length | |
# r = crank radius, half the stroke | |
# A = crank angle after top dead center in radians | |
# using the cosine law | |
# | |
# l^2 = r^2 + x^2 - 2 * r * x * cos(A) | |
# | |
# solving for x | |
# | |
# x = r * cos(A) + sqrt( l^2 - r^2 * (sin(A))^2) | |
# | |
# Top of the stroke is given by | |
# | |
# l + r | |
# | |
# Distance from the top of the stroke is | |
# | |
# distance from top dead center = l + r - x | |
# | |
def calc_piston_position_from_angle(crl, stroke, angle_ATDC): | |
l = crl | |
r = calc_crank_radius(stroke) | |
a = angle_ATDC | |
return (l+r) - (r*math.cos(a) + math.sqrt(l**2 - r**2 * (math.sin(a))**2)) | |
# To solve for angle, same equation, we just re-arrange to | |
# solve for A remember for distance from the top of the | |
# stroke there will be two angle solutions. | |
# | |
# l^2 = r^2 + x^2 - 2 * r * x * cos(A) | |
# | |
# l^2 - (r^2 + x^2) = - 2 * r * x * cos(A) | |
# (l^2 - (r^2 + x^2)) / (- 2 * r * x) = cos(A) | |
# swapping the minus signs around | |
# ((r^2 + x^2) - l^2) / ( 2 * r * x) = cos(A) | |
# A = arccos(((r^2 + x^2) - l^2) / ( 2 * r * x)) | |
# | |
# As before, we need to convert distance from Top Dead | |
# Center to the distance from the center of the crankshaft | |
# (dftdc) | |
# | |
# The value returned is for both solutions, the angle before | |
# top dead center and the angle after top dead center. | |
# | |
def calc_angle_from_piston_position(crl, stroke, dftdc): | |
l = crl | |
r = calc_crank_radius(stroke) | |
x = crl + r - dftdc | |
cos_a = ((r**2 + x**2) - l**2) / (2 * r * x) | |
if (cos_a < -1): | |
cos_a = -1 # could be just outside the domain | |
if (cos_a > 1): | |
cos_a = 1 # could be just outside the domain | |
return math.acos(cos_a) | |
def calc_displacement(bore, stroke, cylinders): | |
return cubic_mm_to_cc(calc_geom_volume_of_cylinder(bore, stroke)) * cylinders | |
def calc_squish_area_ratio(bore, bowl): | |
area_bore = calc_geom_area_of_circle(bore) | |
area_bowl = calc_geom_area_of_circle(bowl) | |
return (area_bore - area_bowl) / area_bore | |
NC50_OVERALL_GEAR_RATIO = 14.220 | |
NC50_TIRE_DIAMETER_IN_INCHES = 18.5 | |
def calc_nc50_mph(gear_ratio, tire_circum_inches, rpm): | |
# Service manual gives the Gear Ratio as 14.220 : 1 | |
# MPH = (RPM * WheelCirc/GearRatio * ft / 12inches * mile / 5280 ft * 60 mins/hour) | |
# 38.7 MPH = 10000rpm * 18.5 * pi / 14.220 / 12 / 5280 * 60 | |
return ( inches_to_miles(per_min_to_per_hour(rpm * tire_circum_inches) / | |
gear_ratio) ) | |
def calc_nc50_rpm(gear_ratio, tire_circum_inches, mph): | |
return ( per_hour_to_per_min(mph) * gear_ratio / | |
inches_to_miles( tire_circum_inches ) ) | |
def calc_tuned_rpm(epo_deg_ATDC, ws, tl): | |
# Find the tuned length of 2 stroke | |
# expansion chamber | |
# epo - Exhaust Port Open,deg past TDC | |
# ws - Wave Speed in m/s | |
# tl - Tuned Length in mm | |
# rpm - Revolutions Per Minute | |
eo = calc_epo_duration_deg(epo_deg_ATDC) | |
ws = ws * 1000 / (12 * 25.4) | |
rpm = eo * ws * 25.4 / tl | |
return rpm | |
def calc_tuned_length(epo_deg_ATDC, ws, rpm): | |
# Find the tuned length of 2 stroke | |
# expansion chamber | |
# epo - Exhaust Port Open,deg past TDC | |
# ws - Wave Speed in m/s | |
# tl - Tuned Length in mm | |
# rpm - Revolutions Per Minute | |
eo = calc_epo_duration_deg(epo_deg_ATDC) | |
ws = ws * 1000 / (12 * 25.4) | |
tl = eo * ws * 25.4 / rpm | |
return tl | |
# http://hyperphysics.phy-astr.gsu.edu/hbase/sound/souspe3.html#c1 | |
# The speed of sound in an ideal gas is given by the relationship | |
# a = sqrt( k * R * T / m ) | |
# I will use celsius as the input temp | |
# k - is the adiabatic constant, Cp/Cv, sometimes represented by greek gamma | |
# k - Specific Heat ratio for Exhaust 1.343 | |
# k - Specific Heat ratio for dry air 1.40 | |
# m - molecular weight of gas, 28.95 for dry air, 29 for exhaust | |
# m - 0.02895 kg per mol | |
# R - Universal gas constant, 8.314510 J/(mol * K) | |
# R - 1545 ft lbf / degrees Rankin | |
def calc_vel_sound_perfect_gas(k, T, m): | |
return math.sqrt( k * CONST_R * celsius_to_kelvin(T) / (m / 1000) ) | |
# stroke is in mm, result is in meters, so divide by 1000 | |
# rpm is revolutions per minute, we need per second so | |
# divide by 60.0 piston has to transverse the stroke twice, | |
# once up, once down. | |
# | |
# In Jennings, the mean piston speed is given by | |
# piston speed in ft/min = 0.166 * stroke in inches * RPM | |
# Piston has to travel twice the stroke and we need to | |
# convert inches to feet so we multiply by 2/12 or 0.16667 | |
# So Jennings equations make sense. | |
def calc_mean_piston_speed_from_rpm(stroke, rpm): | |
return 2 * rpm_to_rps(rpm) * mm_to_meters(stroke) | |
def calc_rpm_from_mean_piston_speed(stroke, mps): | |
return rps_to_rpm(mps / (2 * mm_to_meters(stroke))) | |
def calc_estimate_scavange_ratio(cr): | |
# A guess at the scavange ratio is | |
# (compression_ratio - 1) / compression_ratio | |
return (cr_guard(cr) - 1) / cr_guard(cr) | |
def calc_heat_added_per_unit_mass_gas(btuslb,stoich,scarat): | |
return btuslb * scarat / stoich | |
def calc_adiabatic_ratio(cp, cv): | |
# k - is the adiabatic constant, Cp/Cv, sometimes represented by greek gamma | |
return cp / too_small_guard(cv) | |
def calc_thermal_efficiency(cr, k): | |
# cr - compression ratio | |
# k - is the adiabatic constant, Cp/Cv, sometimes represented by greek gamma | |
return 1 - math.pow((1/cr_guard(cr)),(k-1)) | |
def calc_a(qpri, cv, inTempC): | |
a = qpri / too_small_guard(cv * celsius_to_rankine(inTempC)) | |
return a | |
def calc_mep_over_p1(a, thermeff, k, cr): | |
mepp1 = a * thermeff/too_small_guard( (k-1) * (1 - (1/cr_guard(cr))) ) | |
return mepp1 | |
# Mean Effective Pressure | |
def calc_mep(a, thermeff, k, cr, presskPa): | |
return kPa_to_psi(presskPa) * calc_mep_over_p1(a, thermeff, k, cr) | |
def calc_indicated_mep(mecheff, mep): | |
# mecheff - mechanical efficiency | |
# mep - mean effective pressure | |
return mecheff * mep | |
def calc_carb_size(k, sv, numcarbs, rpm): | |
return k * math.sqrt(cc_to_liters(sv / numcarbs) * rpm) | |
def calc_intake_strokes_per_rev(cycles): | |
return 2 / cycles | |
def calc_cubic_feet_per_min(sv, rpm, cycles, voleff): | |
return cc_to_cf(sv) * rpm * calc_intake_strokes_per_rev(cycles) * voleff | |
def calc_oil_ratio(gallons_of_gas, ounces_of_oil): | |
return us_liquid_gallons_to_fluid_ounces(gallons_of_gas) / ounces_of_oil | |
def calc_oil_ounces_from_gallons_gas_and_ratio(gallons_of_gas, ratio): | |
return us_liquid_gallons_to_fluid_ounces(gallons_of_gas) / ratio | |
def calc_gallons_of_gas_from_oil_ounces_ratio(oil_ounces, ratio): | |
return fluid_ounces_to_us_liquid_gallons(oil_ounces) * ratio | |
def mep_to_hp(mep, sv, rpm, cycles): | |
hp = ft_lbs_per_sec_to_imperial_hp(mep * cc_to_ci(sv) * rpm_to_rps(rpm) * 2 / (12 * cycles)) | |
return hp | |
def hp_to_mep(hp, sv, rpm, cycles): | |
mep = imperial_hp_to_ft_lbs_per_sec(hp) * (12 * cycles) / (cc_to_ci(sv) * rpm_to_rps(rpm) * 2) | |
return mep | |
def hp_and_mep_to_rpm(hp, mep, sv, cycles): | |
rpm = rps_to_rpm(imperial_hp_to_ft_lbs_per_sec(hp) * (12 * cycles) / (cc_to_ci(sv) * mep * 2)) | |
return rpm | |
def hp_and_mep_to_sv(hp, mep, rpm, cycles): | |
sv = ci_to_cc(imperial_hp_to_ft_lbs_per_sec(hp) * (12 * cycles) / (rpm_to_rps(rpm) * mep * 2)) | |
return sv | |
def torque_to_hp(torque_ft_lbs, rpm): | |
return torque_ft_lbs * rpm / (HP_TO_FT_LBS_PER_MIN / (2 * math.pi)) | |
def hp_to_torque(hp, rpm): | |
return (hp * (HP_TO_FT_LBS_PER_MIN / (2 * math.pi))) / rpm | |
# mostly just for documentation | |
def ft_lbs_to_torque_ft_lbs(torque_arm_in_feet, brake_load_in_lbs): | |
return torque_arm_in_feet * brake_load_in_lbs | |
def newton_m_to_torque_newton_m(torque_arm_in_meters, brake_load_in_newtons): | |
return torque_arm_in_meters * brake_load_in_newtons | |
# Flow Though the Venturi (flow through a carb) | |
# From Internal Combustion Fundamentals | |
# John B. Heywood. | |
# Appendix C - Equations for Fluid Flow through a Restriction | |
# 7.2 Carburetors | |
# | |
# Cd = (actual mass flow) / (ideal mass flow) | |
# | |
# The Discard Coefficient really feels like a kluge. Quoting Heywood: | |
# | |
# The discharge coefficient Cd in Eq (7.5) represents the effect of all | |
# deviations from the ideal one-dimensional isentropic flow. It is influenced | |
# by many factors of which the most important are the following: (1) fluid mass | |
# flow rate; (2) orifice length/diameter ratio; (3) orifice/approach-area | |
# ratio; (4) orifice surface area; (5) orifice surface roughness; (6) orifice | |
# inlet and exit chamfers; (7) fluid specific gravity; (8) fluid viscosity; and | |
# (9) fluid surface tension. The use of teh orifice Reynolds number Re = | |
# rho*V*D0/mu as a correlating paramter for the discharge coefficient accounts | |
# for the effects of mass flow rate, fluid density and viscosity, and length | |
# scale to a good first approximation. | |
# | |
# Under reasonable pressure differences Cd varies from 0.8 to 1.0. 0.9 might be | |
# a good guess. | |
# | |
# Again from Heywood: | |
# | |
# Alternatively, the flow or discharge coefficient can be defined in terms of | |
# an effective cross-sectional area of the duct and a reference area. The | |
# reference area Ar is usually taken as the minimum cross-sectional area. The | |
# effective area of the flow restriction Ae is then the cross-sectional area of | |
# the throat of a frictionless nozzle which would pass the measured mass flow | |
# between a large upstream reservoir at the upstream stagnation pressure and a | |
# large downstream reservoir at the downstream measured static pressure. Thus | |
# | |
# Cd = Ae / Ar | |
# | |
# Estimate the Coefficient of Discharge | |
# AT - area of the flow restriction, area of the venturi of the carb, area of throat | |
# Ar - area of the flow reference, I will use the area of the pipe into the | |
# engine, the area of the manifold pipe | |
def estimate_Cd(AT, Ar): | |
return AT / too_small_guard(Ar) | |
# | |
# Using SI units | |
# Cd - Coefficient of Discharge, 0.9 might be a good guess | |
# AT - Area of the venturi throat, the area of the smallest part of the carb, | |
# the slide area in meters squared | |
# p0 - Pressure at the input to the carb, probably close to atmospheric, in pascals | |
# pT - Pressure at the venturi throat, in pascals | |
# k - Adiabtic Ratio, ratio of specific heats Cp/Cv, heat capacity ratio | |
# T0 - Temperature in Kelvin at input | |
# | |
# Returns mass flow rate of the gas through the restriction, using SI units | |
# AT - in meters squared | |
# p0 - in pascals | |
# pT - in pascals | |
# T0 - in Kelvin | |
# | |
# This routine should then return kilograms per second | |
# | |
def flow_through_venturi(Cd, AT, p0, pT, k, T0): | |
a = (Cd * AT * p0) / math.sqrt( CONST_R * T0 ) | |
b = math.pow( (pT / p0), (1.0 / k) ) | |
c1 = 1.0 - math.pow( (pT / p0), ((k - 1.0) / k) ) | |
c2 = (2.0 * k) / (k - 1.0) | |
c = math.sqrt( c2 * c1 ) | |
return a * b * c | |
# | |
# How can we find the maximum CFM through the carb? We should be able to | |
# determine the maximum amount of horsepower for that given amount of air. | |
# | |
# Again from Heywood: | |
# | |
# For given values of p0 and T0, the maximum mass flow occurs when the velocity | |
# at the minimum area or throat equals the velocity of sound. This condition is | |
# called chocked or critical flow. When the flow is choked the pressure at the | |
# throat, pT, is related to the stagnation pressure p0 as follows: | |
# | |
# pT/p0 = (2 / (k + 1)) ^ (k / (k - 1)) | |
# | |
# This tells us that the critical pressure ratio is just dependant on the heat | |
# capacity ratio and we can use the assumption that p0 is close to the | |
# atmospheric value to find the pressure at the throat, the pressure at the | |
# smallest constriction of the carbuerator. | |
# | |
def choked_throat_pressure(p0, k): | |
return p0 * math.pow( (2.0 / (k+1.0)), (k / too_small_guard(k - 1.0)) ) | |
# List routines | |
# https://en.wikipedia.org/wiki/Mazda_K_engine | |
def list_bore_strokes(): | |
print('From Heywood') | |
print('Bore/Stroke small and medium engines 0.8 to 1.2') | |
print('Bore/Stroke large slow speed CI engines 0.5 to 0.8') | |
print('NC50 stock bore - 40.0, stroke 39.6, cyl 1, b/s', str(round(40.0/39.6,2))) | |
print('NC50 shocko bore - 44.0, stroke 39.6, cyl 1, b/s', str(round(44.0/39.6,2))) | |
print('NC50 athena bore - 47.6, stroke 39.6, cyl 1, b/s', str(round(47.6/39.6,2))) | |
print('NC50 metra bore - 47.0, stroke 39.6, cyl 1, b/s', str(round(47.0/39.6,2))) | |
print('TRX250R bore - 66.0, stroke 72.0, cyl 1, b/s', str(round(66.0/72.0,2))) | |
print('ZXI 1100 bore - 80.0, stroke 71.0, cyl 3, b/s', str(round(80.0/71.0,2))) | |
print('06 SXR 800 bore - 82.0, stroke 74.0, cyl 2, b/s', str(round(82.0/74.0,2))) | |
print('87 Must 5.0 bore - 101.6, stroke 76.2, cyl 8, b/s', str(round(101.6/76.2,2))) | |
print('04 Must 4.6 bore - 90.2, stroke 90.0, cyl 8, b/s', str(round(90.2/90.0,2))) | |
print('77 Cad 425 bore - 103.7, stroke 103.0, cyl 8, b/s', str(round(103.7/103.0,2))) | |
print('95 Probe2.5 bore - 84.5, stroke 74.2, cyl 6, b/s', str(round(84.5/74.2,2))) | |
print('16 Ford 5.2 bore - 94.0, stroke 93.0, cyl 8, b/s', str(round(94.0/93.0,2))) | |
print('18 Ford 5.0 bore - 93.0, stroke 92.7, cyl 8, b/s', str(round(93.0/92.7,2))) | |
def list_carb_bores(): | |
print('NC50 stock carb bore - 12.0mm') | |
print('Dellorto carb bore - 15.0mm') | |
print('VM20 carb bore - 20.0mm') | |
print('TRX250R stock carb bore - 34.0mm') | |
def list_manifold_bores(): | |
print('MLM 20mm manifold bore - 21.6mm') | |
def list_connecting_rod_lengths(): | |
print('1985-1986 TRX250R - 125.3mm') | |
print('1987-1989 TRX250R - 130.3mm') | |
print('1977 NC50 - 80.0mm') | |
print('87 Must 5.0 - 129.286 mm, 5.090 in') | |
print('04 Must 4.6 - 150.7mm') | |
print('16 Ford 5.2 Voodo - 150.7mm') | |
# http://www.ridermagazine.com/manufacturer/honda/retrospective-honda-ncna50-express-1977-1983.htm/ | |
# | |
# NC50 | |
# Rev this little 1/20th-liter engine with a 6.5:1 | |
# compression ratio up to 7,000 rpm and it would make over | |
# four horsepower 4.5 on the dyno. | |
# | |
# Numbers are given in rear wheel horsepower for wheeled | |
# vehicles. | |
# | |
# 04 Mustang is 213 based on numerous dyno runs that people | |
# have posted. Edmunds and numerous other quote the Ford | |
# values: | |
# | |
# Engine & Performance | |
# BASE ENGINE SIZE 4.6 L CAM TYPE Single overhead cam (SOHC) | |
# CYLINDERS V8 VALVES 16 | |
# TORQUE 302 ft-lbs. @ 4000 rpm HORSEPOWER 260 hp @ 5250 rpm | |
# TURNING CIRCLE 38.1 ft. | |
# So the Mustang is losing about 260-213, 47 hp or 18% | |
# through the # drive train and this seems correct. The old | |
# general rule is 15%. All wheel drive cars are expected to | |
# lose 25 to 35%. | |
# | |
# http://www.edmunds.com/ford/mustang/2004/st-100299264/features-specs/ | |
# | |
def list_peak_hp_rpms(): | |
print('NC50 stock HP 4.5 @7000') | |
print('NC50 shocko HP 9.0 @8800') | |
print('TRX250R HP 42.0 @7500') | |
print('06 SXR 800 Stock HP 80.0 @6250') | |
print('ZXI 1100 Stock HP 120.0 @6750') | |
print('ZXI 1100 dry pipe HP 150.0 @8000') | |
print('87 Must 5.0 HP 220.0 @4200') | |
print('04 Must 4.6 Stock HP 213.0 @4400') | |
print('04 Must 4.6 Tuned HP 252.0 @5250') | |
print('77 Cad 425 HP 185.0 @4000') | |
print('95 Probe GT 2.5l HP 164.0 @5600') | |
print('16 Ford Voodo 5.2 HP 526.0 @7500') | |
print('18 Ford Coyete5.0 HP 460.0 @7000') | |
def list_rolling_resistance_factors(): | |
print('NC50 Rolling Resistance Factor 0.015') | |
def list_coefficient_of_drag(): | |
print('Unfaired Recumbent Bicycle 0.77') | |
print('NC50 guess 0.32') | |
# http://www.zeperfs.com/en/fiche767-ford-probe-2-5-24v.htm | |
def list_peak_torque(): | |
print('87 Must 5.0 300 ft-lbs @3200') | |
print('04 Must 4.6 Stock 285 ft-lbs @3500') | |
print('04 Must 4.5 Tuned 293 ft-lbs @4300') | |
print('95 Probe GT 2.5l 156 ft-lbs @4800') | |
print('16 Ford Voodo 5.2 439 ft-lbs @4750') | |
print('18 Ford Coyote5.0 420 ft-lbs @4750') | |
# https://en.wikipedia.org/wiki/Mean_piston_speed | |
# http://www.zeperfs.com/en/fiche767-ford-probe-2-5-24v.htm | |
def list_mean_piston_speed(): | |
print('Automotive - 16 m/s') | |
print('High RPM - 20 m/s') | |
print('Practical Limit - 25 m/s') | |
print('') | |
print('Wikipedia') | |
print('Low Speed Diesels - 8.5 m/s') | |
print('Med Speed Diesels - 11.0 m/s') | |
print('Hi Speed Diesels - 14.0 m/s') | |
print('Med Speed Gasoline- 16.0 m/s') | |
print('Hi Speed Gasoline- 20.0 m/s') | |
print('Hi Speed Gasoline- 25.0 m/s') | |
print('NASCAR Sprint Cup - 25.0 m/s') | |
print('Formula One - 30.0 m/s') | |
print('') | |
print('95 Probe GT 2.5l - 13.6 m/s') | |
def list_compression_ratios(): | |
print('CR = (Swept_Volume + Clearance_Volume) / Clearance_Volume') | |
print(' or ') | |
print('CR = Maximum Cylinder Volume / Minimum Cylinder Volume') | |
print('From Heywood:') | |
print('Spark Ignition (SI) 8 to 12') | |
print('Compression Ignition (CI) 12 to 24') | |
print('NC50 stock - 6.5') | |
print('NC50 shocko - 6.5') | |
print('TRX250R - 10.0') | |
print('06 SXR 800 Stock - 7.2') | |
print('ZXI 1100 stock - 5.8') | |
print('87 Must 5.0 - 9.0') | |
print('04 Must GT 4.6L - 9.4') | |
print('77 Cad 425 - 8.2') | |
print('95 Probe GT 2.5l - 9.2') | |
print('16 Ford Voodo 5.2 - 12.0') | |
print('18 Ford Coyote5.0 - 12.0') | |
def list_gear_ratios(): | |
print('NC50 stock - 14.2207792208') | |
print('NC50 26 tooth - 12.3246753247') | |
# From https://www.fueleconomy.gov/feg/atv.shtml | |
def list_power_losses(): | |
print('Engine Losses') | |
print(' Thermal radiator, exh heat : 56 - 60%') | |
print(' Combustion : 3%') | |
print(' Pumping Losses : 3%') | |
print(' Friction : 3%') | |
print('Parasitic Losses') | |
print(' Water Pump, Alternator : 3 - 4%') | |
print('Power to Wheels') | |
print(' Wind Resistance : 13 - 19%') | |
print(' Rolling Resistance : 6 - 9%') | |
print('Drivetrain Losses : 4 - 7%') | |
# Many values from https://en.wikipedia.org/wiki/Energy_density | |
# http://hypertextbook.com/facts/2003/ArthurGolnik.shtml | |
def list_fuel_specific_energy(): | |
print('Fuel Specific Energy in BTUs/lb') | |
print('Energy from Combustion (Cooling Effect)') | |
print('Hydrogen = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(142)), | |
'BTUs/lb, ', round(142,2), 'MJ/kg') | |
print('Methane = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(55.5)), | |
'BTUs/lb, ', round(55.5,2), 'MJ/kg') | |
print('Diesel/Fuel Oil = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(48)), | |
'BTUs/lb, ', round(48,2), 'MJ/kg') | |
print('LPG/Propane/Butane = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(46.4)), | |
'BTUs/lb, ', round(46.4,2), 'MJ/kg') | |
print('Jet fuel/Kerosene = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(46)), | |
'BTUs/lb, ', round(46,2), 'MJ/kg') | |
print('Animal/Veg. Fat = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(37)), | |
'BTUs/lb, ', round(37,2), 'MJ/kg') | |
print('Dimethy Ether DME = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(28.8)), | |
'BTUs/lb, ', round(28.8,2), 'MJ/kg') | |
print('Ethonal E100 = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(26.4)), | |
'BTUs/lb, ', round(26.4,2), 'MJ/kg') | |
print('Methonal M100 = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(19.7)), | |
' BTUs/lb, ', round(19.7,2), 'MJ/kg') | |
print('Gasoline Zittel, Werner & Reinhold Wurster = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(45.7)), | |
'BTUs/lb, ', round(45.7,2), 'MJ/kg') | |
print('Gasoline Caldirola, Manuela = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(47.5)), | |
'BTUs/lb, ', round(47.5,2), 'MJ/kg') | |
print('Gasoline Thomas, George - Sandia Labs = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(44.4)), | |
'BTUs/lb, ', round(44.4,2), 'MJ/kg') | |
print('Gasoline Low Range Val - Nommensen, Arthur = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(36.4)), | |
'BTUs/lb, ', round(36.4,2), 'MJ/kg') | |
print('Gasoline Hi Range Val - Nommensen, Arthur = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(49.6)), | |
'BTUs/lb, ', round(49.6,2), 'MJ/kg') | |
print('Gasoline Harrison, Reid R. = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(44.0)), | |
'BTUs/lb, ', round(44.0,2), 'MJ/kg') | |
print('Gasoline E10 = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(43.54)), | |
'BTUs/lb, ', round(43.54,2), 'MJ/kg') | |
print('Gasoline E85 = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(33.10)), | |
'BTUs/lb, ', round(33.10,2), 'MJ/kg') | |
print('VP C-12 = 18,834 BTUs/lb, ', | |
round(btus_per_lb_to_MJ_per_kg(18834),2),'MJ/kg') | |
print('Pump Gas = 17,920 BTUs/lb, ', | |
round(btus_per_lb_to_MJ_per_kg(17920),2),'MJ/kg') | |
print('Acetone = 12,000 BTUs/lb (225),', | |
round(btus_per_lb_to_MJ_per_kg(12000),2),'MJ/kg') | |
print('Benzole = 17,000 BTUs/lb (153),', | |
round(btus_per_lb_to_MJ_per_kg(17000),2),'MJ/kg') | |
print('Ether = 15,000 BTUs/lb (153),', | |
round(btus_per_lb_to_MJ_per_kg(15000),2),'MJ/kg') | |
print('Methonal = 9,770 BTUs/lb (472),', | |
round(btus_per_lb_to_MJ_per_kg(9770),2), 'MJ/kg') | |
print('Nitrobenzene = 10,800 BTUs/lb (143),', | |
round(btus_per_lb_to_MJ_per_kg(10800),2),'MJ/kg') | |
print('Nitromethane = 5,000 BTUs/lb (258),', | |
round(btus_per_lb_to_MJ_per_kg(5000),2), 'MJ/kg') | |
print('Prop. Oxide = 14,000 BTUs/lb (220),', | |
round(btus_per_lb_to_MJ_per_kg(14000),2),'MJ/kg') | |
print('Diborane = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(78.2)), | |
'BTUs/lb, ', round(78.2,2), 'MJ/kg') | |
print('Natural Gas, LNG at -160C, CNG at 250 bar = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(53.6)), | |
'BTUs/lb, ', round(53.6,2), 'MJ/kg') | |
print('Cude Oil = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(46.3)), | |
'BTUs/lb, ', round(46.3,2), 'MJ/kg') | |
print('Residential Heating Oil = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(46.2)), | |
'BTUs/lb, ', round(46.2,2), 'MJ/kg') | |
print('Diesel fuel = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(45.6)), | |
'BTUs/lb, ', round(45.6,2), 'MJ/kg') | |
print('Jet A Aviation Fuel/Kerosene = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(42.80)), | |
'BTUs/lb, ', round(42.80,2), 'MJ/kg') | |
print('Biodiesel oil/Vegetable Oil = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(42.20)), | |
'BTUs/lb, ', round(42.20,2), 'MJ/kg') | |
print('Dimethylfuran (DMF) = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(42.00)), | |
'BTUs/lb, ', round(42.00,2), 'MJ/kg') | |
print('Body Fat metabolism = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(38.00)), | |
'BTUs/lb, ', round(38.00,2), 'MJ/kg') | |
print('Hydrazine = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(19.50)), | |
'BTUs/lb, ', round(19.50,2), 'MJ/kg') | |
print('Liquid Ammonia = {:,.0f}'.format(MJ_per_kg_to_btus_per_lb(18.00)), | |
'BTUs/lb, ', round(18.00,2), 'MJ/kg') | |
GASOLINE_STOICHIOMETRIC = 14.7 | |
E10_STOICHIOMETRIC = 14.08 | |
E15_STOICHIOMETRIC = 13.79 | |
E85_STOICHIOMETRIC = 9.765 | |
ETHANOL_STOICHIOMETRIC = 9.0078 | |
METHANOL_STOICHIOMETRIC = 6.45 | |
PROPANE_STOICHIOMETRIC = 15.7 | |
def air_fuel_ratio_to_lambda(af_ratio,stoich): | |
return af_ratio / stoich | |
def af_ratio_and_lambda_to_str(af_ratio,stoich): | |
return "%5.2f, lambda - %.4f" % (af_ratio,air_fuel_ratio_to_lambda(af_ratio,stoich)) | |
# http://www.hotrod.com/articles/wideband-oxygen-sensor/ | |
def list_air_fuel_ratio(): | |
print('Air/Fuel Ratio') | |
print('Gasoline Lean - ',af_ratio_and_lambda_to_str(15.0,GASOLINE_STOICHIOMETRIC)) | |
print('Gasoline Stoichiometric - ',af_ratio_and_lambda_to_str(14.7,GASOLINE_STOICHIOMETRIC)) | |
print('Gasoline Max Power Rich - ',af_ratio_and_lambda_to_str(12.5,GASOLINE_STOICHIOMETRIC)) | |
print('Gasoline Max Power Lean - ',af_ratio_and_lambda_to_str(13.23,GASOLINE_STOICHIOMETRIC)) | |
print('Gasoline E10 Stoichiometric - ',af_ratio_and_lambda_to_str(14.08,E10_STOICHIOMETRIC)) | |
print('Gasoline E10 Max Power Rich - ',af_ratio_and_lambda_to_str(12.0,E10_STOICHIOMETRIC)) | |
print('Gasoline E10 Max Power Lean - ',af_ratio_and_lambda_to_str(12.7008,E10_STOICHIOMETRIC)) | |
print('Gasoline E15 Stoichiometric - ',af_ratio_and_lambda_to_str(13.79,E15_STOICHIOMETRIC)) | |
print('Gasoline E15 Max Power Rich - ',af_ratio_and_lambda_to_str(11.75,E15_STOICHIOMETRIC)) | |
print('Gasoline E15 Max Power Lean - ',af_ratio_and_lambda_to_str(12.4362,E15_STOICHIOMETRIC)) | |
print('Gasoline E85 Stoichiometric - ',af_ratio_and_lambda_to_str(9.75,E85_STOICHIOMETRIC)) | |
print('Gasoline E85 Max Power Rich - ',af_ratio_and_lambda_to_str(6.975,E85_STOICHIOMETRIC)) | |
print('Gasoline E85 Max Power Lean - ',af_ratio_and_lambda_to_str(8.469,E85_STOICHIOMETRIC)) | |
print('Ethanol Stoichiometric - ',af_ratio_and_lambda_to_str(9.0078,ETHANOL_STOICHIOMETRIC)) | |
print('Ethanol Max Power Rich - ',af_ratio_and_lambda_to_str(6.429,ETHANOL_STOICHIOMETRIC)) | |
print('Ethanol Max Power Lean - ',af_ratio_and_lambda_to_str(7.8,ETHANOL_STOICHIOMETRIC)) | |
print('Acetone Max Power - ',af_ratio_and_lambda_to_str(9.4,9.4)) | |
print('Benzole Max Power - ',af_ratio_and_lambda_to_str(10.8,10.8)) | |
print('Ether Max Power - ',af_ratio_and_lambda_to_str(9.8,9.8)) | |
print('Methonal Stoichiometric - ',af_ratio_and_lambda_to_str(6.45,METHANOL_STOICHIOMETRIC)) | |
print('Methonal Max Power - ',af_ratio_and_lambda_to_str(4.5,METHANOL_STOICHIOMETRIC)) | |
print('Methonal Peak Torque - ',af_ratio_and_lambda_to_str(4.0,METHANOL_STOICHIOMETRIC)) | |
print('Propane Stoichiometric - ',af_ratio_and_lambda_to_str(15.7,PROPANE_STOICHIOMETRIC)) | |
print('Propane Max Power Rich - ',af_ratio_and_lambda_to_str(13.18,PROPANE_STOICHIOMETRIC)) | |
print('Nitrobenzene Max - ',af_ratio_and_lambda_to_str(8.1,8.1)) | |
print('Nitromethane Rich Consv. - ',af_ratio_and_lambda_to_str(10.1,6.5)) | |
print('Nitromethane Conservative - ',af_ratio_and_lambda_to_str(6.5,6.5)) | |
print('Nitromethane Max Power - ',af_ratio_and_lambda_to_str(2.5,6.5)) | |
print('Nitromethane Max Power - ',af_ratio_and_lambda_to_str(0.5,6.5)) | |
print('Propylene Oxide Max - ',af_ratio_and_lambda_to_str(9.6,9.6)) | |
def list_volumetric_efficiency(): | |
print('Volumetric Efficiency') | |
# From http://www.widman.biz/English/Calculators/CFM.html | |
print('The volumetric efficiency is a factor determined by') | |
print('the efficiency of the turbo, the electronic control') | |
print('systems, the type of carb or fuel injection and the') | |
print('variation of valve timing or opening.') | |
print('') | |
print('A carburated engine normally has a vol eff of 0.70-0.80') | |
print('but electronics can raise this figure as high as 2.0.') | |
print('') | |
print('A diesel engine (2 cycle or 4 cycle) normally has a') | |
print('volumetric efficiency of 0.90.') | |
print('') | |
print('A turbo can raise the volumetric efficiency to between') | |
print('1.5 and 3.0. If you do not know this value for your') | |
print('turbo, it is best to use 3.0') | |
print('') | |
print('Stock Engines = 0.75 - 0.85') | |
print('Mild Built = 0.85 - 0.90') | |
print('Racing Engines = 0.90 - 1.00') | |
print('2Stroke Good Pipe = 1.00') | |
print('2Stroke OK Pipe = 0.90') | |
def list_clearance_volume(): | |
print('Clearance Volume') | |
print('The volume in cc with the piston at Top Dead Center (TDC)') | |
print('NC50 stock - 8cc') | |
# https://en.wikipedia.org/wiki/Mean_effective_pressure | |
# http://www.zeperfs.com/en/fiche767-ford-probe-2-5-24v.htm | |
def list_bmep(): | |
print('Typical Mean Effective Pressure at max Torque') | |
print('Natural asp. spark-ign : 8.5-10.5 bar 850-1050kPa 125-150 psi') | |
print('Boosted spark ignition : 12.5-17 bar 1.25-1.7MPa 180-250 psi') | |
print('Natural asp. 4s diesels: 7-9 bar 700-900 kPa 100-130 psi') | |
print('Boosted car 4s diesels : 14-18 bar 1.4-1.8 MPa 200-269 psi') | |
print('Large low speed 2s dies: up to 19 bar 1.9 MPa 275 psi.') | |
print('Ultra boosted engines : up to 28 bar 32 bar for the Agera R') | |
print('Top Fuel dragster : 80-100 bar 8.0-10MPa 1160-1450 psi') | |
print('') | |
print('Jennings Two Stroke Tuners Handbook') | |
print('2s low speed smooth : 4.8 bar (70 psi)') | |
print('2s ported and plumbing : 7.9 bar (115 psi)') | |
print('2s highly developed : 8.6 bar (125 psi)') | |
print('2s Enduro : 8.0 bar (116 psi)') | |
print('2s Motocross : 9.0 bar (130 psi)') | |
print('2s Road Race : 11.0 bar (160 psi)') | |
print('') | |
print('95 Probe GT 2.5l : 10.6 bar') | |
print('') | |
def list_specific_power(): | |
print('95 Probe GT 2.5l : 0.32 kW/cm2') | |
print('') | |
def list_exhaust_temperatures(): | |
print('Average exhaust temperature in pipe') | |
print('Blair average temperature estimates') | |
print('GP - 650') | |
print('MX - 600 (TRX250R 6 inches down on the header)') | |
print('Enduro - 500') | |
print('JetSki - 400') | |
def list_exhaust_port_open(): | |
print('Exhaust Port Open (epo) in Degrees After Top Dead Center (ATDC)') | |
print('NC50 - ', 130.0) | |
print('TRX250R - 88.5') | |
def list_exhaust_port_close(): | |
print('Exhaust Port Close (epc) in Degrees After Top Dead Center (ATDC)') | |
print('NC50 - 180.0') | |
def list_moped_tire_sizes(): | |
print('Moped Tire Sizes') | |
print('PA50 - Honda Hobbit - Tire (Size 2.25x17)') | |
print('NC50 - Honda Express - Tire (Size 2.25x14)') | |
print('QT50 - Yamahopper - Tire (Size 2.25x14)') | |
print('FA50 - Suzuki Shuttle - Tire (Size 2.25x14)') | |
print('SH50 - Yamaha Razz - Tire (Size 2.50x10)') | |
print('NU50 - Honda Urban Express') | |
print('Includes (2) Tire Sizes - (1) 2.75x14 and (1) 2.25x16 NU50 Models') | |
print('CG50/CY50 Yamaha Jogs (Size 3.00x10)') | |
print('Metric Size for the Yamaha Jogs CG50/CY50 (Size 80/90x10)') | |
def list_moped_rim_sizes(): | |
print('NC50 Stock - 14 inches') | |
print('NU50 Rear - 16 inches') | |
# https://en.wikipedia.org/wiki/Atmosphere | |
def list_specific_heat_ratios(): | |
print('Heat capacity ratio or Adiabatic index or') | |
print('ratio of specific heats or Poisson constant') | |
print('is the ration of the heat capacity at a') | |
print('constant pressure to the heat capacity at a') | |
print('constant volume. gamma = Cp/Cv') | |
print('Dry Air contains') | |
print(' -- 78.09 % Nitrogen, N2') | |
print(' -- 20.95 % Oxygen, O2') | |
print(' -- 0.93 % Argon, Ar') | |
print(' -- 0.039% Carbon Dioxide, CO2') | |
print('Air contains') | |
print(' -- about 1% water vapor at sea level') | |
print(' -- about 0.4% over the entire atmospher') | |
print('1.403 - Ratio Specific Heats Dry Air 0C') | |
print('1.400 - Ratio Specific Heats Dry Air 20C') | |
print('1.401 - Ratio Specific Heats Dry Air 100C') | |
print('1.398 - Ratio Specific Heats Dry Air 200C') | |
print('1.393 - Ratio Specific Heats Dry Air 400C') | |
print('1.365 - Ratio Specific Heats Dry Air 1000C') | |
print('1.088 - Ratio Specific Heats Dry Air 2000C') | |
print('1.470 - Ratio Specific Heats N2 -181C') | |
print('1.404 - Ratio Specific Heats N2 15C') | |
print('1.450 - Ratio Specific Heats O2 -181C') | |
print('1.415 - Ratio Specific Heats O2 -76C') | |
print('1.400 - Ratio Specific Heats O2 20C') | |
print('1.399 - Ratio Specific Heats O2 100C') | |
print('1.397 - Ratio Specific Heats O2 200C') | |
print('1.394 - Ratio Specific Heats O2 400C') | |
print('1.400 - Ratio Specific Heats NO2 20C') | |
print('1.310 - Ratio Specific Heats CO2 0C') | |
print('1.300 - Ratio Specific Heats CO2 20C') | |
print('1.281 - Ratio Specific Heats CO2 100C') | |
print('1.235 - Ratio Specific Heats CO2 400C') | |
print('1.195 - Ratio Specific Heats CO2 1000C') | |
print('1.320 - Ratio Specific Heats CH4 Methane 20C') | |
print('1.343 - Ratio Specific Heats Exhaust') | |
# From Wikipedia Speed of Sound article | |
def list_speed_of_sound(): | |
print('Wikipedia Speed of Sound 20C in dry air - 768 mph') | |
# Display Subroutines | |
def display_ratio(title, ratio): | |
print(title) | |
print('Ratio : ', ratio) | |
print('') | |
def display_pressure(title, kPa): | |
print(title) | |
print('Pounds per Square Inch : ', kPa_to_psi(kPa)) | |
print('Bar : ', kPa_to_bar(kPa)) | |
print('Kilo Pascals : ', kPa) | |
print('Mega Pascals : ', kPa_to_MPa(kPa)) | |
print('Inches of Mercury : ', kPa_to_inHg(kPa)) | |
print('Inches of Water : ', kPa_to_inH2O(kPa)) | |
print('Standard Atmospheres : ', kPa_to_std_atm(kPa)) | |
print('Torr : ', std_atm_to_torr(kPa_to_std_atm(kPa))) | |
print('') | |
def display_distance(title, mm): | |
print(title) | |
print('Millimeters : ', mm) | |
print('Centimeters : ', mm_to_cm(mm)) | |
print('Meters : ', mm_to_meters(mm)) | |
print('Inches : ', mm_to_inches(mm)) | |
print('Feet : ', mm_to_feet(mm)) | |
print('Yards : ', mm_to_yards(mm)) | |
print('Kilometers : ', mm_to_km(mm)) | |
print('Miles : ', mm_to_miles(mm)) | |
print('') | |
def display_area(title, mm_squared): | |
print(title) | |
print('Millimeters ^ 2 : ', mm_squared) | |
print('Centimeters ^ 2 : ', mm_to_cm(mm_to_cm(mm_squared))) | |
print('Meters ^ 2 : ', mm_to_meters(mm_to_meters(mm_squared))) | |
print('Inches ^ 2 : ', mm_to_inches(mm_to_inches(mm_squared))) | |
print('Feet ^ 2 : ', mm_to_feet(mm_to_feet(mm_squared))) | |
print('Yards ^ 2 : ', mm_to_yards(mm_to_yards(mm_squared))) | |
print('Kilometers ^ 2 : ', mm_to_km(mm_to_km(mm_squared))) | |
print('Miles ^ 2 : ', mm_to_miles(mm_to_miles(mm_squared))) | |
print('') | |
def display_angle(title, degrees): | |
print(title) | |
print('Degrees : ', degrees) | |
print('Radians : ', math.radians(degrees)) | |
print('') | |
def display_angular_velocity(title, rpm): | |
print(title) | |
print('Revolutions/Minute : ', rpm) | |
print('Revolutions/Second(Hz) : ', rpm_to_rps(rpm)) | |
print('Radians per Second : ', rpm_to_rad_per_sec(rpm)) | |
print('Degrees per Second : ', rpm_to_deg_per_sec(rpm)) | |
print('') | |
def display_hp(title, hp): | |
print(title) | |
print('HP US or Imperial : ', hp) | |
print('HP metric (aka PS) : ', imperial_hp_to_metric_hp(hp)) | |
print('HP (UK) : ', hp_to_hp_uk(hp)) | |
print('Watts : ', imperial_hp_to_watts(hp)) | |
print('Kilo Watts : ', imperial_hp_to_kilowatts(hp)) | |
print('BTUs per Second : ', imperial_hp_to_btus_per_sec(hp)) | |
print('BTUs per Minute : ', imperial_hp_to_btus_per_minute(hp)) | |
print('BTUs per Hour : ', imperial_hp_to_btus_per_hour(hp)) | |
print('Foot-Lbs per Second : ', imperial_hp_to_ft_lbs_per_sec(hp)) | |
print('Foot-Lbs per Minute : ', imperial_hp_to_ft_lbs_per_min(hp)) | |
print('kg-meters per Second : ', imperial_hp_to_kg_m_per_sec(hp)) | |
print('') | |
def display_energy(title, ft_lbs_force): | |
print(title) | |
print('Energy in Pound Feet : ', ft_lbs_force) | |
print('Energy in Pound Inches : ', ft_lbs_to_inch_lbs(ft_lbs_force)) | |
print('Energy in Kg Meters : ', ft_lbs_to_kg_m(ft_lbs_force)) | |
print('Energy in Newton Meters: ', ft_lbs_to_newton_m(ft_lbs_force)) | |
print('Energy in Joules : ', ft_lbs_to_joules(ft_lbs_force)) | |
print('Energy in BTUs : ', ft_lbs_to_btus(ft_lbs_force)) | |
print('Energy in calories : ', ft_lbs_to_calories(ft_lbs_force)) | |
print('') | |
def display_specific_energy(title, MJ_per_kg): | |
print(title) | |
print('Specific Energy MJ/kg : ', round(MJ_per_kg,2)) | |
print('Specific Energy BTUs/lb: ', round(MJ_per_kg_to_btus_per_lb(MJ_per_kg),2)) | |
print('') | |
def display_temperature(title, temp): | |
print(title) | |
print('Celsius : ', temp) | |
print('Kelvin : ', celsius_to_kelvin(temp)) | |
print('Fahrenheit : ', celsius_to_fahrenheit(temp)) | |
print('Rankine : ', celsius_to_rankine(temp)) | |
print('') | |
def display_volume(title, cc): | |
print(title) | |
print('Volume in cc : ',cc) | |
print('Volume in liters : ',cc_to_liters(cc)) | |
print('Volume in milliliters : ',cc_to_ml(cc)) | |
print('Volume in cubic inches : ',cc_to_ci(cc)) | |
print('Volume in cubic feet : ',cc_to_cf(cc)) | |
print('') | |
def display_mass(title, kg): | |
print(title) | |
print('Mass in kilograms : ',kg) | |
print('Mass in pounds (lb) : ',kg_to_lbs(kg)) | |
print('') | |
def display_force(title, kg): | |
print(title) | |
print('Force in kilograms : ',kg) | |
print('Force in pounds (lb) : ',kg_to_lbs(kg)) | |
print('') | |
def display_liquid_capacity(title, cc): | |
display_volume(title, cc) | |
print('Volume in gallons : ',cc_to_us_liquid_gallons(cc)) | |
print('Volume in quarts : ',cc_to_quarts(cc)) | |
print('Volume in pints : ',cc_to_pints(cc)) | |
print('Volume in fluid ounces : ',cc_to_fluid_ounces(cc)) | |
def display_velocity(title, ms): | |
print(title) | |
print('Meters per second : ', ms) | |
print('Feet per second : ', meters_sec_to_feet_sec(ms)) | |
print('Feet per minute : ', meters_sec_to_feet_min(ms)) | |
print('Kilometers per hour : ', meters_sec_to_km_hour(ms)) | |
print('Miles per hour : ', meters_sec_to_miles_hour(ms)) | |
print('') | |
def display_volumetric_capacity(title, cc_sec): | |
print(title) | |
print('Cubic CM (CC) per Second : ', cc_sec) | |
print('Cubic Feet per Min (CFM) : ', cc_sec_to_cfm(cc_sec)) | |
print('Liters per Second : ', cc_sec_to_liters_sec(cc_sec)) | |
print('Liters per Minute : ', cc_sec_to_liters_min(cc_sec)) | |
print('') | |
# http://pelagiaresearchlibrary.com/advances-in-applied-science/vol3-iss4/AASR-2012-3-4-1915-1922.pdf | |
def display_thermal_efficiency(title, eff): | |
print(title) | |
print('Increasing the compression ratio of an') | |
print('engine can improve the thermal efficiency') | |
print('of the engine by producing more power output.') | |
print('The ideal theoretical cycle, the Otto cycle,') | |
print('upon which spark ignition (SI) engines are') | |
print('based, has a thermal efficiency, which') | |
print('increases with compression ratio, and is') | |
print('given by ') | |
print('1 - (1/cr) ** (k-1), where k = 1.4 for air') | |
print('Thermal Efficiency : ', eff) | |
print('Efficiency as Percentage : ', decimal_to_percent(eff)) | |
print('') | |
def display_mep(title, mep): | |
print(title) | |
list_bmep() | |
display_pressure('', mep) | |
print('') | |
def display_mean_piston_speed(title, ms): | |
print(title) | |
list_mean_piston_speed() | |
display_velocity('', ms) | |
print('') | |
def prompt(s, default): | |
val = input((s % default) + ' : ') | |
print('') | |
return float(val or default) | |
def selection(): | |
print('') | |
return input('Selection : ').strip() | |
# | |
# Ask routines | |
# | |
def ask_specific_heat_ratio(k=1.343): | |
print('Ratio of Specific Heats') | |
list_specific_heat_ratios() | |
k = prompt('Computed Adiabatic Ratio[%s]', k) | |
print('') | |
return k | |
def ask_gear_ratio(ratio=14.2207792208): | |
print('Gear Ratios') | |
list_gear_ratios() | |
ratio = prompt('Gear Ratio[%s]', ratio) | |
print('') | |
return ratio | |
def ask_fuel_specific_energy_btus_per_lb(): | |
print('Fuel Specific Energy') | |
list_fuel_specific_energy() | |
btuslb = prompt('Fuel Energy in BTUs/lb [%s]', 17920) | |
print('') | |
return btuslb | |
def ask_fuel_specific_energy_MJ_per_kg(): | |
print('Fuel Specific Energy') | |
list_fuel_specific_energy() | |
btuslb = prompt('Fuel Energy in MJ/kg [%s]', 41.6819258225) | |
print('') | |
return btuslb | |
def ask_fuel_air_ratio(): | |
print('Fuel Air Ratio') | |
list_air_fuel_ratio() | |
ratio = prompt('Fuel Air Ratio [%s]', 14.6) | |
print('') | |
return ratio | |
def ask_boost(): | |
print('Forced Air Induction') | |
boostPSI = prompt('Super/Turbo Charger Boost in PSI [%s]', 0) | |
boostkPa = psi_to_kPa(boostPSI) | |
print('') | |
return boostkPa | |
def ask_cycles(): | |
cycles = 0 | |
while (cycles != 2) and (cycles != 4): | |
print('Two Stroke or Four Stroke?') | |
cycles = prompt('Number of Engine Cycles [%s]', 2) | |
print('') | |
return cycles | |
def ask_intake_temperature(): | |
inTempC = fahrenheit_to_celsius(prompt('Intake Temperature deg F [%s]', 100)) | |
display_temperature('Intake Temperature', inTempC) | |
return inTempC | |
def ask_baro_pressure(): | |
print('Barometric Pressure (check weather app)') | |
print('or enter manifold pressure if partial throttle') | |
print('Fully closed throttle is probably 12 inHg') | |
print('Wide Open Throttle is probably close to Barometric') | |
print('There is about 1 inHg per 1000 feet of altitude') | |
presskPa = inHg_to_kPa(prompt('Barometric Pressure in inHg [%s std]', 29.92)) | |
display_pressure('',presskPa) | |
return presskPa | |
def ask_length(title, default): | |
length = prompt(title + ' in mm [%s]', default) | |
display_distance(title, length) | |
return length | |
def ask_lbs_mass(title, default): | |
lbs = prompt(title + ' in lbs mass [%s]', default) | |
display_mass(title, lbs_to_kg(lbs)) | |
return lbs | |
def ask_sq_ft_area(title, default): | |
sq_ft_area = prompt(title + 'in square feet [%s]', default) | |
display_area(title, feet_to_mm(feet_to_mm(sq_ft_area))) | |
return sq_ft_area | |
def ask_mph(title, default): | |
mph = prompt(title + ' in MPH [%s]', default) | |
display_velocity(title, miles_hour_to_meters_sec(mph)) | |
return mph | |
def ask_cylinder_head_bowl_diameter(): | |
band = ask_length('Inner Diameter of Squish Band', 30) | |
return band | |
def ask_diameter(title, default): | |
diameter = ask_length(title, default) | |
return diameter | |
def ask_arc_segment_length(title, default): | |
length = ask_length(title, default) | |
return length | |
def ask_angle(title, default): | |
angle = prompt(title + ' in degrees [%s]', default) | |
display_angle('Angle', angle) | |
return angle | |
def ask_bore(): | |
list_bore_strokes() | |
bore = ask_length('Bore', 40.0) | |
return bore | |
def ask_carb_bore(): | |
list_carb_bores() | |
bore = ask_length('Carb Bore', 20.0) | |
return bore | |
def ask_manifold_bore(): | |
list_manifold_bores() | |
bore = ask_length('Manifold Bore', 21.6) | |
return bore | |
def ask_stroke(): | |
list_bore_strokes() | |
stroke = ask_length('Stroke', 39.6) | |
return stroke | |
def ask_connecting_rod_length(): | |
list_connecting_rod_lengths() | |
crl = ask_length('Connecting Rod Length', 80) | |
return crl | |
def ask_exhaust_port_open(): | |
list_exhaust_port_open() | |
epo = ask_angle('Exhaust Port Open ATDC', 115.0) | |
return epo | |
def ask_exhaust_port_close(): | |
list_exhaust_port_close() | |
epc = ask_angle('Exhaust Port Close ATDC', 180.0) | |
return epc | |
def ask_crank_angle_atdc(): | |
epo = ask_angle('Crank Angle After Top Dead Center (ATDC)', 88.5) | |
display_angle('Crank Angle', epo) | |
return epo | |
def ask_cylinders(): | |
cyl = prompt('Cylinders [%s]', 1) | |
print('') | |
return cyl | |
def ask_rpm(): | |
list_peak_hp_rpms() | |
rpm = prompt('RPM [%s]', 7000.0) | |
print('') | |
return rpm | |
def ask_rolling_resistance_factor(): | |
list_rolling_resistance_factors() | |
Cr = prompt('Rolling Resistance Factor [%s]', 0.015) | |
return Cr | |
def ask_coefficient_of_drag(): | |
list_coefficient_of_drag() | |
Cd = prompt('Coefficient of Drag [%s]', 0.32) | |
return Cd | |
def ask_mean_piston_speed(): | |
list_mean_piston_speed() | |
mps = prompt('Mean Piston Speed in m/s [%s]', 16) | |
print('') | |
return mps | |
def ask_mep(): | |
list_bmep() | |
mep = prompt('Mean Effective Pressure in PSI [%s]', 100) | |
print('') | |
return mep | |
def ask_ft_lbs_force(): | |
list_peak_torque() | |
ft_lbs_force = prompt('Foot Lbs Force [%s]', 550) | |
print('') | |
return ft_lbs_force | |
def ask_hp(): | |
list_peak_hp_rpms() | |
hp = prompt('Horsepower [%s]', 1) | |
print('') | |
return hp | |
def ask_watts(): | |
watts = prompt('Watts [%s]', 745.69987158227) | |
print('') | |
return watts | |
def ask_kilowatts(): | |
kilowatts = prompt('KiloWatts [%s]', 0.74569987158227) | |
print('') | |
return kilowatts | |
def ask_ft_lbs_per_sec(): | |
ft_lbs_per_sec = prompt('Foot Lbs per Second [%s]', 550) | |
print('') | |
return ft_lbs_per_sec | |
def ask_ft_lbs_per_min(): | |
ft_lbs_per_min = prompt('Foot Lbs per Minute [%s]', 33000) | |
print('') | |
return ft_lbs_per_min | |
def ask_kg_m_per_sec(): | |
kg_m_sec = prompt('KG Meters per Second [%s]', 75) | |
print('') | |
return kg_m_sec | |
def ask_volumetric_eff(): | |
list_volumetric_efficiency() | |
voleff = prompt('Volumetric Efficiency [%s]',0.9) | |
print('') | |
return voleff | |
def ask_clearance_volume(): | |
list_clearance_volume() | |
clear_vol = prompt('Clearance Volume in cc [%s]',8.0) | |
print('') | |
return clear_vol | |
def ask_scavange_ratio(cr): | |
sr = calc_estimate_scavange_ratio(cr) | |
print('Scavange Ratio') | |
print('Est. of Scavange Ratio based on Compression - ', sr) | |
sr = prompt('Scavange Ratio [%s]', sr) | |
print('') | |
return sr | |
def ask_compression_ratio(): | |
list_compression_ratios() | |
cr = prompt('Effective Compression Ratio [%s]', 6.5) | |
print('') | |
return cr | |
def ask_overall_mechanical_efficiency(): | |
list_power_losses() | |
mecheff = prompt('Overall Mechanical Efficiency [%s]', 0.53) | |
print('') | |
return mecheff | |
def ask_heat_added_per_unit_mass_gas(btuslb,stoich,scarat): | |
qpri = calc_heat_added_per_unit_mass_gas(btuslb,stoich,scarat) | |
print("Heat added per unit mass of gas (Q') in btus/lb") | |
print("Q' Computed", qpri) | |
qpri = prompt("Value to use for Q' [%s] ",qpri) | |
print('') | |
return qpri | |
def ask_cp(): | |
cp = prompt('Cp(Specific Heat at Constant Press) Btu/lbm F [%s] ', 0.24) | |
return cp | |
def ask_cv(): | |
cv = prompt('Cv(Specific Heat at Constant Volume) Btu/lbm F [%s] ', 0.1715) | |
return cv | |
def ask_adiabatic_ratio(cp, cv): | |
k = calc_adiabatic_ratio(cp, cv) | |
# let the user modify it, if so desired. | |
k = ask_specific_heat_ratio(k) | |
print('') | |
return k | |
def ask_moped_rim_size(): | |
list_moped_rim_sizes() | |
rim_inches = prompt('Rim Size in Inches [%s]', 14) | |
return rim_inches | |
def ask_moped_tire_size(): | |
list_moped_tire_sizes() | |
tire_width_inches = prompt('Tire Width Inches [%s]', 2.25) | |
return tire_width_inches | |
def ask_tire_circumference(circ): | |
tire_circumference_inches = prompt('Tire Circumference Inches [%s]', circ) | |
return tire_circumference_inches | |
def horsepower_torque_from_mep(mep, sv, rpm, cycles): | |
hp = mep_to_hp(mep, sv, rpm, cycles) | |
list_peak_hp_rpms() | |
print('') | |
display_hp('\nHorsepower', hp) | |
torque = hp_to_torque(hp, rpm) | |
display_energy('\nTorque', torque) | |
def mep_from_horsepower(hp, sv, rpm, cycles): | |
mep = hp_to_mep(hp, sv, rpm, cycles) | |
display_mep('BMEP', psi_to_kPa(mep)) | |
def rpm_from_hp_and_mep(hp, mep, sv, cycles): | |
rpm = hp_and_mep_to_rpm(hp, mep, sv, cycles) | |
display_angular_velocity('RPM', rpm) | |
def sv_from_hp_mep_and_rpm(hp, mep, rpm, cycles): | |
cc = hp_and_mep_to_sv(hp, mep, rpm, cycles) | |
display_volume('Displacement per Cylinder', cc) | |
def prompt_bhp_from_bmep(): | |
print('\nCompute Brake Horsepower from BMEP\n') | |
cycles = ask_cycles() | |
sv = ask_displacement() | |
rpm = ask_rpm() | |
mep = ask_mep() | |
horsepower_torque_from_mep(mep, sv, rpm, cycles) | |
def prompt_bmep_from_bhp(): | |
print('\nCompute BMEP from Brake Horsepower\n') | |
cycles = ask_cycles() | |
sv = ask_displacement() | |
rpm = ask_rpm() | |
hp = ask_hp() | |
mep_from_horsepower(hp, sv, rpm, cycles) | |
def prompt_rpm_from_bmep_and_bhp(): | |
print('\nCompute RPM needed given BMEP and HP\n') | |
cycles = ask_cycles() | |
sv = ask_displacement() | |
hp = ask_hp() | |
mep = ask_mep() | |
rpm_from_hp_and_mep(hp, mep, sv, cycles) | |
def prompt_sv_from_hp_mep_and_rpm(): | |
print('\nCompute Swept Volume (Displacement) needed given BMEP, HP and RPM\n') | |
cycles = ask_cycles() | |
hp = ask_hp() | |
mep = ask_mep() | |
rpm = ask_rpm() | |
sv_from_hp_mep_and_rpm(hp, mep, rpm, cycles) | |
def display_cylinder_pressures_and_temperatures(p1kPa, t1C, qpri, cr, cv, k): | |
display_pressure('Cylinder Pressure at Intake Close', p1kPa) | |
display_temperature('Mixture Temperature at Intake Close', t1C) | |
p2kPa = p1kPa * math.pow(cr_guard(cr), k) | |
t2C = kelvin_to_celsius(celsius_to_kelvin(t1C)* (p2kPa/(cr_guard(cr)*p1kPa)) ) | |
display_pressure('Cylinder Pressure at Peak Compression', p2kPa) | |
display_temperature('Mixture Temperature at Peak Compression', t2C) | |
t1r = celsius_to_rankine(t1C) | |
t2r = celsius_to_rankine(t2C) | |
t3r = t2r + qpri/cv | |
t4r = t1r * (t3r/t2r) | |
p3kPa = p2kPa * (t3r/t2r) | |
p4kPa = p3kPa * math.pow(1/cr_guard(cr),k) | |
display_pressure('Cylinder Pressure at Combustion', p3kPa) | |
display_temperature('Cylinder Temperature at Combustion', | |
rankine_to_celsius(t3r)) | |
display_pressure('Cylinder Pressure at Exhaust', p4kPa) | |
display_temperature('Cylinder Temperature at Exhaust', | |
rankine_to_celsius(t4r)) | |
def prompt_air_cycle(): | |
print('\nCharles Fayette Taylor Air Cycle Computation of HP\n') | |
print('First we can calculate Mean Effective Pressure independent') | |
print('of the geometry, just from thermodynamics\n') | |
# *** First *** | |
# Things we can know without bore, stroke, displacement, cycles, etc. | |
# ie Thermodynamics Intrinsic calculations | |
presskPa = ask_baro_pressure() | |
boostkPa = ask_boost() | |
presskPa += boostkPa | |
display_pressure('Total Boost', presskPa) | |
inTempC = ask_intake_temperature() | |
cr = ask_compression_ratio() | |
btuslb = ask_fuel_specific_energy_btus_per_lb() | |
stoich = ask_fuel_air_ratio() | |
voleff = ask_volumetric_eff() | |
scarat = ask_scavange_ratio(cr) | |
qpri = ask_heat_added_per_unit_mass_gas(btuslb,stoich,scarat) * voleff | |
cp = ask_cp() | |
cv = ask_cv() | |
k = ask_adiabatic_ratio(cp, cv) | |
thermeff = calc_thermal_efficiency(cr, k) | |
display_thermal_efficiency('Thermal Efficiency', thermeff) | |
a = calc_a(qpri, cv, inTempC) | |
print("Q' / (T1 * Cv) : ", a) | |
print('') | |
mep = calc_mep(a, thermeff, k, cr, presskPa) | |
mecheff = ask_overall_mechanical_efficiency() | |
display_mep('\nCalculated Mean Effective Pressure before efficiency', psi_to_kPa(mep)) | |
imep = calc_indicated_mep(mecheff, mep) | |
display_mep('\nIndicated Mean Effective Pressure', psi_to_kPa(imep)) | |
display_cylinder_pressures_and_temperatures(presskPa, inTempC, qpri, cr, cv, k) | |
# *** Next *** | |
# Things we need bore, stroke, cycles, etc. | |
# ie Thermodynamics Extrinsic calculations | |
ask_extrinsic_outcome(imep, voleff) | |
# | |
# Once we have the thermodynamic intrinsics calculations, we can do other | |
# calculations: | |
# - calculate the necessary RPM needed for a specifc horsepower | |
# - calculate the CFM required for a specific horsepower | |
# | |
def ask_extrinsic_outcome(imep, voleff): | |
display_mep('\nCurrent Indicated Mean Effective Pressure', psi_to_kPa(imep)) | |
choice = '' | |
while choice.strip() != 'x': | |
print('\nBMEP Menu') | |
print('1. Find HP from Displacement, Cycles and RPM') | |
print('2. Find RPM from Cycles, Displacement and HP') | |
print('3. Find Displacement from HP, Cycles and RPM') | |
print('4. Find Intake CFM from IMEP, Displacement, Cycles and RPM') | |
print('x. Exit') | |
choice = selection() | |
if choice == '1': | |
cycles = ask_cycles() | |
sv = ask_displacement() | |
rpm = ask_rpm() | |
cfm = calc_cubic_feet_per_min(sv, rpm, cycles, voleff) | |
display_volumetric_capacity('Intake CFM, Cubic Feet per Minute', per_min_to_per_sec(cf_to_cc(cfm))) | |
horsepower_torque_from_mep(imep, sv, rpm, cycles) | |
if choice == '2': | |
cycles = ask_cycles() | |
sv = ask_displacement() | |
hp = ask_hp() | |
rpm_from_hp_and_mep(hp, imep, sv, cycles) | |
if choice == '3': | |
cycles = ask_cycles() | |
hp = ask_hp() | |
rpm = ask_rpm() | |
sv_from_hp_mep_and_rpm(hp, imep, rpm, cycles) | |
if choice == '4': | |
cycles = ask_cycles() | |
sv = ask_displacement() | |
rpm = ask_rpm() | |
cfm = calc_cubic_feet_per_min(sv, rpm, cycles, voleff) | |
display_volumetric_capacity('Intake CFM, Cubic Feet per Minute', per_min_to_per_sec(cf_to_cc(cfm))) | |
def prompt_mean_piston_speed_from_rpm(): | |
print('\nMean Piston Speed from RPM') | |
stroke = ask_stroke() | |
rpm = ask_rpm() | |
mps = calc_mean_piston_speed_from_rpm(stroke, rpm) | |
display_mean_piston_speed('Mean Piston Speed', mps) | |
def prompt_rpm_from_mean_piston_speed(): | |
print('\nRPM from Mean Piston Speed') | |
stroke = ask_stroke() | |
mps = ask_mean_piston_speed() | |
rpm = calc_rpm_from_mean_piston_speed(stroke, mps) | |
display_angular_velocity('RPM', rpm) | |
def prompt_carb_size(): | |
print('\nJennings Carb Sizing') | |
cycles = ask_cycles() | |
sv = ask_displacement() | |
rpm = ask_rpm() | |
voleff = ask_volumetric_eff() | |
cfm = calc_cubic_feet_per_min(sv, rpm, cycles, voleff) | |
display_volumetric_capacity('Intake CFM, Cubic Feet per Minute', per_min_to_per_sec(cf_to_cc(cfm))) | |
numcarbs = prompt('Number of Carbs or Venturis [%s]', 1) | |
print('Min Carb Bore ', calc_carb_size(0.65, sv, numcarbs, rpm)) | |
print('Safe Carb Bore ', calc_carb_size(0.80, sv, numcarbs, rpm)) | |
print('Max Carb Bore ', calc_carb_size(0.90, sv, numcarbs, rpm)) | |
def prompt_scooter_mph_from_hp(): | |
print('\nCalculate Possible Max Scooter MPH from HP') | |
# | |
# There is a good bit of info about cycling drag on bicycles. | |
# | |
# From https://visforvoltage.org/forum-topic/general/526-horsepower-calculations | |
# | |
# Following is from Bidwell's "Secrets of El Ninja": | |
# Force required = Cr x Wt + (Cd x A x V^2)/391 | |
# This is assuming a flat surface and steady speed and zero relative wind. Using what you have, and integrating with #s provided by Bidwell... | |
# Cr: Rolling resistance factor = .015 | |
# Wt: Weight in pounds = 100 + [your weight] = 250 lbs | |
# Cd: coefficient of drag = .77 (for unfaired recumbent bicycle) | |
# A: Area = 4 square feet (just a guss) | |
# V: Velocity in mph = 40 | |
# Force Required = (.015 x 250 lbs) + (.77 x 4 x 1600)/(391) = 16.35 | |
# I think the unit for force is pounds. | |
# Pick say an arbitrary wheel size of 1 ft, then the torque required would be 16.35 ft lbs. Given 40 mph, it will need to spin at 560.5 rpm. | |
# Following is from http://en.wikipedia.org/wiki/Torque : | |
# Power (hp) = (torque (lbf x ft) x angular speed (rpm))/5252 = 1.745 hp or 1301.97 watts. | |
# I may have screwed something up, and this doesn't take into | |
# account the 2% grade. This is the fist time I've done the | |
# above calculations, but they look like they may be close. | |
# This doesn't take into account the power required to accelerate, | |
# only constant speed. | |
# XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX | |
# XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX | |
# XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX | |
Cr = ask_rolling_resistance_factor() | |
scooter_lbs = ask_lbs_mass('Scooter weight in lbs', 100) | |
rider_lbs = ask_lbs_mass('Rider and backpack weight in lbs', 200) | |
Cd = ask_coefficient_of_drag() | |
A = ask_sq_ft_area('Frontal area in square feet', 3) | |
mph = ask_mph('Maximum Velocity', 25) | |
rolling_resistance = (Cr * (scooter_lbs + rider_lbs)) | |
drag_force = (Cd * A * (mph * mph))/(391) | |
force_lbs = rolling_resistance + drag_force | |
display_force('Rolling Resistance', lbs_to_kg(rolling_resistance)) | |
display_force('Drag Force ', lbs_to_kg(drag_force)) | |
display_force('Force required', lbs_to_kg(force_lbs)) | |
# now we need the radius of the wheel for ft-lbs | |
circum_inches = prompt_moped_tire_circumference() | |
radius_feet = inches_to_feet(calc_geom_radius_from_circumference(circum_inches)) | |
display_distance('Tire Radius', feet_to_mm(radius_feet)) | |
torque = force_lbs * radius_feet | |
display_energy('Torque', torque) | |
ratio = ask_gear_ratio() | |
rpm = calc_nc50_rpm(ratio, circum_inches, mph) | |
display_angular_velocity('RPM',rpm) | |
# XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX | |
# XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX | |
# XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX | |
# This is a calculation of the maximum mass flow through a carb, | |
# through a venturi. This happens when the speed of the fluid, air, | |
# through the venturi approachs the speed sound. | |
def prompt_carb_mass_flow(): | |
print('\nCompute Max Mass Flow through a Carb') | |
bore = ask_carb_bore() | |
AT = calc_geom_area_of_circle(bore) | |
display_area('\nArea of Carb Bore', AT) | |
manifold_bore = ask_manifold_bore() | |
Aref = calc_geom_area_of_circle(manifold_bore) | |
display_area('\nArea of Manifold Bore', Aref) | |
Cd = estimate_Cd(AT, Aref) | |
print('\nEstimate of Coefficient of Discharge : ', Cd, '\n') | |
presskPa = ask_baro_pressure() | |
cp = ask_cp() | |
cv = ask_cv() | |
k = ask_adiabatic_ratio(cp, cv) | |
inTempC = ask_intake_temperature() | |
pT = choked_throat_pressure(presskPa, k) | |
display_pressure('\nChoked Throat Pressure', pT) | |
print('\nCritical Pressure Ratio: ', pT / too_small_guard(presskPa)) | |
# convert to SI units | |
AT = mm_to_meters(mm_to_meters(AT)) | |
p0 = kPa_to_Pa(presskPa) | |
pT = kPa_to_Pa(pT) | |
T0 = celsius_to_kelvin(inTempC) | |
flow_kg_per_sec = flow_through_venturi(Cd, AT, p0, pT, k, T0) | |
print('\nFlow in Kg per Second : ', flow_kg_per_sec) | |
def prompt_bore_stroke(): | |
print('\nDisplacement') | |
bore = ask_bore() | |
stroke = ask_stroke() | |
crl = ask_connecting_rod_length() | |
display_ratio('Ratio of Bore to Stroke', bore / too_small_guard(stroke)) | |
display_ratio('Ratio of Connecting Rod Length to Crank Radius', crl / too_small_guard(calc_crank_radius(stroke))) | |
display_ratio('Ratio of Connecting Rod Length to Stroke ', crl / too_small_guard(stroke)) | |
cc = calc_displacement(bore, stroke, 1) | |
display_volume('Displacement per Cylinder', cc) | |
cyl = ask_cylinders() | |
cc = calc_displacement(bore, stroke, cyl) | |
display_volume('Displacement', cc) | |
return cc | |
def prompt_swept_volume(): | |
cc = prompt('calc_displacement (Swept Volume) in cc [%s]', 250) | |
display_volume('Displacement', cc) | |
return cc | |
def prompt_squish_ratio(): | |
print('\nSquish Area Ratio') | |
bore = ask_bore() | |
bowl = ask_cylinder_head_bowl_diameter() | |
ratio = calc_squish_area_ratio(bore, bowl) | |
display_ratio('Squish Area Ratio', ratio) | |
def prompt_trapped_compression_ratio(): | |
print('\Trapped Compression Ratio') | |
sv = ask_displacement() | |
crl = ask_connecting_rod_length() | |
epo = ask_exhaust_port_open() | |
print('Not Done Yet, More Code to Write') | |
def prompt_connecting_rod(): | |
print('\nFind Connnecting Rod Length') | |
upper_bearing_diameter = ask_diameter('Upper Bearing', 20) | |
lower_bearing_diameter = ask_diameter('Lower Bearing', 29.5) | |
length = ask_length('Distance from top of upper bearing to bottom of lower bearing', 104.75) | |
length = length - ((upper_bearing_diameter / 2) + (lower_bearing_diameter / 2)) | |
display_distance('Connecting Rod Length', length) | |
display_distance('Crank Radius', calc_crank_radius(length)) | |
def prompt_piston_position(title): | |
print(title) | |
stroke = ask_stroke() | |
crl = ask_connecting_rod_length() | |
a = ask_crank_angle_atdc() | |
d = calc_piston_position_from_angle(crl, stroke, math.radians(a)) | |
display_distance('Distance from Top of Stroke', d) | |
return d | |
def prompt_piston_pos_from_crank_angle(): | |
prompt_piston_position('\nFind Piston Position from Crank Angle') | |
def prompt_piston_angle(): | |
print('\nFind Crank Angle Before or After Top Dead Center') | |
stroke = ask_stroke() | |
crl = ask_connecting_rod_length() | |
dftdc = ask_length('Distance from Top Dead Center', 0) | |
angle = calc_angle_from_piston_position(crl, stroke, dftdc) | |
display_angle('Angle Before or After Top Dead Center', math.degrees(angle)) | |
def prompt_moped_tire_circumference(): | |
rim_inches = ask_moped_rim_size() | |
tire_width_inches = ask_moped_tire_size() | |
circum_inches = calc_geom_circumference(rim_inches + 2 * tire_width_inches) | |
circum_inches = ask_tire_circumference(circum_inches) | |
display_distance('Tire Circumference', inches_to_mm(circum_inches)) | |
return circum_inches | |
def prompt_nc50_mph(): | |
print('\nNC50 MPH from RPM') | |
circum_inches = prompt_moped_tire_circumference() | |
rpm = prompt('RPM [%s]', 10000.0) | |
ratio = ask_gear_ratio() | |
mph = calc_nc50_mph(ratio, circum_inches, rpm) | |
display_velocity('Velocity', miles_hour_to_meters_sec(mph)) | |
def prompt_nc50_rpm(): | |
print('\nNC50 RPM from MPH') | |
circum_inches = prompt_moped_tire_circumference() | |
mph = prompt('MPH [%s]', 40.0) | |
ratio = ask_gear_ratio() | |
display_angular_velocity('RPM',calc_nc50_rpm(ratio, circum_inches, mph)) | |
def prompt_tuned_rpm(): | |
print('Tuned RPM for Expansion Chamber') | |
epo = ask_exhaust_port_open() | |
list_exhaust_temperatures() | |
T = prompt('Temperature of Exhaust Gas degC [%s]', 400) | |
ws = prompt('Exhaust Wave Speed in m/s [%s]', | |
calc_vel_sound_perfect_gas(1.343, T, 29.0)) | |
tl = ask_length('Tuned Length', 740) | |
display_angular_velocity('RPM',calc_tuned_rpm(epo, ws, tl)) | |
def prompt_tuned_length(): | |
print('Tuned Length for Expansion Chamber, given RPM') | |
epo = ask_exhaust_port_open() | |
list_exhaust_temperatures() | |
T = prompt('Temperature of Exhaust Gas degC [%s]', 400) | |
ws = prompt('Exhaust Wave Speed in m/s [%s]', | |
calc_vel_sound_perfect_gas(1.343, T, 29.0)) | |
rpm = ask_rpm() | |
len = calc_tuned_length(epo, ws, rpm) | |
display_distance('', len) | |
def prompt_speed_sound(): | |
list_speed_of_sound() | |
print('Speed of Sound in an Ideal Gas') | |
k = ask_specific_heat_ratio() | |
T = prompt('Temperature of Gas degC [%s]', 100) | |
print('28.95 - Dry Air') | |
print('29.00 - Exhaust') | |
m = prompt('Molecular Mass of Gas [%s]', 28.95) | |
display_velocity('Speed of Sound', calc_vel_sound_perfect_gas(k, T, m)) | |
def prompt_ft_lbs_force(): | |
ft_lbs_force = ask_ft_lbs_force() | |
display_energy('Energy', ft_lbs_force) | |
def prompt_btus_per_lb_specific_energy(): | |
btus_per_lb = ask_fuel_specific_energy_btus_per_lb() | |
display_specific_energy('Specific Energy', | |
btus_per_lb_to_MJ_per_kg(btus_per_lb)) | |
def prompt_MJ_per_kg_specific_energy(): | |
MJ_per_kg = ask_fuel_specific_energy_MJ_per_kg() | |
display_specific_energy('Specific Energy', MJ_per_kg) | |
def prompt_horsepower(): | |
hp = ask_hp() | |
display_hp('Horsepower', hp) | |
def prompt_metric_horsepower(): | |
hp = ask_hp() | |
display_hp('Horsepower', metric_hp_to_imperial_hp(hp)) | |
def prompt_watts(): | |
watts = ask_watts() | |
display_hp('Horsepower', watts_to_imperial_hp(watts)) | |
def prompt_kilowatts(): | |
kilowatts = ask_kilowatts() | |
display_hp('Horsepower', kilowatts_to_imperial_hp(kilowatts)) | |
def prompt_ft_lbs_per_sec(): | |
ft_lbs_per_sec = ask_ft_lbs_per_sec() | |
display_hp('Horsepower', ft_lbs_per_sec_to_imperial_hp(ft_lbs_per_sec)) | |
def prompt_ft_lbs_per_min(): | |
ft_lbs_per_min = ask_ft_lbs_per_min() | |
display_hp('Horsepower', ft_lbs_per_min_to_imperial_hp(ft_lbs_per_min)) | |
def prompt_kg_m_per_sec(): | |
kg_m_per_sec = ask_kg_m_per_sec() | |
display_hp('Horsepower', kg_m_per_sec_to_imperial_hp(kg_m_per_sec)) | |
def prompt_port_segment(): | |
bore = ask_bore() | |
segment_length = ask_arc_segment_length('Port Segment Length', 20) | |
display_distance('Chord Length', | |
calc_geom_chord_from_arc_length(segment_length, | |
bore / 2)) | |
def bmep_menu(): | |
choice = '' | |
while choice.strip() != 'x': | |
print('\nBMEP Menu') | |
print('1. Find HP from BMEP') | |
print('2. Find BMEP from HP') | |
print('3. Find RPM given HP, BMEP, Displacement, and Cycles') | |
print('4. Find Displacement given HP, BMEP, RPM and Cycles') | |
print('x. Exit') | |
choice = selection() | |
if choice == '1': | |
prompt_bhp_from_bmep() | |
if choice == '2': | |
prompt_bmep_from_bhp() | |
if choice == '3': | |
prompt_rpm_from_bmep_and_bhp() | |
if choice == '4': | |
prompt_sv_from_hp_mep_and_rpm() | |
def horsepower_menu(): | |
choice = '' | |
while choice.strip() != 'x': | |
print('\nHorsepower Menu') | |
print('1. Convert Horsepower') | |
print('2. Convert Metric Horsepower') | |
print('3. Convert Watts') | |
print('4. Convert KiloWatts') | |
print('5. Convert Foot Lbs per Second') | |
print('6. Convert Foot Lbs per Minute') | |
print('7. Convert KG Meters per Second') | |
print('x. Exit') | |
choice = selection() | |
if choice == '1': | |
prompt_horsepower() | |
if choice == '2': | |
prompt_metric_horsepower() | |
if choice == '3': | |
prompt_watts() | |
if choice == '4': | |
prompt_kilowatts() | |
if choice == '5': | |
prompt_ft_lbs_per_sec() | |
if choice == '6': | |
prompt_ft_lbs_per_min() | |
if choice == '7': | |
prompt_kg_m_per_sec() | |
def ideal_gas_menu(): | |
choice = '' | |
while choice.strip() != 'x': | |
print('\nIdeal Gas Menu') | |
print('1. Speed Sound in an Ideal Gas') | |
print('x. Exit') | |
choice = selection() | |
if choice == '1': | |
prompt_speed_sound() | |
def ask_bore_stroke_or_swept_volume(): | |
choice = '' | |
while (choice.strip() != 'b') and (choice.strip() != 'd'): | |
print('\nChoose Displacement Calculation') | |
print('b. Bore - Stroke - Cyl') | |
print('d. Final Displacement (Swept Volume)') | |
choice = selection() | |
print('Choice is - ', choice) | |
return choice.strip() | |
def ask_displacement(): | |
choice = ask_bore_stroke_or_swept_volume() | |
if (choice == 'b'): | |
disp = prompt_bore_stroke() | |
else: | |
disp = volume_menu() | |
print('') | |
return disp | |
def oil_ratio_menu(): | |
choice = '' | |
while choice.strip() != 'x': | |
print('\nOil Ratio Menu') | |
print('1. Find Oil Ratio from Gallons of Gas and Ounces of Oil') | |
print('2. Find Ounces of Oil from Gallons of Gas and Oil Ratio') | |
print('3. Find Gallons of Gas from Ounces of Oil and Oil Ratio') | |
print('x. Exit') | |
choice = selection() | |
print('') | |
if choice == '1': | |
gallons_of_gas = prompt('Gallons of Gas [%s]', 5) | |
ounces_of_oil = prompt('Ounces of Oil [%s]', 16) | |
print('Oil Ratio : ', calc_oil_ratio(gallons_of_gas, ounces_of_oil), 'to 1') | |
if choice == '2': | |
gallons_of_gas = prompt('Gallons of Gas [%s]', 5) | |
oil_ratio = prompt('Oil Ratio [%s]', 40) | |
print('Ounces of Oil : ', calc_oil_ounces_from_gallons_gas_and_ratio(gallons_of_gas, oil_ratio)) | |
if choice == '3': | |
ounces_of_oil = prompt('Ounces of Oil [%s]', 16) | |
oil_ratio = prompt('Oil Ratio [%s]', 40) | |
print('Gallons of Gas : ', calc_gallons_of_gas_from_oil_ounces_ratio(ounces_of_oil, oil_ratio)) | |
def measurement_menu(): | |
choice = '' | |
while choice.strip() != 'x': | |
print('\nMeasurement Menu') | |
print('1. Convert Feet') | |
print('2. Convert Inches') | |
print('3. Convert Millimeters') | |
print('4. Convert Yards') | |
print('5. Convert Miles') | |
print('6. Convert Kilometers') | |
print('x. Exit') | |
choice = selection() | |
if choice == '1': | |
feet = prompt('Feet [%s]', 1) | |
display_distance('', feet_to_mm(feet)) | |
if choice == '2': | |
inches = prompt('Inches [%s]', 1) | |
display_distance('', inches_to_mm(inches)) | |
if choice == '3': | |
mm = prompt('Millimeters [%s]', MM_PER_INCH) | |
display_distance('', mm) | |
if choice == '4': | |
yards = prompt('Yards [%s]', YARDS_PER_MILE) | |
display_distance('', yards_to_mm(yards)) | |
if choice == '5': | |
miles = prompt('Miles [%s]', 1) | |
display_distance('', miles_to_mm(miles)) | |
if choice == '6': | |
km = prompt('Kilometers [%s]', 1) | |
display_distance('', km_to_mm(km)) | |
def velocity_menu(): | |
choice = '' | |
while choice.strip() != 'x': | |
print('\nVelocity Menu') | |
print('1. Convert Meters/Second') | |
print('2. Convert Feet/Second') | |
print('3. Convert Feet/Minute') | |
print('4. Convert Kilometers/Hour') | |
print('5. Convert Miles/Hour') | |
print('x. Exit') | |
choice = selection() | |
if choice == '1': | |
meters_sec = prompt('Meters/Second [%s]', 10) | |
display_velocity('', meters_sec) | |
if choice == '2': | |
feet_sec = prompt('Feet/Second [%s]', 88) | |
display_velocity('', feet_sec_to_meters_sec(feet_sec)) | |
if choice == '3': | |
feet_min = prompt('Feet/Minute [%s]', 4000) | |
display_velocity('', feet_min_to_meters_sec(feet_min)) | |
if choice == '4': | |
km_hour = prompt('Kilometers/Hour [%s]', 100) | |
display_velocity('', km_hour_to_meters_sec(km_hour)) | |
if choice == '5': | |
mph = prompt('Miles/Hour [%s]', 60) | |
display_velocity('', miles_hour_to_meters_sec(mph)) | |
def angular_velocity_menu(): | |
choice = '' | |
while choice.strip() != 'x': | |
print('\nAngular Velocity Menu') | |
print('1. Convert Revolutions/Minute (RPM)') | |
print('2. Convert Revolutions/Second (RPS or Hz)') | |
print('x. Exit') | |
choice = selection() | |
if choice == '1': | |
rpm = prompt('Revolutions/Minute (RPM) [%s]', 10000) | |
display_angular_velocity('', rpm) | |
if choice == '2': | |
rps = prompt('Revolutions/Minute (RPS or Hz) [%s]', 50.0/3.0) | |
display_angular_velocity('', rps_to_rpm(rps)) | |
def volume_menu_print(): | |
print('1. Convert Cubic Centimeters') | |
print('2. Convert Cubic Inches') | |
print('3. Convert Cubic Feet') | |
print('4. Convert Liters') | |
def volume_menu(): | |
choice = '' | |
cc = 1 | |
while choice.strip() != 'x': | |
print('\nVolume Menu') | |
volume_menu_print() | |
print('x. Exit') | |
choice = selection() | |
if choice == '1': | |
cc = prompt('Cubic Centimeters, CCs, [%s]', 250) | |
display_volume('', cc) | |
if choice == '2': | |
ci = prompt('Cubic Inches, CI, [%s]', 302) | |
cc = ci_to_cc(ci) | |
display_volume('', cc) | |
if choice == '3': | |
cf = prompt('Cubic Feet, CF, [%s]', 1) | |
cc = cf_to_cc(cf) | |
display_volume('', cc) | |
if choice == '4': | |
liters = prompt('Liters [%s]', 1) | |
cc = liters_to_cc(liters) | |
display_volume('', cc) | |
return cc | |
def mass_menu_print(): | |
print('1. Convert Pounds') | |
print('2. Convert Kilograms') | |
def mass_menu(): | |
choice = '' | |
kg = 1 | |
while choice.strip() != 'x': | |
print('\nMass Menu') | |
mass_menu_print() | |
print('x. Exit') | |
choice = selection() | |
if choice == '1': | |
m = prompt('Pounds, [%s]', 100) | |
kg = lbs_to_kg(m) | |
display_mass('', kg) | |
if choice == '2': | |
kg = prompt('Kilograms, [%s]', 100) | |
display_mass('', kg) | |
return kg | |
def liquid_capacity_menu(): | |
choice = '' | |
while choice.strip() != 'x': | |
print('\nVolume Menu') | |
volume_menu_print() | |
print('5. Convert Gallons') | |
print('6. Convert Quarts') | |
print('7. Convert Pints') | |
print('8. Convert Fluid Ounces') | |
print('x. Exit') | |
choice = selection() | |
if choice == '1': | |
cc = prompt('Cubic Centimeters, CCs, [%s]', 250) | |
display_liquid_capacity('', cc) | |
if choice == '2': | |
ci = prompt('Cubic Inches, CI, [%s]', 302) | |
display_liquid_capacity('', ci_to_cc(ci)) | |
if choice == '3': | |
cf = prompt('Cubic Feet, CF, [%s]', 1) | |
display_liquid_capacity('', cf_to_cc(cf)) | |
if choice == '4': | |
liters = prompt('Liters [%s]', 1) | |
display_liquid_capacity('', liters_to_cc(liters)) | |
if choice == '5': | |
gallons = prompt('Gallons [%s]', 1) | |
display_liquid_capacity('', us_liquid_gallons_to_cc(gallons)) | |
if choice == '6': | |
quarts = prompt('Quarts [%s]', 4) | |
display_liquid_capacity('', quarts_to_cc(quarts)) | |
if choice == '7': | |
pints = prompt('Pints [%s]', 8) | |
display_liquid_capacity('', pints_to_cc(pints)) | |
if choice == '8': | |
fluid_ounces = prompt('Fluid Ounces [%s]', 128) | |
display_liquid_capacity('', fluid_ounces_to_cc(fluid_ounces)) | |
def temperature_menu(): | |
choice = '' | |
while choice.strip() != 'x': | |
print('\nTemperature Menu') | |
print('1. Convert Celsius') | |
print('2. Convert Fahrenheit') | |
print('3. Convert Kelvin') | |
print('4. Convert Rankine') | |
print('x. Exit') | |
choice = selection() | |
if choice == '1': | |
temp = prompt('Celsius Temperature [%s]', 100.0) | |
display_temperature('', temp) | |
if choice == '2': | |
temp = prompt('Fahrenheit Temperature [%s]', 100.0) | |
display_temperature('', fahrenheit_to_celsius(temp)) | |
if choice == '3': | |
temp = prompt('Kevin Temperature [%s]', 273.15) | |
display_temperature('', kelvin_to_celsius(temp)) | |
if choice == '4': | |
temp = prompt('Rankine Temperature [%s]', 459.67) | |
display_temperature('', rankine_to_celsius(temp)) | |
def pressure_menu(): | |
choice = '' | |
while choice.strip() != 'x': | |
print('\nPressure Menu') | |
print('1. Convert Bar') | |
print('2. Convert PSI') | |
print('3. Convert kPa') | |
print('x. Exit') | |
choice = selection() | |
print('') | |
if choice == '1': | |
bar = prompt('Bar [%s]', 20.0) | |
display_pressure('', bar_to_kPa(bar)) | |
if choice == '2': | |
psi = prompt('PSI [%s]', 100.0) | |
display_pressure('', psi_to_kPa(psi)) | |
if choice == '3': | |
kPa = prompt('KiloPascals [%s]', 1.0) | |
display_pressure('', kPa) | |
def mean_piston_speed_menu(): | |
choice = '' | |
while choice.strip() != 'x': | |
print('\nMean Piston Speed Menu') | |
print('1. Calculate Mean Piston Speed from RPM') | |
print('2. Calculate RPM from Mean Piston Speed') | |
print('x. Exit') | |
choice = selection() | |
print('') | |
if choice == '1': | |
prompt_mean_piston_speed_from_rpm() | |
if choice == '2': | |
prompt_rpm_from_mean_piston_speed() | |
def energy_menu(): | |
choice = '' | |
while choice.strip() != 'x': | |
print('\nEnergy (Torque) Menu') | |
print('1. Convert Ft-Lbs of Force') | |
print('x. Exit') | |
choice = selection() | |
print('') | |
if choice == '1': | |
prompt_ft_lbs_force() | |
def specific_energy_menu(): | |
choice = '' | |
while choice.strip() != 'x': | |
print('\nSpecific Energy Menu') | |
print('1. Convert BTUs/lb') | |
print('2. Convert MJ/kg') | |
print('x. Exit') | |
choice = selection() | |
print('') | |
if choice == '1': | |
prompt_btus_per_lb_specific_energy() | |
if choice == '2': | |
prompt_MJ_per_kg_specific_energy() | |
def port_mapping_menu(): | |
choice = '' | |
while choice.strip() != 'x': | |
print('\nPort Mapping Menu') | |
print('1. Port Segment Measurement') | |
print('x. Exit') | |
choice = selection() | |
print('') | |
if choice == '1': | |
prompt_port_segment() | |
def prompt_cr_w_cyl_wall_ports(): | |
print('CR = (Swept_Volume + Clearance_Volume) / Clearance_Volume') | |
print(' or ') | |
print('CR = Maximum Cylinder Volume / Minimum Cylinder Volume') | |
print('With Cylinder Wall Ports, there are two Compression Ratios') | |
print('to consider. The static compression ratio which is from the') | |
print('point where the exhaust port fully closes to top dead center.') | |
print('The full compression ratio from the bottom of the exhaust') | |
print('port opening to top dead center. This assumes that at maximum') | |
print('efficiency, the exhaust pipe reflection will be able to fully') | |
print('plug the exhaust port on the compression stroke.') | |
clear_vol = ask_clearance_volume() | |
display_volume('Clearance Volume', clear_vol) | |
bore = ask_bore() | |
stroke = ask_stroke() | |
display_ratio('\nRatio of Bore to Stroke', bore / too_small_guard(stroke)) | |
crl = ask_connecting_rod_length() | |
epo = ask_exhaust_port_open() | |
epc = ask_exhaust_port_close() | |
d = calc_piston_position_from_angle(crl, stroke, math.radians(epo)) | |
print('\nStroke Length for Static Compression : ', d) | |
cc = calc_displacement(bore, d, 1) | |
print('\nStatic Compression Ratio : ',(cc + clear_vol)/too_small_guard(clear_vol)) | |
d = calc_piston_position_from_angle(crl, stroke, math.radians(epc)) | |
cc = calc_displacement(bore, d, 1) | |
print('Full Compression Ratio : ',(cc + clear_vol)/too_small_guard(clear_vol)) | |
def prompt_cr_wo_cyl_wall_ports(): | |
print('CR = (Swept_Volume + Clearance_Volume) / Clearance_Volume') | |
print(' or ') | |
print('CR = Maximum Cylinder Volume / Minimum Cylinder Volume') | |
clear_vol = ask_clearance_volume() | |
display_volume('Clearance Volume', clear_vol) | |
disp = ask_displacement() | |
print('Compression Ratio : ', (disp + clear_vol) / too_small_guard(clear_vol)) | |
def prompt_compression_ratio(): | |
choice = '' | |
while choice.strip() != 'x': | |
print('\nCompression Ratio Menu') | |
print('1. With Cylinder Wall Ports') | |
print('2. Without Cylinder Wall Ports') | |
print('x. Exit') | |
choice = selection() | |
print('') | |
if choice == '1': | |
prompt_cr_w_cyl_wall_ports() | |
if choice == '2': | |
prompt_cr_wo_cyl_wall_ports() | |
choice = '' | |
while choice.strip() != 'x': | |
dispatch = { | |
'1' : ask_displacement, | |
'2' : prompt_air_cycle, | |
'3' : prompt_nc50_mph, | |
'4' : prompt_nc50_rpm, | |
'5' : prompt_tuned_rpm, | |
'6' : prompt_tuned_length, | |
'7' : mean_piston_speed_menu, | |
'8' : prompt_carb_size, | |
'9' : prompt_carb_mass_flow, | |
'10' : prompt_squish_ratio, | |
'11' : prompt_connecting_rod, | |
'12' : prompt_piston_pos_from_crank_angle, | |
'13' : prompt_piston_angle, | |
'14' : prompt_compression_ratio, | |
'15' : oil_ratio_menu, | |
'16' : port_mapping_menu, | |
'17' : prompt_scooter_mph_from_hp, | |
'a' : angular_velocity_menu, | |
'b' : bmep_menu, | |
'd' : measurement_menu, | |
'e' : energy_menu, | |
'h' : horsepower_menu, | |
'i' : ideal_gas_menu, | |
'l' : liquid_capacity_menu, | |
'm' : mass_menu, | |
'p' : pressure_menu, | |
's' : specific_energy_menu, | |
't' : temperature_menu, | |
'v' : velocity_menu, | |
'w' : volume_menu | |
} | |
print('\nMenu') | |
print(' 1. Calculate Displacement') | |
print(' 2. Air Cycle') | |
print(' 3. NC50 MPH from RPM') | |
print(' 4. NC50 RPM from MPH') | |
print(' 5. Find Tuned RPM of Exhaust') | |
print(' 6. Find Tuned Length of Exhaust') | |
print(' 7. Mean Piston Speed') | |
print(' 8. Carb Sizing') | |
print(' 9. Carb Mass Flow') | |
print('10. Cylinder Head Squish Ratio') | |
print('11. Find Connecting Rod Length') | |
print('12. Find Piston Position from Angle') | |
print('13. Find Crank Angle from Piston Position') | |
print('14. Find Compression Ratio') | |
print('15. Oil Ratio Mixture') | |
print('16. Port Mapping') | |
print('17. Calculate Scooter MPH from HP') | |
print(' a. Convert Angular Velocity') | |
print(' b. Convert BMEP') | |
print(' d. Convert Distance') | |
print(' e. Convert Energy (Torque)') | |
print(' h. Convert Horsepower') | |
print(' i. Ideal Gas') | |
print(' l. Convert Liquid Capacity') | |
print(' m. Convert Mass') | |
print(' p. Convert Pressure') | |
print(' s. Convert Specific Energy') | |
print(' t. Convert Temperature') | |
print(' v. Convert Velocity') | |
print(' w. Convert Volume') | |
print(' x. Exit') | |
choice = selection() | |
if choice in dispatch: | |
dispatch[choice]() | |
print('Done.') | |
# #!perl | |
# use strict; | |
# use Math::Complex; | |
# use Math::Trig; | |
# # | |
# # Supporting subroutines. | |
# # | |
# | |
# # degrees to radians | |
# sub dtor { | |
# my($deg) = @_; | |
# return $deg * pi / 180.0; | |
# } | |
# | |
# # radians to degrees | |
# sub rtod { | |
# my($rad) = @_; | |
# return $rad * 180.0 / pi; | |
# } | |
# | |
# # piston position | |
# sub pistPos { | |
# my($strokeMeters, $crankMeters, $connRodLenMeters, $rad, | |
# $heightTop, $heightBottom) = @_; | |
# | |
# $$heightTop = $crankMeters + $connRodLenMeters - $crankMeters * | |
# cos($rad) - sqrt($connRodLenMeters * $connRodLenMeters - | |
# ($connRodLenMeters * sin($rad)) * ($connRodLenMeters * sin($rad))); | |
# $$heightBottom = $strokeMeters - $$heightTop; | |
# } | |
# | |
# sub crankFact { | |
# # From Page 515 of Blair | |
# # YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY | |
# my($thisCrank) = @_; | |
# # CRT = 50 | |
# my($crt) = 50; | |
# # XCL = 330 | |
# my($xcl) = 330; | |
# # XCAL = CRT / CRNK | |
# my($scal) = $crt / $thisCrank; | |
# # BOR = BO * SCAL / 2; | |
# | |
# # XCL = 330 | |
# my($xcl) = 330; | |
# | |
# # ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ | |
# # Working Backwords from the end | |
# # of the Subroutine..... | |
# # ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ | |
# | |
# | |
# # REM VALUES FOR THE SQ VEL PLOT | |
# # XPLOT = XL3 + 5 | |
# my($xSquishPlotMin) = $xL3 + 5; | |
# # XSMAX = XPLOT + 150 | |
# # I think here he is just giving some valid range to plot | |
# my($xSquishPlotMax) = $xSquishPlotMin + 150; | |
# # XSQ1 = XPLOT | |
# my($xSquish1) = $xSquishPlotMin; | |
# # X(1) = XPLOT | |
# my($xMinPlot) = $xSquishPlotMin; | |
# # YSQ1 = YET | |
# my($ySquish1) = $yet; | |
# # Y(1) = YET | |
# my($yMinPlot) = $yet; | |
# # J=1 | |
# my($j) = 1; | |
# # XV10 = XPLOT + 10 * (XSMAX-XPLOT)/25 | |
# my($xVelocity10Pos) = $xSquishPlotMin+10*($xSquishPlotMax - $xSquishPlotMin)/25; | |
# # XV20 = XPLOT + 20 * (XSMAX-XPLOT)/25 | |
# my($xVelocity20Pos) = $xSquishPlotMin+20*($xSquishPlotMax - $xSquishPlotMin)/25; | |
# } | |
# | |
# sub getInput { | |
# my($bore, $stroke, $connRodLen, $rpm, $exhaustOpen, $trappedCompressionRatio, | |
# $squishClearance, $squishAreaRatio) = @_; | |
# print "Enter Bore Size in mm (TRX = 66) : "; | |
# $$bore = <>; | |
# | |
# if (($$bore eq "") || ($$bore == 0)) { | |
# $$bore = 66; | |
# } | |
# | |
# print "Enter Stroke Length in mm (TRX = 72) : "; | |
# $$stroke = <>; | |
# | |
# if (($$stroke eq "") || ($$stroke == 0)) { | |
# $$stroke = 72; | |
# } | |
# | |
# print "Enter Connecting Rod Length in mm (TRX = 125.3) : "; | |
# $$connRodLen = <>; | |
# | |
# if (($$connRodLen eq "") || ($$connRodLen == 0)) { | |
# $$connRodLen = 125.3; | |
# } | |
# | |
# print "Enter Engine RPM (TRX = 9500) : "; | |
# $$rpm = <>; | |
# | |
# if (($$rpm eq "") || ($$rpm == 0)) { | |
# $$rpm = 9500; | |
# } | |
# | |
# print "Exhaust Port Opens in Degrees ATDC (TRX = 88.5) : "; | |
# $$exhaustOpen = <>; | |
# | |
# if (($$exhaustOpen eq "") || ($$exhaustOpen == 0)) { | |
# $$exhaustOpen = 88.5; | |
# } | |
# | |
# print "Enter Trapped Compression Ratio (TRX = 8.63) : "; | |
# $$trappedCompressionRatio = <>; | |
# | |
# if (($$trappedCompressionRatio eq "") || ($$trappedCompressionRatio == 0)) { | |
# $$trappedCompressionRatio = 8.63; | |
# } | |
# | |
# print "Enter Squish Area Ratio (TRX = 30) : "; | |
# $$squishAreaRatio = <>; | |
# | |
# if (($$squishAreaRatio eq "") || ($$squishAreaRatio == 0)) { | |
# $$squishAreaRatio = 30; | |
# } | |
# | |
# print "Enter Squish Clearance in mm (TRX = 1) : "; | |
# $$squishClearance = <>; | |
# | |
# if (($$squishClearance eq "") || ($$squishClearance == 0)) { | |
# $$squishClearance = 1; | |
# } | |
# | |
# # print "Exhaust Closes in Degrees BTDC : "; | |
# # $exhaustClose = <>; | |
# # print "Piston to Head Clearance in mm : "; | |
# # $squish = <>; | |
# # print "Piston Crown Radius in mm : "; | |
# # $pistonCrownRadius = <>; | |
# # print "Squish Band Radius in mm : "; | |
# # $squishBandRadius = <>; | |
# # print "Bowl Chamber Radius in mm : "; | |
# # $radiusChamber = <>; | |
# # print "Squish Blending Radius in mm : "; | |
# # $radiusSquish = <>; | |
# # print "Squish Area Ratio : "; | |
# # $$squishAreaRatio = <>; | |
# } | |
# | |
# sub mainCalc { | |
# my($bore, $stroke, $connRodLen, $rpm, $exhaustOpen, | |
# $squishClearance, $trappedCompressionRatio, | |
# $squishAreaRatio) = @_; | |
# my($heightTop) = 0; # height to the top of the stroke | |
# my($heightBottom) = 0; # height to the bottom of the stroke | |
# my($pMax) = 1; | |
# my($sqVMax) = 0; | |
# my($sweptVolume) = 0; | |
# my($strokeVolume) = 0; | |
# my($crank) = 0; | |
# my($crankMeters) = 0; | |
# my($squishClearMeters) = 0; | |
# my($exhaustPortRadians) = 0; | |
# my($heightExhaustOpenTop) = 0; | |
# my($heightExOpenTopMeters) = 0; | |
# my($heightExhaustOpenBot) = 0; | |
# my($heightExOpenBotMeters) = 0; | |
# my($angleDown) = 0; | |
# my($trappedSweptVolume) = 0; | |
# my($clearanceVolume) = 0; | |
# my($areaSquishArea) = 0; | |
# my($bowlArea) = 0; | |
# my($volumeSquishBand) = 0; | |
# my($volumeBowlSquished) = 0; | |
# my($volumeBowl) = 0; | |
# my($depthBowl) = 0; | |
# my($diameterBowl) = 0; | |
# my($volumeSquish1) = 0; | |
# my($volumeBowl1) = 0; | |
# my($volumeCylAtExOpen) = 0; | |
# my($volumeTrapped) = 0; | |
# my($GASR) = 0; | |
# my($pressureTrapped) = 0; | |
# my($tempatureTrapped) = 0; | |
# my($pressureCylinderPoint1) = 0; | |
# my($tempatureCylinderPoint1) = 0; | |
# my($GAMMA) = 0; | |
# my($massOfTrapped) = 0; | |
# my($pressureSquish1) = 0; | |
# my($pressureBowl1) = 0; | |
# my($tempatureSquish1) = 0; | |
# my($tempatureBowl1) = 0; | |
# my($ratioHeatOfSquish1) = 0; | |
# my($ratioHeatOfBowl1) = 0; | |
# my($massSquish1) = 0; | |
# my($massBowl1) = 0; | |
# my($degreeChange) = 0; | |
# my($deltaTime) = 0; | |
# | |
# my($boreMeters) = $bore / 1000.0; | |
# my($strokeMeters) = $stroke / 1000.0; | |
# my($connRodLenMeters) = $connRodLen / 1000.0; | |
# | |
# # PA = PI * BOM * BOM / 4 | |
# print "Bore Meters - $boreMeters\n"; | |
# my($pistonArea) = pi * $boreMeters * $boreMeters / 4.0; | |
# # print "Squish Area Ratio : "; | |
# print "Piston Area in meters squared : $pistonArea \n"; | |
# | |
# # SV = PA * STM | |
# $strokeVolume = $pistonArea * $strokeMeters; | |
# print "Stroke Volume in meters cubed : $strokeVolume \n"; | |
# | |
# # CRNK = ST / 2 | |
# $crank = $stroke / 2; | |
# print "Crank Distance in mm : $crank \n"; | |
# | |
# # CRNKM = CRL / 1000 | |
# $crankMeters = $crank / 1000.0; | |
# print "Crank Distance in Meters : $crankMeters \n"; | |
# | |
# # SQM = SQ / 1000 | |
# $squishClearMeters = $squishClearance / 1000.0; | |
# print "Squish Clearance in Meters : $squishClearMeters \n"; | |
# | |
# # SV = PA * STM | |
# $sweptVolume = $pistonArea * $strokeMeters; | |
# print "Swept Volume (in meters cubed) : $sweptVolume \n"; | |
# $exhaustPortRadians = &dtor(360 - $exhaustOpen); | |
# print "Exhaust Port Radians : $exhaustPortRadians \n"; | |
# &pistPos($strokeMeters, $crankMeters, $connRodLenMeters, | |
# $exhaustPortRadians, | |
# \$heightTop, \$heightBottom); | |
# | |
# $heightExOpenTopMeters = $heightTop; | |
# $heightExhaustOpenTop = $heightTop * 1000; | |
# print "Piston Height Exhaust Open Top : $heightExhaustOpenTop\n"; | |
# | |
# $heightExOpenBotMeters = $heightBottom; | |
# $heightExhaustOpenBot = $heightBottom * 1000; | |
# print "Piston Height Exhaust Open Bottom : $heightExhaustOpenBot\n"; | |
# | |
# $angleDown = 360 - $exhaustOpen; | |
# $trappedSweptVolume = $pistonArea * $heightExOpenTopMeters; | |
# print "Trapped Swept Volume : $trappedSweptVolume\n"; | |
# # | |
# # We know the volume trapped in the head, the clearance volume, | |
# # is the sum of the volume of the bown + the volume of the | |
# # squish area. See figure 4.2 | |
# # | |
# # We also know (Trapped Swept Volume + the Clearance Volume) | |
# # divided by the Clearance Volume gives us the trapped | |
# # compression ratio. In this case we use the trapped | |
# # compression ratio as an input, so we calculate the resulting | |
# # clearance volume | |
# # | |
# # TCR = (TSV+CV)/CV -- Solve for CV | |
# # | |
# # TCR * CV = TSV + CV | |
# # | |
# # TCR * CV - CV = TSV | |
# # | |
# # CV = TSV / (TCR - 1) | |
# # | |
# $clearanceVolume = $trappedSweptVolume / ($trappedCompressionRatio - 1); | |
# print "Clearance Volume : $clearanceVolume\n"; | |
# | |
# # ASQ = PA * SAR | |
# $areaSquishArea = $squishAreaRatio * $pistonArea; | |
# print "Area of the Squish Area : $areaSquishArea\n"; | |
# | |
# $bowlArea = $pistonArea - $areaSquishArea; | |
# print "Bowl Area : $bowlArea\n"; | |
# | |
# # Note this assumes a flat area | |
# $volumeSquishBand = $squishClearMeters * $areaSquishArea; | |
# print "Volumes of the Squish Band : $volumeSquishBand\n"; | |
# | |
# $volumeBowlSquished = $squishClearMeters * $bowlArea; | |
# print "Volume of Squish Under Bowl : $volumeBowlSquished\n"; | |
# | |
# # Again if we assume that the squish area is flat, we can compute | |
# # the area of the bowl by whats left over. | |
# $volumeBowl = $clearanceVolume - $volumeBowlSquished - $volumeSquishBand; | |
# print "Volume of the Bowl : $volumeBowl\n"; | |
# | |
# # | |
# # area of circle = pi * diameter * diameter / 4 | |
# # | |
# $diameterBowl = sqrt(4 * $bowlArea / pi); | |
# print "Diameter of the Bowl : $diameterBowl\n"; | |
# | |
# # volume of area to be squished when the exhaust closes | |
# # VS1 = HEOT1 * ASQ + VSQBAND | |
# $volumeSquish1 = $heightExOpenTopMeters * $areaSquishArea + $volumeSquishBand; | |
# print "Volume Squish at Exhaust Close : $volumeSquish1\n"; | |
# | |
# # volume of area of the bowl when the exhaust closes | |
# # VB1 = HEOT1*ABL+VBS+VBOWL | |
# $volumeBowl1 = $heightExOpenTopMeters * $bowlArea + $volumeBowlSquished + $volumeBowl; | |
# print "Volume Bowl at Exhaust Close : $volumeBowl1\n"; | |
# | |
# # VCYL1 = HEOT1*PA+CVOL | |
# $volumeCylAtExOpen = $heightExOpenTopMeters * $pistonArea + $clearanceVolume; | |
# print "Volume of Cylinder @ Exhaust Close : $volumeCylAtExOpen\n"; | |
# | |
# # VTRAP = VCYL1 | |
# $volumeTrapped = $volumeCylAtExOpen; | |
# print "Trapped Volume of the Cylinder : $volumeTrapped\n"; | |
# | |
# # Constant | |
# $GASR = 287; | |
# | |
# # PTRAP = 101325 | |
# # Pressure at the Trap Point | |
# $pressureTrapped = 101325; | |
# | |
# # Page 513 | |
# # TTRAP = 293 | |
# # Tempature at the Trap Point | |
# $tempatureTrapped = 293; | |
# | |
# # PCYL1 = PTRAP | |
# $pressureCylinderPoint1 = $pressureTrapped; | |
# print "Pressure of Cylinder at Point 1 : $pressureCylinderPoint1\n"; | |
# | |
# # TCYL1 = TTRAP | |
# $tempatureCylinderPoint1 = $tempatureTrapped; | |
# print "Tempature of Cylinderat Point 1 : $tempatureCylinderPoint1\n"; | |
# | |
# # GAMMA = 1.4 | |
# $GAMMA = 1.4; | |
# | |
# # MTRAP = PTRAP * VTRAP/(GASR * TTRAP) | |
# # Mass is conserved | |
# $massOfTrapped = $pressureTrapped * $volumeTrapped / | |
# ($GASR * $tempatureTrapped); | |
# print "Mass of Gas Trapped in Cylinder : $massOfTrapped\n"; | |
# | |
# # Everything must start in balance and end in balance | |
# # PS1 = PCYL1 | |
# $pressureSquish1 = $pressureCylinderPoint1; | |
# print "Pressure of Squish at Point 1 : $pressureSquish1\n"; | |
# | |
# # PB1 = PCYL1 | |
# $pressureBowl1 = $pressureCylinderPoint1; | |
# print "Pressure of Bowl at Point 1 : $pressureBowl1\n"; | |
# | |
# # TS1 = TCYL1 | |
# $tempatureSquish1 = $tempatureCylinderPoint1; | |
# print "Tempature of Squish at Point 1 : $tempatureSquish1\n"; | |
# | |
# # TB1 = TCLY1 | |
# $tempatureBowl1 = $tempatureCylinderPoint1; | |
# print "Tempature of Bowl at Point 1 : $tempatureBowl1\n"; | |
# | |
# # RHOS1 = PS1/(GASR*TS1) | |
# $ratioHeatOfSquish1 = $pressureSquish1 / ($GASR * $tempatureSquish1); | |
# print "Ratio of Heat of Squish Point 1 : $ratioHeatOfSquish1\n"; | |
# | |
# # RHOB1 = PB1/(GASR*TB1) | |
# $ratioHeatOfBowl1 = $pressureBowl1 / ($GASR * $tempatureBowl1); | |
# print "Ratio of Heat of Bowl Point 1 : $ratioHeatOfBowl1\n"; | |
# | |
# # MS1 = MTRAP*VS1/VCYL1 | |
# $massSquish1 = $massOfTrapped * $volumeSquish1 / $volumeCylAtExOpen; | |
# print "Mass of Gas at Squish Point 1 : $massSquish1\n"; | |
# | |
# # MB1 = MTRAP - MS1 | |
# $massBowl1 = $massOfTrapped - $massSquish1; | |
# print "Mass of Gas at Bowl Point 1 : $massBowl1\n"; | |
# | |
# # DC = 1 | |
# $degreeChange = 1; | |
# print "Degree Change : $degreeChange\n"; | |
# | |
# # DT=DC/(6*RPM) | |
# # The equation is partially reduced. | |
# # DC Rev min 60 sec | |
# # ---- * ------- * ----- * ------ | |
# # 360 Deg Rev min | |
# $deltaTime = $degreeChange / (6 * $rpm); | |
# print "Delta Time : $deltaTime\n"; | |
# # GOSUB CRANKFACT | |
# &crankFact($crank); | |
# | |
# | |
# # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | |
# | |
# } | |
# | |
# | |
# # | |
# # MAINLINE | |
# # | |
# print "Ed's Cheap 2 Stroke Hemi-Spherical Squish Design\n"; | |
# print << "WHYDOIT"; | |
# | |
# Why create another program to do the the 2 stroke squish calculations? | |
# | |
# A couple of reasons. First I want to solve for specific parameters that | |
# are inputs to Dr. Blairs program. The other reason is that I want to build | |
# this program is that I am interested in playing with the algorithms for | |
# computing the maximum squish velocity. | |
# | |
# WHYDOIT | |
# | |
# my($i) = 0; | |
# my($bore) = 0; | |
# my($stroke) = 0; | |
# my($connRodLen) = 0; | |
# my($rpm) = 0; | |
# my($exhaustOpen) = 0; | |
# my($trappedCompressionRatio) = 0; | |
# my($squishClearance) = 0; | |
# my($squishAreaRatio) = 0; | |
# | |
# &getInput(\$bore, \$stroke, \$connRodLen, \$rpm, \$exhaustOpen, | |
# \$trappedCompressionRatio, \$squishClearance, | |
# \$squishAreaRatio); | |
# | |
# for ($i = 0; $i < 360; $i++) { | |
# } | |
# | |
# &mainCalc($bore, $stroke, $connRodLen, $rpm, $exhaustOpen, | |
# $squishClearance, $trappedCompressionRatio, | |
# $squishAreaRatio); | |
# 1; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment