Energy based changes

This commit is contained in:
max
2025-12-18 02:30:17 +01:00
parent c22452c66c
commit fa68f73055
5 changed files with 220 additions and 295 deletions

View File

@@ -9,188 +9,139 @@
private int currentGear = 1;
public float[] GearRatios { get; set; } =
{
3.8f, // 1st - Lower for better launch
3.8f, // 1st
2.5f, // 2nd
1.8f, // 3rd
1.3f, // 4th
1.0f, // 5th - Direct drive
0.8f, // 6th - Overdrive
0.65f // 7th - Double overdrive (optional)
1.0f, // 5th
0.8f, // 6th
0.65f // 7th
};
public float FinalDriveRatio { get; set; } = 5.0f;
public float FinalDriveRatio { get; set; } = 4.0f;
public float Efficiency { get; set; } = 0.95f;
public float ClutchEngagement { get; set; } = 0f; // 0 = disengaged, 1 = fully engaged
// Calculated
public float GearRatio => GetCurrentGearRatio();
public float TotalRatio => GearRatio * FinalDriveRatio;
// Clutch properties
public float ClutchStiffness { get; set; } = 500f; // Nm/(rad/s) - how strongly clutch pulls speeds together
public float MaxClutchTorque { get; set; } = 4500f; // Maximum torque clutch can transmit
public float MaxClutchTorque { get; set; } = 450f;
public float ClutchStiffness { get; set; } = 20f; // Softer spring
// State
public float SpeedDifference { get; private set; } // rad/s
public float ClutchTorque { get; private set; }
public float TransmittedPower { get; private set; }
private float previousWheelOmega = 0f;
public float ClutchSlipRatio { get; private set; }
public Drivetrain(Engine engine, WheelSystem wheelSystem)
{
Engine = engine;
WheelSystem = wheelSystem;
previousWheelOmega = wheelSystem.AngularVelocity;
}
public void GearUp()
{
if (currentGear < GearRatios.Length)
currentGear++;
}
public void GearDown()
{
if (currentGear > 1)
currentGear--;
}
private float GetCurrentGearRatio()
{
if (currentGear == 0) return 0f; // Neutral
if (currentGear == -1) return -3.5f; // Reverse (example ratio)
if (currentGear > 0 && currentGear <= GearRatios.Length)
return GearRatios[currentGear - 1];
return 0f; // Invalid gear
}
public float CalculateSpeedDifference()
{
if (TotalRatio == 0) return 0f;
float engineOmega = Engine.AngularVelocity;
float wheelOmega = WheelSystem.AngularVelocity;
float expectedWheelOmega = engineOmega / TotalRatio;
SpeedDifference = wheelOmega - expectedWheelOmega;
return SpeedDifference;
}
public float CalculateClutchTorque()
{
if (ClutchEngagement <= 0.01f)
{
ClutchTorque = 0;
return 0f;
}
CalculateSpeedDifference();
float torque = -SpeedDifference * ClutchStiffness * ClutchEngagement;
torque = Math.Clamp(torque, -MaxClutchTorque, MaxClutchTorque);
float actualThrottle = Engine.GetActualThrottle();
float availableEngineTorque = Engine.GetTorqueOutput();
float maxTorqueAtClutch = maxEngineTorque * TotalRatio * Efficiency;
torque = maxTorqueAtClutch;
ClutchTorque = torque;
return torque;
}
public void ApplyDrivetrainWork(float deltaTime)
public void Update(float deltaTime)
{
if (ClutchEngagement <= 0.01f || TotalRatio == 0)
{
ClutchTorque = 0;
TransmittedPower = 0;
ClutchSlipRatio = 1f;
return;
}
CalculateSpeedDifference();
float clutchTorque = CalculateClutchTorque();
// Calculate expected vs actual wheel speeds
float expectedWheelOmega = Engine.AngularVelocity / TotalRatio;
float actualWheelOmega = WheelSystem.AngularVelocity;
float omegaDifference = actualWheelOmega - expectedWheelOmega;
bool engineDrivingWheels = clutchTorque > 0;
bool wheelsDrivingEngine = clutchTorque < 0;
// Calculate max torque clutch can transmit
float maxClutchTorque = MaxClutchTorque * ClutchEngagement;
if (engineDrivingWheels)
// Simple spring model: torque tries to sync speeds
float desiredTorque = -omegaDifference * ClutchStiffness;
// Clamp to clutch capacity
desiredTorque = Math.Clamp(desiredTorque, -maxClutchTorque, maxClutchTorque);
// Also limit by engine capability when accelerating
if (desiredTorque > 0)
{
// Engine -> Wheels (normal driving)
ApplyEngineToWheels(clutchTorque, deltaTime);
}
else if (wheelsDrivingEngine)
{
// Wheels -> Engine (engine braking)
ApplyWheelsToEngine(clutchTorque, deltaTime);
float engineTorque = Engine.GetTorqueOutput() * Engine.GetActualThrottle();
float maxEngineTorqueAtWheels = engineTorque * TotalRatio * Efficiency;
desiredTorque = Math.Min(desiredTorque, maxEngineTorqueAtWheels);
}
TransmittedPower = clutchTorque * SpeedDifference;
ClutchTorque = desiredTorque;
// Calculate energy transfer based on torque
float energyTransferred = 0f;
if (omegaDifference > 0.01f) // Wheels → Engine (engine braking)
{
// Power = torque × angular velocity (at slower side - engine)
float power = ClutchTorque * (Engine.AngularVelocity);
energyTransferred = power * deltaTime;
// Wheels lose energy, engine gains (minus efficiency losses)
float wheelEnergyLoss = Math.Abs(energyTransferred);
float engineEnergyGain = wheelEnergyLoss * Efficiency;
WheelSystem.TotalEnergy -= wheelEnergyLoss;
Engine.FlywheelEnergy += engineEnergyGain;
}
else if (omegaDifference < -0.01f) // Engine → Wheels (acceleration)
{
// Power = torque × angular velocity (at faster side - engine)
float power = -ClutchTorque * Engine.AngularVelocity; // Negative torque, positive power
energyTransferred = power * deltaTime;
// Engine loses energy, wheels gain
float engineEnergyLoss = Math.Abs(energyTransferred);
float wheelEnergyGain = engineEnergyLoss * Efficiency;
Engine.FlywheelEnergy -= engineEnergyLoss;
WheelSystem.TotalEnergy += wheelEnergyGain;
}
else
{
// Nearly synchronized
energyTransferred = 0;
}
// Calculate transmitted power
TransmittedPower = energyTransferred / deltaTime;
// Calculate clutch slip CORRECTLY:
// Slip = 0 when torque < max torque (clutch can handle it)
// Slip = 1 when torque = max torque (clutch is slipping)
if (maxClutchTorque > 0)
{
float torqueRatio = Math.Abs(ClutchTorque) / maxClutchTorque;
// If we're transmitting max torque, clutch is slipping
// If we're transmitting less, clutch is gripping
ClutchSlipRatio = torqueRatio; // 0 = no slip, 1 = full slip
}
else
{
ClutchSlipRatio = 1f;
}
}
private void ApplyEngineToWheels(float clutchTorque, float deltaTime)
// Other methods...
public float GearRatio => GetCurrentGearRatio();
public float TotalRatio => GearRatio * FinalDriveRatio;
private float GetCurrentGearRatio()
{
// Existing logic for engine driving wheels
float netWheelTorque = clutchTorque * Efficiency - WheelSystem.ResistanceTorque;
float netEngineTorque = -clutchTorque / TotalRatio;
// Apply to both
Engine.ApplyTorque(netEngineTorque, deltaTime);
WheelSystem.ApplyTorque(netWheelTorque, deltaTime);
if (currentGear == 0) return 0f;
if (currentGear == -1) return -3.5f;
if (currentGear > 0 && currentGear <= GearRatios.Length)
return GearRatios[currentGear - 1];
return 0f;
}
private void ApplyWheelsToEngine(float clutchTorque, float deltaTime)
{
// Wheels driving engine (engine braking)
// Negative clutchTorque means wheels are trying to spin engine faster
float wheelTorque = clutchTorque; // Negative value
float engineTorque = -clutchTorque / TotalRatio; // Positive resistance
// Apply resistance to wheels
WheelSystem.ApplyTorque(wheelTorque, deltaTime);
Engine.ApplyTorque(-engineTorque, deltaTime); // Negative = slowing
}
public float GetEquivalentInertiaAtEngine()
{
float wheelInertia = WheelSystem.GetTotalInertia();
return Engine.MomentOfInertia + (wheelInertia * TotalRatio * TotalRatio);
}
public float CalculateEngineLoad(float deltaTime)
{
if (ClutchEngagement <= 0.01f) return 0f;
float wheelResistanceTorque = WheelSystem.ResistanceTorque;
float engineLoadTorque = wheelResistanceTorque / (TotalRatio * Efficiency);
float inertiaLoad = CalculateInertiaLoad(deltaTime);
return engineLoadTorque + inertiaLoad;
}
private float CalculateInertiaLoad(float deltaTime)
{
float wheelAlpha = (WheelSystem.AngularVelocity - previousWheelOmega) / deltaTime;
previousWheelOmega = WheelSystem.AngularVelocity;
float inertiaTorque = wheelAlpha * WheelSystem.GetTotalInertia();
return inertiaTorque / (TotalRatio * TotalRatio * Efficiency);
}
public void Update(float deltaTime)
{
ApplyDrivetrainWork(deltaTime);
}
// Helper methods
public float GetSpeedDifferenceRPM()
{
return SpeedDifference * PhysicsUtil.RAD_PER_SEC_TO_RPM;
float expectedWheelOmega = Engine.AngularVelocity / TotalRatio;
float actualWheelOmega = WheelSystem.AngularVelocity;
return (actualWheelOmega - expectedWheelOmega) * PhysicsUtil.RAD_PER_SEC_TO_RPM;
}
public string GetCurrentGearName()
@@ -202,5 +153,13 @@
_ => currentGear.ToString()
};
}
public float GetClutchSlipPercent()
{
return ClutchSlipRatio * 100f;
}
public void GearUp() { if (currentGear < GearRatios.Length) currentGear++; }
public void GearDown() { if (currentGear > 1) currentGear--; }
}
}