Engineering approach-controlled signals is a bit difficult with the current formula-based animated object system, but not impossible. Please read the following things carefully.
Things you need to know first- StateFunction: Takes the value that is returned by the function, rounds it toward the nearest integer, and displays that state as defined by States.
- value: Returns the value the function last returned.
- delta: Returns the time since the last evaluation of the function in seconds.
The first important thing to build upon is the fact that StateFunction selects the state as obtained by rounding the function result toward the nearest integer. That is, if the function returns [0 ... 0.49], state 0 is selected. If the function returns [0.51 ... 1.49], state 1 is selected. If it returns [1.51 ... 2.49], state 2 is selected, and so on.
The next thing to build upon is that
value+delta acts as a counter. The variable
value is the last result. Add
delta to that, and you accumulate the elapsed time with every call in seconds.
Engineering approach-control for a two-aspect signalLet's start with a simple two-aspect signal. The states are 0 (red), and 1 (green). We can make use of the things presented above by starting to count from 0 (red). As soon as the counter reaches 0.51, state 1 would be selected (green), which means that it takes 0.5 seconds for the delay. We will start with this incomplete function as a building block:
if[trackDistance>DISTANCE | section==0, 0, value+delta]
Explanation: We want the signal to appear red whenever the track distance from the train to the signal is greater than
DISTANCE meters (substitute any value here). But, we also want it to appear red if the underlying section is red. Therefore, we just
or these two conditions together. If the condition is met, the function returns 0. It also means that if the condition is not met any longer, our counter would start counting from 0, which is what we want.
As soon as the condition is not met any longer, our counter would start counting, and as soon as it reaches 0.51, the green state would be displayed. There are still two problems: The most important problem is that the counter is unbounded. It would continue counting far beyond 1.49, which is the point up to which state 1 (green) would be displayed. As soon as the counter reached 1.51, state 2 would be displayed. If this state does not exist, no state would be displayed at all. We thus need to limit the reach of the counter (still incomplete):
if[trackDistance>DISTANCE | section==0, 0, min[value+delta, 1]]
Here, the
min function ensures that if
value+delta is indeed below 1, that value would take effect. If
value+delta was more than 1, then 1 would be returned. Note that you can use any value between 0.51 and 1.49 for this to work. I just used 1 here as I think it is more intuitive - because it lets us remember that we want to count up to 1, which is the state index for green.
The second problem is that up to now, we can only employ a delay of exactly 0.5 seconds. To change that, we need to count more slowly. If you want to employ a delay of
DELAY seconds, this formula would do the job:
if[trackDistance>DISTANCE | section==0, 0, min[value + 0.5*delta/DELAY, 1]]
This is the first working formula you can insert in your object. Just substitute
DELAY for the number of seconds you want the signal to remain red.
By the way, you can still employ a RefreshRate parameter to increase performance, but it will affect the precision of the delay you want to employ. In fact, the actual delay will be somewhere between
DELAY and
DELAY+RefreshRate. Generally, a RefreshRate of 1 second should be acceptable here.
What about three-aspect signals or more?Using the above code, you could easily subsitute the 1 in the
min function for a 2 or more, but this would mean that you get a transition from red to yellow, and then from yellow to green, instead of from red to the desired aspect directly. Therefore, we need to change our approach a bit. Keep in mind that until counting up to 0.49, the red state displays. After that, we simply jump to the desired state directly:
if[trackDistance>DISTANCE | section==0, 0, if[value<0.5, value + 0.5*value/DELAY, section]]
This also means that should the section change from yellow to green any any time later, the change would occur immediately - only the change from red to anything else but red is delayed. Of course, this code also works for two aspects.
However, please note that in the above code, I assume that
section equals the definition of the states, e.g. 0=red, 1=yellow, 2=green, or something like that. If you work with other values in your route, then you can either use null objects in the States definition, or change the
section variable appropriately.
For example, if you use 0=red, 2=yellow, 4=green, you would use
section/2. If you use anything more arbitrary, you could use if-conditions to select the correct state (or null objects).
Things to keep in mindWe have developed code to produce approach-control for a signal. Mind that a signal is the visual representation of a section. As we did not change the value of the section itself, but only that of the signal (the visual representation), an actually green section would only
appear red under the right conditions, but functionally would remain green. Therefore, you won't get any
Passed a red signal messages or get penalized when passing such a signal under the right conditions.
This is a minor compromise that you are likely willing to make as it only affects the transition phase, and because there are no current alternatives.