// Components/Crankshaft.cs using System; namespace FluidSim.Components { public class Crankshaft { public double AngularVelocity { get; set; } // rad/s public double CrankAngle { get; set; } // rad, 0 … 4π (four‑stroke cycle) public double PreviousAngle { get; private set; } // for TDC detection public double Inertia { get; set; } = 0.2; public double FrictionConstant { get; set; } = 2.0; // N·m public double FrictionViscous { get; set; } = 0.005; // N·m per rad/s private double externalTorque; /// Idle speed before any combustion torque is applied. public Crankshaft(double initialRPM = 400.0) { AngularVelocity = initialRPM * 2.0 * Math.PI / 60.0; CrankAngle = 0.0; PreviousAngle = 0.0; } public void AddTorque(double torque) => externalTorque += torque; public void Step(double dt) { // Save previous angle PreviousAngle = CrankAngle; // Friction double friction = FrictionConstant * Math.Sign(AngularVelocity) + FrictionViscous * AngularVelocity; double netTorque = externalTorque - friction; double alpha = netTorque / Inertia; AngularVelocity += alpha * dt; if (AngularVelocity < 0) AngularVelocity = 0; // stall CrankAngle += AngularVelocity * dt; // Wrap to [0, 4π) if (CrankAngle >= 4.0 * Math.PI) CrankAngle -= 4.0 * Math.PI; else if (CrankAngle < 0) CrankAngle += 4.0 * Math.PI; externalTorque = 0.0; } } }