250cc mx engine, and dyno
This commit is contained in:
@@ -8,21 +8,46 @@ namespace FluidSim.Components
|
||||
public float CrankAngle; // rad, 0 … 4π
|
||||
public float PreviousAngle;
|
||||
|
||||
public float Inertia = 0.2f;
|
||||
public float Inertia = 0.2f; // kg·m²
|
||||
public float FrictionConstant; // N·m
|
||||
public float FrictionViscous; // N·m per rad/s
|
||||
|
||||
public float LastNetTorque { get; private set; }
|
||||
public float AveragePower { get; private set; } // smoothed, watts
|
||||
public float AverageTorque { get; private set; } // smoothed, Nm
|
||||
|
||||
private float externalTorque;
|
||||
private float _loadTorque; // external brake torque (Nm)
|
||||
|
||||
// Power averaging buffer
|
||||
private readonly float[] _powerBuffer;
|
||||
private int _powerBufIdx;
|
||||
private int _powerBufCount;
|
||||
private float _powerBufSum;
|
||||
|
||||
// Torque averaging buffer (same size as power buffer)
|
||||
private readonly float[] _torqueBuffer;
|
||||
private int _torqueBufIdx;
|
||||
private int _torqueBufCount;
|
||||
private float _torqueBufSum;
|
||||
|
||||
public Crankshaft(float initialRPM = 400f)
|
||||
{
|
||||
AngularVelocity = initialRPM * 2f * MathF.PI / 60f;
|
||||
CrankAngle = 0f;
|
||||
PreviousAngle = 0f;
|
||||
|
||||
_powerBuffer = new float[16384];
|
||||
_torqueBuffer = new float[16384];
|
||||
}
|
||||
|
||||
public void AddTorque(float torque) => externalTorque += torque;
|
||||
|
||||
public void SetLoadTorque(float torque)
|
||||
{
|
||||
_loadTorque = Math.Max(torque, 0f);
|
||||
}
|
||||
|
||||
public void Step(float dt)
|
||||
{
|
||||
if (float.IsNaN(AngularVelocity) || float.IsInfinity(AngularVelocity))
|
||||
@@ -32,10 +57,17 @@ namespace FluidSim.Components
|
||||
|
||||
PreviousAngle = CrankAngle;
|
||||
|
||||
// Internal friction torque
|
||||
float friction = FrictionConstant * MathF.Sign(AngularVelocity)
|
||||
+ FrictionViscous * AngularVelocity;
|
||||
|
||||
// Net torque from gas pressure minus friction (used for power/torque display)
|
||||
float netTorque = externalTorque - friction;
|
||||
float alpha = netTorque / Inertia;
|
||||
LastNetTorque = netTorque;
|
||||
|
||||
// Total torque after subtracting external load (brake)
|
||||
float totalNetTorque = netTorque - _loadTorque;
|
||||
float alpha = totalNetTorque / Inertia;
|
||||
AngularVelocity += alpha * dt;
|
||||
|
||||
if (AngularVelocity < 0f) AngularVelocity = 0f;
|
||||
@@ -46,6 +78,35 @@ namespace FluidSim.Components
|
||||
else if (CrankAngle < 0f)
|
||||
CrankAngle += 4f * MathF.PI;
|
||||
|
||||
// ---- Power averaging ----
|
||||
float instantPower = netTorque * AngularVelocity;
|
||||
if (_powerBufCount == _powerBuffer.Length)
|
||||
{
|
||||
_powerBufSum -= _powerBuffer[_powerBufIdx];
|
||||
}
|
||||
else
|
||||
{
|
||||
_powerBufCount++;
|
||||
}
|
||||
_powerBuffer[_powerBufIdx] = instantPower;
|
||||
_powerBufSum += instantPower;
|
||||
_powerBufIdx = (_powerBufIdx + 1) % _powerBuffer.Length;
|
||||
AveragePower = _powerBufSum / _powerBufCount;
|
||||
|
||||
// ---- Torque averaging ----
|
||||
if (_torqueBufCount == _torqueBuffer.Length)
|
||||
{
|
||||
_torqueBufSum -= _torqueBuffer[_torqueBufIdx];
|
||||
}
|
||||
else
|
||||
{
|
||||
_torqueBufCount++;
|
||||
}
|
||||
_torqueBuffer[_torqueBufIdx] = netTorque;
|
||||
_torqueBufSum += netTorque;
|
||||
_torqueBufIdx = (_torqueBufIdx + 1) % _torqueBuffer.Length;
|
||||
AverageTorque = _torqueBufSum / _torqueBufCount;
|
||||
|
||||
externalTorque = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,13 +107,11 @@ namespace FluidSim.Components
|
||||
|
||||
if (closes < opens)
|
||||
{
|
||||
// Wrap‑around case (e.g., exhaust: opens near 480°, closes near 30°)
|
||||
effectiveClose += 720f;
|
||||
}
|
||||
duration = effectiveClose - effectiveOpen;
|
||||
if (duration <= 0f) return 0f;
|
||||
|
||||
// Map the angle into the [opens, opens+duration] window
|
||||
float mapped = deg;
|
||||
if (mapped < opens) mapped += 720f;
|
||||
if (mapped < opens || mapped > effectiveClose) return 0f;
|
||||
@@ -153,6 +151,10 @@ namespace FluidSim.Components
|
||||
|
||||
public void PreStep(float dt)
|
||||
{
|
||||
// Speed‑dependent spark advance (simple linear)
|
||||
float rpm = Crankshaft.AngularVelocity * 60f / (2f * MathF.PI);
|
||||
SparkAdvance = Math.Clamp(10f + rpm * 0.002f, 5f, 40f); // 10° at idle, ~30° at 10k rpm
|
||||
|
||||
float prevVolume = cylinderVolume;
|
||||
float crankAngleRad = Crankshaft.CrankAngle + PhaseOffset;
|
||||
cylinderVolume = ComputeVolume(crankAngleRad);
|
||||
@@ -170,7 +172,7 @@ namespace FluidSim.Components
|
||||
float prevDeg = (Crankshaft.PreviousAngle + PhaseOffset) * 180f / MathF.PI % 720f;
|
||||
float currDeg = crankAngleRad * 180f / MathF.PI % 720f;
|
||||
|
||||
// Intake closing
|
||||
// Intake closing – triggers fuel injection
|
||||
if (prevDeg >= IVO && prevDeg < IVC && currDeg >= IVC)
|
||||
{
|
||||
trappedAirMass = _airMass;
|
||||
|
||||
Reference in New Issue
Block a user