@@ -602,70 +602,81 @@ public override void Initialize()
602602 CylAreaM2 = ( float ) ( ( Math . PI * ( CylDiameterM * CylDiameterM ) / 4.0f ) ) ;
603603 CylVolumeM3 = CylAreaM2 * CylStrokeM ;
604604
605- // Estimate the piping volume that results in the intended full service cylinder pressure
606- if ( CylPipeVolumeM3 <= 0 && AuxCylVolumeRatio > 0 )
605+ // Estimate the piping volume if it has not been defined yet
606+ // Piping volume cannot be 0 as this can cause division by 0
607+ if ( CylPipeVolumeM3 <= 0 )
607608 {
608- // Assuming 70 psi as brake pipe pressure
609- float nomPipePressurePSI = 70.0f ;
610- float nomCylPressurePSI = nomPipePressurePSI * ( AuxCylVolumeRatio / ( AuxCylVolumeRatio + 1.0f ) ) ;
611-
612- float tempPipeVolumeM3 = ( - ( CylVolumeM3 * OneAtmospherePSI ) - nomCylPressurePSI * ( CylVolumeM3 + AuxResVolumeM3 ) + ( nomPipePressurePSI * AuxResVolumeM3 ) )
613- / ( CylCount * nomCylPressurePSI ) ;
614-
615- CylPipeVolumeM3 = Math . Max ( tempPipeVolumeM3 , 0.05f * CylVolumeM3 ) ;
616-
617- // Produce a warning if the brake configuration will be unable to achieve desired pressure due to aux res too small
618- // If car has a supply res or a main res, aux res size doesn't matter
619- if ( tempPipeVolumeM3 < 0.05f * CylVolumeM3 && ! ( ( Car as MSTSWagon ) . SupplyReservoirPresent || Car is MSTSLocomotive ) )
620- Trace . TraceWarning ( $ "Auxiliary reservoir on car { Car . WagFilePath } appears to be too small for the brake cylinder(s). " +
621- $ "Consider increasing the auxiliary reservoir size, reducing cylinder size, or using a supply reservoir to provide sufficient cylinder pressures.") ;
609+ if ( AuxCylVolumeRatio > 0 && ! ( ( Car as MSTSWagon ) . SupplyReservoirPresent || Car is MSTSLocomotive ) )
610+ { // User has defined a triple valve ratio and the cylinder will be drawing air from the aux res
611+ // Set piping volume to produce expected pressure for the triple valve ratio
612+ // Assuming 70 psi as brake pipe pressure
613+ float nomPipePressurePSI = 70.0f ;
614+ float nomCylPressurePSI = nomPipePressurePSI * ( AuxCylVolumeRatio / ( AuxCylVolumeRatio + 1.0f ) ) ;
615+
616+ float tempPipeVolumeM3 = ( - ( CylVolumeM3 * OneAtmospherePSI ) - nomCylPressurePSI * ( CylVolumeM3 + AuxResVolumeM3 ) + ( nomPipePressurePSI * AuxResVolumeM3 ) )
617+ / ( CylCount * nomCylPressurePSI ) ;
618+
619+ // Piping volume must be at least 5% of full cylinder volume
620+ CylPipeVolumeM3 = Math . Max ( tempPipeVolumeM3 , 0.05f * CylVolumeM3 ) ;
621+
622+ // Produce a warning if the brake configuration will be unable to achieve desired pressure due to aux res too small
623+ // If car has a supply res or a main res, aux res size doesn't matter
624+ if ( tempPipeVolumeM3 < 0.05f * CylVolumeM3 )
625+ Trace . TraceWarning ( $ "Auxiliary reservoir on car { Car . WagFilePath } appears to be too small for the brake cylinder(s). " +
626+ $ "Consider increasing the auxiliary reservoir size, reducing cylinder size, or using a supply reservoir to provide sufficient cylinder pressures.") ;
627+ }
628+ else // Assume piping volume is 20% of full cylinder volume
629+ CylPipeVolumeM3 = 0.20f * CylVolumeM3 ;
622630 }
623631
624632 // Advanced brake cylinder sim needs a spring pressure defined, otherwise it can remain 0
625633 if ( BrakeCylinderSpringPressurePSI <= 0 )
626634 BrakeCylinderSpringPressurePSI = 5.0f ;
627635
628636 // Precalculate the relationship between air in cylinder lines and cylinder travel
637+ if ( CylTravelTab == null ) // May have been initialized already
638+ {
639+ // Assumptions from PRR characteristic curve:
640+ // pg 40: https://ia600906.us.archive.org/24/items/braketestsreport00penn/braketestsreport00penn.pdf
641+ // Brake cylinder reaches rated travel at 50 psi
642+ // Brake cylinder travel is 80% of nominal when pressure reaches the spring counter-pressure
643+ // Other assumptions:
644+ // Brake cylinder travel remains at 0 until reaching half the spring counter-pressure
645+ // Brake cylinder travel is linear w.r.t. total air in the cylinder line, not entirely accurate but greatly simplifies code
646+ float [ ] airPV = new float [ 5 ] ;
647+ float [ ] cylTravel = new float [ 5 ] ;
648+
649+ float nomPSI = 50.0f ;
650+
651+ // Prevent interpolator error. Max cyl pressure and nominal pressure need to be slightly offset
652+ if ( ReferencePressurePSI == nomPSI )
653+ nomPSI -= 5.0f ;
654+ // Prevent interpolator error. Spring pressure should never be this large
655+ if ( BrakeCylinderSpringPressurePSI >= nomPSI )
656+ BrakeCylinderSpringPressurePSI = nomPSI - 5.0f ;
657+
658+ // 0 cylinder travel with 0 air in cylinder
659+ cylTravel [ 0 ] = 0 ;
660+ airPV [ 0 ] = AdvancedBrakeCylinderAir ( 0 , true ) ;
661+ // 0 cylinder travel when pressure is insufficient to budge spring
662+ cylTravel [ 1 ] = 0 ;
663+ airPV [ 1 ] = AdvancedBrakeCylinderAir ( BrakeCylinderSpringPressurePSI / 2.0f , true ) ;
664+ // 80% cylinder travel when spring pressure is fully overcome
665+ cylTravel [ 2 ] = CylStrokeM * 0.8f ;
666+ airPV [ 2 ] = AdvancedBrakeCylinderAir ( BrakeCylinderSpringPressurePSI , true ) ;
667+ // 100% cylinder travel at 50 psi, with linear change in travel between 50 psi and max pressure
668+ // This will work whether the max cylinder pressure is above or below 50 psi
669+ float strokePerPsi = ( CylStrokeM - cylTravel [ 2 ] ) / ( 50.0f - BrakeCylinderSpringPressurePSI ) ;
670+
671+ cylTravel [ 3 ] = ( strokePerPsi * ( Math . Min ( nomPSI , ReferencePressurePSI ) - 50.0f ) ) + CylStrokeM ;
672+ airPV [ 3 ] = AdvancedBrakeCylinderAir ( Math . Min ( nomPSI , ReferencePressurePSI ) , true ) ;
673+
674+ cylTravel [ 4 ] = ( strokePerPsi * ( Math . Max ( nomPSI , ReferencePressurePSI ) - 50.0f ) ) + CylStrokeM ;
675+ airPV [ 4 ] = AdvancedBrakeCylinderAir ( Math . Max ( nomPSI , ReferencePressurePSI ) , true ) ;
676+
677+ CylTravelTab = new Interpolator ( airPV , cylTravel ) ;
629678
630- // Assumptions from PRR characteristic curve:
631- // pg 40: https://ia600906.us.archive.org/24/items/braketestsreport00penn/braketestsreport00penn.pdf
632- // Brake cylinder reaches rated travel at 50 psi
633- // Brake cylinder travel is 80% of nominal when pressure reaches the spring counter-pressure
634- // Other assumptions:
635- // Brake cylinder travel remains at 0 until reaching half the spring counter-pressure
636- // Brake cylinder travel is linear w.r.t. total air in the cylinder line, not entirely accurate but greatly simplifies code
637- float [ ] airPV = new float [ 5 ] ;
638- float [ ] cylTravel = new float [ 5 ] ;
639-
640- float nomPSI = 50.0f ;
641-
642- // Prevent interpolator error. Max cyl pressure and nominal pressure need to be slightly offset
643- if ( ReferencePressurePSI == nomPSI )
644- nomPSI -= 5.0f ;
645- // Prevent interpolator error. Spring pressure should never be this large
646- if ( BrakeCylinderSpringPressurePSI >= nomPSI )
647- BrakeCylinderSpringPressurePSI = nomPSI - 5.0f ;
648-
649- // 0 cylinder travel with 0 air in cylinder
650- cylTravel [ 0 ] = 0 ;
651- airPV [ 0 ] = AdvancedBrakeCylinderAir ( 0 , true ) ;
652- // 0 cylinder travel when pressure is insufficient to budge spring
653- cylTravel [ 1 ] = 0 ;
654- airPV [ 1 ] = AdvancedBrakeCylinderAir ( BrakeCylinderSpringPressurePSI / 2.0f , true ) ;
655- // 80% cylinder travel when spring pressure is fully overcome
656- cylTravel [ 2 ] = CylStrokeM * 0.8f ;
657- airPV [ 2 ] = AdvancedBrakeCylinderAir ( BrakeCylinderSpringPressurePSI , true ) ;
658- // 100% cylinder travel at 50 psi, with linear change in travel between 50 psi and max pressure
659- // This will work whether the max cylinder pressure is above or below 50 psi
660- float strokePerPsi = ( CylStrokeM - cylTravel [ 2 ] ) / ( 50.0f - BrakeCylinderSpringPressurePSI ) ;
661-
662- cylTravel [ 3 ] = ( strokePerPsi * ( Math . Min ( nomPSI , ReferencePressurePSI ) - 50.0f ) ) + CylStrokeM ;
663- airPV [ 3 ] = AdvancedBrakeCylinderAir ( Math . Min ( nomPSI , ReferencePressurePSI ) , true ) ;
664-
665- cylTravel [ 4 ] = ( strokePerPsi * ( Math . Max ( nomPSI , ReferencePressurePSI ) - 50.0f ) ) + CylStrokeM ;
666- airPV [ 4 ] = AdvancedBrakeCylinderAir ( Math . Max ( nomPSI , ReferencePressurePSI ) , true ) ;
667-
668- CylTravelTab = new Interpolator ( airPV , cylTravel ) ;
679+ }
669680 }
670681 if ( CylVolumeM3 <= 0 && AuxCylVolumeRatio > 0 )
671682 CylVolumeM3 = AuxResVolumeM3 / AuxCylVolumeRatio / CylCount ;
0 commit comments