<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title> – Custom signals</title>
    <link>/docs/motorcortex-io-tools/motorcortex-desk/custom-signals/</link>
    <description>Recent content in Custom signals on </description>
    <generator>Hugo -- gohugo.io</generator>
    
	  <atom:link href="/docs/motorcortex-io-tools/motorcortex-desk/custom-signals/index.xml" rel="self" type="application/rss+xml" />
    
    
      
        
      
    
    
    <item>
      <title>Docs: Custom signal syntax</title>
      <link>/docs/motorcortex-io-tools/motorcortex-desk/custom-signals/syntax/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/motorcortex-io-tools/motorcortex-desk/custom-signals/syntax/</guid>
      <description>
        
        
        &lt;h4 id=&#34;referring-to-a-signal&#34;&gt;Referring to a signal&lt;/h4&gt;
&lt;p&gt;Every reference to another signal is wrapped in &lt;code&gt;${…}&lt;/code&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Written&lt;/th&gt;
&lt;th&gt;Reads&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${root/ManipulatorControl/jointTorquesActual}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;That parameter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${root/ManipulatorControl/jointTorquesActual[0]}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;One element of an array parameter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${x}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The plot&amp;rsquo;s X axis: seconds since the time origin, or the X-source signal in XY mode&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;${t}&lt;/code&gt; and &lt;code&gt;${time}&lt;/code&gt; are accepted for the X axis as well, and all three spellings collapse to one reference.&lt;/p&gt;
&lt;p&gt;A leading &lt;code&gt;y =&lt;/code&gt; is stripped, so &lt;code&gt;y = ${root/a} * 2&lt;/code&gt; and &lt;code&gt;${root/a} * 2&lt;/code&gt; are the same expression.&lt;/p&gt;
&lt;h4 id=&#34;operators&#34;&gt;Operators&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;+&lt;/code&gt; &lt;code&gt;-&lt;/code&gt; &lt;code&gt;*&lt;/code&gt; &lt;code&gt;/&lt;/code&gt; &lt;code&gt;%&lt;/code&gt; &lt;code&gt;^&lt;/code&gt;, parentheses, and unary sign.&lt;/p&gt;
&lt;p&gt;Unary minus binds looser than &lt;code&gt;^&lt;/code&gt;, so &lt;code&gt;-${a}^2&lt;/code&gt; is −(a²), as in ordinary mathematical notation. Write &lt;code&gt;(-${a})^2&lt;/code&gt;
if you meant to square the negated value.&lt;/p&gt;
&lt;h4 id=&#34;when-an-expression-will-not-compile&#34;&gt;When an expression will not compile&lt;/h4&gt;
&lt;p&gt;It is never stored. The editor stays open with the parser&amp;rsquo;s message, so the plot never carries a trace that
silently produces nothing.&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: Custom signal functions</title>
      <link>/docs/motorcortex-io-tools/motorcortex-desk/custom-signals/functions/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/motorcortex-io-tools/motorcortex-desk/custom-signals/functions/</guid>
      <description>
        
        
        &lt;h4 id=&#34;functions&#34;&gt;Functions&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;abs&lt;/code&gt; &lt;code&gt;sqrt&lt;/code&gt; &lt;code&gt;exp&lt;/code&gt; &lt;code&gt;log&lt;/code&gt; &lt;code&gt;log10&lt;/code&gt; &lt;code&gt;log2&lt;/code&gt; &lt;code&gt;sin&lt;/code&gt; &lt;code&gt;cos&lt;/code&gt; &lt;code&gt;tan&lt;/code&gt; &lt;code&gt;asin&lt;/code&gt; &lt;code&gt;acos&lt;/code&gt; &lt;code&gt;atan&lt;/code&gt; &lt;code&gt;sinh&lt;/code&gt; &lt;code&gt;cosh&lt;/code&gt; &lt;code&gt;tanh&lt;/code&gt; &lt;code&gt;floor&lt;/code&gt; &lt;code&gt;ceil&lt;/code&gt;
&lt;code&gt;round&lt;/code&gt; &lt;code&gt;sign&lt;/code&gt; &lt;code&gt;atan2&lt;/code&gt; &lt;code&gt;pow&lt;/code&gt; &lt;code&gt;hypot&lt;/code&gt; &lt;code&gt;min&lt;/code&gt; &lt;code&gt;max&lt;/code&gt; &lt;code&gt;clamp&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;min&lt;/code&gt; and &lt;code&gt;max&lt;/code&gt; are variadic and pure: they compare their arguments at the current sample and nothing else. So
&lt;code&gt;max(${root/a}, 0)&lt;/code&gt; clamps a signal at zero. For the rolling versions see the &lt;strong&gt;Windows&lt;/strong&gt; tab.&lt;/p&gt;
&lt;h4 id=&#34;angles&#34;&gt;Angles&lt;/h4&gt;
&lt;p&gt;The controller works in radians; you usually want to read degrees.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Written&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;deg(v)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Converts radians to degrees&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rad(v)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Converts degrees to radians&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A joint error is far easier to judge in degrees, which is why the worked example wraps the subtraction in &lt;code&gt;deg(…)&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&#34;constants&#34;&gt;Constants&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;pi&lt;/code&gt;, &lt;code&gt;e&lt;/code&gt;, &lt;code&gt;tau&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A constant on its own is a valid expression, so &lt;code&gt;0.5&lt;/code&gt; draws a horizontal reference line at 0.5, handy for marking
a tolerance band against a live signal.&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: Custom signal time windows</title>
      <link>/docs/motorcortex-io-tools/motorcortex-desk/custom-signals/windows/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/motorcortex-io-tools/motorcortex-desk/custom-signals/windows/</guid>
      <description>
        
        
        &lt;p&gt;These functions read a trailing time window rather than only the current sample. All of them are spelled
&lt;code&gt;(signal, seconds)&lt;/code&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Function&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;average(v, s)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Rolling mean over the last &lt;em&gt;s&lt;/em&gt; seconds. The usual way to make a noisy error readable. &lt;code&gt;avg&lt;/code&gt; is accepted too&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;movmax(v, s)&lt;/code&gt; / &lt;code&gt;movmin(v, s)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The extreme over the window. &lt;code&gt;maximum&lt;/code&gt; and &lt;code&gt;minimum&lt;/code&gt; are accepted too&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rate(v, s)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Change per second across the window. A derivative whose window length is also its smoothing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=&#34;two-worked-lines&#34;&gt;Two worked lines&lt;/h4&gt;
&lt;p&gt;Smooth a noisy torque signal over two seconds:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;average(${root/ManipulatorControl/jointTorquesActual[0]}, 2)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Peak-to-peak of the same signal over five seconds:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;movmax(${root/ManipulatorControl/jointTorquesActual[0]}, 5) - movmin(${root/ManipulatorControl/jointTorquesActual[0]}, 5)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The rolling functions take the signal-processing spelling rather than overloading &lt;code&gt;min&lt;/code&gt; and &lt;code&gt;max&lt;/code&gt;, because a rolling
minimum and a two-argument minimum cannot be told apart by their arguments.&lt;/p&gt;
&lt;h4 id=&#34;how-the-window-behaves&#34;&gt;How the window behaves&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;It answers from the very first sample rather than leaving the trace blank while the window fills, so a fresh
&lt;code&gt;average&lt;/code&gt; is simply a mean over fewer points at first.&lt;/li&gt;
&lt;li&gt;It is measured against controller time, not against the X axis, so it keeps its meaning in XY mode.&lt;/li&gt;
&lt;li&gt;Each call site keeps its own history. That history restarts when you edit the expression, when the session
reconnects, or when time runs backwards. A window never blends two timelines.&lt;/li&gt;
&lt;/ul&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: Custom signals over arrays</title>
      <link>/docs/motorcortex-io-tools/motorcortex-desk/custom-signals/arrays/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/motorcortex-io-tools/motorcortex-desk/custom-signals/arrays/</guid>
      <description>
        
        
        &lt;p&gt;A reference with no index reads the &lt;strong&gt;whole&lt;/strong&gt; parameter, and the formula is then evaluated element by element:
element &lt;em&gt;i&lt;/em&gt; of the result is computed from element &lt;em&gt;i&lt;/em&gt; of every array input. This is what turns the worked example&amp;rsquo;s
single expression into one trace per joint.&lt;/p&gt;
&lt;p&gt;Each element gets its own colour, axis and visibility, exactly like the channels of an ordinary array parameter.&lt;/p&gt;
&lt;h4 id=&#34;mixing-widths&#34;&gt;Mixing widths&lt;/h4&gt;
&lt;p&gt;Two kinds of reference broadcast, giving the same number to every element:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a &lt;strong&gt;scalar&lt;/strong&gt; parameter, &lt;code&gt;${root/Logic/mode}&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;an &lt;strong&gt;indexed&lt;/strong&gt; reference, &lt;code&gt;${…/jointPositionsTarget[0]}&lt;/code&gt;, which always reads element 0 whatever element of the
formula it is feeding.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So this subtracts joint 0&amp;rsquo;s target from every joint&amp;rsquo;s actual:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;${root/ManipulatorControl/jointPositionsActual} - ${root/ManipulatorControl/jointPositionsTarget[0]}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The formula&amp;rsquo;s width is the &lt;strong&gt;widest&lt;/strong&gt; unindexed array it reads. Combining arrays of different widths is allowed, but
the elements past the end of the shorter one have no value to read and simply produce no sample, so those traces stay
empty. Index the shorter array if you meant to broadcast it.&lt;/p&gt;
&lt;h4 id=&#34;width-is-re-derived-not-fixed&#34;&gt;Width is re-derived, not fixed&lt;/h4&gt;
&lt;p&gt;The width comes from the parameter tree whenever the tree can answer. A formula written while disconnected therefore
fans out on connect, and collapses back to a single trace if you edit the expression so it no longer reads an array.&lt;/p&gt;
&lt;h4 id=&#34;one-formula-one-signal&#34;&gt;One formula, one signal&lt;/h4&gt;
&lt;p&gt;Removing any single element removes the whole formula. From your side it is one signal, and a partial one would
immediately be rebuilt.&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: Custom signal lifecycle</title>
      <link>/docs/motorcortex-io-tools/motorcortex-desk/custom-signals/lifecycle/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/motorcortex-io-tools/motorcortex-desk/custom-signals/lifecycle/</guid>
      <description>
        
        
        &lt;h4 id=&#34;inputs-are-subscribed-for-you&#34;&gt;Inputs are subscribed for you&lt;/h4&gt;
&lt;p&gt;A signal a formula reads that is not already plotted is added &lt;strong&gt;hidden&lt;/strong&gt;: it subscribes normally so the formula has
data, takes a palette colour, and shows a live value, without drawing a line you did not ask for.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;/docs/motorcortex-io-tools/motorcortex-desk/custom-signals/_media/custom-signal-hidden-inputs.png&#34;
         alt=&#34;An auto-added input listed dimmed below the plotted traces&#34; width=&#34;800&#34;/&gt;&lt;/a&gt;
&lt;/figure&gt;

&lt;p&gt;Plotting one by hand promotes it to an ordinary visible trace, and it then survives the formula that pulled it in.
Inputs that no formula still references are dropped again.&lt;/p&gt;
&lt;h4 id=&#34;validation&#34;&gt;Validation&lt;/h4&gt;
&lt;p&gt;References are checked against the live parameter tree when you commit. An unknown path, a non-numeric parameter or
a channel outside the array is refused, with every problem named at once rather than one per attempt.&lt;/p&gt;
&lt;p&gt;The check is skipped while disconnected, where there is nothing to check against, which is why a formula written
offline can still be saved, and is validated on the next connect.&lt;/p&gt;
&lt;h4 id=&#34;saving-and-restoring&#34;&gt;Saving and restoring&lt;/h4&gt;
&lt;p&gt;Custom signals and their auto-added inputs are written to &lt;code&gt;traces.json&lt;/code&gt; along with the ordinary traces, so a saved
setup restores them. See
&lt;a href=&#34;/docs/motorcortex-io-tools/motorcortex-desk/plotting/&#34;&gt;Plotting&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&#34;formulas-with-no-live-input&#34;&gt;Formulas with no live input&lt;/h4&gt;
&lt;p&gt;A formula that reads no controller signal (a bare constant, or one reading only &lt;code&gt;${x}&lt;/code&gt;) has no publish cycle to
ride on, so it is driven by a local 30 Hz clock instead. &lt;code&gt;sin(${x})&lt;/code&gt; therefore draws with no controller connected at
all, which makes it a quick way to check that a plot is alive.&lt;/p&gt;

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