/// <summary> /// Main Update method /// - computes slip characteristics to get new axle force /// - computes axle dynamic model according to its driveType /// - computes wheelslip indicators /// </summary> /// <param name="timeSpan"></param> public virtual void Update(float timeSpan) { //Update axle force ( = k * loadTorqueNm) axleForceN = AxleWeightN * SlipCharacteristics(AxleSpeedMpS - TrainSpeedMpS, TrainSpeedMpS, AdhesionK, AdhesionConditions, Adhesion2); // The Axle module subtracts brake force from the motive force for calculation purposes. However brake force is already taken into account in the braking module. // And thus there is a duplication of the braking effect in OR. To compensate for this, after the slip characteristics have been calculated, the output of the axle module // has the brake force "added" back in to give the appropriate motive force output for the locomotive. Braking force is handled separately. // Hence CompensatedAxleForce is the actual output force on the axle. var compensateAxleForceN = axleForceN; switch (driveType) { case AxleDriveType.NotDriven: //Axle revolutions integration axleSpeedMpS = AxleRevolutionsInt.Integrate(timeSpan, axleDiameterM * axleDiameterM / (4.0f * (totalInertiaKgm2)) * (2.0f * transmissionRatio / axleDiameterM * (-Math.Abs(brakeRetardForceN)) - AxleForceN)); break; case AxleDriveType.MotorDriven: //Axle revolutions integration if (TrainSpeedMpS == 0.0f) { dampingNs = 0.0f; brakeRetardForceN = 0.0f; } axleSpeedMpS = AxleRevolutionsInt.Integrate(timeSpan, axleDiameterM * axleDiameterM / (4.0f * (totalInertiaKgm2)) * (2.0f * transmissionRatio / axleDiameterM * motor.DevelopedTorqueNm * transmissionEfficiency - Math.Abs(brakeRetardForceN) - (axleSpeedMpS > 0.0 ? Math.Abs(dampingNs) : 0.0f)) - AxleForceN); //update motor values motor.RevolutionsRad = axleSpeedMpS * 2.0f * transmissionRatio / (axleDiameterM); motor.Update(timeSpan); break; case AxleDriveType.ForceDriven: //Axle revolutions integration if (TrainSpeedMpS > 0.01f) { axleSpeedMpS = AxleRevolutionsInt.Integrate(timeSpan, ( driveForceN * transmissionEfficiency - brakeRetardForceN - slipDerivationMpSS * dampingNs - Math.Abs(SlipSpeedMpS) * frictionN - AxleForceN ) / totalInertiaKgm2 ); compensateAxleForceN = axleForceN + brakeRetardForceN; if (Math.Abs(compensateAxleForceN) > Math.Abs(driveForceN)) { compensateAxleForceN = driveForceN; } if (brakeRetardForceN > driveForceN && AxleSpeedMpS < 0.1f) { axleSpeedMpS = 0.0f; axleForceN = -brakeRetardForceN + driveForceN; compensateAxleForceN = driveForceN; } } else if (TrainSpeedMpS < -0.01f) { axleSpeedMpS = AxleRevolutionsInt.Integrate(timeSpan, ( driveForceN * transmissionEfficiency + brakeRetardForceN - slipDerivationMpSS * dampingNs + Math.Abs(SlipSpeedMpS) * frictionN - AxleForceN ) / totalInertiaKgm2 ); compensateAxleForceN = axleForceN - brakeRetardForceN; if (Math.Abs(compensateAxleForceN) > Math.Abs(driveForceN)) { compensateAxleForceN = driveForceN; } if (brakeRetardForceN > Math.Abs(driveForceN) && AxleSpeedMpS > -0.1f) { axleSpeedMpS = 0.0f; axleForceN = brakeRetardForceN - driveForceN; compensateAxleForceN = driveForceN; } } else { if (Math.Abs(driveForceN) < 1f) { Reset(); axleSpeedMpS = 0.0f; //axleForceN = 0.0f; } else { axleForceN = driveForceN - brakeRetardForceN; compensateAxleForceN = driveForceN; if (Math.Abs(axleSpeedMpS) < 0.01f) { Reset(); } } //Reset(TrainSpeedMpS); //axleForceN = driveForceN - brakeRetardForceN; //axleSpeedMpS = AxleRevolutionsInt.Value; } break; default: totalInertiaKgm2 = inertiaKgm2; break; } if (timeSpan > 0.0f) { slipDerivationMpSS = (SlipSpeedMpS - previousSlipSpeedMpS) / timeSpan; previousSlipSpeedMpS = SlipSpeedMpS; slipDerivationPercentpS = (SlipSpeedPercent - previousSlipPercent) / timeSpan; previousSlipPercent = SlipSpeedPercent; } //Stability Correction if (StabilityCorrection) { if (slipDerivationPercentpS > 300.0f) { adhesionK += 0.0001f * slipDerivationPercentpS; } else { adhesionK = (adhesionK <= 0.7f) ? 0.7f : (adhesionK - 0.005f); } } // Set output MotiveForce to actual value exclusive of brake force. compensatedaxleForceN = CompensatedFilterMovingAverage.Update(Math.Abs(compensatedaxleForceN) > Math.Abs(driveForceN) ? driveForceN : compensateAxleForceN); axleForceN = FilterMovingAverage.Update(Math.Abs(axleForceN) > Math.Abs(driveForceN) ? driveForceN : axleForceN); }
/// <summary> /// Main Update method /// - computes slip characteristics to get new axle force /// - computes axle dynamic model according to its driveType /// - computes wheelslip indicators /// </summary> /// <param name="timeSpan"></param> public virtual void Update(float timeSpan) { //Update axle force ( = k * loadTorqueNm) axleForceN = AxleWeightN * SlipCharacteristics(AxleSpeedMpS - TrainSpeedMpS, TrainSpeedMpS, AdhesionK, AdhesionConditions, Adhesion2); switch (driveType) { case AxleDriveType.NotDriven: //Axle revolutions integration axleSpeedMpS = AxleRevolutionsInt.Integrate(timeSpan, axleDiameterM * axleDiameterM / (4.0f * (totalInertiaKgm2)) * (2.0f * transmissionRatio / axleDiameterM * (-Math.Abs(brakeRetardForceN)) - AxleForceN)); break; case AxleDriveType.MotorDriven: //Axle revolutions integration if (TrainSpeedMpS == 0.0f) { dampingNs = 0.0f; brakeRetardForceN = 0.0f; } axleSpeedMpS = AxleRevolutionsInt.Integrate(timeSpan, axleDiameterM * axleDiameterM / (4.0f * (totalInertiaKgm2)) * (2.0f * transmissionRatio / axleDiameterM * motor.DevelopedTorqueNm * transmissionEfficiency - Math.Abs(brakeRetardForceN) - (axleSpeedMpS > 0.0 ? Math.Abs(dampingNs) : 0.0f)) - AxleForceN); //update motor values motor.RevolutionsRad = axleSpeedMpS * 2.0f * transmissionRatio / (axleDiameterM); motor.Update(timeSpan); break; case AxleDriveType.ForceDriven: //Axle revolutions integration if (TrainSpeedMpS > 0.01f) { axleSpeedMpS = AxleRevolutionsInt.Integrate(timeSpan, ( driveForceN * transmissionEfficiency - brakeRetardForceN - slipDerivationMpSS * dampingNs - Math.Abs(SlipSpeedMpS) * frictionN - AxleForceN ) / totalInertiaKgm2 ); if (brakeRetardForceN > driveForceN && AxleSpeedMpS < 0.1f) { axleSpeedMpS = 0.0f; axleForceN = -brakeRetardForceN + driveForceN; } } else if (TrainSpeedMpS < -0.01f) { axleSpeedMpS = AxleRevolutionsInt.Integrate(timeSpan, ( driveForceN * transmissionEfficiency + brakeRetardForceN - slipDerivationMpSS * dampingNs + Math.Abs(SlipSpeedMpS) * frictionN - AxleForceN ) / totalInertiaKgm2 ); if (brakeRetardForceN > Math.Abs(driveForceN) && AxleSpeedMpS > -0.1f) { axleSpeedMpS = 0.0f; axleForceN = brakeRetardForceN - driveForceN; } } else { if (Math.Abs(driveForceN) < 1f) { Reset(); axleSpeedMpS = 0.0f; //axleForceN = 0.0f; } else { axleForceN = driveForceN - brakeRetardForceN; if (Math.Abs(axleSpeedMpS) < 0.01f) { Reset(); } } //Reset(TrainSpeedMpS); //axleForceN = driveForceN - brakeRetardForceN; //axleSpeedMpS = AxleRevolutionsInt.Value; } break; default: totalInertiaKgm2 = inertiaKgm2; break; } if (timeSpan > 0.0f) { slipDerivationMpSS = (SlipSpeedMpS - previousSlipSpeedMpS) / timeSpan; previousSlipSpeedMpS = SlipSpeedMpS; slipDerivationPercentpS = (SlipSpeedPercent - previousSlipPercent) / timeSpan; previousSlipPercent = SlipSpeedPercent; } //Stability Correction if (StabilityCorrection) { if (slipDerivationPercentpS > 300.0f) { adhesionK += 0.0001f * slipDerivationPercentpS; } else { adhesionK = (adhesionK <= 0.7f) ? 0.7f : (adhesionK - 0.005f); } } axleForceN = FilterMovingAverage.Update(Math.Abs(axleForceN) > Math.Abs(driveForceN) ? driveForceN : axleForceN); }