/// <summary> /// This function updates periodically the locomotive's motive force. /// </summary> protected override void UpdateMotiveForce(float elapsedClockSeconds, float t, float AbsSpeedMpS, float AbsWheelSpeedMpS) { if (PowerOn) { if (TractiveForceCurves == null) { float maxForceN = Math.Min(t * MaxForceN * (1 - PowerReduction), AbsWheelSpeedMpS == 0.0f ? (t * MaxForceN * (1 - PowerReduction)) : (t * DieselEngines.CurrentRailOutputPowerW / AbsWheelSpeedMpS)); float maxPowerW = 0.98f * DieselEngines.MaximumRailOutputPowerW; //0.98 added to let the diesel engine handle the adhesion-caused jittering if (DieselEngines.HasGearBox) { MotiveForceN = DieselEngines.MotiveForceN; } else { if (maxForceN * AbsWheelSpeedMpS > maxPowerW) { maxForceN = maxPowerW / AbsWheelSpeedMpS; } if (AbsSpeedMpS > MaxSpeedMpS - 0.05f) { maxForceN = 20 * (MaxSpeedMpS - AbsSpeedMpS) * maxForceN; } if (AbsSpeedMpS > (MaxSpeedMpS)) { maxForceN = 0; } MotiveForceN = maxForceN; } } else { if (t > (DieselEngines.MaxOutputPowerW / DieselEngines.MaxPowerW)) { t = (DieselEngines.MaxOutputPowerW / DieselEngines.MaxPowerW); } MotiveForceN = TractiveForceCurves.Get(t, AbsWheelSpeedMpS) * (1 - PowerReduction); if (MotiveForceN < 0 && !TractiveForceCurves.AcceptsNegativeValues()) { MotiveForceN = 0; } } DieselFlowLps = DieselEngines.DieselFlowLps; partialFuelConsumption += DieselEngines.DieselFlowLps * elapsedClockSeconds; if (partialFuelConsumption >= 0.1) { DieselLevelL -= partialFuelConsumption; partialFuelConsumption = 0; } if (DieselLevelL <= 0.0f) { PowerOn = false; SignalEvent(Event.EnginePowerOff); foreach (DieselEngine de in DieselEngines) { if (de.EngineStatus != DieselEngine.Status.Stopping || de.EngineStatus != DieselEngine.Status.Stopped) { de.Stop(); } } } // MassKG = InitialMassKg - MaxDieselLevelL * DieselWeightKgpL + DieselLevelL * DieselWeightKgpL; } if (MaxForceN > 0 && MaxContinuousForceN > 0 && PowerReduction < 1) { MotiveForceN *= 1 - (MaxForceN - MaxContinuousForceN) / (MaxForceN * MaxContinuousForceN) * AverageForceN * (1 - PowerReduction); float w = (ContinuousForceTimeFactor - elapsedClockSeconds) / ContinuousForceTimeFactor; if (w < 0) { w = 0; } AverageForceN = w * AverageForceN + (1 - w) * MotiveForceN; } }
/// <summary> /// This function updates periodically the locomotive's motive force. /// </summary> protected override void UpdateMotiveForce(double elapsedClockSeconds, float t, float AbsSpeedMpS, float AbsWheelSpeedMpS) { if (PowerOn) { if (TractiveForceCurves == null) { float maxForceN = Math.Min(t * MaxForceN * (1 - PowerReduction), AbsWheelSpeedMpS == 0.0f ? (t * MaxForceN * (1 - PowerReduction)) : (t * LocomotiveMaxRailOutputPowerW / AbsWheelSpeedMpS)); float maxPowerW = 0.98f * LocomotiveMaxRailOutputPowerW; //0.98 added to let the diesel engine handle the adhesion-caused jittering if (DieselEngines.HasGearBox) { MotiveForceN = DieselEngines.MotiveForceN; } else { if (maxForceN * AbsWheelSpeedMpS > maxPowerW) { maxForceN = maxPowerW / AbsWheelSpeedMpS; } if (AbsSpeedMpS > MaxSpeedMpS - 0.05f) { maxForceN = 20 * (MaxSpeedMpS - AbsSpeedMpS) * maxForceN; } if (AbsSpeedMpS > (MaxSpeedMpS)) { maxForceN = 0; } MotiveForceN = maxForceN; } } else { // Caps throttle setting if more then one diesel engine fitted // As tractive force table is combined output, a ratio of diesel engine powers is used to adjust throttle setting. // In principal, a locomotive with two engines should never exceed 50% throttle if one engine is shut down (if of equal power) if (DieselEngines.Count > 1) { if (t > (DieselEngines.CurrentRailOutputPowerW / DieselEngines.MaximumRailOutputPowerW)) { t = (DieselEngines.CurrentRailOutputPowerW / DieselEngines.MaximumRailOutputPowerW); } } MotiveForceN = (float)TractiveForceCurves.Get(t, AbsWheelSpeedMpS) * (1 - PowerReduction); if (MotiveForceN < 0 && !TractiveForceCurves.HasNegativeValues) { MotiveForceN = 0; } } DieselFlowLps = DieselEngines.DieselFlowLps; partialFuelConsumption += DieselEngines.DieselFlowLps * (float)elapsedClockSeconds; if (partialFuelConsumption >= 0.1) { DieselLevelL -= partialFuelConsumption; partialFuelConsumption = 0; } if (DieselLevelL <= 0.0f) { PowerOn = false; SignalEvent(TrainEvent.EnginePowerOff); foreach (DieselEngine de in DieselEngines) { if (de.EngineStatus != DieselEngine.Status.Stopping || de.EngineStatus != DieselEngine.Status.Stopped) { de.Stop(); } } } // MassKG = InitialMassKg - MaxDieselLevelL * DieselWeightKgpL + DieselLevelL * DieselWeightKgpL; } if (MaxForceN > 0 && MaxContinuousForceN > 0 && PowerReduction < 1) { MotiveForceN *= 1 - (MaxForceN - MaxContinuousForceN) / (MaxForceN * MaxContinuousForceN) * AverageForceN * (1 - PowerReduction); float w = (float)(ContinuousForceTimeFactor - elapsedClockSeconds) / ContinuousForceTimeFactor; if (w < 0) { w = 0; } AverageForceN = w * AverageForceN + (1 - w) * MotiveForceN; } }
/// <summary> /// This function updates periodically the locomotive's motive force. /// </summary> protected override void UpdateMotiveForce(float elapsedClockSeconds, float t, float AbsSpeedMpS, float AbsWheelSpeedMpS) { if (PowerOn) { if (TractiveForceCurves == null) { float maxForceN = Math.Min(t * MaxForceN, AbsWheelSpeedMpS == 0.0f ? (t * MaxForceN) : (t * DieselEngines.MaxOutputPowerW / AbsWheelSpeedMpS)); float maxPowerW = 0.98f * DieselEngines.MaxOutputPowerW; //0.98 added to let the diesel engine handle the adhesion-caused jittering if (DieselEngines.HasGearBox) { MotiveForceN = DieselEngines.MotiveForceN; } else { if (maxForceN * AbsWheelSpeedMpS > maxPowerW) { maxForceN = maxPowerW / AbsWheelSpeedMpS; } if (AbsSpeedMpS > MaxSpeedMpS - 0.05f) { maxForceN = 20 * (MaxSpeedMpS - AbsSpeedMpS) * maxForceN; } if (AbsSpeedMpS > (MaxSpeedMpS)) { maxForceN = 0; } MotiveForceN = maxForceN; } } else { if (t > (DieselEngines.MaxOutputPowerW / DieselEngines.MaxPowerW)) { t = (DieselEngines.MaxOutputPowerW / DieselEngines.MaxPowerW); } MotiveForceN = TractiveForceCurves.Get(t, AbsWheelSpeedMpS); if (MotiveForceN < 0) { MotiveForceN = 0; } } DieselFlowLps = DieselEngines.DieselFlowLps; partialFuelConsumption += DieselEngines.DieselFlowLps * elapsedClockSeconds; if (partialFuelConsumption >= 0.1) { DieselLevelL -= partialFuelConsumption; partialFuelConsumption = 0; } if (DieselLevelL <= 0.0f) { PowerOn = false; SignalEvent(Event.EnginePowerOff); } MassKG = InitialMassKg - MaxDieselLevelL * DieselWeightKgpL + DieselLevelL * DieselWeightKgpL; } if (DynamicBrakePercent > 0 && DynamicBrakeForceCurves != null) { float f = DynamicBrakeForceCurves.Get(.01f * DynamicBrakePercent, AbsWheelSpeedMpS); if (f > 0) { MotiveForceN -= (SpeedMpS > 0 ? 1 : -1) * f; switch (Direction) { case Direction.Forward: //MotiveForceN *= 1; //Not necessary break; case Direction.Reverse: MotiveForceN *= -1; break; case Direction.N: default: MotiveForceN *= 0; break; } } } if (MaxForceN > 0 && MaxContinuousForceN > 0) { MotiveForceN *= 1 - (MaxForceN - MaxContinuousForceN) / (MaxForceN * MaxContinuousForceN) * AverageForceN; float w = (ContinuousForceTimeFactor - elapsedClockSeconds) / ContinuousForceTimeFactor; if (w < 0) { w = 0; } AverageForceN = w * AverageForceN + (1 - w) * MotiveForceN; } }
public override void LoadFromWagFile(string wagFilePath) { base.LoadFromWagFile(wagFilePath); if (Simulator.Settings.VerboseConfigurationMessages) // Display locomotivve name for verbose error messaging { Trace.TraceInformation("\n\n ================================================= {0} =================================================", LocomotiveName); } NormalizeParams(); // Check to see if Speed of Max Tractive Force has been set - use ORTS value as first priority, if not use MSTS, last resort use an arbitary value. if (SpeedOfMaxContinuousForceMpS == 0) { if (MSTSSpeedOfMaxContinuousForceMpS != 0) { SpeedOfMaxContinuousForceMpS = MSTSSpeedOfMaxContinuousForceMpS; // Use MSTS value if present if (Simulator.Settings.VerboseConfigurationMessages) { Trace.TraceInformation("Speed Of Max Continuous Force: set to default value {0}", FormatStrings.FormatSpeedDisplay(SpeedOfMaxContinuousForceMpS, IsMetric)); } } else if (MaxPowerW != 0 && MaxContinuousForceN != 0) { SpeedOfMaxContinuousForceMpS = MaxPowerW / MaxContinuousForceN; if (Simulator.Settings.VerboseConfigurationMessages) { Trace.TraceInformation("Speed Of Max Continuous Force: set to 'calculated' value {0}", FormatStrings.FormatSpeedDisplay(SpeedOfMaxContinuousForceMpS, IsMetric)); } } else { SpeedOfMaxContinuousForceMpS = 10.0f; // If not defined then set at an "arbitary" value of 22mph if (Simulator.Settings.VerboseConfigurationMessages) { Trace.TraceInformation("Speed Of Max Continuous Force: set to 'arbitary' value {0}", FormatStrings.FormatSpeedDisplay(SpeedOfMaxContinuousForceMpS, IsMetric)); } } } if (DieselEngines == null) { DieselEngines = new DieselEngines(this); } // Create a diesel engine block if none exits, typically for a MSTS or BASIC configuration if (DieselEngines.Count == 0) { DieselEngines.Add(new DieselEngine()); DieselEngines[0].InitFromMSTS(this); DieselEngines[0].Initialize(true); } // Check initialization of power values for diesel engines for (int i = 0; i < DieselEngines.Count; i++) { DieselEngines[i].InitDieselRailPowers(this); } if (GearBox != null && GearBox.IsInitialized) { GearBox.CopyFromMSTSParams(DieselEngines[0]); if (DieselEngines[0].GearBox == null) { DieselEngines[0].GearBox = GearBox; DieselEngines[0].GearBox.UseLocoGearBox(DieselEngines[0]); } for (int i = 1; i < DieselEngines.Count; i++) { if (DieselEngines[i].GearBox == null) { DieselEngines[i].GearBox = new GearBox(GearBox, DieselEngines[i]); } } if (GearBoxController == null) { GearBoxController = new MSTSNotchController(GearBox.NumOfGears + 1); } } InitialMassKg = MassKG; // If traction force curves not set (BASIC configuration) then check that power values are set, otherwise locomotive will not move. if (TractiveForceCurves == null && LocomotiveMaxRailOutputPowerW == 0) { if (MaxPowerW != 0) { LocomotiveMaxRailOutputPowerW = MaxPowerW; // Set to default power value if (Simulator.Settings.VerboseConfigurationMessages) { Trace.TraceInformation("MaxRailOutputPower (BASIC Config): set to default value = {0}", FormatStrings.FormatPower(LocomotiveMaxRailOutputPowerW, IsMetric, false, false)); } } else { LocomotiveMaxRailOutputPowerW = 2500000.0f; // If no default value then set to arbitary value if (Simulator.Settings.VerboseConfigurationMessages) { Trace.TraceInformation("MaxRailOutputPower (BASIC Config): set at arbitary value = {0}", FormatStrings.FormatPower(LocomotiveMaxRailOutputPowerW, IsMetric, false, false)); } } if (MaximumDieselEnginePowerW == 0) { MaximumDieselEnginePowerW = LocomotiveMaxRailOutputPowerW; // If no value set in ENG file, then set the Prime Mover power to same as RailOutputPower (typically the MaxPower value) if (Simulator.Settings.VerboseConfigurationMessages) { Trace.TraceInformation("Maximum Diesel Engine Prime Mover Power set the same as MaxRailOutputPower {0} value", FormatStrings.FormatPower(MaximumDieselEnginePowerW, IsMetric, false, false)); } } } // Check force assumptions set for diesel if (Simulator.Settings.VerboseConfigurationMessages) { float ThrottleSetting = 1.0f; // Must be at full throttle for these calculations if (TractiveForceCurves == null) // Basic configuration - ie no force and Power tables, etc { float CalculatedMaxContinuousForceN = ThrottleSetting * LocomotiveMaxRailOutputPowerW / SpeedOfMaxContinuousForceMpS; Trace.TraceInformation("Diesel Force Settings (BASIC Config): Max Starting Force {0}, Calculated Max Continuous Force {1} @ speed of {2}", FormatStrings.FormatForce(MaxForceN, IsMetric), FormatStrings.FormatForce(CalculatedMaxContinuousForceN, IsMetric), FormatStrings.FormatSpeedDisplay(SpeedOfMaxContinuousForceMpS, IsMetric)); Trace.TraceInformation("Diesel Power Settings (BASIC Config): Prime Mover {0}, Max Rail Output Power {1}", FormatStrings.FormatPower(MaximumDieselEnginePowerW, IsMetric, false, false), FormatStrings.FormatPower(LocomotiveMaxRailOutputPowerW, IsMetric, false, false)); if (MaxForceN < MaxContinuousForceN) { Trace.TraceInformation("!!!! Warning: Starting Tractive force {0} is less then Calculated Continuous force {1}, please check !!!!", FormatStrings.FormatForce(MaxForceN, IsMetric), FormatStrings.FormatForce(CalculatedMaxContinuousForceN, IsMetric), FormatStrings.FormatSpeedDisplay(SpeedOfMaxContinuousForceMpS, IsMetric)); } } else // Advanced configuration - { float StartingSpeedMpS = 0.1f; // Assumed starting speed for diesel - can't be zero otherwise error will occurr float StartingForceN = (float)TractiveForceCurves.Get(ThrottleSetting, StartingSpeedMpS); float CalculatedMaxContinuousForceN = (float)TractiveForceCurves.Get(ThrottleSetting, SpeedOfMaxContinuousForceMpS); Trace.TraceInformation("Diesel Force Settings (ADVANCED Config): Max Starting Force {0} Calculated Max Continuous Force {1}, @ speed of {2}", FormatStrings.FormatForce(StartingForceN, IsMetric), FormatStrings.FormatForce(CalculatedMaxContinuousForceN, IsMetric), FormatStrings.FormatSpeedDisplay(SpeedOfMaxContinuousForceMpS, IsMetric)); Trace.TraceInformation("Diesel Power Settings (ADVANCED Config): Prime Mover {0}, Max Rail Output Power {1} @ {2} rpm", FormatStrings.FormatPower(DieselEngines.MaxPowerW, IsMetric, false, false), FormatStrings.FormatPower(DieselEngines.MaximumRailOutputPowerW, IsMetric, false, false), MaxRPM); if (StartingForceN < MaxContinuousForceN) { Trace.TraceInformation("!!!! Warning: Calculated Starting Tractive force {0} is less then Calculated Continuous force {1}, please check !!!!", FormatStrings.FormatForce(StartingForceN, IsMetric), FormatStrings.FormatForce(CalculatedMaxContinuousForceN, IsMetric), FormatStrings.FormatSpeedDisplay(SpeedOfMaxContinuousForceMpS, IsMetric)); } } // Check that MaxPower value is realistic - Calculate power - metric - P = F x V float CalculatedContinuousPowerW = MaxContinuousForceN * SpeedOfMaxContinuousForceMpS; if (MaxPowerW < CalculatedContinuousPowerW) { Trace.TraceInformation("!!!! Warning: MaxPower {0} is less then continuous force calculated power {1} @ speed of {2}, please check !!!!", FormatStrings.FormatPower(MaxPowerW, IsMetric, false, false), FormatStrings.FormatPower(CalculatedContinuousPowerW, IsMetric, false, false), FormatStrings.FormatSpeedDisplay(SpeedOfMaxContinuousForceMpS, IsMetric)); } Trace.TraceInformation("===================================================================================================================\n\n"); } }
/// <summary> /// This function updates periodically the locomotive's motive force. /// </summary> protected override void UpdateMotiveForce(float elapsedClockSeconds, float t, float AbsSpeedMpS, float AbsWheelSpeedMpS) { // This section calculates the motive force of the locomotive as follows: // Basic configuration (no TF table) - uses P = F /speed relationship - requires power and force parameters to be set in the ENG file. // Advanced configuration (TF table) - use a user defined tractive force table // With Simple adhesion apart from correction for rail adhesion, there is no further variation to the motive force. // With Advanced adhesion the raw motive force is fed into the advanced (axle) adhesion model, and is corrected for wheel slip and rail adhesion if (PowerOn) { if (TractiveForceCurves == null) { float maxForceN = Math.Min(t * MaxForceN * (1 - PowerReduction), AbsSpeedMpS == 0.0f ? (t * MaxForceN * (1 - PowerReduction)) : (t * LocomotiveMaxRailOutputPowerW / AbsSpeedMpS)); float maxPowerW = LocomotiveMaxRailOutputPowerW * (DieselEngines.ApparentThrottleSetting / 100.0f); if (DieselEngines.HasGearBox) { MotiveForceN = DieselEngines.MotiveForceN; } else { if (maxForceN * AbsSpeedMpS > maxPowerW) { maxForceN = maxPowerW / AbsSpeedMpS; } // CTN - Not sure what impact that these following have??? if (AbsSpeedMpS > MaxSpeedMpS - 0.05f) { maxForceN = 20 * (MaxSpeedMpS - AbsSpeedMpS) * maxForceN; } // CTN - Sets power to zero, which I don't think is correct if (AbsSpeedMpS > (MaxSpeedMpS)) { maxForceN = 0; } MotiveForceN = maxForceN; } } else { MotiveForceN = TractiveForceCurves.Get((DieselEngines.ApparentThrottleSetting / 100.0f), AbsSpeedMpS) * (1 - PowerReduction); if (MotiveForceN < 0 && !TractiveForceCurves.AcceptsNegativeValues()) { MotiveForceN = 0; } } DieselFlowLps = DieselEngines.DieselFlowLps; partialFuelConsumption += DieselEngines.DieselFlowLps * elapsedClockSeconds; if (partialFuelConsumption >= 0.1) { DieselLevelL -= partialFuelConsumption; partialFuelConsumption = 0; } if (DieselLevelL <= 0.0f) { PowerOn = false; SignalEvent(Event.EnginePowerOff); foreach (DieselEngine de in DieselEngines) { if (de.EngineStatus != DieselEngine.Status.Stopping || de.EngineStatus != DieselEngine.Status.Stopped) { de.Stop(); } } } } if (MaxForceN > 0 && MaxContinuousForceN > 0 && PowerReduction < 1) { MotiveForceN *= 1 - (MaxForceN - MaxContinuousForceN) / (MaxForceN * MaxContinuousForceN) * AverageForceN * (1 - PowerReduction); float w = (ContinuousForceTimeFactor - elapsedClockSeconds) / ContinuousForceTimeFactor; if (w < 0) { w = 0; } AverageForceN = w * AverageForceN + (1 - w) * MotiveForceN; } }