ChannelSelector
ChannelSelector stores a set of values and fades its output between them as the selection changes.7 minute read
ChannelSelector stores a set of values and fades its output between them as
the selection changes. Pick a channel by number, or by raising its enable flag.
Use it to switch a gain, a speed limit or a mode setpoint between preset values without stepping the machine.
It switches between stored numbers, not between live signals. The values live in
channelValue, a persistent parameter array you configure. To blend two live signals, useSimpleSwitchinstead.
flowchart LR
i1(["channelEnable"]) --> B["ChannelSelector"]
i2(["timeScaleFactor"]) --> B
p1(["channelValue"]) --> B
p2(["useChannelNumberSelection"]) --> B
p3(["channelNumberSelection"]) --> B
p4(["defaultChannel"]) --> B
B --> o1(["output"])
B --> o2(["activeChannel"])
B --> o3(["faderValue"])
B --> o4(["channelPriority"])
channelPrioritydoes nothing. It is published, and it is filled in with a value per channel at startup, but the block never reads it. When you select by enable flags, the highest-numbered enabled channel wins — put the channel that should take precedence last.
Changing the selection mid-fade is safe. The block always fades from wherever the output currently is, so a change part-way through picks up cleanly with no step.
Signals
Inputs
| Path | Unit | Range | Description |
|---|---|---|---|
channelEnable |
- | true or false per channel | Which channels are available. The highest-numbered enabled channel is the one selected. Ignored when useChannelNumberSelection is true. Every flag is cleared at startup, so your application must rewrite them after each restart. |
timeScaleFactor |
- | above 0 | Speeds up or slows down the fade while it runs. 0 freezes it. Reset to 1 every time the controller starts. A negative value leaves the output stuck. |
Outputs
| Path | Unit | Description |
|---|---|---|
output |
signal unit | The single blended value. One output, whatever the channel count. |
activeChannel |
- | Which channel the output is heading for, counting from 0. |
faderValue |
- | How far through the fade, 0 at the departure value and 1 on arrival. The straight-line fraction even when the shape is cosine. |
channelPriority |
- | Published but not used by anything. See the callout above. |
Parameters
| Path | Unit | Default | Range | Effect |
|---|---|---|---|---|
channelValue |
signal unit | zeros | unbounded | The stored value for each channel. This is what the output fades to. Writable at run time. |
useChannelNumberSelection |
- | false | - | When true, the selection comes from channelNumberSelection and channelEnable is ignored. |
channelNumberSelection |
- | 0 | 0 to one below the channel count | Which channel to select, when the mode above is true. A value equal to the channel count is wrongly accepted and reads past the end of the value list — the output then becomes meaningless. Stay within range. |
defaultChannel |
- | 0 | 0 to one below the channel count | Which channel is enabled at startup. Not range-checked — a value outside the channel count corrupts memory before the first cycle. Set it carefully. |
fadeTime |
s | 5.0 | one task period to 10 | How long the output takes to reach a newly selected value. Above 10 is silently reduced to 10, with a warning in the log. |
fadeType |
- | 0 | 0 or 1 | 0 straight line, 1 cosine. Both take the same time. |
All are persistent and survive a controller restart. No parameters exist below this block.
Setup
-
Decide how many channels you need. The channel count is fixed when the controller is built and defaults to 2.
-
Write the value for each channel into
channelValue. -
Set
defaultChannelto the channel that should be active at startup. Check it is within the channel count — this one is not validated. -
Set
fadeTime. Start with a second or two. -
Choose a selection mode:
- By number — set
useChannelNumberSelectiontrue and writechannelNumberSelection. Simpler, and the mode that is fully validated. - By flags — leave it false and raise
channelEnableper channel, remembering the highest-numbered enabled channel wins.
- By number — set
-
Start the controller and confirm
activeChannelmatches what you asked for andoutputsettles on that channel’s value.The output is not stable until one fade time after startup. The block always starts a fade at start, even when the destination is the value it is already on. Do not act on
outputuntilfaderValuereaches 1. -
Change the selection and watch
outputtravel to the new value.
Tuning
- Trace
channelValueandoutputtogether. The gap between the current and next value is the size of the change the fade will produce. - Set
fadeTimefrom that gap and what the machine downstream can take. - Use the cosine shape unless you need the shortest transit — it has the same duration but no rate step at either end.
- Watch
activeChannelto confirm the selection is what you intended. With flag selection this is where a wrong assumption about priority shows up. - If you need to pause a change part-way, set
timeScaleFactorto 0. The blend freezes exactly where it is and resumes when you set it back. - Change the selection mid-fade freely — the block re-departs from wherever the output is.
fadeTimeis in seconds, so a task-rate change does not move it. ButtimeScaleFactorreturns to 1 after every restart.
The fade always starts from the output, never from the previous channel’s value.
| Symptom | Cause | Action |
|---|---|---|
| The wrong channel was selected | With flag selection the highest-numbered enabled channel wins, not the highest priority | Reorder your channels, or select by number |
Setting channelPriority changed nothing |
Expected: the block does not read it | Use channel order, or select by number |
| The output is nonsense and stays that way | channelNumberSelection equals the channel count, which reads past the end of the value list |
Use 0 to one below the count |
| The controller misbehaved from startup | defaultChannel is outside the channel count, which is not validated |
Set it within range |
| The output moved right after startup | Expected: the block always fades once at start | Wait for faderValue to reach 1 |
| The enable flags were cleared after a restart | Expected: all flags are cleared at startup | Rewrite them from your application |
| The fade is shorter than I asked for | A time above 10 is reduced to 10 | Check the log; 10 seconds is the maximum |
| A log warning mentions fade time, but I changed the channel number | The range check reuses the fade-time message | Check channelNumberSelection too |
| 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 output stuck and never arrives | timeScaleFactor is negative, which is not rejected |
Write a positive value |
| A rate step at the start or end of a fade | The straight-line shape does that | Set fadeType to 1 |
A signal scaled by faderValue does not match |
Expected: faderValue is the straight-line fraction |
Apply the same cosine yourself |
| I need to blend two live signals | This block switches stored values only | Use SimpleSwitch |
| I need more channels | The count is fixed when the controller is built | Rebuild, or use a second instance |
A starting point for a three-channel speed preset:
channelValue = [0.1, 0.5, 1.0]
useChannelNumberSelection = true
channelNumberSelection = 0
defaultChannel = 0
fadeTime = 1.0
fadeType = 1
Limits and errors
| Limit | Set by | What happens | Reported |
|---|---|---|---|
| Selection by flags | channelEnable |
The highest-numbered enabled channel wins. Priority is not consulted | activeChannel |
channelPriority |
Fixed | Published and never read. Setting it has no effect | Not applicable |
channelNumberSelection |
Partly checked | Clamped, but one too high — a value equal to the channel count is accepted and reads past the end of the value list | Logged, with the wrong message text |
defaultChannel |
Nothing | Not checked at all. A value outside the channel count writes outside the enable array at startup | Not reported |
| Fade duration | fadeTime |
The output reaches the selected value in that time, divided by timeScaleFactor |
faderValue |
| 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 |
| Departure point | Fixed | Every fade starts from the current output, so a mid-fade change is continuous | Not reported |
timeScaleFactor |
Nothing | Not checked. 0 freezes; negative leaves the output stuck short of the target | Not reported |
timeScaleFactor persistence |
Fixed | Forced to 1 at every controller start | Not reported |
| Startup | Fixed | Every enable flag is cleared, the default channel is enabled, and one fade always runs | faderValue |
| Values that are not numbers | Nothing | Not caught by the range checks | Not reported |
| Output count | Fixed | One output, whatever the channel count | Not reported |
| Channel count | Fixed at build time | Cannot be changed from the tree | Not reported |
The block logs a warning when the fade time or the channel number is written out of range — both using the fade-time wording. Every other condition above shows as a value on a trace, or not at all.
Verified against motorcortex-control3 3.30.0 (bc348fd).