engine-sim/engine.py
2025-06-13 15:34:38 -04:00

128 lines
3.6 KiB
Python

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.wheel_speed = 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.fuel_capacity = 0
# 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.1 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
# 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._update_temps(dt)