113 lines
3.8 KiB
C#
113 lines
3.8 KiB
C#
using System;
|
|
|
|
namespace FluidSim.Components
|
|
{
|
|
public class Crankshaft
|
|
{
|
|
public float AngularVelocity; // rad/s
|
|
public float CrankAngle; // rad, 0 … 4π
|
|
public float PreviousAngle;
|
|
|
|
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))
|
|
AngularVelocity = 0f;
|
|
if (float.IsNaN(externalTorque) || float.IsInfinity(externalTorque))
|
|
externalTorque = 0f;
|
|
|
|
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;
|
|
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;
|
|
|
|
CrankAngle += AngularVelocity * dt;
|
|
if (CrankAngle >= 4f * MathF.PI)
|
|
CrankAngle -= 4f * MathF.PI;
|
|
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;
|
|
}
|
|
}
|
|
} |