<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title> – Switching and routing</title>
    <link>/docs/developing-control-applications/control-blocks/switching-and-routing/</link>
    <description>Recent content in Switching and routing on </description>
    <generator>Hugo -- gohugo.io</generator>
    
	  <atom:link href="/docs/developing-control-applications/control-blocks/switching-and-routing/index.xml" rel="self" type="application/rss+xml" />
    
    
      
        
      
    
    
    <item>
      <title>Docs: ChannelSelector</title>
      <link>/docs/developing-control-applications/control-blocks/switching-and-routing/channel-selector/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/switching-and-routing/channel-selector/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version&#34;&gt;
  &lt;span class=&#34;c3-version__control c3-version__control--static&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;span class=&#34;c3-version__value&#34;&gt;3.30–3.34&lt;/span&gt;
  &lt;/span&gt;

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

      </description>
    </item>
    
    <item>
      <title>Docs: ConfigurationSelector</title>
      <link>/docs/developing-control-applications/control-blocks/switching-and-routing/configuration-selector/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/switching-and-routing/configuration-selector/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version&#34;&gt;
  &lt;span class=&#34;c3-version__control c3-version__control--static&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;span class=&#34;c3-version__value&#34;&gt;3.30–3.34&lt;/span&gt;
  &lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;ConfigurationSelector&lt;/code&gt; holds up to &lt;strong&gt;five&lt;/strong&gt; matrices of the same size and
publishes whichever one you select. All five can be edited while the controller
runs, so a gain set, a transformation or a model&amp;rsquo;s coefficients can be changed
and switched without rebuilding.&lt;/p&gt;
&lt;p&gt;Set the matrix size to 1×1 and it becomes a five-way switch between single
numbers.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    p0([&amp;quot;configurationIndex&amp;quot;]) --&amp;gt; B[&amp;quot;ConfigurationSelector&amp;quot;]
    p1([&amp;quot;configuration0&amp;quot;]) --&amp;gt; B
    p2([&amp;quot;configuration1&amp;quot;]) --&amp;gt; B
    p3([&amp;quot;configuration2&amp;quot;]) --&amp;gt; B
    p4([&amp;quot;configuration3&amp;quot;]) --&amp;gt; B
    p5([&amp;quot;configuration4&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The switch is instantaneous.&lt;/strong&gt; The output steps to the new matrix on the
same cycle the index changes — there is no fade. That is usually what you
want for a set of coefficients, because a blend of two validated
configurations is a third one nobody validated. If the block downstream
cannot take a step, smooth it there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Matrices are stored one column at a time, not one row at a time.&lt;/strong&gt; For a
3×3, tree elements 0, 1, 2 are the &lt;strong&gt;first column&lt;/strong&gt;, not the first row. Fill
them in that order or you will get the transpose of the matrix you meant.
This catches nearly everyone once.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;An index above 4 silently selects &lt;code&gt;configuration0&lt;/code&gt;.&lt;/strong&gt; Nothing reports that
your request was rejected, so check &lt;code&gt;output&lt;/code&gt; matches what you expected.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;depends on use&lt;/td&gt;
&lt;td&gt;The selected matrix, published one column at a time. Updated every cycle, so an edit to the active configuration appears on the next one.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This block has &lt;strong&gt;no inputs.&lt;/strong&gt; The selection and all five matrices are
parameters, so everything about it is configured rather than driven.&lt;/p&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;configurationIndex&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0 to 4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Which configuration appears on the output. &lt;strong&gt;Anything above 4 silently selects &lt;code&gt;configuration0&lt;/code&gt;.&lt;/strong&gt; Persistent, so the controller comes back up on whichever configuration it was left on.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;configuration0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;depends on use&lt;/td&gt;
&lt;td&gt;zeros&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The matrix selected at index 0. &lt;strong&gt;Column-major&lt;/strong&gt; — see the callout above.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;configuration1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;depends on use&lt;/td&gt;
&lt;td&gt;zeros&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The matrix selected at index 1.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;configuration2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;depends on use&lt;/td&gt;
&lt;td&gt;zeros&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The matrix selected at index 2.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;configuration3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;depends on use&lt;/td&gt;
&lt;td&gt;zeros&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The matrix selected at index 3.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;configuration4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;depends on use&lt;/td&gt;
&lt;td&gt;zeros&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The matrix selected at index 4.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All are persistent and survive a controller restart. &lt;strong&gt;All five configurations
exist whether or not you use them&lt;/strong&gt;, and each is the full matrix size, so an
unused configuration still occupies its place in the tree. &lt;strong&gt;No parameters
exist below this block.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The matrix size is fixed when the controller is built and cannot be changed
from the tree.&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Work out the storage order for your matrix size before you write anything.
For a 3×3, the nine values run down the first column, then the second, then
the third.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Write your first matrix into &lt;code&gt;configuration0&lt;/code&gt; in that order.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Read &lt;code&gt;output&lt;/code&gt; back and confirm it matches. &lt;strong&gt;If it looks like the transpose
of what you typed, you filled it row by row&lt;/strong&gt; — refill it column by column.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fill the other configurations you need. Leave the rest at zero.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;configurationIndex&lt;/code&gt; and confirm &lt;code&gt;output&lt;/code&gt; changes to the matching
matrix.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Confirm the index survives a controller restart, and that the output comes
back on the right configuration.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Whatever consumes &lt;code&gt;output&lt;/code&gt; will act on the new values immediately&lt;/strong&gt; when
you change the index — there is no fade. If that is a controller gain, the
machine&amp;rsquo;s behaviour changes on that cycle.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;There is nothing to tune in this block itself. The tuning lives in the
matrices you put in it and in whatever consumes them.&lt;/li&gt;
&lt;li&gt;Use it to hold alternative tunings side by side: a cautious set in
&lt;code&gt;configuration0&lt;/code&gt;, a production set in &lt;code&gt;configuration1&lt;/code&gt;, a diagnostic set in
&lt;code&gt;configuration2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Keep &lt;code&gt;configuration0&lt;/code&gt; as your safe fallback. It is what you get when the
index is out of range, so it is the one that must always be sane.&lt;/li&gt;
&lt;li&gt;Edit a configuration while the controller runs and the change reaches
&lt;code&gt;output&lt;/code&gt; on the next cycle — including the one currently selected. &lt;strong&gt;Editing
the active configuration changes the machine&amp;rsquo;s behaviour immediately&lt;/strong&gt;, one
element at a time as you type them. Edit an inactive one and switch to it
instead.&lt;/li&gt;
&lt;li&gt;Verify each configuration by selecting it and reading &lt;code&gt;output&lt;/code&gt; back, rather
than trusting what you wrote.&lt;/li&gt;
&lt;li&gt;Nothing here depends on the task rate, so none of this needs re-checking
after a rate change.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/configuration-selector-step-8f82ec3b.svg&#34; alt=&#34;One entry of the selected matrix as the index changes. This block stepsstraight to the new value on the same cycle; a faded switch, shown forcomparison, would take time to getthere.&#34;&gt;&lt;/p&gt;
&lt;p&gt;The step is the point. Smooth it downstream if you need it smoothed.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;The matrix came back transposed&lt;/td&gt;
&lt;td&gt;It was filled row by row; storage is column by column&lt;/td&gt;
&lt;td&gt;Refill it column by column&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output does not match any configuration I set&lt;/td&gt;
&lt;td&gt;The index is above 4, so &lt;code&gt;configuration0&lt;/code&gt; is selected&lt;/td&gt;
&lt;td&gt;Use 0 to 4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Changing the index did nothing&lt;/td&gt;
&lt;td&gt;The two configurations hold the same values, or the index is out of range both times&lt;/td&gt;
&lt;td&gt;Read &lt;code&gt;output&lt;/code&gt; back to see which is active&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The machine&amp;rsquo;s behaviour changed while I was typing values&lt;/td&gt;
&lt;td&gt;Expected: edits to the &lt;strong&gt;active&lt;/strong&gt; configuration reach the output immediately&lt;/td&gt;
&lt;td&gt;Edit an inactive configuration, then switch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The machine stepped when I changed the index&lt;/td&gt;
&lt;td&gt;Expected: this block does not fade&lt;/td&gt;
&lt;td&gt;Smooth it in the block downstream&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output was zeros at startup&lt;/td&gt;
&lt;td&gt;The selected configuration is still all zeros&lt;/td&gt;
&lt;td&gt;Fill it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A configuration I never use is cluttering the tree&lt;/td&gt;
&lt;td&gt;Expected: all five always exist&lt;/td&gt;
&lt;td&gt;Leave them at zero&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The index reverted to something I did not set&lt;/td&gt;
&lt;td&gt;It is persistent — it came back from the saved configuration&lt;/td&gt;
&lt;td&gt;Set and save it deliberately&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I need more than five&lt;/td&gt;
&lt;td&gt;Not possible — five is fixed when the controller is built&lt;/td&gt;
&lt;td&gt;Use a second instance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I need a different matrix size&lt;/td&gt;
&lt;td&gt;Fixed when the controller is built&lt;/td&gt;
&lt;td&gt;Rebuild&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I need to fade between two configurations&lt;/td&gt;
&lt;td&gt;Not possible here, and usually not wise&lt;/td&gt;
&lt;td&gt;Put a switch downstream of this block&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for a 3×3 used to hold two gain sets:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;configuration0 = &amp;lt;the cautious set, column by column&amp;gt;
configuration1 = &amp;lt;the production set, column by column&amp;gt;
configurationIndex = 0
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;configurationIndex&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Checked&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Anything above 4 selects &lt;code&gt;configuration0&lt;/code&gt;.&lt;/strong&gt; The block never reads outside its configurations&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not reported&lt;/strong&gt; — the fallback is silent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage order&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Every matrix, including &lt;code&gt;output&lt;/code&gt;, is laid out &lt;strong&gt;one column at a time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Switching&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Instantaneous.&lt;/strong&gt; The output steps on the same cycle the index changes&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configuration edits&lt;/td&gt;
&lt;td&gt;The tree&lt;/td&gt;
&lt;td&gt;Reach &lt;code&gt;output&lt;/code&gt; on the next cycle, including for the currently selected configuration&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configuration count&lt;/td&gt;
&lt;td&gt;Fixed at &lt;strong&gt;five&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cannot be extended from the tree&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Matrix size&lt;/td&gt;
&lt;td&gt;Fixed at build time&lt;/td&gt;
&lt;td&gt;All five configurations and the output share one size&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Values that are not numbers&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not checked. A bad value in the selected configuration is copied to the output&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Startup&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;The output is set from the saved index &lt;strong&gt;before the first cycle runs&lt;/strong&gt;, so it is never briefly zero&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Values&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No range checking of any kind. The matrices mean whatever the block downstream makes of them&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This block &lt;strong&gt;logs nothing, ever&lt;/strong&gt;. Every condition above shows as a value on a
trace, or not at all.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.30.0 (bc348fd).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: SimpleSwitch</title>
      <link>/docs/developing-control-applications/control-blocks/switching-and-routing/simple-switch/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/switching-and-routing/simple-switch/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version&#34;&gt;
  &lt;span class=&#34;c3-version__control c3-version__control--static&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;span class=&#34;c3-version__value&#34;&gt;3.30–3.34&lt;/span&gt;
  &lt;/span&gt;

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

      </description>
    </item>
    
    <item>
      <title>Docs: SimpleSwitch3D</title>
      <link>/docs/developing-control-applications/control-blocks/switching-and-routing/simple-switch-3d/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/switching-and-routing/simple-switch-3d/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version&#34;&gt;
  &lt;span class=&#34;c3-version__control c3-version__control--static&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;span class=&#34;c3-version__value&#34;&gt;3.30–3.34&lt;/span&gt;
  &lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;SimpleSwitch3D&lt;/code&gt; cross-fades between two sets of signals &lt;strong&gt;and their first and
second derivatives&lt;/strong&gt;. A boolean picks which set you want and all three levels
travel there together over a configured time.&lt;/p&gt;
&lt;p&gt;Use it where a feedforward path downstream needs position, velocity and
acceleration together, and the source of all three has to change.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The 3D in the name means &lt;strong&gt;three derivative levels&lt;/strong&gt;, not three axes. The
channel count is set when the controller is built and defaults to one, the
same as &lt;code&gt;SimpleSwitch&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;input1, input1Dot, input1DDot&amp;quot;]) --&amp;gt; B[&amp;quot;SimpleSwitch3D&amp;quot;]
    i2([&amp;quot;input2, input2Dot, input2DDot&amp;quot;]) --&amp;gt; B
    i3([&amp;quot;toggle&amp;quot;]) --&amp;gt; B
    i4([&amp;quot;doInstantToggle&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output, outputDot, outputDDot&amp;quot;])
    B --&amp;gt; o2([&amp;quot;isOn&amp;quot;])
    B --&amp;gt; o3([&amp;quot;isOff&amp;quot;])
    B --&amp;gt; o4([&amp;quot;faderValue&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;During a fade, &lt;code&gt;outputDot&lt;/code&gt; is not the rate of change of &lt;code&gt;output&lt;/code&gt;.&lt;/strong&gt; All
three levels are blended with the same fraction, which leaves out the part of
the derivative that comes from the blend itself moving. The error is zero
before and after the fade, largest in the middle, and grows with the gap
between the two sources. The figure under Tuning shows the size of it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do not feed &lt;code&gt;outputDot&lt;/code&gt; to anything that must agree with &lt;code&gt;output&lt;/code&gt; during a
handover.&lt;/strong&gt; Differentiate &lt;code&gt;output&lt;/code&gt; yourself, or keep the two sources close
together while you switch.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Fading in and fading out are configured separately&lt;/strong&gt; — their own times and
their own shapes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The value selected when &lt;code&gt;toggle&lt;/code&gt; is false. This is where the block starts.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input1Dot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Its rate of change. &lt;strong&gt;You supply this&lt;/strong&gt; — the block does not compute it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input1DDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second²&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Its acceleration. Also supplied by you.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The value selected when &lt;code&gt;toggle&lt;/code&gt; is true.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input2Dot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Its rate of change.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input2DDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second²&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Its acceleration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;toggle&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true or false&lt;/td&gt;
&lt;td&gt;Which input set the output should travel to. A &lt;strong&gt;level&lt;/strong&gt;, not a pulse. Flipping it back mid-fade reverses from wherever it had got to.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;doInstantToggle&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true or false&lt;/td&gt;
&lt;td&gt;While true, all three outputs &lt;strong&gt;snap&lt;/strong&gt; to the selected set every cycle with no fade. Also a &lt;strong&gt;level&lt;/strong&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Nothing checks that the derivative inputs really are the derivatives of the
value inputs. If you wire them inconsistently you get a consistent blend of
inconsistent data.&lt;/p&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;The blended value.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second&lt;/td&gt;
&lt;td&gt;The blended rate. &lt;strong&gt;Not the rate of change of &lt;code&gt;output&lt;/code&gt; during a fade&lt;/strong&gt; — see the callout above.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second²&lt;/td&gt;
&lt;td&gt;The blended acceleration. Same caveat, larger.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isOn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;The fade to &lt;code&gt;input2&lt;/code&gt; has completed. Goes true a few cycles early.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isOff&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;The fade to &lt;code&gt;input1&lt;/code&gt; has completed. &lt;strong&gt;Starts true.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;faderValue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;How far through the fade, 0 to 1. &lt;strong&gt;The straight-line fraction even when the shape is cosine.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fadeInTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;one task period to &lt;strong&gt;10&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;How long it takes to travel to &lt;code&gt;input2&lt;/code&gt;. &lt;strong&gt;Values above 10 are silently reduced to 10&lt;/strong&gt;, with a warning in the log.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fadeOutTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;one task period to &lt;strong&gt;10&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;How long it takes to travel back. Same ceiling.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fadeInType&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0 or 1&lt;/td&gt;
&lt;td&gt;Shape of the fade to &lt;code&gt;input2&lt;/code&gt;. 0 straight line, 1 cosine.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fadeOutType&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0 or 1&lt;/td&gt;
&lt;td&gt;Shape of the fade back to &lt;code&gt;input1&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;1.0&lt;/td&gt;
&lt;td&gt;0 upward&lt;/td&gt;
&lt;td&gt;Speeds up or slows down the fade while it runs. 0 &lt;strong&gt;freezes&lt;/strong&gt; it. &lt;strong&gt;Reset to 1 every time the controller starts.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All are persistent and survive a controller restart, &lt;strong&gt;except that
&lt;code&gt;timeScaleFactor&lt;/code&gt; is forced back to 1 at startup&lt;/strong&gt;. &lt;strong&gt;No parameters exist below
this block.&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;fadeInType&lt;/code&gt; / &lt;code&gt;fadeOutType&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;What the machine does&lt;/th&gt;
&lt;th&gt;Effect on the derivative error&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt; straight line&lt;/td&gt;
&lt;td&gt;Constant blend rate, stopping dead at each end&lt;/td&gt;
&lt;td&gt;The error is constant through the fade and steps at both ends&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt; cosine&lt;/td&gt;
&lt;td&gt;The blend eases away from one set and into the other&lt;/td&gt;
&lt;td&gt;The error is zero at both ends and peaks in the middle. &lt;strong&gt;Larger at its peak&lt;/strong&gt; than the straight line, but smooth&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Connect both sets of three signals. All six must have the same number of
channels.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Leave &lt;code&gt;toggle&lt;/code&gt; false. Confirm &lt;code&gt;output&lt;/code&gt; matches &lt;code&gt;input1&lt;/code&gt; and &lt;code&gt;isOff&lt;/code&gt; is true.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;fadeInTime&lt;/code&gt; and &lt;code&gt;fadeOutTime&lt;/code&gt;. Start with a second or two.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set both shapes to 1 unless you need the shortest transit.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Bring the two sources close together before switching — this both reduces
the motion and reduces the derivative error to nearly nothing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;toggle&lt;/code&gt; true and watch all three outputs travel to the &lt;code&gt;input2&lt;/code&gt; set.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 6 hands the machine over to whatever &lt;code&gt;input2&lt;/code&gt; is carrying&lt;/strong&gt;, and
the derivative outputs will be wrong for the duration of the fade. If
anything downstream acts on &lt;code&gt;outputDot&lt;/code&gt;, check the size of the gap first.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Confirm &lt;code&gt;isOn&lt;/code&gt; goes true and the outputs match the &lt;code&gt;input2&lt;/code&gt; set.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Trace both value inputs together before switching. &lt;strong&gt;The gap between them
drives both the motion and the derivative error.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Close that gap before switching wherever you can. A handover between two
sources that already agree is nearly free.&lt;/li&gt;
&lt;li&gt;Set the fade time from the gap and what the machine can take.&lt;/li&gt;
&lt;li&gt;Lengthen the fade to reduce the derivative error: the error is proportional
to the gap divided by the fade time, so doubling the time halves it.&lt;/li&gt;
&lt;li&gt;Use the cosine shape for a smooth blend, the straight line if you would
rather the error be constant and predictable than smooth.&lt;/li&gt;
&lt;li&gt;Watch &lt;code&gt;faderValue&lt;/code&gt; for the fade progress. With the cosine shape the outputs
lag it early and lead it late.&lt;/li&gt;
&lt;li&gt;Fade times are in seconds, so a task-rate change does not move them.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/simple-switch-3d-derivative-a567437d.svg&#34; alt=&#34;During a cosine fade between two sources held still, the published outputDotstays at zero while the output is visibly moving. The true rate of change peaksin the middle of the fade; the published value never leaveszero.&#34;&gt;&lt;/p&gt;
&lt;p&gt;With both sources standing still the whole of &lt;code&gt;outputDot&lt;/code&gt; is missing. In
general the shortfall is the gap between the sources times the blend&amp;rsquo;s own
rate.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A feedforward path fought the machine during a handover&lt;/td&gt;
&lt;td&gt;&lt;code&gt;outputDot&lt;/code&gt; did not match &lt;code&gt;output&lt;/code&gt; during the fade&lt;/td&gt;
&lt;td&gt;Differentiate &lt;code&gt;output&lt;/code&gt; yourself, or close the gap before switching&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDot&lt;/code&gt; read zero while &lt;code&gt;output&lt;/code&gt; was moving&lt;/td&gt;
&lt;td&gt;Expected: both sources were still, so the whole derivative is the blend&amp;rsquo;s own motion, which is not published&lt;/td&gt;
&lt;td&gt;See the callout at the top&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The derivative error is worse than I expected&lt;/td&gt;
&lt;td&gt;The gap is large or the fade is short&lt;/td&gt;
&lt;td&gt;Close the gap, or lengthen the fade&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDDot&lt;/code&gt; is further out than &lt;code&gt;outputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Expected: the second derivative is missing two terms, not one&lt;/td&gt;
&lt;td&gt;Same actions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The machine moved when I flipped the toggle&lt;/td&gt;
&lt;td&gt;Expected: the two value inputs held different values&lt;/td&gt;
&lt;td&gt;Match them first, or lengthen the fade&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The outputs stepped instead of fading&lt;/td&gt;
&lt;td&gt;&lt;code&gt;doInstantToggle&lt;/code&gt; is true&lt;/td&gt;
&lt;td&gt;Set it false — it is a level, not a pulse&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The fade is shorter than I asked for&lt;/td&gt;
&lt;td&gt;A time above 10 is reduced to 10&lt;/td&gt;
&lt;td&gt;Check the log; 10 seconds is the maximum&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The fade time reads back as a tiny number&lt;/td&gt;
&lt;td&gt;A value below one task period was raised to it&lt;/td&gt;
&lt;td&gt;Write a longer time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The fade is slower or faster than the time I set&lt;/td&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactor&lt;/code&gt; is not 1&lt;/td&gt;
&lt;td&gt;Set it to 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactor&lt;/code&gt; reverted after a restart&lt;/td&gt;
&lt;td&gt;Expected: it is forced to 1 at startup&lt;/td&gt;
&lt;td&gt;Set it from your application after start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The fade froze part-way&lt;/td&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactor&lt;/code&gt; is 0&lt;/td&gt;
&lt;td&gt;Set it above 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The switch stuck at one end&lt;/td&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactor&lt;/code&gt; is negative, which is not rejected&lt;/td&gt;
&lt;td&gt;Write a positive value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The switch never fades at all&lt;/td&gt;
&lt;td&gt;The task period read as zero at startup, which is not guarded here&lt;/td&gt;
&lt;td&gt;Restart the controller&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A rate step at the start or end&lt;/td&gt;
&lt;td&gt;The straight-line shape does that&lt;/td&gt;
&lt;td&gt;Set the type to 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isOn&lt;/code&gt; went true slightly early&lt;/td&gt;
&lt;td&gt;Expected: the completion test has a small tolerance&lt;/td&gt;
&lt;td&gt;Watch &lt;code&gt;faderValue&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A signal scaled by &lt;code&gt;faderValue&lt;/code&gt; does not match&lt;/td&gt;
&lt;td&gt;Expected: it is the straight-line fraction&lt;/td&gt;
&lt;td&gt;Apply the same cosine yourself&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The derivative outputs never made sense&lt;/td&gt;
&lt;td&gt;The derivative inputs may not be the derivatives of the value inputs&lt;/td&gt;
&lt;td&gt;Nothing checks this — verify upstream&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Everything became invalid and stayed that way&lt;/td&gt;
&lt;td&gt;A fade time that is not a number is not caught&lt;/td&gt;
&lt;td&gt;Rewrite the fade times&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for a handover between two profile sources:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;fadeInTime      = 2.0
fadeOutTime     = 0.5
fadeInType      = 1
fadeOutType     = 1
timeScaleFactor = 1.0
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Derivative consistency&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;outputDot&lt;/code&gt; and &lt;code&gt;outputDDot&lt;/code&gt; do not match &lt;code&gt;output&lt;/code&gt; during a fade.&lt;/strong&gt; The shortfall is zero at both ends and peaks in the middle, proportional to the gap between the sources&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not reported at all&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Derivative inputs&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not checked against the value inputs. Inconsistent inputs blend consistently&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fade duration&lt;/td&gt;
&lt;td&gt;&lt;code&gt;fadeInTime&lt;/code&gt;, &lt;code&gt;fadeOutTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All three levels reach the far end in exactly that time, divided by &lt;code&gt;timeScaleFactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;faderValue&lt;/code&gt;, &lt;code&gt;isOn&lt;/code&gt;, &lt;code&gt;isOff&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fade time range&lt;/td&gt;
&lt;td&gt;Fixed at &lt;strong&gt;one task period to 10 s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Out-of-range values are &lt;strong&gt;clamped and written back&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Logged as a warning&lt;/strong&gt;, once per write&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output rate during a fade&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not limited.&lt;/strong&gt; Use &lt;code&gt;SoftSwitch&lt;/code&gt; when the output&amp;rsquo;s derivatives must stay within limits&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not checked. 0 freezes; negative runs the fade backwards until it sticks&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactor&lt;/code&gt; persistence&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Forced to 1 at every controller start&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Task period&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not guarded here&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A zero task period leaves the fade frozen. &lt;code&gt;SimpleSwitch&lt;/code&gt; guards this; this block does not&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;faderValue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Always the &lt;strong&gt;unshaped&lt;/strong&gt; fraction&lt;/td&gt;
&lt;td&gt;Not applicable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;doInstantToggle&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The input&lt;/td&gt;
&lt;td&gt;A &lt;strong&gt;level&lt;/strong&gt;. While true, every cycle snaps&lt;/td&gt;
&lt;td&gt;&lt;code&gt;faderValue&lt;/code&gt; reads 0 or 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Values that are not numbers&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not caught by the range check&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Startup state&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;All three outputs start on the &lt;code&gt;input1&lt;/code&gt; set; &lt;code&gt;isOff&lt;/code&gt; starts true&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isOff&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel count&lt;/td&gt;
&lt;td&gt;Fixed at build time&lt;/td&gt;
&lt;td&gt;All six inputs and three outputs share one channel count&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.30.0 (bc348fd).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: SoftSwitch</title>
      <link>/docs/developing-control-applications/control-blocks/switching-and-routing/soft-switch/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/switching-and-routing/soft-switch/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version&#34;&gt;
  &lt;span class=&#34;c3-version__control c3-version__control--static&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;span class=&#34;c3-version__value&#34;&gt;3.30–3.34&lt;/span&gt;
  &lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;SoftSwitch&lt;/code&gt; cross-fades between two sets of signals &lt;strong&gt;and their first and
second derivatives&lt;/strong&gt;, and can work out its own fade time from velocity,
acceleration and jerk limits instead of taking a duration.&lt;/p&gt;
&lt;p&gt;Use it for a handover where the output&amp;rsquo;s derivatives matter — where a
feedforward path or a compliance model is consuming them, and a fade that
respects a speed limit is worth more than a fade of a fixed length.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;input1, input1Dot, input1DDot&amp;quot;]) --&amp;gt; B[&amp;quot;SoftSwitch&amp;quot;]
    i2([&amp;quot;input2, input2Dot, input2DDot&amp;quot;]) --&amp;gt; B
    i3([&amp;quot;toggle&amp;quot;]) --&amp;gt; B
    i4([&amp;quot;doInstantToggle&amp;quot;]) --&amp;gt; B
    i5([&amp;quot;timeScaleFactor&amp;quot;]) --&amp;gt; B
    i6([&amp;quot;timeScaleFactorDot&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output, outputDot, outputDDot&amp;quot;])
    B --&amp;gt; o2([&amp;quot;isOn&amp;quot;])
    B --&amp;gt; o3([&amp;quot;isOff&amp;quot;])
    B --&amp;gt; o4([&amp;quot;isDone&amp;quot;])
    B --&amp;gt; o5([&amp;quot;faderValue&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The derivatives are correct here.&lt;/strong&gt; &lt;code&gt;outputDot&lt;/code&gt; really is the rate of
change of &lt;code&gt;output&lt;/code&gt;, right through the fade, including the part that comes
from the blend itself moving. &lt;code&gt;SimpleSwitch3D&lt;/code&gt; does not do this — if you need
derivatives you can trust during a handover, this is the block.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Two ways to set the timing.&lt;/strong&gt; With &lt;code&gt;maxConstraintsEnable&lt;/code&gt; false you give a
duration. With it true you give velocity, acceleration and jerk limits and
the block computes the duration so the &lt;strong&gt;output&lt;/strong&gt; respects them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;In limit mode, the timing is worked out at the moment you flip the
toggle&lt;/strong&gt;, from the gap between the inputs at that instant. If the inputs move
apart afterwards, the limits will be exceeded.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The set selected when &lt;code&gt;toggle&lt;/code&gt; is false. Where the block starts.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input1Dot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Its rate of change. &lt;strong&gt;You supply this&lt;/strong&gt;; it is used to make &lt;code&gt;outputDot&lt;/code&gt; correct.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input1DDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second²&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Its acceleration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The set selected when &lt;code&gt;toggle&lt;/code&gt; is true.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input2Dot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Its rate of change.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input2DDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second²&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Its acceleration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;toggle&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true or false&lt;/td&gt;
&lt;td&gt;Which set the output travels to. A &lt;strong&gt;level&lt;/strong&gt;, not a pulse. Flipping it back mid-fade reverses smoothly, with no step in any derivative.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;doInstantToggle&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true or false&lt;/td&gt;
&lt;td&gt;While true, all three outputs &lt;strong&gt;snap&lt;/strong&gt; to the selected set. A &lt;strong&gt;level&lt;/strong&gt; — leave it true and the block never fades again.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;any&lt;/td&gt;
&lt;td&gt;Stretches the fade&amp;rsquo;s clock. 0 &lt;strong&gt;freezes&lt;/strong&gt; it with nothing lost. A negative value is used as its magnitude; the fade does not run backwards.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactorDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1/s&lt;/td&gt;
&lt;td&gt;any&lt;/td&gt;
&lt;td&gt;How fast &lt;code&gt;timeScaleFactor&lt;/code&gt; is itself changing. &lt;strong&gt;Set this whenever you ramp the scale factor&lt;/strong&gt;, or &lt;code&gt;outputDDot&lt;/code&gt; will be wrong.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;If the derivative inputs are not really the derivatives of the value inputs,
the outputs will be a consistent blend of inconsistent data. Nothing checks
this.&lt;/p&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;The blended value.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second&lt;/td&gt;
&lt;td&gt;Its true rate of change, including the blend&amp;rsquo;s own contribution.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second²&lt;/td&gt;
&lt;td&gt;Its true acceleration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isOn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;The fade to &lt;code&gt;input2&lt;/code&gt; is &lt;strong&gt;complete&lt;/strong&gt;. Not just started.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isOff&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;The fade to &lt;code&gt;input1&lt;/code&gt; is complete. &lt;strong&gt;Starts true.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isDone&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;No fade is in progress, in either direction.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;faderValue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;How far through the fade, 0 at &lt;code&gt;input1&lt;/code&gt; and 1 at &lt;code&gt;input2&lt;/code&gt;. &lt;strong&gt;This is the shaped fraction&lt;/strong&gt;, so scaling another signal by it matches this switch&amp;rsquo;s own profile.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxConstraintsEnable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;false&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;False: the fade takes &lt;code&gt;fadeInTime&lt;/code&gt; or &lt;code&gt;fadeOutTime&lt;/code&gt;. True: the duration is derived from the limit parameters below.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;switchType&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0 or 1&lt;/td&gt;
&lt;td&gt;0 quintic, 1 jerk-limited. See the table below. &lt;strong&gt;Changing it during a fade produces a kink&lt;/strong&gt; — change it only when &lt;code&gt;isDone&lt;/code&gt; is true.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fadeInTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;Fade duration to &lt;code&gt;input2&lt;/code&gt;, when limits are off. A value under one task period makes the switch snap.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fadeOutTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;Fade duration back to &lt;code&gt;input1&lt;/code&gt;, when limits are off.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;delayBeforeFadeIn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;0 upward&lt;/td&gt;
&lt;td&gt;Wait before a fade to &lt;code&gt;input2&lt;/code&gt; starts. Applies in &lt;strong&gt;both&lt;/strong&gt; timing modes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;delayBeforeFadeOut&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;0 upward&lt;/td&gt;
&lt;td&gt;Wait before a fade back starts.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fadeInMaxVel&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second&lt;/td&gt;
&lt;td&gt;zeros&lt;/td&gt;
&lt;td&gt;0 upward&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Per channel.&lt;/strong&gt; The most the output may move per second while fading in. &lt;strong&gt;0 means this limit is not applied.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fadeInMaxAcc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second²&lt;/td&gt;
&lt;td&gt;zeros&lt;/td&gt;
&lt;td&gt;0 upward&lt;/td&gt;
&lt;td&gt;Per channel. 0 means not applied.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fadeInMaxJerk&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second³&lt;/td&gt;
&lt;td&gt;zeros&lt;/td&gt;
&lt;td&gt;0 upward&lt;/td&gt;
&lt;td&gt;Per channel. 0 means not applied.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fadeOutMaxVel&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second&lt;/td&gt;
&lt;td&gt;zeros&lt;/td&gt;
&lt;td&gt;0 upward&lt;/td&gt;
&lt;td&gt;Per channel, for the fade back.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fadeOutMaxAcc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second²&lt;/td&gt;
&lt;td&gt;zeros&lt;/td&gt;
&lt;td&gt;0 upward&lt;/td&gt;
&lt;td&gt;Per channel.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fadeOutMaxJerk&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second³&lt;/td&gt;
&lt;td&gt;zeros&lt;/td&gt;
&lt;td&gt;0 upward&lt;/td&gt;
&lt;td&gt;Per channel.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fadeInJerkFactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0.333&lt;/td&gt;
&lt;td&gt;0 to 0.5&lt;/td&gt;
&lt;td&gt;Shapes the jerk-limited profile. &lt;strong&gt;Ignored when &lt;code&gt;maxConstraintsEnable&lt;/code&gt; is true&lt;/strong&gt; — the block computes its own.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fadeInAccFactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0.429&lt;/td&gt;
&lt;td&gt;0 to 0.5&lt;/td&gt;
&lt;td&gt;Same, and same caveat.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fadeOutJerkFactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0.333&lt;/td&gt;
&lt;td&gt;0 to 0.5&lt;/td&gt;
&lt;td&gt;Same.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fadeOutAccFactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0.429&lt;/td&gt;
&lt;td&gt;0 to 0.5&lt;/td&gt;
&lt;td&gt;Same.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All are persistent and survive a controller restart. Negative limits and times
are used as their magnitude. &lt;strong&gt;No parameters exist below this block.&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;switchType&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;What the machine does&lt;/th&gt;
&lt;th&gt;Limits that apply&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt; quintic&lt;/td&gt;
&lt;td&gt;Value, velocity and acceleration all start and end at zero. The smoothest shape&lt;/td&gt;
&lt;td&gt;Any of the three that is non-zero&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt; jerk-limited&lt;/td&gt;
&lt;td&gt;Reaches its acceleration and velocity plateaus and holds them, so it covers ground faster&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;A channel is ignored unless both its velocity and acceleration limits are set.&lt;/strong&gt; A zero jerk limit degenerates the profile to a second-order one&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Connect both sets of three signals. All six must have the same number of
channels.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Leave &lt;code&gt;toggle&lt;/code&gt; false. Confirm &lt;code&gt;output&lt;/code&gt; matches &lt;code&gt;input1&lt;/code&gt; and &lt;code&gt;isOff&lt;/code&gt; is true.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Start in time mode: leave &lt;code&gt;maxConstraintsEnable&lt;/code&gt; false and set &lt;code&gt;fadeInTime&lt;/code&gt;
and &lt;code&gt;fadeOutTime&lt;/code&gt; to a second or two.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;toggle&lt;/code&gt; true and watch all three outputs travel to the &lt;code&gt;input2&lt;/code&gt; set.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 4 hands the machine over to whatever &lt;code&gt;input2&lt;/code&gt; is carrying&lt;/strong&gt;, at
whatever rate the gap and the fade time imply. In time mode nothing limits
that rate. Check the gap first.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Confirm &lt;code&gt;isOn&lt;/code&gt; and &lt;code&gt;isDone&lt;/code&gt; go true and the outputs match the &lt;code&gt;input2&lt;/code&gt; set.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now try limit mode: set &lt;code&gt;fadeInMaxVel&lt;/code&gt; per channel, set
&lt;code&gt;maxConstraintsEnable&lt;/code&gt; true, and toggle again.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Confirm the fade actually got slower or faster.&lt;/strong&gt; If nothing changed, the
solve found no limits to apply and silently fell back to &lt;code&gt;fadeInTime&lt;/code&gt; —
nothing reports this.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Decide which mode you want. Limits are usually the right answer for a
handover on a real axis, because they bound what the machine does rather
than how long it takes.&lt;/li&gt;
&lt;li&gt;In limit mode, set the velocity limit first, per channel, in the signal&amp;rsquo;s
own units. Leave acceleration and jerk at 0 until you need them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Verify the mode took effect&lt;/strong&gt; by comparing the fade duration against the
time-mode default. A silent fallback looks exactly like a correctly derived
five-second fade.&lt;/li&gt;
&lt;li&gt;Remember the &lt;strong&gt;slowest channel sets the duration for all of them&lt;/strong&gt;. One
channel with a much smaller limit will slow the whole switch.&lt;/li&gt;
&lt;li&gt;With the jerk-limited shape, set both a velocity and an acceleration limit
per channel or that channel is skipped entirely.&lt;/li&gt;
&lt;li&gt;Close the gap between the two input sets before switching wherever you can.
In limit mode this shortens the fade automatically.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;timeScaleFactor&lt;/code&gt; for an override, and set &lt;code&gt;timeScaleFactorDot&lt;/code&gt; while
you ramp it or &lt;code&gt;outputDDot&lt;/code&gt; will be wrong for the duration of the ramp.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/soft-switch-constrained-99970aa2.svg&#34; alt=&#34;Two fades between the same two values, with the fade time derived from avelocity limit of 0.5 and of 1.5. The faster fade&amp;rsquo;s velocity peaks at exactly1.5 — the limit is met, not approached.&#34;&gt;&lt;/p&gt;
&lt;p&gt;In limit mode the duration is whatever it needs to be. In time mode the
duration is fixed and the velocity is whatever it turns out to be.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Setting limits changed nothing&lt;/td&gt;
&lt;td&gt;The solve found nothing to constrain and fell back to the fade times, silently&lt;/td&gt;
&lt;td&gt;Check every limit is non-zero on at least one channel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Limits are set but ignored with the jerk-limited shape&lt;/td&gt;
&lt;td&gt;That shape skips any channel without &lt;strong&gt;both&lt;/strong&gt; a velocity and an acceleration limit&lt;/td&gt;
&lt;td&gt;Set both, per channel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The fade was slower than one channel&amp;rsquo;s limit implies&lt;/td&gt;
&lt;td&gt;Expected: the slowest channel sets the duration for all&lt;/td&gt;
&lt;td&gt;Raise that channel&amp;rsquo;s limits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output exceeded the limit I set&lt;/td&gt;
&lt;td&gt;The inputs moved apart after the toggle; the duration was fixed at the moment you flipped it&lt;/td&gt;
&lt;td&gt;Close the gap before switching&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fadeInJerkFactor&lt;/code&gt; has no effect&lt;/td&gt;
&lt;td&gt;Expected: the factors are computed for you in limit mode&lt;/td&gt;
&lt;td&gt;Turn limits off to use them&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A kink appeared mid-fade&lt;/td&gt;
&lt;td&gt;&lt;code&gt;switchType&lt;/code&gt; was changed while a fade was running&lt;/td&gt;
&lt;td&gt;Change it only when &lt;code&gt;isDone&lt;/code&gt; is true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output moved very fast in time mode&lt;/td&gt;
&lt;td&gt;Expected: time mode does not limit the rate&lt;/td&gt;
&lt;td&gt;Use limit mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The switch snapped instead of fading&lt;/td&gt;
&lt;td&gt;A fade time under one task period&lt;/td&gt;
&lt;td&gt;Lengthen it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The outputs stepped instead of fading&lt;/td&gt;
&lt;td&gt;&lt;code&gt;doInstantToggle&lt;/code&gt; is true&lt;/td&gt;
&lt;td&gt;Set it false — it is a level, not a pulse&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The fade froze part-way&lt;/td&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactor&lt;/code&gt; is 0&lt;/td&gt;
&lt;td&gt;Set it above 0. Nothing was lost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A negative &lt;code&gt;timeScaleFactor&lt;/code&gt; did not reverse the fade&lt;/td&gt;
&lt;td&gt;Expected: the magnitude is used&lt;/td&gt;
&lt;td&gt;Use the toggle to reverse&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDDot&lt;/code&gt; was wrong while I changed the override&lt;/td&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactorDot&lt;/code&gt; was left at 0&lt;/td&gt;
&lt;td&gt;Set it while ramping&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isOn&lt;/code&gt; and &lt;code&gt;isOff&lt;/code&gt; are both false mid-fade&lt;/td&gt;
&lt;td&gt;Expected: both require the fade to have completed&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;faderValue&lt;/code&gt; for progress&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The derivative outputs never made sense&lt;/td&gt;
&lt;td&gt;The derivative inputs may not match the value inputs&lt;/td&gt;
&lt;td&gt;Nothing checks this — verify upstream&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The machine moved when I flipped the toggle&lt;/td&gt;
&lt;td&gt;Expected: the two input sets held different values&lt;/td&gt;
&lt;td&gt;Match them first&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Everything became invalid and stayed that way&lt;/td&gt;
&lt;td&gt;An input that is not a number is not caught&lt;/td&gt;
&lt;td&gt;Fix the upstream signal&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for a limit-based handover on a single axis:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;maxConstraintsEnable = true
switchType           = 0
fadeInMaxVel         = 0.5
fadeInMaxAcc         = 5.0
fadeOutMaxVel        = 1.0
fadeOutMaxAcc        = 10.0
fadeInTime           = 5.0
fadeOutTime          = 5.0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;fadeInTime&lt;/code&gt; and &lt;code&gt;fadeOutTime&lt;/code&gt; are still worth setting sensibly — they are what
you fall back to if the limits do not apply.&lt;/p&gt;
&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Derivative consistency&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;outputDot&lt;/code&gt; and &lt;code&gt;outputDDot&lt;/code&gt; are the true derivatives of &lt;code&gt;output&lt;/code&gt;&lt;/strong&gt;, through the fade&lt;/td&gt;
&lt;td&gt;Not applicable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timing mode&lt;/td&gt;
&lt;td&gt;&lt;code&gt;maxConstraintsEnable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Limits derive the duration; otherwise the fade times do&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not reported&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Limit solve failure&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;If no limit constrains anything, the block &lt;strong&gt;silently uses &lt;code&gt;fadeInTime&lt;/code&gt;/&lt;code&gt;fadeOutTime&lt;/code&gt;&lt;/strong&gt; instead&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not reported&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Limit validity window&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;The duration is solved &lt;strong&gt;when the toggle changes&lt;/strong&gt;, from the gap at that moment. Later input movement is not accounted for&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Limits per channel&lt;/td&gt;
&lt;td&gt;The limit arrays&lt;/td&gt;
&lt;td&gt;Each channel respects its own; &lt;strong&gt;the slowest sets the duration for all&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zero limits&lt;/td&gt;
&lt;td&gt;Checked&lt;/td&gt;
&lt;td&gt;A zero limit is &lt;strong&gt;skipped&lt;/strong&gt;, not treated as zero&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jerk-limited shape&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;A channel without &lt;strong&gt;both&lt;/strong&gt; a velocity and an acceleration limit is ignored. A zero jerk limit degenerates the profile to second order&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Factor parameters&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;The four factors are &lt;strong&gt;ignored in limit mode&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output rate in time mode&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not limited&lt;/strong&gt; at all&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sub-cycle fades&lt;/td&gt;
&lt;td&gt;Checked&lt;/td&gt;
&lt;td&gt;A fade time under one task period makes the switch &lt;strong&gt;snap&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isDone&lt;/code&gt; stays true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Limit and time signs&lt;/td&gt;
&lt;td&gt;Checked&lt;/td&gt;
&lt;td&gt;Negatives are used as their magnitude&lt;/td&gt;
&lt;td&gt;Read the values back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;switchType&lt;/code&gt; mid-fade&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not guarded. An in-flight fade changes shape and keeps its old timing&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Partly checked&lt;/td&gt;
&lt;td&gt;Negatives are negated. &lt;strong&gt;0 freezes the fade with nothing lost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Values that are not numbers&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not checked anywhere&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Startup&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;All three outputs start on the &lt;code&gt;input1&lt;/code&gt; set; &lt;code&gt;isOff&lt;/code&gt; and &lt;code&gt;isDone&lt;/code&gt; start true, and any fade in flight is cleared&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isDone&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel count&lt;/td&gt;
&lt;td&gt;Fixed at build time&lt;/td&gt;
&lt;td&gt;All inputs, outputs and limit arrays share one channel count&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This block &lt;strong&gt;logs nothing, ever&lt;/strong&gt; — unlike the other switches, it has no fade
time ceiling and no warnings. Every condition above shows as a value on a
trace, or not at all.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.30.0 (bc348fd).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: LevelSwitch</title>
      <link>/docs/developing-control-applications/control-blocks/switching-and-routing/level-switch/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/switching-and-routing/level-switch/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version&#34;&gt;
  &lt;span class=&#34;c3-version__control c3-version__control--static&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;span class=&#34;c3-version__value&#34;&gt;3.30–3.34&lt;/span&gt;
  &lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;LevelSwitch&lt;/code&gt; compares one signal against one level and publishes two
complementary flags. A deadband holds the decision while the signal sits near
the level, so the output does not chatter on noise.&lt;/p&gt;
&lt;p&gt;Use it to raise a flag when a pressure, a speed or a position crosses a
threshold.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;input&amp;quot;]) --&amp;gt; B[&amp;quot;LevelSwitch&amp;quot;]
    p1([&amp;quot;switchLevel&amp;quot;]) --&amp;gt; B
    p2([&amp;quot;deadband&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;isLower&amp;quot;])
    B --&amp;gt; o2([&amp;quot;isHigher&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;isHigher&lt;/code&gt; is always the exact opposite of &lt;code&gt;isLower&lt;/code&gt;. Read whichever reads
better in your logic; they can never disagree.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The deadband is split either side of the level.&lt;/strong&gt; A deadband of 2 around a
level of 5 switches to high at 6 and back to low at 4. Size it from the noise
on your signal, not from the level.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The signal to compare. Compared as-is, with no filtering — feed it a filtered signal if it is noisy beyond what the deadband can absorb.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isLower&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True while the input is below the level. &lt;strong&gt;Starts true&lt;/strong&gt;, before the first comparison has run.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isHigher&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True while the input is above the level. Always the complement of &lt;code&gt;isLower&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;switchLevel&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The level to compare against. The output switches high at &lt;code&gt;switchLevel + deadband/2&lt;/code&gt; and back low at &lt;code&gt;switchLevel - deadband/2&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;deadband&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0 upward&lt;/td&gt;
&lt;td&gt;Total width of the hold region, &lt;strong&gt;split either side of the level&lt;/strong&gt;. With 0 the output switches exactly at the level and will chatter on any noise. &lt;strong&gt;A negative value removes the hysteresis&lt;/strong&gt; and is not rejected.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Both are persistent and survive a controller restart. &lt;strong&gt;No parameters exist
below this block.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Connect the signal you want to watch to &lt;code&gt;input&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;switchLevel&lt;/code&gt; to the value you want to detect.&lt;/li&gt;
&lt;li&gt;Leave &lt;code&gt;deadband&lt;/code&gt; at 0 for a first look, and watch &lt;code&gt;isHigher&lt;/code&gt; while the
signal crosses the level.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;isHigher&lt;/code&gt; flickers at the crossing, the signal is noisy — go to Tuning.&lt;/li&gt;
&lt;li&gt;Confirm &lt;code&gt;isLower&lt;/code&gt; and &lt;code&gt;isHigher&lt;/code&gt; are always opposite. They are computed to
be, so a disagreement means you are reading two different cycles.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This block only reads a signal and raises a flag. It does not move anything and
cannot be made to.&lt;/p&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Trace &lt;code&gt;input&lt;/code&gt; while the machine does what you want to detect, and note how
far the signal wanders when it is sitting still near the level.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;deadband&lt;/code&gt; to about twice that wander. That is the whole tuning.&lt;/li&gt;
&lt;li&gt;Check the crossing again. &lt;code&gt;isHigher&lt;/code&gt; should switch once, cleanly, in each
direction.&lt;/li&gt;
&lt;li&gt;If it still chatters, the deadband is smaller than the noise. Double it.&lt;/li&gt;
&lt;li&gt;If the flag now arrives too late, the deadband is too wide — remember it
delays the switch by half its width in each direction.&lt;/li&gt;
&lt;li&gt;If you cannot get both, the signal needs filtering upstream rather than a
wider deadband here. A wider deadband costs you accuracy in both directions;
a filter costs you a little delay in one.&lt;/li&gt;
&lt;li&gt;Nothing here depends on the task rate, so none of this needs re-checking
after a rate change.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/level-switch-hysteresis-a8ff8ada.svg&#34; alt=&#34;As the input sweeps up through the level and back down, a zero deadbandswitches at the level itself, while a deadband of 4 switches two units above onthe way up and two below on the waydown.&#34;&gt;&lt;/p&gt;
&lt;p&gt;The gap between the two switching points is the deadband.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;The flag chatters at the crossing&lt;/td&gt;
&lt;td&gt;&lt;code&gt;deadband&lt;/code&gt; is smaller than the noise on the signal&lt;/td&gt;
&lt;td&gt;Widen it, or filter the input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The flag chatters with &lt;code&gt;deadband&lt;/code&gt; set&lt;/td&gt;
&lt;td&gt;The signal is noisier than you measured&lt;/td&gt;
&lt;td&gt;Trace the input at rest near the level and re-measure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The flag arrives later than expected&lt;/td&gt;
&lt;td&gt;Expected: the deadband delays the switch by half its width&lt;/td&gt;
&lt;td&gt;Narrow it, or move &lt;code&gt;switchLevel&lt;/code&gt; down by half the deadband&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The flag never switches&lt;/td&gt;
&lt;td&gt;The signal never reaches &lt;code&gt;switchLevel ± deadband/2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check the level, and check the input is actually connected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The hysteresis disappeared&lt;/td&gt;
&lt;td&gt;&lt;code&gt;deadband&lt;/code&gt; is negative, which is not rejected&lt;/td&gt;
&lt;td&gt;Write a positive value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isHigher&lt;/code&gt; reads true at exactly the level&lt;/td&gt;
&lt;td&gt;Expected with a zero deadband: the tie goes to high&lt;/td&gt;
&lt;td&gt;Set a deadband&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isLower&lt;/code&gt; read true before anything ran&lt;/td&gt;
&lt;td&gt;Expected: it starts true until the first cycle&lt;/td&gt;
&lt;td&gt;Ignore the outputs until the controller is running&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Both flags read the same&lt;/td&gt;
&lt;td&gt;Not possible in one cycle&lt;/td&gt;
&lt;td&gt;You are comparing readings from different cycles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The flag did not update after a restart&lt;/td&gt;
&lt;td&gt;Expected: the previous decision is held for one cycle&lt;/td&gt;
&lt;td&gt;Ignore the first cycle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A NaN reached the input and the flag froze&lt;/td&gt;
&lt;td&gt;The decision is held when the input is not a number&lt;/td&gt;
&lt;td&gt;Fix the upstream signal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I need to watch several signals&lt;/td&gt;
&lt;td&gt;Not possible — this block is single channel&lt;/td&gt;
&lt;td&gt;Use one instance per signal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I need to disable it&lt;/td&gt;
&lt;td&gt;Not possible — there is no enable&lt;/td&gt;
&lt;td&gt;Ignore the outputs in your own logic&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for a signal that sits within ±0.5 of its value at rest:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;switchLevel = &amp;lt;the value you want to detect&amp;gt;
deadband    = 2.0
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Switching point&lt;/td&gt;
&lt;td&gt;&lt;code&gt;switchLevel&lt;/code&gt;, &lt;code&gt;deadband&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;High at &lt;code&gt;switchLevel + deadband/2&lt;/code&gt;, low at &lt;code&gt;switchLevel - deadband/2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isLower&lt;/code&gt;, &lt;code&gt;isHigher&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inside the deadband&lt;/td&gt;
&lt;td&gt;&lt;code&gt;deadband&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;The decision is held&lt;/strong&gt; — this is the hysteresis and the reason the block exists&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exactly at the level, zero deadband&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Reads &lt;code&gt;isHigher&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;deadband&lt;/code&gt; sign&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not checked.&lt;/strong&gt; A negative value overlaps the two thresholds and removes the hysteresis&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt; value&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not checked. A NaN input holds the previous decision rather than switching&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Initial state&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isLower&lt;/code&gt; reads true and &lt;code&gt;isHigher&lt;/code&gt; false until the first cycle runs&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel count&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;One signal per instance, always&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Task rate&lt;/td&gt;
&lt;td&gt;Not used&lt;/td&gt;
&lt;td&gt;The block has no time dependence at all; the decision is instantaneous&lt;/td&gt;
&lt;td&gt;Not applicable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This block &lt;strong&gt;logs nothing, ever&lt;/strong&gt;. Every condition above shows as a value on a
trace, or not at all.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.30.0 (bc348fd).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: FlipFlop</title>
      <link>/docs/developing-control-applications/control-blocks/switching-and-routing/flip-flop/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/switching-and-routing/flip-flop/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version&#34;&gt;
  &lt;span class=&#34;c3-version__control c3-version__control--static&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;span class=&#34;c3-version__value&#34;&gt;3.30–3.34&lt;/span&gt;
  &lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;FlipFlop&lt;/code&gt; holds a true/false state that is &lt;strong&gt;flipped&lt;/strong&gt; by holding its input
true for a configured time. It also reports when the input rises and falls.&lt;/p&gt;
&lt;p&gt;Use it to turn a held button into a latched mode, without the state flickering
on a brief or bouncing contact.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;input&amp;quot;]) --&amp;gt; B[&amp;quot;FlipFlop&amp;quot;]
    i2([&amp;quot;reset&amp;quot;]) --&amp;gt; B
    p1([&amp;quot;setTimer&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output&amp;quot;])
    B --&amp;gt; o2([&amp;quot;triggerRisingEdge&amp;quot;])
    B --&amp;gt; o3([&amp;quot;triggerFallingEdge&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The output toggles; it does not follow the input.&lt;/strong&gt; Hold the input true for
&lt;code&gt;setTimer&lt;/code&gt; seconds and the output flips to the opposite of whatever it was.
Hold it again and it flips back. One flip per press, however long you hold.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;triggerRisingEdge&lt;/code&gt; and &lt;code&gt;triggerFallingEdge&lt;/code&gt; report the &lt;em&gt;input&lt;/em&gt;, not the
output.&lt;/strong&gt; They are true for a single cycle when the input changes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true or false&lt;/td&gt;
&lt;td&gt;Hold it true for &lt;code&gt;setTimer&lt;/code&gt; seconds to flip the output. Releasing before then flips nothing and arms the next attempt. This is a &lt;strong&gt;level&lt;/strong&gt;, held for as long as you want it read.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;reset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true or false&lt;/td&gt;
&lt;td&gt;Forces &lt;code&gt;output&lt;/code&gt; false and restarts the timer. The block clears it back to false once acted on, so it is a &lt;strong&gt;pulse&lt;/strong&gt;. &lt;strong&gt;It does not stick while &lt;code&gt;input&lt;/code&gt; is still held&lt;/strong&gt; — the timer restarts and the output flips true again after &lt;code&gt;setTimer&lt;/code&gt; seconds. Release &lt;code&gt;input&lt;/code&gt; first.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;The latched state. &lt;strong&gt;Survives a controller restart&lt;/strong&gt; — it is not cleared at startup.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;triggerRisingEdge&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True for one cycle when &lt;code&gt;input&lt;/code&gt; goes from false to true.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;triggerFallingEdge&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True for one cycle when &lt;code&gt;input&lt;/code&gt; goes from true to false.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;setTimer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;one task period&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;How long &lt;code&gt;input&lt;/code&gt; must be held true before &lt;code&gt;output&lt;/code&gt; flips. &lt;strong&gt;Values of 0 or below are replaced by one task period and written back&lt;/strong&gt;, so this is also the shortest usable setting. Set it above the longest contact bounce you expect.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;It is persistent and survives a controller restart. &lt;strong&gt;No parameters exist below
this block.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Connect your button, sensor or condition to &lt;code&gt;input&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;setTimer&lt;/code&gt; to how long the condition must hold before it counts —
50 ms is a reasonable first value for a physical button.&lt;/li&gt;
&lt;li&gt;Hold &lt;code&gt;input&lt;/code&gt; true and watch &lt;code&gt;output&lt;/code&gt; flip after that time.&lt;/li&gt;
&lt;li&gt;Release, hold again, and confirm &lt;code&gt;output&lt;/code&gt; flips back. &lt;strong&gt;One flip per
press.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Tap &lt;code&gt;input&lt;/code&gt; briefly and confirm &lt;code&gt;output&lt;/code&gt; does not change.&lt;/li&gt;
&lt;li&gt;Pulse &lt;code&gt;reset&lt;/code&gt; with &lt;code&gt;input&lt;/code&gt; released, and confirm &lt;code&gt;output&lt;/code&gt; goes false and
stays false.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This block only latches a flag. It does not move anything and cannot be made
to — but whatever your &lt;code&gt;output&lt;/code&gt; enables downstream &lt;strong&gt;will&lt;/strong&gt; act the moment it
flips.&lt;/p&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;There is one number here: &lt;code&gt;setTimer&lt;/code&gt;. Everything else is wiring.&lt;/li&gt;
&lt;li&gt;Trace &lt;code&gt;input&lt;/code&gt; while the operator does what you want to detect. Look at how
long the signal is genuinely held, and how long any bounce or glitch lasts.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;setTimer&lt;/code&gt; above the longest glitch and comfortably below the shortest
real press. For a physical button those are usually milliseconds and
hundreds of milliseconds respectively, so there is a wide margin.&lt;/li&gt;
&lt;li&gt;Confirm a real press flips the output and a glitch does not.&lt;/li&gt;
&lt;li&gt;If a real press sometimes fails to register, &lt;code&gt;setTimer&lt;/code&gt; is too long, or the
input is dropping out mid-press. Trace &lt;code&gt;triggerFallingEdge&lt;/code&gt; — a pulse there
during the press means the input dropped and the timer restarted.&lt;/li&gt;
&lt;li&gt;If glitches still get through, &lt;code&gt;setTimer&lt;/code&gt; is shorter than the glitch.
Lengthen it.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setTimer&lt;/code&gt; is in seconds, so a task-rate change does not move it — but the
lower bound of one task period does change with the rate.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/flip-flop-toggle-b8667a22.svg&#34; alt=&#34;Two presses each held past the 0.05 s hold time. The first flips the outputtrue, the second flips it back false. The output changes once per press, whenthe hold time elapses, not when the inputchanges.&#34;&gt;&lt;/p&gt;
&lt;p&gt;The delay between each input rise and the matching output change is &lt;code&gt;setTimer&lt;/code&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;The output follows the input instead of latching&lt;/td&gt;
&lt;td&gt;It never did — this block toggles on a held input&lt;/td&gt;
&lt;td&gt;Read the callout at the top&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A press did nothing&lt;/td&gt;
&lt;td&gt;It was shorter than &lt;code&gt;setTimer&lt;/code&gt;, or the input dropped out mid-press&lt;/td&gt;
&lt;td&gt;Trace &lt;code&gt;triggerFallingEdge&lt;/code&gt; during the press&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output flipped when I wanted it set&lt;/td&gt;
&lt;td&gt;Expected: every completed hold flips it&lt;/td&gt;
&lt;td&gt;Check &lt;code&gt;output&lt;/code&gt; before acting, or use &lt;code&gt;reset&lt;/code&gt; to force it false&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A reset did not stick&lt;/td&gt;
&lt;td&gt;Expected: &lt;code&gt;input&lt;/code&gt; was still held, so the timer restarted&lt;/td&gt;
&lt;td&gt;Release &lt;code&gt;input&lt;/code&gt; first, then reset&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output was still set after a restart&lt;/td&gt;
&lt;td&gt;Expected: the latch is not cleared at startup&lt;/td&gt;
&lt;td&gt;Pulse &lt;code&gt;reset&lt;/code&gt; in your own startup logic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Glitches are getting through&lt;/td&gt;
&lt;td&gt;&lt;code&gt;setTimer&lt;/code&gt; is shorter than the glitch&lt;/td&gt;
&lt;td&gt;Lengthen it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real presses are being missed&lt;/td&gt;
&lt;td&gt;&lt;code&gt;setTimer&lt;/code&gt; is longer than the press&lt;/td&gt;
&lt;td&gt;Shorten it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;setTimer&lt;/code&gt; reads back as a tiny number&lt;/td&gt;
&lt;td&gt;Expected: 0 and negatives are replaced by one task period&lt;/td&gt;
&lt;td&gt;Write a positive value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The block never flips, whatever I do&lt;/td&gt;
&lt;td&gt;&lt;code&gt;setTimer&lt;/code&gt; is not a valid number&lt;/td&gt;
&lt;td&gt;Rewrite it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;triggerRisingEdge&lt;/code&gt; was true for only one cycle&lt;/td&gt;
&lt;td&gt;Expected: both trigger outputs are one cycle wide&lt;/td&gt;
&lt;td&gt;Latch it yourself if you need it longer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The trigger outputs do not match the output&lt;/td&gt;
&lt;td&gt;Expected: they report the &lt;strong&gt;input&lt;/strong&gt;, not the output&lt;/td&gt;
&lt;td&gt;Watch &lt;code&gt;output&lt;/code&gt; for the output&amp;rsquo;s changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A &lt;code&gt;reset&lt;/code&gt; write disappeared&lt;/td&gt;
&lt;td&gt;Expected: the block clears it once acted on&lt;/td&gt;
&lt;td&gt;Read &lt;code&gt;output&lt;/code&gt; to confirm the reset took&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The hold time changed after a task-rate change&lt;/td&gt;
&lt;td&gt;Only if &lt;code&gt;setTimer&lt;/code&gt; was at its lower bound of one task period&lt;/td&gt;
&lt;td&gt;Set it explicitly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I need several of these&lt;/td&gt;
&lt;td&gt;Not possible — this block is single channel&lt;/td&gt;
&lt;td&gt;Use one instance per signal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I need to disable it&lt;/td&gt;
&lt;td&gt;Not possible — there is no enable&lt;/td&gt;
&lt;td&gt;Hold &lt;code&gt;input&lt;/code&gt; false in your own logic&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for a physical button on a 1 ms task:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;setTimer = 0.05
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hold time&lt;/td&gt;
&lt;td&gt;&lt;code&gt;setTimer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The output flips exactly once, &lt;code&gt;setTimer&lt;/code&gt; seconds after the input rises&lt;/td&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repeated flips&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;One flip per press.&lt;/strong&gt; Holding longer changes nothing; release and hold again to flip back&lt;/td&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Short presses&lt;/td&gt;
&lt;td&gt;&lt;code&gt;setTimer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Anything shorter is ignored entirely&lt;/td&gt;
&lt;td&gt;&lt;code&gt;triggerRisingEdge&lt;/code&gt; still pulses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;setTimer&lt;/code&gt; at 0 or below&lt;/td&gt;
&lt;td&gt;Checked&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Replaced by one task period and written back&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Read the value back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;setTimer&lt;/code&gt; not a valid number&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not checked. The timer never advances and the block never flips, silently&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;reset&lt;/code&gt; while &lt;code&gt;input&lt;/code&gt; is held&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The output clears, then flips true again after &lt;code&gt;setTimer&lt;/code&gt;. &lt;strong&gt;A reset only sticks with the input released&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Startup state&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; is &lt;strong&gt;not&lt;/strong&gt; cleared at startup and carries across a restart&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trigger width&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Both trigger outputs are exactly one cycle wide&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trigger source&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Both report the &lt;strong&gt;input&amp;rsquo;s&lt;/strong&gt; edges, despite their names&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel count&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;One signal per instance, always&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This block &lt;strong&gt;logs nothing, ever&lt;/strong&gt;. Every condition above shows as a value on a
trace, or not at all.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.30.0 (bc348fd).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: Delay</title>
      <link>/docs/developing-control-applications/control-blocks/switching-and-routing/delay/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/switching-and-routing/delay/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version&#34;&gt;
  &lt;span class=&#34;c3-version__control c3-version__control--static&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;span class=&#34;c3-version__value&#34;&gt;3.30–3.34&lt;/span&gt;
  &lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Delay&lt;/code&gt; holds a signal back by a whole number of task cycles and passes it on
unchanged. Use it to line signals up in time — a sensor reading against the
command that produced it, a feedforward term against the feedback path it has
to meet. It changes nothing about the signal&amp;rsquo;s size or shape: every frequency
comes through at full amplitude, just later.&lt;/p&gt;
&lt;p&gt;It is the one block here whose job is to add lag rather than avoid it.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;input — signal to hold back&amp;quot;]) --&amp;gt; B[&amp;quot;Delay&amp;quot;]
    B --&amp;gt; o1([&amp;quot;output — the same signal, later&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;Delay in seconds = &lt;code&gt;delaysamples&lt;/code&gt; × task period [s]. On a 1 ms task,
&lt;code&gt;delaysamples&lt;/code&gt; 25 is 25 ms. The lag is the same at every frequency, and it
reaches half a cycle of phase at $1/(2 \times$ delay$)$ Hz — 20 Hz for a
25 ms delay. Inside a feedback loop that is where the delay alone inverts the
sign, so a delay in a loop costs stability directly.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;This block has no enable, no disable, no &lt;code&gt;isEnabled&lt;/code&gt; and no reset.&lt;/strong&gt; It is
always running. Set &lt;code&gt;delaysamples&lt;/code&gt; to 0 to pass the signal straight through.
The delay is counted in &lt;strong&gt;samples, not seconds&lt;/strong&gt; — see Limits and errors.&lt;/p&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The signal to hold back. One element per channel; the channel count is fixed by the machine configuration.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;The same signal, &lt;code&gt;delaysamples&lt;/code&gt; cycles later, unchanged in size and shape. Equals &lt;code&gt;input&lt;/code&gt; exactly while &lt;code&gt;delaysamples&lt;/code&gt; is 0. &lt;strong&gt;Reads zero for the first &lt;code&gt;delaysamples&lt;/code&gt; cycles after every controller start&lt;/strong&gt;, then begins reproducing the input.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;delaysamples&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;samples&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0 – a ceiling fixed when the machine is built&lt;/td&gt;
&lt;td&gt;How many task cycles to hold the signal back, shared by all channels. 0 passes the signal straight through. A value above the ceiling is corrected silently — see Limits and errors. Note the path name is all lower case.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;delaysamples&lt;/code&gt; is persistent and survives a controller restart. The input and
output do not. &lt;strong&gt;No parameters exist below this block.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Work out the delay you need in &lt;strong&gt;seconds&lt;/strong&gt;, then divide by the task period
to get samples. On a 1 ms task, 25 ms is 25 samples.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Find the ceiling: write a large number to &lt;code&gt;delaysamples&lt;/code&gt; and read it back.
The value you get is the largest delay this instance supports, and it is
fixed when the machine is built.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;delaysamples&lt;/code&gt; to 0 and link the source signal into &lt;code&gt;input&lt;/code&gt;. &lt;code&gt;output&lt;/code&gt;
equals &lt;code&gt;input&lt;/code&gt; sample for sample, which confirms the link.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;delaysamples&lt;/code&gt; to the value from step 1. Read it back and confirm it was
accepted.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 4 emits stale data for a moment.&lt;/strong&gt; Raising the delay while the
machine runs pushes out samples that were never recorded at the new depth.
Change &lt;code&gt;delaysamples&lt;/code&gt; with the axis at rest, or accept a brief burst of
wrong values on &lt;code&gt;output&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Trace &lt;code&gt;input&lt;/code&gt; and &lt;code&gt;output&lt;/code&gt; together and measure the offset between the same
feature on each. It should be your delay in seconds.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Trace every element of both. An element that reads zero while the machine
moves is an unwired channel.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;p&gt;There is almost nothing to tune. The delay is either the right number of
samples or it is not.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Measure the misalignment you are correcting, in seconds, off a trace of the
two signals you want to line up.&lt;/li&gt;
&lt;li&gt;Divide by the task period and round to the nearest whole number. This block
cannot delay by a fraction of a sample, so the task rate sets how finely you
can align.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;delaysamples&lt;/code&gt;, then re-measure the offset on a trace. Adjust by one
sample at a time.&lt;/li&gt;
&lt;li&gt;If the alignment you need is finer than one task period, this block cannot
deliver it. Raise the task rate, or accept the rounding.&lt;/li&gt;
&lt;li&gt;Re-check &lt;code&gt;delaysamples&lt;/code&gt; after any task-rate change. &lt;strong&gt;The delay is counted
in samples, so the same setting is a different delay in seconds.&lt;/strong&gt; Rescale
it by the ratio of the old and new task periods.&lt;/li&gt;
&lt;li&gt;If the delay sits inside a feedback loop, re-check the loop&amp;rsquo;s stability
after every change. A delay costs phase margin at every frequency.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/delay-shift-d33da00e.svg&#34; alt=&#34;A 2 Hz sine and the same signal at two delay settings: the 25-sample tracelags the dashed input by 25 ms and the 100-sample trace by 100 ms, with nochange in amplitude.&#34;&gt;&lt;/p&gt;
&lt;p&gt;Read the delay off any curve as its horizontal offset from the dashed input.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; reads zero for a while after every start&lt;/td&gt;
&lt;td&gt;Expected: the block has nothing recorded yet, so it emits zeros for &lt;code&gt;delaysamples&lt;/code&gt; cycles&lt;/td&gt;
&lt;td&gt;Gate the consumer off a delay of at least that long after start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A burst of wrong values on &lt;code&gt;output&lt;/code&gt; right after raising &lt;code&gt;delaysamples&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Expected: the deeper slots hold data that was never recorded&lt;/td&gt;
&lt;td&gt;Change the delay at rest, not in motion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; jumped after lowering &lt;code&gt;delaysamples&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Expected: the output skips forward in time by the difference&lt;/td&gt;
&lt;td&gt;Change the delay at rest, or step it down one sample at a time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The delay in seconds changed after a task-rate change&lt;/td&gt;
&lt;td&gt;Expected: the delay is counted in samples, not seconds&lt;/td&gt;
&lt;td&gt;Rescale &lt;code&gt;delaysamples&lt;/code&gt; by the ratio of the task periods&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;delaysamples&lt;/code&gt; reads back lower than written&lt;/td&gt;
&lt;td&gt;Above the ceiling for this instance&lt;/td&gt;
&lt;td&gt;Work within the value you read back; the ceiling is fixed when the machine is built&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You need a delay finer than one task period&lt;/td&gt;
&lt;td&gt;Not possible — only whole samples are available&lt;/td&gt;
&lt;td&gt;Raise the task rate, or accept the rounding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The loop that consumes &lt;code&gt;output&lt;/code&gt; went unstable&lt;/td&gt;
&lt;td&gt;Expected: a delay costs phase margin at every frequency&lt;/td&gt;
&lt;td&gt;Reduce the delay, or retune the loop for it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You cannot switch the block off&lt;/td&gt;
&lt;td&gt;Expected: there is no enable of any kind&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;delaysamples&lt;/code&gt; to 0, which is a true pass-through&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You cannot flush the stored samples&lt;/td&gt;
&lt;td&gt;There is no reset in this block&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;delaysamples&lt;/code&gt; to 0 and back, or restart the controller&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; is a filtered version of &lt;code&gt;input&lt;/code&gt; rather than a shifted one&lt;/td&gt;
&lt;td&gt;Not possible — this block cannot change a signal&amp;rsquo;s shape&lt;/td&gt;
&lt;td&gt;Check you are looking at this block&amp;rsquo;s output and not a filter&amp;rsquo;s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Some channels are delayed more than others&lt;/td&gt;
&lt;td&gt;Not possible — all channels share one delay&lt;/td&gt;
&lt;td&gt;Use a separate instance per channel group&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A non-numeric value appeared on &lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A non-numeric value reached &lt;code&gt;input&lt;/code&gt; &lt;code&gt;delaysamples&lt;/code&gt; cycles ago&lt;/td&gt;
&lt;td&gt;Fix the source; the value clears itself after &lt;code&gt;delaysamples&lt;/code&gt; cycles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The block costs more processing time than expected&lt;/td&gt;
&lt;td&gt;Expected: the work grows with the delay, not with the signal&lt;/td&gt;
&lt;td&gt;Use the smallest delay that does the job&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for aligning a sensor reading with a 25 ms transport lag on a
1 ms task:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;delaysamples = 25
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;delaysamples&lt;/code&gt; ≤ the instance ceiling&lt;/td&gt;
&lt;td&gt;Machine configuration&lt;/td&gt;
&lt;td&gt;A larger value is replaced by the ceiling. The ceiling is not readable directly — discover it with Setup step 2&lt;/td&gt;
&lt;td&gt;Silently; read &lt;code&gt;delaysamples&lt;/code&gt; back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delay resolution&lt;/td&gt;
&lt;td&gt;Task rate&lt;/td&gt;
&lt;td&gt;Whole samples only. The task period is the finest alignment available&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delay in seconds&lt;/td&gt;
&lt;td&gt;Task rate&lt;/td&gt;
&lt;td&gt;Scales directly with the task period, so a task-rate change silently changes the delay in wall-clock terms&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;Unbounded — whatever the input carries reaches the output unchanged. Limit it downstream if the consumer needs a bound&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stored samples&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;There is &lt;strong&gt;no reset input and no enable.&lt;/strong&gt; Setting &lt;code&gt;delaysamples&lt;/code&gt; to 0 and back is the only way to flush from the parameter tree&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel count&lt;/td&gt;
&lt;td&gt;Machine configuration&lt;/td&gt;
&lt;td&gt;Fixed once the controller starts; it cannot be changed at runtime&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block raises no errors or warnings and logs nothing. Every failure above
shows as a value on a trace, not as a message.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.30.0 (bc348fd).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: HostInModule</title>
      <link>/docs/developing-control-applications/control-blocks/switching-and-routing/host-in/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/switching-and-routing/host-in/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version&#34;&gt;
  &lt;span class=&#34;c3-version__control c3-version__control--static&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;span class=&#34;c3-version__value&#34;&gt;3.30–3.34&lt;/span&gt;
  &lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;HostInModule&lt;/code&gt; is the entry point for a remote host commanding motion — a
teleoperation link, a vision system, a hand controller. It turns a stream of
positions arriving over a network into a setpoint the machine can safely
follow.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tracking is relative.&lt;/strong&gt; The machine follows the host&amp;rsquo;s &lt;em&gt;movement&lt;/em&gt;, not its
absolute position, so the two do not need to start in the same place. You can
engage tracking with the host anywhere and the machine will not jump.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;input&amp;quot;]) --&amp;gt; B[&amp;quot;HostInModule&amp;quot;]
    i2([&amp;quot;track/enable&amp;quot;]) --&amp;gt; B
    p1([&amp;quot;offset&amp;quot;]) --&amp;gt; B
    p2([&amp;quot;track/factor&amp;quot;]) --&amp;gt; B
    p3([&amp;quot;track/enableFader/fadeInTime, fadeOutTime&amp;quot;]) --&amp;gt; B
    p4([&amp;quot;track/syncFader/speed, enable&amp;quot;]) --&amp;gt; B
    p5([&amp;quot;track/watchdog/timeout, enable&amp;quot;]) --&amp;gt; B
    p6([&amp;quot;filter/order, omega, beta&amp;quot;]) --&amp;gt; B
    p7([&amp;quot;interpolator/sampleFactor&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output&amp;quot;])
    B --&amp;gt; o2([&amp;quot;inputFilteredOffset&amp;quot;])
    B --&amp;gt; o3([&amp;quot;track/isTracking&amp;quot;])
    B --&amp;gt; o4([&amp;quot;track/enableFader/value&amp;quot;])
    B --&amp;gt; o5([&amp;quot;track/syncFader/value, fadeTime&amp;quot;])
    B --&amp;gt; o6([&amp;quot;filter/output&amp;quot;])
    B --&amp;gt; o7([&amp;quot;interpolator/output&amp;quot;])
    B --&amp;gt; o8([&amp;quot;reference, resetting&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If the host stops writing &lt;code&gt;track/enable&lt;/code&gt;, tracking is dropped&lt;/strong&gt; after
&lt;code&gt;track/watchdog/timeout&lt;/code&gt; — a tenth of a second by default. This is the
block&amp;rsquo;s main safety feature. Leave the watchdog on.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Two of the signals below are read-only in the tree.&lt;/strong&gt; &lt;code&gt;reference&lt;/code&gt; and
&lt;code&gt;resetting&lt;/code&gt; are published for you to watch, but only your application can set
them. You cannot trigger a reset from the parameter tree.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nothing here limits the machine&amp;rsquo;s speed.&lt;/strong&gt; &lt;code&gt;track/factor&lt;/code&gt; multiplies every
movement the host makes, and it is not bounded. The limits belong in the
blocks downstream — check they are in place before raising it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;An orientation instance has its signals under &lt;code&gt;eulerZYX/&lt;/code&gt; and &lt;code&gt;quaternion/&lt;/code&gt;
instead of at the top level. Everything else below is the same.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;host unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The host&amp;rsquo;s position stream, one value per channel. &lt;strong&gt;A value that is not a number poisons the output permanently&lt;/strong&gt; — only a reset recovers it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;track/enable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true or false&lt;/td&gt;
&lt;td&gt;Engages tracking. &lt;strong&gt;The host must keep writing this&lt;/strong&gt;, not just set it once: the watchdog drops tracking if writes stop.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;machine unit&lt;/td&gt;
&lt;td&gt;The setpoint for the machine.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputFilteredOffset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;host unit&lt;/td&gt;
&lt;td&gt;The host&amp;rsquo;s input after filtering and the offset — what tracking actually follows. &lt;strong&gt;Trace this against &lt;code&gt;input&lt;/code&gt; to see what the filter is doing.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;track/isTracking&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Tracking authority is not zero.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;track/enableFader/value&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;How much authority tracking currently has, 0 to 1. Ramps rather than stepping.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;track/syncFader/value&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;How far through a sync move, 0 to 1.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;track/syncFader/fadeTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Computed, not set:&lt;/strong&gt; how long the current sync move will take. &lt;strong&gt;-1 means no sync move will happen.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;filter/output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;host unit&lt;/td&gt;
&lt;td&gt;The filtered input, before the offset.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;interpolator/output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;host unit&lt;/td&gt;
&lt;td&gt;The interpolated input, before the filter.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;reference&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;machine unit&lt;/td&gt;
&lt;td&gt;Where a reset sends the output. &lt;strong&gt;Set by your application, not from the tree.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;resetting&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;A reset is in effect. Also application-set.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;offset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;host unit&lt;/td&gt;
&lt;td&gt;zeros&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Added to the host&amp;rsquo;s input after filtering. &lt;strong&gt;Changing it does not jump the machine&lt;/strong&gt; — the block deliberately absorbs the discontinuity.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;track/factor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Motion scaling. 0.1 makes the machine move a tenth of what the host does; 10 makes it move ten times as much. &lt;strong&gt;Not limited.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;track/enableFader/fadeInTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;0.1&lt;/td&gt;
&lt;td&gt;0 upward&lt;/td&gt;
&lt;td&gt;How long tracking takes to reach full authority. 0 means instant.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;track/enableFader/fadeOutTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;0.1&lt;/td&gt;
&lt;td&gt;0 upward&lt;/td&gt;
&lt;td&gt;How long it takes to release.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;track/syncFader/enable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Whether to move the machine to the host&amp;rsquo;s absolute position when tracking engages. Off means pure relative tracking from wherever the machine is.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;track/syncFader/speed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;machine unit per second&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0 upward&lt;/td&gt;
&lt;td&gt;How fast that sync move goes. &lt;strong&gt;A speed of 0 means the machine never syncs&lt;/strong&gt; and the output stays put. On an orientation instance the default is 1 rad/s.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;track/watchdog/enable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Whether to drop tracking when the host stops writing. &lt;strong&gt;Leave this on.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;track/watchdog/timeout&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.01&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;How long to wait before deciding the host is gone.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;filter/order&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0, 1 or 2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The low-pass order. 0 disables filtering. Values outside the range are clamped.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;filter/omega&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;rad/s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;15.7&lt;/strong&gt; (2.5 Hz)&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;The cut-off. Negative values are used as their magnitude.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;filter/beta&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.707&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;Damping, order 2 only. 0.707 gives the flattest response.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;interpolator/sampleFactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1 upward&lt;/td&gt;
&lt;td&gt;How many control cycles pass between host updates. 1 disables interpolation.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All are persistent and survive a controller restart. &lt;strong&gt;No parameters exist
below this block&lt;/strong&gt; beyond those listed.&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Connect the host&amp;rsquo;s stream to &lt;code&gt;input&lt;/code&gt; and have it write &lt;code&gt;track/enable&lt;/code&gt;
&lt;strong&gt;every cycle it wants tracking&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Leave &lt;code&gt;track/enable&lt;/code&gt; false. Confirm &lt;code&gt;output&lt;/code&gt; is stationary.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;interpolator/sampleFactor&lt;/code&gt; to how many control cycles pass between host
updates. If the host writes at 100 Hz on a 1 kHz task, that is 10.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;filter/omega&lt;/code&gt; — go to Tuning.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;track/factor&lt;/code&gt; to 1 for a first test, and &lt;strong&gt;check the machine&amp;rsquo;s own
speed and position limits are configured&lt;/strong&gt;, because this block has none.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Leave &lt;code&gt;track/syncFader/enable&lt;/code&gt; false so tracking starts from wherever the
machine is.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Have the host raise &lt;code&gt;track/enable&lt;/code&gt; and move slowly.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 7 gives a remote operator control of the machine.&lt;/strong&gt; Start with a
small &lt;code&gt;track/factor&lt;/code&gt;, a slow host, and someone at the stop button.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Confirm &lt;code&gt;output&lt;/code&gt; follows the host&amp;rsquo;s movement and &lt;code&gt;track/isTracking&lt;/code&gt; is true.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Have the host stop writing &lt;code&gt;track/enable&lt;/code&gt; entirely, and confirm tracking
drops within &lt;code&gt;track/watchdog/timeout&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Set &lt;code&gt;interpolator/sampleFactor&lt;/code&gt; first, from the host&amp;rsquo;s real update rate. Too
low and you see a step at each host update; too high and the output is
stale. Trace &lt;code&gt;interpolator/output&lt;/code&gt; against &lt;code&gt;input&lt;/code&gt; to check.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;filter/omega&lt;/code&gt; from the noise on the host&amp;rsquo;s signal. Lower is smoother
and adds more lag. Trace &lt;code&gt;filter/output&lt;/code&gt; against &lt;code&gt;interpolator/output&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Leave &lt;code&gt;filter/order&lt;/code&gt; at 2 and &lt;code&gt;filter/beta&lt;/code&gt; at 0.707 unless you have a
reason. Order 1 has less lag and less rejection; order 0 is no filter at
all.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;track/factor&lt;/code&gt; from the working ratio you want between the host&amp;rsquo;s motion
and the machine&amp;rsquo;s. &lt;strong&gt;Raise it in steps&lt;/strong&gt;, checking the machine&amp;rsquo;s limits hold
at each one.&lt;/li&gt;
&lt;li&gt;Set the fade times from how abruptly you are willing for authority to change
— a tenth of a second is a reasonable default for a hand controller.&lt;/li&gt;
&lt;li&gt;Turn on the sync move only if the machine should meet the host&amp;rsquo;s absolute
position. Set &lt;code&gt;track/syncFader/speed&lt;/code&gt; to a safe approach speed and read
&lt;code&gt;track/syncFader/fadeTime&lt;/code&gt; back to see how long it will take.&lt;/li&gt;
&lt;li&gt;Tighten &lt;code&gt;track/watchdog/timeout&lt;/code&gt; as far as the host&amp;rsquo;s jitter allows. Too
tight drops tracking on a network hiccup; too loose leaves the machine
following a dead host for longer.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/host-in-tracking-74353f40.svg&#34; alt=&#34;Tracking faded in at 0.2 seconds and out at 0.9. The output picks up thehost&amp;rsquo;s movement as authority ramps in, and holds where it was when authorityramps out.&#34;&gt;&lt;/p&gt;
&lt;p&gt;The output holds at its last value when tracking releases. It does not spring
back.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;The machine jumped when tracking engaged&lt;/td&gt;
&lt;td&gt;The sync move is on and the host was far away&lt;/td&gt;
&lt;td&gt;Turn &lt;code&gt;track/syncFader/enable&lt;/code&gt; off, or lower the sync speed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The machine never reaches the host&amp;rsquo;s position&lt;/td&gt;
&lt;td&gt;Expected without the sync move — tracking is relative&lt;/td&gt;
&lt;td&gt;Turn the sync move on if you want absolute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The sync move never happens&lt;/td&gt;
&lt;td&gt;&lt;code&gt;track/syncFader/speed&lt;/code&gt; is 0&lt;/td&gt;
&lt;td&gt;Set it above 0; check &lt;code&gt;track/syncFader/fadeTime&lt;/code&gt; is not -1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tracking dropped by itself&lt;/td&gt;
&lt;td&gt;The host stopped writing &lt;code&gt;track/enable&lt;/code&gt; and the watchdog fired&lt;/td&gt;
&lt;td&gt;The host must write it continuously&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tracking drops on network hiccups&lt;/td&gt;
&lt;td&gt;&lt;code&gt;track/watchdog/timeout&lt;/code&gt; is too tight&lt;/td&gt;
&lt;td&gt;Lengthen it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tracking does not drop when the host dies&lt;/td&gt;
&lt;td&gt;&lt;code&gt;track/watchdog/enable&lt;/code&gt; is false&lt;/td&gt;
&lt;td&gt;Set it true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The machine moves too far for the host&amp;rsquo;s movement&lt;/td&gt;
&lt;td&gt;&lt;code&gt;track/factor&lt;/code&gt; is too high&lt;/td&gt;
&lt;td&gt;Lower it, and check the machine&amp;rsquo;s own limits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The machine overspeeds&lt;/td&gt;
&lt;td&gt;This block has no speed limit&lt;/td&gt;
&lt;td&gt;Set the limits downstream&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output is noisy&lt;/td&gt;
&lt;td&gt;&lt;code&gt;filter/omega&lt;/code&gt; is too high, or the order is 0&lt;/td&gt;
&lt;td&gt;Lower the cut-off, or use order 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The machine lags the host&lt;/td&gt;
&lt;td&gt;The filter, the interpolator, or both&lt;/td&gt;
&lt;td&gt;Raise &lt;code&gt;filter/omega&lt;/code&gt;; check &lt;code&gt;sampleFactor&lt;/code&gt; matches the host&amp;rsquo;s real rate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output steps at each host update&lt;/td&gt;
&lt;td&gt;&lt;code&gt;interpolator/sampleFactor&lt;/code&gt; is too low&lt;/td&gt;
&lt;td&gt;Set it to the real ratio&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output is stale and smooth&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sampleFactor&lt;/code&gt; is too high&lt;/td&gt;
&lt;td&gt;Lower it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Changing &lt;code&gt;offset&lt;/code&gt; did not move the machine&lt;/td&gt;
&lt;td&gt;Expected: the block absorbs the change deliberately&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authority switches abruptly&lt;/td&gt;
&lt;td&gt;The fade times are 0&lt;/td&gt;
&lt;td&gt;Set them above 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output froze and stays wrong&lt;/td&gt;
&lt;td&gt;A value that is not a number reached the input&lt;/td&gt;
&lt;td&gt;Reset from your application; fix the link&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I cannot reset from the tree&lt;/td&gt;
&lt;td&gt;&lt;code&gt;reference&lt;/code&gt; and &lt;code&gt;resetting&lt;/code&gt; are read-only there&lt;/td&gt;
&lt;td&gt;Your application must do it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A restart resumed tracking oddly&lt;/td&gt;
&lt;td&gt;The filter and interpolator keep their history across a restart&lt;/td&gt;
&lt;td&gt;Re-engage tracking after a start&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for a hand controller at 100 Hz on a 1 kHz task:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;track/factor                  = 1.0
track/enableFader/fadeInTime  = 0.1
track/enableFader/fadeOutTime = 0.1
track/syncFader/enable        = false
track/watchdog/enable         = true
track/watchdog/timeout        = 0.01
filter/order                  = 2
filter/omega                  = 15.7
filter/beta                   = 0.707
interpolator/sampleFactor     = 10
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tracking&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Relative.&lt;/strong&gt; The machine follows increments, scaled by &lt;code&gt;track/factor&lt;/code&gt;. The host&amp;rsquo;s absolute position is irrelevant unless the sync move is on&lt;/td&gt;
&lt;td&gt;&lt;code&gt;track/isTracking&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;track/factor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not limited.&lt;/strong&gt; It multiplies every host movement&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Machine speed and position&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing here&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;This block imposes no limits at all.&lt;/strong&gt; They belong downstream&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Host loss&lt;/td&gt;
&lt;td&gt;&lt;code&gt;track/watchdog/…&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tracking is &lt;strong&gt;dropped&lt;/strong&gt; if &lt;code&gt;track/enable&lt;/code&gt; stops being written&lt;/td&gt;
&lt;td&gt;&lt;code&gt;track/isTracking&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authority&lt;/td&gt;
&lt;td&gt;The enable fader&lt;/td&gt;
&lt;td&gt;Ramps in and out rather than switching&lt;/td&gt;
&lt;td&gt;&lt;code&gt;track/enableFader/value&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sync move&lt;/td&gt;
&lt;td&gt;&lt;code&gt;track/syncFader/…&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Speed-limited move to the host&amp;rsquo;s position on engage. &lt;strong&gt;Never completes before the fade-in does&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;track/syncFader/value&lt;/code&gt;, &lt;code&gt;…/fadeTime&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;syncFader/speed&lt;/code&gt; of 0&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;No sync move happens&lt;/strong&gt; and the output holds&lt;/td&gt;
&lt;td&gt;&lt;code&gt;…/fadeTime&lt;/code&gt; reads -1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Filtering&lt;/td&gt;
&lt;td&gt;&lt;code&gt;filter/…&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Order clamped to 0, 1 or 2; &lt;code&gt;omega&lt;/code&gt; and &lt;code&gt;beta&lt;/code&gt; used as magnitudes. &lt;strong&gt;Cannot be made unstable&lt;/strong&gt; from the tree&lt;/td&gt;
&lt;td&gt;&lt;code&gt;filter/output&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interpolation&lt;/td&gt;
&lt;td&gt;&lt;code&gt;interpolator/sampleFactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Interpolates between the &lt;strong&gt;last two&lt;/strong&gt; host samples, so the output lags by one host period&lt;/td&gt;
&lt;td&gt;&lt;code&gt;interpolator/output&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;offset&lt;/code&gt; changes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Handled&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Neither a filter transient nor a position jump — the block absorbs both&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Values that are not numbers&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not checked. One bad sample poisons the output &lt;strong&gt;permanently&lt;/strong&gt; until a reset&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reset and reference&lt;/td&gt;
&lt;td&gt;Application only&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not writable from the tree&lt;/strong&gt;, only published&lt;/td&gt;
&lt;td&gt;&lt;code&gt;resetting&lt;/code&gt;, &lt;code&gt;reference&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Startup&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;The filter and interpolator keep their history; the watchdog defaults tracking to &lt;strong&gt;off&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel count&lt;/td&gt;
&lt;td&gt;Fixed at build time&lt;/td&gt;
&lt;td&gt;Cannot be changed from the tree&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This block &lt;strong&gt;logs nothing, ever&lt;/strong&gt;. Every condition above shows as a value on a
trace, or not at all.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.30.0 (bc348fd).&lt;/p&gt;

      </description>
    </item>
    
  </channel>
</rss>
