165 lines
6.0 KiB
C#
165 lines
6.0 KiB
C#
namespace Car_simulation
|
||
{
|
||
public class Drivetrain
|
||
{
|
||
// Connected components
|
||
public Engine Engine { get; private set; }
|
||
public WheelSystem WheelSystem { get; private set; }
|
||
|
||
private int currentGear = 1;
|
||
public float[] GearRatios { get; set; } =
|
||
{
|
||
3.8f, // 1st
|
||
2.5f, // 2nd
|
||
1.8f, // 3rd
|
||
1.3f, // 4th
|
||
1.0f, // 5th
|
||
0.8f, // 6th
|
||
0.65f // 7th
|
||
};
|
||
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
|
||
|
||
// Clutch properties
|
||
public float MaxClutchTorque { get; set; } = 400f;
|
||
public float ClutchStiffness { get; set; } = 50f;
|
||
|
||
// State
|
||
public float ClutchTorque { get; private set; }
|
||
public float TransmittedPower { get; private set; }
|
||
public float ClutchSlipRatio { get; private set; }
|
||
|
||
public Drivetrain(Engine engine, WheelSystem wheelSystem)
|
||
{
|
||
Engine = engine;
|
||
WheelSystem = wheelSystem;
|
||
}
|
||
|
||
public void Update(float deltaTime)
|
||
{
|
||
if (ClutchEngagement <= 0.01f || TotalRatio == 0)
|
||
{
|
||
ClutchTorque = 0;
|
||
TransmittedPower = 0;
|
||
ClutchSlipRatio = 1f;
|
||
return;
|
||
}
|
||
|
||
// Calculate expected vs actual wheel speeds
|
||
float expectedWheelOmega = Engine.AngularVelocity / TotalRatio;
|
||
float actualWheelOmega = WheelSystem.AngularVelocity;
|
||
float omegaDifference = actualWheelOmega - expectedWheelOmega;
|
||
|
||
// Calculate max torque clutch can transmit
|
||
float maxClutchTorque = MaxClutchTorque * ClutchEngagement;
|
||
|
||
// 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)
|
||
{
|
||
float engineTorque = Engine.GetTorqueOutput() * Engine.GetActualThrottle();
|
||
float maxEngineTorqueAtWheels = engineTorque * TotalRatio * Efficiency;
|
||
desiredTorque = Math.Min(desiredTorque, maxEngineTorqueAtWheels);
|
||
}
|
||
|
||
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;
|
||
}
|
||
}
|
||
|
||
// Other methods...
|
||
public float GearRatio => GetCurrentGearRatio();
|
||
public float TotalRatio => GearRatio * FinalDriveRatio;
|
||
|
||
private float GetCurrentGearRatio()
|
||
{
|
||
if (currentGear == 0) return 0f;
|
||
if (currentGear == -1) return -3.5f;
|
||
if (currentGear > 0 && currentGear <= GearRatios.Length)
|
||
return GearRatios[currentGear - 1];
|
||
return 0f;
|
||
}
|
||
|
||
public float GetSpeedDifferenceRPM()
|
||
{
|
||
float expectedWheelOmega = Engine.AngularVelocity / TotalRatio;
|
||
float actualWheelOmega = WheelSystem.AngularVelocity;
|
||
return (actualWheelOmega - expectedWheelOmega) * PhysicsUtil.RAD_PER_SEC_TO_RPM;
|
||
}
|
||
|
||
public string GetCurrentGearName()
|
||
{
|
||
return currentGear switch
|
||
{
|
||
-1 => "R",
|
||
0 => "N",
|
||
_ => currentGear.ToString()
|
||
};
|
||
}
|
||
|
||
public float GetClutchSlipPercent()
|
||
{
|
||
return ClutchSlipRatio * 100f;
|
||
}
|
||
|
||
public void GearUp() { if (currentGear < GearRatios.Length) currentGear++; }
|
||
public void GearDown() { if (currentGear > 1) currentGear--; }
|
||
}
|
||
} |