@@ -41,6 +41,7 @@ public class AirSinglePipe : MSTSBrakeSystem
41
41
protected float ControlResPressurePSI = 64 ;
42
42
protected float FullServPressurePSI = 50 ;
43
43
protected float MaxCylPressurePSI = 64 ;
44
+ protected float MaxTripleValveCylPressurePSI ;
44
45
protected float AuxCylVolumeRatio = 2.5f ;
45
46
protected float AuxBrakeLineVolumeRatio ;
46
47
protected float EmergResVolumeM3 = 0.07f ;
@@ -53,6 +54,10 @@ public class AirSinglePipe : MSTSBrakeSystem
53
54
protected float EmergencyValveActuationRatePSIpS = 0 ;
54
55
protected float EmergResChargingRatePSIpS = 1.684f ;
55
56
protected float EmergAuxVolumeRatio = 1.4f ;
57
+ protected bool RelayValveFitted = false ;
58
+ public float RelayValveRatio { get ; protected set ; } = 1 ;
59
+ protected float RelayValveApplicationRatePSIpS = 50 ;
60
+ protected float RelayValveReleaseRatePSIpS = 50 ;
56
61
protected string DebugType = string . Empty ;
57
62
protected string RetainerDebugState = string . Empty ;
58
63
protected bool MRPAuxResCharging ;
@@ -121,6 +126,11 @@ public override void InitializeFromCopy(BrakeSystem copy)
121
126
TwoPipes = thiscopy . TwoPipes ;
122
127
MRPAuxResCharging = thiscopy . MRPAuxResCharging ;
123
128
HoldingValve = thiscopy . HoldingValve ;
129
+ RelayValveFitted = thiscopy . RelayValveFitted ;
130
+ RelayValveRatio = thiscopy . RelayValveRatio ;
131
+ RelayValveApplicationRatePSIpS = thiscopy . RelayValveApplicationRatePSIpS ;
132
+ RelayValveReleaseRatePSIpS = thiscopy . RelayValveReleaseRatePSIpS ;
133
+ MaxTripleValveCylPressurePSI = thiscopy . MaxTripleValveCylPressurePSI ;
124
134
}
125
135
126
136
// Get the brake BC & BP for EOT conditions
@@ -233,6 +243,21 @@ public override void Parse(string lowercasetoken, STFReader stf)
233
243
case "wagon(ortsbrakeinsensitivity" : BrakeInsensitivityPSIpS = stf . ReadFloatBlock ( STFReader . UNITS . PressureRateDefaultPSIpS , 0.07f ) ; break ;
234
244
case "wagon(ortsemergencyvalveactuationrate" : EmergencyValveActuationRatePSIpS = stf . ReadFloatBlock ( STFReader . UNITS . PressureRateDefaultPSIpS , 15f ) ; break ;
235
245
case "wagon(ortsmainrespipeauxrescharging" : MRPAuxResCharging = this is AirTwinPipe && stf . ReadBoolBlock ( true ) ; break ;
246
+ case "wagon(ortsbrakerelayvalveratio" :
247
+ RelayValveRatio = stf . ReadFloatBlock ( STFReader . UNITS . None , null ) ;
248
+ if ( RelayValveRatio != 0 )
249
+ {
250
+ RelayValveFitted = true ;
251
+ }
252
+ else
253
+ {
254
+ RelayValveRatio = 1 ;
255
+ RelayValveFitted = false ;
256
+ }
257
+ break ;
258
+ case "wagon(ortsbrakerelayvalveapplicationrate" : RelayValveApplicationRatePSIpS = stf . ReadFloatBlock ( STFReader . UNITS . PressureRateDefaultPSIpS , null ) ; break ;
259
+ case "wagon(ortsbrakerelayvalvereleaserate" : RelayValveReleaseRatePSIpS = stf . ReadFloatBlock ( STFReader . UNITS . PressureRateDefaultPSIpS , null ) ; break ;
260
+ case "wagon(ortsmaxtriplevalvecylinderpressure" : MaxTripleValveCylPressurePSI = stf . ReadFloatBlock ( STFReader . UNITS . PressureDefaultPSI , null ) ; break ;
236
261
}
237
262
}
238
263
@@ -298,13 +323,16 @@ public override void Initialize(bool handbrakeOn, float maxPressurePSI, float fu
298
323
if ( Car . Simulator . Settings . SimpleControlPhysics && EmergResVolumeM3 > 2.0 )
299
324
EmergResVolumeM3 = 0.7f ;
300
325
326
+ if ( MaxTripleValveCylPressurePSI == 0 ) MaxTripleValveCylPressurePSI = MaxCylPressurePSI / RelayValveRatio ;
327
+
301
328
BrakeLine1PressurePSI = Car . Train . EqualReservoirPressurePSIorInHg ;
302
329
BrakeLine2PressurePSI = Car . Train . BrakeLine2PressurePSI ;
303
330
BrakeLine3PressurePSI = 0 ;
304
331
if ( maxPressurePSI > 0 )
305
332
ControlResPressurePSI = maxPressurePSI ;
306
333
FullServPressurePSI = fullServPressurePSI ;
307
- CylPressurePSI = AutoCylPressurePSI = immediateRelease ? 0 : Math . Min ( ( maxPressurePSI - BrakeLine1PressurePSI ) * AuxCylVolumeRatio , MaxCylPressurePSI ) ;
334
+ AutoCylPressurePSI = immediateRelease ? 0 : Math . Min ( ( maxPressurePSI - BrakeLine1PressurePSI ) * AuxCylVolumeRatio , MaxCylPressurePSI ) ;
335
+ CylPressurePSI = AutoCylPressurePSI * RelayValveRatio ;
308
336
AuxResPressurePSI = Math . Max ( TwoPipes ? maxPressurePSI : maxPressurePSI - AutoCylPressurePSI / AuxCylVolumeRatio , BrakeLine1PressurePSI ) ;
309
337
if ( ( Car as MSTSWagon ) . EmergencyReservoirPresent )
310
338
EmergResPressurePSI = Math . Max ( AuxResPressurePSI , maxPressurePSI ) ;
@@ -324,6 +352,8 @@ public override void Initialize(bool handbrakeOn, float maxPressurePSI, float fu
324
352
AuxBrakeLineVolumeRatio = 3.1f ;
325
353
326
354
CylVolumeM3 = EmergResVolumeM3 / EmergAuxVolumeRatio / AuxCylVolumeRatio ;
355
+
356
+ RelayValveFitted |= ( loco != null && ( loco . DynamicBrakeAutoBailOff || loco . DynamicBrakePartialBailOff ) ) || ( Car as MSTSWagon ) . BrakeValve == MSTSWagon . BrakeValveType . DistributingValve ;
327
357
}
328
358
329
359
/// <summary>
@@ -420,8 +450,8 @@ public override void Update(float elapsedClockSeconds)
420
450
dp = ( AuxResPressurePSI - AutoCylPressurePSI ) * AuxCylVolumeRatio / ( 1 + AuxCylVolumeRatio ) ;
421
451
if ( ( ( Car as MSTSWagon ) . BrakeValve == MSTSWagon . BrakeValveType . Distributor ) && TripleValveState != ValveState . Emergency && dp > threshold - AutoCylPressurePSI )
422
452
dp = threshold - AutoCylPressurePSI ;
423
- if ( AutoCylPressurePSI + dp > MaxCylPressurePSI )
424
- dp = MaxCylPressurePSI - AutoCylPressurePSI ;
453
+ if ( AutoCylPressurePSI + dp > MaxTripleValveCylPressurePSI )
454
+ dp = MaxTripleValveCylPressurePSI - AutoCylPressurePSI ;
425
455
if ( BrakeLine1PressurePSI > AuxResPressurePSI - dp / AuxCylVolumeRatio && ! BleedOffValveOpen )
426
456
dp = ( AuxResPressurePSI - BrakeLine1PressurePSI ) * AuxCylVolumeRatio ;
427
457
if ( dp < 0 )
@@ -527,11 +557,12 @@ public override void Update(float elapsedClockSeconds)
527
557
if ( AutoCylPressurePSI < 0 )
528
558
AutoCylPressurePSI = 0 ;
529
559
530
- if ( Car is MSTSLocomotive && ( Car as MSTSWagon ) . BrakeValve == MSTSWagon . BrakeValveType . DistributingValve )
560
+ float demandedPressurePSI = 0 ;
561
+ var loco = Car as MSTSLocomotive ;
562
+ if ( loco != null && ( Car as MSTSWagon ) . BrakeValve == MSTSWagon . BrakeValveType . DistributingValve )
531
563
{
532
564
// For distributing valves, we use AutoCylPressurePSI as "Application Chamber/Pipe" pressure
533
565
// CylPressurePSI is the actual pressure applied to cylinders
534
- var loco = Car as MSTSLocomotive ;
535
566
var engineBrakeStatus = loco . EngineBrakeController . Notches [ loco . EngineBrakeController . CurrentNotch ] . Type ;
536
567
var trainBrakeStatus = loco . TrainBrakeController . Notches [ loco . TrainBrakeController . CurrentNotch ] . Type ;
537
568
// BailOff
@@ -544,8 +575,8 @@ public override void Update(float elapsedClockSeconds)
544
575
if ( trainBrakeStatus == ControllerState . Emergency )
545
576
{
546
577
float dp = elapsedClockSeconds * MaxApplicationRatePSIpS ;
547
- if ( dp > MaxCylPressurePSI - AutoCylPressurePSI )
548
- dp = MaxCylPressurePSI - AutoCylPressurePSI ;
578
+ if ( dp > MaxCylPressurePSI / RelayValveRatio - AutoCylPressurePSI )
579
+ dp = MaxCylPressurePSI / RelayValveRatio - AutoCylPressurePSI ;
549
580
AutoCylPressurePSI += dp ;
550
581
}
551
582
// Release pipe open
@@ -558,15 +589,13 @@ public override void Update(float elapsedClockSeconds)
558
589
loco . Train . BrakeLine3PressurePSI = AutoCylPressurePSI ;
559
590
560
591
// Equalization between application chamber and brake cylinders
561
- // TODO: Drain air from main reservoir
562
- CylPressurePSI = AutoCylPressurePSI ;
592
+ demandedPressurePSI = AutoCylPressurePSI ;
563
593
}
564
594
else
565
595
{
566
- if ( Car is MSTSLocomotive loco && loco . EngineType != TrainCar . EngineTypes . Control ) // TODO - Control cars ned to be linked to power suppy requirements.
596
+ demandedPressurePSI = Math . Max ( AutoCylPressurePSI , BrakeLine3PressurePSI ) ;
597
+ if ( loco != null && loco . EngineType != TrainCar . EngineTypes . Control ) // TODO - Control cars ned to be linked to power suppy requirements.
567
598
{
568
- float demandedPressurePSI = Math . Max ( AutoCylPressurePSI , BrakeLine3PressurePSI ) ;
569
- // if (Car is MSTSLocomotive loco && loco.LocomotivePowerSupply.MainPowerSupplyOn)
570
599
if ( loco . LocomotivePowerSupply . MainPowerSupplyOn )
571
600
{
572
601
if ( loco . Train . LeadLocomotiveIndex >= 0 )
@@ -600,6 +629,7 @@ public override void Update(float elapsedClockSeconds)
600
629
{
601
630
demandedPressurePSI = CylPressurePSI ;
602
631
}
632
+ demandedPressurePSI /= RelayValveRatio ;
603
633
if ( demandedPressurePSI < BrakeLine3PressurePSI )
604
634
demandedPressurePSI = BrakeLine3PressurePSI ;
605
635
}
@@ -621,34 +651,35 @@ public override void Update(float elapsedClockSeconds)
621
651
}
622
652
}
623
653
}
624
- // TODO: this first clause is intended for locomotives fitted with some sort of proportional valve
625
- // i.e. the triple valve is not directly attached to the physical brake cylinder
626
- // This allows e.g. blending, variable load, or higher pressures than provided by triple valves
627
- if ( loco . DynamicBrakeAutoBailOff || loco . DynamicBrakeAutoBailOff )
628
- {
629
- if ( demandedPressurePSI > CylPressurePSI )
630
- {
631
- float dp = elapsedClockSeconds * loco . EngineBrakeApplyRatePSIpS ;
632
- if ( dp > demandedPressurePSI - CylPressurePSI )
633
- dp = demandedPressurePSI - CylPressurePSI ;
634
- /* TODO: Proportional valves need air from the main reservoir
635
- if (BrakeLine2PressurePSI - dp * AuxBrakeLineVolumeRatio / AuxCylVolumeRatio < CylPressurePSI + dp)
636
- dp = (BrakeLine2PressurePSI - CylPressurePSI) / (1 + AuxBrakeLineVolumeRatio / AuxCylVolumeRatio);
637
- BrakeLine2PressurePSI -= dp * AuxBrakeLineVolumeRatio / AuxCylVolumeRatio;*/
638
- CylPressurePSI += dp ;
639
- }
640
- else if ( demandedPressurePSI < CylPressurePSI ) CylPressurePSI = Math . Max ( demandedPressurePSI , CylPressurePSI - elapsedClockSeconds * loco . EngineBrakeReleaseRatePSIpS ) ;
641
- }
642
- else // Rest of cases
654
+ }
655
+ }
656
+ if ( RelayValveFitted )
657
+ {
658
+ demandedPressurePSI *= RelayValveRatio ;
659
+ if ( demandedPressurePSI > CylPressurePSI )
660
+ {
661
+ float dp = elapsedClockSeconds * RelayValveApplicationRatePSIpS ;
662
+ if ( dp > demandedPressurePSI - CylPressurePSI )
663
+ dp = demandedPressurePSI - CylPressurePSI ;
664
+ if ( TwoPipes )
643
665
{
644
- CylPressurePSI = Math . Max ( AutoCylPressurePSI , BrakeLine3PressurePSI ) ;
666
+ if ( BrakeLine2PressurePSI - dp * AuxBrakeLineVolumeRatio / AuxCylVolumeRatio < CylPressurePSI + dp )
667
+ dp = ( BrakeLine2PressurePSI - CylPressurePSI ) / ( 1 + AuxBrakeLineVolumeRatio / AuxCylVolumeRatio ) ;
668
+ BrakeLine2PressurePSI -= dp * AuxBrakeLineVolumeRatio / AuxCylVolumeRatio ;
645
669
}
670
+ if ( MaxCylPressurePSI < CylPressurePSI + dp )
671
+ dp = MaxCylPressurePSI - CylPressurePSI ;
672
+ CylPressurePSI += dp ;
646
673
}
647
- else
674
+ else if ( demandedPressurePSI < CylPressurePSI )
648
675
{
649
- CylPressurePSI = Math . Max ( AutoCylPressurePSI , BrakeLine3PressurePSI ) ;
676
+ CylPressurePSI = Math . Max ( Math . Max ( demandedPressurePSI , CylPressurePSI - elapsedClockSeconds * RelayValveReleaseRatePSIpS ) , 0 ) ;
650
677
}
651
678
}
679
+ else
680
+ {
681
+ CylPressurePSI = demandedPressurePSI ;
682
+ }
652
683
653
684
// During braking wheelslide control is effected throughout the train by additional equipment on each vehicle. In the piping to each pair of brake cylinders are fitted electrically operated
654
685
// dump valves. When axle rotations which are sensed electrically, differ by a predetermined speed the dump valves are operated releasing brake cylinder pressure to both axles of the affected
@@ -670,7 +701,6 @@ public override void Update(float elapsedClockSeconds)
670
701
{
671
702
Car . WheelBrakeSlideProtectionActive = true ;
672
703
AutoCylPressurePSI -= elapsedClockSeconds * MaxReleaseRatePSIpS ;
673
- CylPressurePSI = AutoCylPressurePSI ;
674
704
Car . WheelBrakeSlideProtectionTimerS -= elapsedClockSeconds ;
675
705
676
706
// Lockout WSP dump valve if it is open for greater then 7 seconds continuously
0 commit comments