import math class Engine: def __init__(self, idle_rpm=750, max_rpm=7000, redline_rpm=6500, flywheel_inertia=0.025, fuel_efficiency=0.3, torque_curve=None): # General stuff self.rpm = idle_rpm self.throttle = 0.0 self.load = 0.0 self.gear = None self.ignition = True self.revCut = False self.idle_rpm = idle_rpm self.max_rpm = max_rpm self.redline_rpm = redline_rpm self.flywheel_inertia = flywheel_inertia self.fuel_efficiency = fuel_efficiency self.torque_curve = torque_curve or self.default_torque_curve self.instant_torque = 0 self.engineFriction = 5 self.peak_torque = 163 # Nm -> 120 ft/lb self.engine_brake_strength = 40 # Nm self.engine_brake_torque = 0 self.starting = False # Fluids self.oil_temp = 0 self.oil_pressure = 0 self.oil_capacity = 0 self.coolant_temp = 0 self.coolant_pressure = 0 self.coolant_capacity = 0 self.max_fuel_capacity = 68 # Liter self.fuel_capacity = self.max_fuel_capacity # Fuel self.fuel_rate = 0 self.afr = 0 # Timing stuff self.kr = 0 self.timing_advance = 0 self.ignition_timing = 0 # Exhaust stuff self.exhaust_temp = 0 self.turbo_boost = 0 # Environment self.ambient_temp = 0 self.altitude = 0 self.intake_pressure = 0 self.vehicle_mass = 0 self.drivetrain_loss = 0 # Just a parabolic curve for now def default_torque_curve(self, rpm): rpm_ratio = rpm / self.max_rpm return max(0.0, -4 * (rpm_ratio - 0.5) ** 2 + 1) def start(self, dt): self.ignition = True self.starting = True def update(self, throttle, load, dt): self.throttle = throttle self.load = load if self.starting: available_torque = self.torque_curve(self.rpm) self.instant_torque = (available_torque * self.peak_torque) + 10 rpm_change = (self.instant_torque / self.flywheel_inertia) self.rpm += rpm_change * dt if self.rpm > 2000: self.starting = False throttle = 0 # Idle -- Eventually should have learning alg to find the % throttle needed if (self.rpm < self.idle_rpm): self.throttle = 0.1 # Rev limit if (self.rpm > self.redline_rpm): self.revCut = True if self.revCut and self.rpm > self.redline_rpm - 100: self.throttle = 0 else: self.revCut = False # Engine friction if (self.rpm > 0): friction_force = self.engineFriction else: friction_force = 0 # Engine braking torque (If throttle closed) if self.throttle == 0 and self.rpm > self.idle_rpm + 200 or not self.ignition: engine_brake_torque = self.engine_brake_strength * (self.rpm / self.max_rpm) else: engine_brake_torque = 0 # Transmission Load # Calculate torque if self.ignition: available_torque = self.torque_curve(self.rpm) else: available_torque = 0 self.instant_torque = (self.throttle * available_torque * self.peak_torque) - engine_brake_torque - friction_force rpm_change = (self.instant_torque / self.flywheel_inertia) self.rpm += rpm_change * dt self.fuel_rate = self.rpm * throttle * self.fuel_efficiency # self.fuel_capacity -= self.fuel_rate #self._update_temps(dt)