SimpleSwitch
SimpleSwitch cross-fades between two sets of signals.8 minute read
SimpleSwitch cross-fades between two sets of signals. A boolean picks which
set you want and the output travels there over a configured time, in a straight
line or along a smooth cosine.
Use it to hand a machine over between two sources — two setpoint generators, two controllers, manual and automatic — without a step at the changeover.
flowchart LR
i1(["input1 — selected when toggle is false"]) --> B["SimpleSwitch"]
i2(["input2 — selected when toggle is true"]) --> B
i3(["toggle"]) --> B
i4(["doInstantToggle"]) --> B
B --> o1(["output"])
B --> o2(["isOn"])
B --> o3(["isOff"])
B --> o4(["faderValue"])
Fading in and fading out are configured separately — their own times and their own shapes. A switch can ease in gently over two seconds and drop back in a tenth of one.
The fade is on the mixing fraction, not on the signals. If
input1andinput2are both moving, the output is a blend of two moving signals, and its rate of change during the fade is not bounded by anything you set here. UseSoftSwitchwhen the output’s velocity and acceleration must stay within limits.
Signals
Inputs
| Path | Unit | Range | Description |
|---|---|---|---|
input1 |
signal unit | unbounded | The set selected when toggle is false. This is where the block starts. |
input2 |
signal unit | unbounded | The set selected when toggle is true. |
toggle |
- | true or false | Which input the output should travel to. A level, not a pulse — hold it. Flipping it back mid-fade reverses the fade from wherever it had got to. |
doInstantToggle |
- | true or false | While true, the output snaps to the selected input every cycle with no fade. Also a level: leave it true and the switch never fades again. |
Outputs
| Path | Unit | Description |
|---|---|---|
output |
signal unit | The blend. Same number of channels as the inputs. |
isOn |
- | The fade to input2 has completed. Goes true a few cycles before faderValue actually reaches 1. |
isOff |
- | The fade to input1 has completed. Starts true. |
faderValue |
- | How far through the fade, 0 at input1 and 1 at input2. This is the straight-line fraction even when the fade shape is cosine, so scaling another signal by it will not match this switch’s own shape. |
Parameters
| Path | Unit | Default | Range | Effect |
|---|---|---|---|---|
fadeInTime |
s | 5.0 | one task period to 10 | How long it takes to travel to input2. Values above 10 are silently reduced to 10, with a warning in the log. |
fadeOutTime |
s | 5.0 | one task period to 10 | How long it takes to travel back to input1. Same ceiling. |
fadeInType |
- | 0 | 0 or 1 | The shape of the fade to input2. 0 straight line, 1 cosine. |
fadeOutType |
- | 0 | 0 or 1 | The shape of the fade back to input1. |
timeScaleFactor |
- | 1.0 | 0 upward | Speeds up or slows down the fade while it runs. 0 freezes the switch mid-fade, which is a useful way to hold a handover. Reset to 1 every time the controller starts, so a saved value is not kept. |
All are persistent and survive a controller restart, except that
timeScaleFactor is forced back to 1 at startup. No parameters exist below
this block.
fadeInType / fadeOutType |
What the machine does | When to use it |
|---|---|---|
| 0 straight line | The output moves at a constant rate, then stops dead | Fast handovers, or when the signals are already smooth |
| 1 cosine | The output eases away from one input and eases into the other | Anywhere a step in rate would be felt. Same duration as the straight line — only the shape changes |
Setup
-
Connect the two signal sets to
input1andinput2. They must have the same number of channels. -
Leave
togglefalse. Confirmoutputmatchesinput1andisOffis true. -
Set
fadeInTimeandfadeOutTime. Start slow — a second or two. -
Set both shapes to 1 unless you have a reason not to. The cosine costs nothing and removes the rate step at each end.
-
Set
toggletrue and watchoutputtravel toinput2.Step 5 hands the machine over to whatever
input2is carrying. If the two inputs differ, the machine moves the difference over the fade time. Check whatinput2is holding before you flip the toggle. -
Confirm
isOngoes true andoutputmatchesinput2. -
Set
toggleback to false and confirm it travels back overfadeOutTime.
Tuning
- Trace both inputs together before switching. The size of the gap between them is the size of the motion the fade will produce.
- Set the fade time from that gap and what the machine can take: the average rate is the gap divided by the fade time.
- Use the cosine shape unless you need the shortest possible transit. It has the same duration but no rate step at either end, so the peak rate is higher in the middle and zero at both ends.
- Fade out is usually the more urgent direction. It is normal to set
fadeOutTimemuch shorter thanfadeInTime. - Watch
faderValueto see the fade progress. Remember it is the straight-line fraction, so with the cosine shape the output will lag it early and lead it late. - If a handover must be able to pause, use
timeScaleFactor. Setting it to 0 freezes the blend exactly where it is. - Fade times are in seconds, so a task-rate change does not move them — but the lower bound of one task period does change.
Both shapes arrive together. Only the way they get there differs.
| Symptom | Cause | Action |
|---|---|---|
| The machine moved when I flipped the toggle | Expected: the two inputs held different values | Match them before switching, or lengthen the fade |
| The output stepped instead of fading | doInstantToggle is true |
Set it false — it is a level, not a pulse |
| The fade is shorter than I asked for | fadeInTime above 10 is reduced to 10 |
Check the log; 10 seconds is the maximum |
| The fade time reads back as 10 | Same cause | Split the handover, or fade a scaling signal instead |
| The fade time reads back as a tiny number | A value below one task period was raised to it | Write a longer time |
| The fade is slower or faster than the time I set | timeScaleFactor is not 1 |
Set it to 1 |
timeScaleFactor reverted after a restart |
Expected: it is forced to 1 at startup | Set it from your application after start |
| The fade froze part-way | timeScaleFactor is 0 |
Set it above 0 |
| The switch stuck at one end and will not come back | timeScaleFactor is negative, which is not rejected |
Write a positive value |
| A rate step at the start or end of the fade | The straight-line shape does that | Set the type to 1 |
| The output jerked mid-fade | One of the inputs moved during the fade — the block does not limit that | Use SoftSwitch if the output’s rate must stay bounded |
| I reversed the toggle mid-fade and it went back from where it was | Expected, and usually what you want | Nothing |
isOn went true slightly early |
Expected: the completion test has a small tolerance | Watch faderValue for the exact end |
A signal scaled by faderValue does not match the fade |
Expected: faderValue is the straight-line fraction, not the shaped one |
Apply the same cosine yourself |
| The output is all zeros | An input is not connected — unconnected inputs read 0 | Check both |
| Everything became invalid and stayed that way | A fade time that is not a number is not caught by the range check | Rewrite the fade times |
A starting point for a handover between two setpoint sources:
fadeInTime = 2.0
fadeOutTime = 0.5
fadeInType = 1
fadeOutType = 1
timeScaleFactor = 1.0
Limits and errors
| Limit | Set by | What happens | Reported |
|---|---|---|---|
| Fade duration | fadeInTime, fadeOutTime |
The blend reaches the far end in exactly that time, divided by timeScaleFactor |
faderValue, isOn, isOff |
| Fade time range | Fixed at one task period to 10 s | Out-of-range values are clamped and written back | Logged as a warning, once per write |
| Output rate during a fade | Nothing | Not limited. The output’s rate is the gap between the inputs divided by the fade time, plus whatever the inputs are doing themselves | Not reported |
timeScaleFactor |
Nothing | Not checked. 0 freezes the fade; a negative value runs it backwards until it sticks at an end | Not reported |
timeScaleFactor persistence |
Fixed | Forced to 1 at every controller start, discarding a saved value | Not reported |
| Fade shape | fadeInType, fadeOutType |
Independent per direction. Both take the same time | Not reported |
faderValue |
Fixed | Always the unshaped fraction, whatever the shape in use | Not applicable |
doInstantToggle |
The input | A level. While true, every cycle snaps to the selected input | faderValue reads 0 or 1 |
| Values that are not numbers | Nothing | Not caught by the range check. A bad fade time makes the output invalid permanently | Not reported |
| Startup state | Fixed | The output starts on input1 and isOff starts true |
isOff |
| Channel count | Fixed at build time | Both inputs and the output share one channel count | Not reported |
The block logs a warning when a fade time is written outside its range. Every other condition above shows as a value on a trace, or not at all.
Verified against motorcortex-control3 3.30.0 (bc348fd).