Rail3D*

   

 

Swiss Speed Signals



At junctions, the signal system used in Britain, which is the “default” around which Rail3D is built, does not explicitly tell drivers the permitted speed for the route they are being directed to. The driver sees “geographic” information about the route that has been set — junction “feathers”, sometimes supplemented by letter or number indicators — and uses knowledge of the route to decide whether a speed reduction is required.

In most other parts of the world, the signals leading up to junctions inform the driver about the maximum speed for the route that is set. This kind of signalling has been harder to model accurately in Rail3D, but with recent additions to signal scripting, and the possibility to set speed limits on individual links, it is now quite straightforward.

As an example, I’ve set up the Swiss “L”-type signal system (some of the first non-British custom signals to be made for Rail3D) to work with the new features.

1 Overview of the Swiss “L”-system

The Swiss “L”-system is a good example of speed-based signalling. As well as “Stop” and “Clear”, main signals can also use coloured lights to display three other proceed aspects (Fahrbegriffe), corresponding to maximum speeds as follows:

Fahrbegriff Lights Speed (km/hr)
- Red stop
1 Green clear
2 Green+Yellow 40
3 Green+Green 60
4 Green+Green+Green 90

(see Roland Smiderkal’s site for a complete description)

Distant signals, which can be either standalone signals or a separate head mounted on the main signal, can display corresponding warning aspects (“expect fb1″, “expect fb2″, etc.).


The main signal (upper head) shows fb3 (60km/hr); the distant head below it shows “expect fb4″ (90km/hr)

1.1 Typical signal sequence

Approaching a station, a driver would normally see:

  1. a standalone distant for the entry signal
  2. the entry signal, also carrying the distant for the exit signal on the same mast
  3. the exit signal (a main signal with no distant)

If a non-stop train were being routed through the straight track, all of these would show fb 1 (green).

If the train were routed into a loop track, the entry signal and its distant would show a more restrictive aspect, depending on the speed limit over the loop points. The driver would start braking after passing the distant, and would thus pass the entry signal at the correct speed. The aspect of the exit signal would reflect the speed limit at the loop exit, which is usually but not always the same as that at the entrance.

1.2 Common exit signal

At smaller stations, instead of having an exit signal for each track, a single exit signal is placed near the points at the station exit. Drivers know which track the signal applies to from the aspect it is showing (e.g. if it shows fb 1 it applies to the straight track; if it shows fb 3 it applies to the loop). A numbered sign can be placed near the end of the track to tell drivers they have permission to depart if that aspect is shown. Where two tracks have the same speed limit, it’s possible to use a Fahrtstellungsmelder that lights up on the track that has permission to depart, or there can be a rule that drivers have to await instructions from the stationmaster.

2 Modeling this in Rail3D

Since we now have the possibility to apply speed limits to individual links, and script functions that can detect these limits, it has become possible to automate the existing Swiss signal models so that they display the correct aspects automatically, corresponding to the speed limit for the route that is set.

Up to now, we have had a whole range of Swiss signal models with different names like 3J40, 3J90, etc. to correspond to the different speed indications. To build an entry signal capable of showing two or three different speed aspects for the main signal and another set of two or three for the distant was theoretically possible, but too tedious to bother with.

I’m now in the process of simplifying the signal set (the old names are kept for compatibility with existing layouts). Basically, there are three main models: distant (names with “2D”), main + distant (names with “3″), and main only (“2″). I will keep a few different sizes of head — for signals such as intermediate block signals that don’t need to be able to display any speed aspects, two lamps are enough. All the models use a common script.

2.1 What the script does

The script includes a set of procedures for setting the lamps for the different aspects. Every signal model in the L-series has the same numbering for the lamps (1–5 for the main head, 6–10 for the distant). By putting these into separate procedures, it should be easy to adapt the script to other signal systems.

The main business comes in the OnSetLamps() procedure. This checks the state of the signal and the next signal ahead. If a route is set from the signal, it gets the lowest speed limit in the section ahead of each of them (if no limit is set, the limit is read as zero). It translates the speed limit to the corresponding signal aspect, and displays it. Naturally, there are a few complications to deal with different possible combinations (what if the next signal is at stop?).

2.2 Setting it up on your layout

The script is embedded in the signal models: you don’t have to do anything special to get it to work, other than placing a few signals on your layout and setting speed limits for the diverging links.

2.3 Common exit signals

There are a number of different possible ways to set this up. For the moment, my preferred option is to use a “dummy” signal as the combined exit signal (this has a minimal state table that allows it to display a stop aspect when there is no route set, but does not include the usual script), and to “drive” it from a Fahrbegrifftafel on each track. The Fahrbegrifftafel doesn’t have any visible lamps or arms, but it does run the script, which recognises what it is and sets the relevant signal aspects on the common exit signal when a route is set from the Fahrbegrifftafel. Rail3D’s internal signal logic prevents more than one Fahrbegrifftafel setting an exit route at once, and the speed limits are detected correctly as long as they are between the Fahrbegrifftafel and the exit signal.

The Fahrbegrifftafel gives the driver permission to start when the exit signal shows fb4 (3x green).

3 Demo layout

There is a demonstration layout available from

http://www.markhodson.nl/rail3d/2kdlayouts/ch_speed_sig_demo.trp

This includes two four track stations, both arranged (slightly implausibly) so that each track has a different speed limit, so that you can see all the different signal aspects working. The northern station has common exit signals, the southern one has an exit signal for each track.

4 Appendix: the gory details

//Sets signal aspects according to speed limit
//Main head
//ID 1 green
//ID 2 yellow
//ID 3 red
//ID 4 yellow
//ID 5 green
//Distant
//ID 6 yellow   ID 7 yellow
//                      ID 8 green
//ID 10 green  ID 9 yellow

//IncludeScript "swiss_speed_sig.cpp"

Init()
{
	float vff=3.6; //3.6 converts km/hr to m/sec
	float vfb2=40/vff;
	float vfb3=60/vff;
	float vfb4=90/vff;
	float lim=40/vff;
	signal nextsig;
	signal setsig;
	string SigID="null";
	string nSigID="null";
	string SigType="null";
}

//Lamp setting procedures - main signal
SetStop()
{
	//red
	Signal.SetLamp(1,0,0,0,0);
	Signal.SetLamp(2,0,0,0,0);
	Signal.SetLamp(3,255,0,0,0);
	Signal.SetLamp(4,0,0,0,0);
	Signal.SetLamp(5,0,0,0,0);
	//debug.printL("Stop: "SigID);
}
SetFB1()
{
	//Fahrbegriff 1 - clear
	Signal.SetLamp(1,0,255,150,0);
	Signal.SetLamp(2,0,0,0,0);
	Signal.SetLamp(3,0,0,0,0);
	Signal.SetLamp(4,0,0,0,0);
	Signal.SetLamp(5,0,0,0,0);
	//debug.printL("Fahrbegriff 1 "SigID);
}
SetFB2()
{
	//Fahrbegriff 2 - 40 km/hr
	Signal.SetLamp(1,0,255,150,0);
	Signal.SetLamp(2,0,0,0,0);
	Signal.SetLamp(3,0,0,0,0);
	Signal.SetLamp(4,255,225,0,0);
	Signal.SetLamp(5,0,0,0,0);
	//debug.printL("Fahrbegriff 2 "SigID);
}
SetFB3()
{
	//Fahrbegriff 3 - 60 km/hr
	Signal.SetLamp(1,0,255,150,0);
	Signal.SetLamp(2,0,0,0,0);
	Signal.SetLamp(3,0,255,150,0);
	Signal.SetLamp(4,0,0,0,0);
	Signal.SetLamp(5,0,0,0,0);
	//debug.printL("Fahrbegriff 3 "SigID);
}
SetFB4()
{
	//Fahrbegriff 4 - 90 km/hr
	Signal.SetLamp(1,0,255,150,0);
	Signal.SetLamp(2,0,0,0,0);
	Signal.SetLamp(3,0,255,150,0);
	Signal.SetLamp(4,0,0,0,0);
	Signal.SetLamp(5,0,255,150,0);
	//debug.printL("Fahrbegriff 4 "SigID);
}

//Distant signal

SetCau()
{
	//Vorsignal - caution
	Signal.SetLamp(6,255,225,0,0);
	Signal.SetLamp(7,255,225,0,0);
	Signal.SetLamp(8,0,0,0,0);
	Signal.SetLamp(9,0,0,0,0);
	Signal.SetLamp(10,0,0,0,0);
}

SetdFB1()
{
	//Vorsignal Fahrbegriff 1 - clear
	Signal.SetLamp(6,0,0,0,0);
	Signal.SetLamp(7,0,0,0,0);
	Signal.SetLamp(8,0,255,150,0);
	Signal.SetLamp(9,0,0,0,0);
	Signal.SetLamp(10,0,255,150,0);
	//debug.printL("Fahrbegriff 1 "SigID);
}
SetdFB2()
{
	//VorsignalFahrbegriff 2 - 40 km/hr
	Signal.SetLamp(6,255,225,0,0);
	Signal.SetLamp(7,0,0,0,0);
	Signal.SetLamp(8,0,255,150,0);
	Signal.SetLamp(9,0,0,0,0);
	Signal.SetLamp(10,0,0,0,0);
	//debug.printL("Fahrbegriff 2 "SigID);
}
SetdFB3()
{
	//VorsignalFahrbegriff 3 - 60 km/hr
	Signal.SetLamp(6,255,225,0,0);
	Signal.SetLamp(7,0,0,0,0);
	Signal.SetLamp(8,0,255,150,0);
	Signal.SetLamp(9,0,0,0,0);
	Signal.SetLamp(10,0,255,150,0);
	//debug.printL("Fahrbegriff 3 "SigID);
}
SetdFB4()
{
	//VorsignalFahrbegriff 4 - 90 km/hr
	Signal.SetLamp(6,0,0,0,0);
	Signal.SetLamp(7,0,0,0,0);
	Signal.SetLamp(8,0,255,150,0);
	Signal.SetLamp(9,255,225,0,0);
	Signal.SetLamp(10,0,255,150,0);
	//debug.printL("Fahrbegriff 4 "SigID);
}
//Common exit signal
SetCFB1()
{
	//Fahrbegriff 1 - clear
	nextsig.SetLamp(1,0,255,150,0);
	nextsig.SetLamp(2,0,0,0,0);
	nextsig.SetLamp(3,0,0,0,0);
	nextsig.SetLamp(4,0,0,0,0);
	nextsig.SetLamp(5,0,0,0,0);
	//debug.printL("Fahrbegriff 1 "SigID);
}
SetCFB2()
{
	//Fahrbegriff 2 - 40 km/hr
	nextsig.SetLamp(1,0,255,150,0);
	nextsig.SetLamp(2,0,0,0,0);
	nextsig.SetLamp(3,0,0,0,0);
	nextsig.SetLamp(4,255,225,0,0);
	nextsig.SetLamp(5,0,0,0,0);
	//debug.printL("Fahrbegriff 2 "SigID);
}
SetCFB3()
{
	//Fahrbegriff 3 - 60 km/hr
	nextsig.SetLamp(1,0,255,150,0);
	nextsig.SetLamp(2,0,0,0,0);
	nextsig.SetLamp(3,0,255,150,0);
	nextsig.SetLamp(4,0,0,0,0);
	nextsig.SetLamp(5,0,0,0,0);
	//debug.printL("Fahrbegriff 3 "SigID);
}
SetCFB4()
{
	//Fahrbegriff 4 - 90 km/hr
	nextsig.SetLamp(1,0,255,150,0);
	nextsig.SetLamp(2,0,0,0,0);
	nextsig.SetLamp(3,0,255,150,0);
	nextsig.SetLamp(4,0,0,0,0);
	nextsig.SetLamp(5,0,255,150,0);
	//debug.printL("Fahrbegriff 4 "SigID);
}

// Main script

OnSetLamps()
{
	SigID=Signal.GetID();
	SigType=Signal.GetType();
	SigType=Left(SigType,10);
	//setsig=Signal;
	if(SigType=="CH_Ltype2D")
	{
		//it's a distant
		//debug.printL("Polling Distant "SigID);
		nextsig=Signal.NextSignal();
		if(nextsig)
		{
			nSigID=nextsig.GetID();
			//debug.printL("distant "SigID "Polling "nSigID);

			if(!nextsig.IsOn())
			{

				lim=nextsig.GetRouteLimit();
				//SigID=nextsig.GetID();
				//debug.printL(SigID" next Limit "lim);
				if((lim>0)&&(lim<=vfb2))
				{
					SetdFB2();
				}
					if((lim>vfb2)&&(lim<=vfb3))
				{
					SetdFB3();
				}
					if((lim>vfb3)&&(lim<=vfb4))
				{
					SetdFB4();
				}
					if((lim>vfb4)||(lim==0))
				{
					SetdFB1();
				}		
			}
			else
			{
				SetCau();
			}
		}
	}
	else
	{
		//it's a stop signal
		//debug.printL("Stopsig "SigID);
		if(Signal.IsHidden())
		{
			//setsig=Signal.NextSignal();
		}
		if(!Signal.IsOn())
		{
			lim=Signal.GetRouteLimit();
			nextsig=Signal.NextSignal();
			//debug.printL(SigID" Limit "lim);
			if((lim<=vfb2)&&(lim>0))
			{
				SetFB2();
				if(SigType=="CH_Gruppen")
				{
					SetCFB2();
				}
			}
				if((lim>vfb2)&&(lim<=vfb3))
			{
				SetFB3();
				if(SigType=="CH_Gruppen")
				{
					SetCFB3();
				}
			}
				if((lim>vfb3)&&(lim<=vfb4))
			{
				SetFB4();
				if(SigType=="CH_Gruppen")
				{
					SetCFB4();
				}
			}
				if((lim>vfb4)||(lim==0))
			{
				SetFB1();
				if(SigType=="CH_Gruppen")
				{
					SetCFB1();
				}
			}		
			//nextsig=Signal.NextSignal();
			if(nextsig)
			{
				nSigID=nextsig.GetID();
				//debug.printL("distant "SigID "Polling "nSigID);

				if(!nextsig.IsOn())
				{

					lim=nextsig.GetRouteLimit();
					//SigID=nextsig.GetID();
					//debug.printL(SigID" next Limit "lim);
					if((lim>0)&&(lim<=vfb2))
					{
						SetdFB2();
					}
						if((lim>vfb2)&&(lim<=vfb3))
					{
						SetdFB3();
					}
						if((lim>vfb3)&&(lim<=vfb4))
					{
						SetdFB4();
					}
						if((lim>vfb4)||(lim==0))
					{
						SetdFB1();
					}		
				}
				else
				{
					SetCau();
				}
			}

		}
		else
		{
			SetStop();
			SetCau();
		}
	}
}

Mark Hodson October 22, 2007, at 05:56 pm



import