MultiSine
MultiSine adds together a set of sine waves and an offset.7 minute read
MultiSine adds together a set of sine waves and an offset. Its job here is
cancelling a repeating disturbance — motor cogging, a ballscrew’s lead
error, a gearbox’s tooth-meshing ripple. Fit the error as a few harmonics, put
them here, and the correction cancels it.
The input is not time. It is usually a position, so frequency is in
cycles per unit of input, not hertz. The disturbances this block cancels
repeat with position, not with the clock.
flowchart LR
i1(["input — usually a position"]) --> B["MultiSine"]
i2(["disable"]) --> B
B --> o1(["output — the summed correction"])
B --> o2(["isEnabled"])
The output is
gain× Σamplitude[i]· sin(2π ·frequency[i]· input +phase[i]) +offset, summed over harmonics 1 toorder.
Element 0 of amplitude, frequency and phase is never used. The first
harmonic goes in element 1. Anything written to element 0 is ignored
silently.
Never write order larger than the array length. It is not checked, and a
value past the end reads memory outside the array. Find the ceiling with Setup
step 2.
The block ships with gain at 0, so it produces nothing until you set it.
That is deliberate — an unconfigured correction should inject nothing.
Signals
Inputs
| Path | Unit | Range | Description |
|---|---|---|---|
input |
m or rad, usually a position | unbounded | What the correction is periodic in. The block writes zero here on every disabled cycle, so a trace reads zero while it is off. |
Outputs
| Path | Unit | Description |
|---|---|---|
output |
N or N·m, or whatever you are correcting | The summed correction. Zero — not a pass-through — while disabled, and zero whenever order is 0 or gain is 0. |
isEnabled |
- | True when enable is true and disable is false. It does not mean output is being produced: gain = 0 gives zero while this reads true. |
Parameters
| Path | Unit | Default | Range | Effect |
|---|---|---|---|---|
enable |
- | true | - | False makes the output zero. |
order |
- | 1 | 1 up to the array length minus 1 | How many harmonics to sum. Not checked — a value past the array length reads out of bounds. 0 gives zero output. |
gain |
- | 0.0 | any | Scales the whole sum. This is the fade-in knob — raise it from 0 to bring a correction in without touching the fit. |
offset |
output unit | 0.0 | any | Added after the gain. A constant term. |
amplitude |
output unit | all 0 | any | One per harmonic. Element 0 is ignored — start at element 1. |
frequency |
cycles per input unit | all 0 | any | How many times each harmonic repeats per unit of input. Not hertz. Element 0 ignored. |
phase |
rad | all 0 | any | Where each harmonic starts. Element 0 ignored. |
All are persistent and survive a restart, which is how a fitted correction ships with a machine. No parameters exist below this block.
Setup
-
Measure the disturbance. Move the axis slowly through at least one full period of the effect you are cancelling and record the error against position.
-
Find the array length by reading
amplitudeback from the parameter tree.ordermust stay at least one below it. -
Work out the fundamental spatial period. For motor cogging that is one pole pitch, so the frequency is the pole count per motor revolution — a number of cycles per revolution, not per second.
-
Set
orderfirst, then the three arrays. Setting the order afterwards from an application clears everything, includingoffset. -
Write the fundamental into element 1, its second harmonic into element 2, and so on. Leave element 0 alone; it does nothing.
-
Leave
gainat 0 and confirmoutputis zero. -
Raise
gainfrom 0 toward 1 in steps, watching the error you are trying to cancel.Step 7 injects a real force into the machine. A correction with the wrong phase adds to the disturbance instead of cancelling it, doubling it at full gain. Raise the gain slowly and watch the error get smaller, not larger.
-
If the error grew, shift each
phaseby π and repeat.
Tuning
- Get the frequency right before anything else. A correction at the wrong spatial period cannot be rescued by amplitude or phase.
- Tune one harmonic at a time, starting with the fundamental in element 1. Set the others' amplitudes to zero while you do it.
- For each harmonic: raise its amplitude until the error stops improving, then adjust its phase to minimise what is left. The two interact, so go back and forth once or twice.
- Add the next harmonic only when the previous one has stopped improving. Two or three is usually enough; more fits noise.
- Use
gainas the master switch. It lets you compare with and without the whole correction, and lets you ramp it in on a running machine. - Re-check after any mechanical change. The fit belongs to the hardware.
- Nothing here depends on the task rate.
Read each harmonic’s contribution off how the shape changes as one is added.
| Symptom | Cause | Action |
|---|---|---|
The output is zero and isEnabled reads true |
gain is 0 — the default — or order is 0 |
Set gain above 0 |
| Writing an amplitude did nothing | It went into element 0, which is ignored | Start at element 1 |
| The disturbance got worse | The phase is inverted, so the correction adds instead of cancelling | Shift every phase by π |
| The correction cancels at one position and adds at another | The frequency is wrong | Re-derive it as cycles per unit of input, per Setup step 3 |
| The correction works at low speed and not at high speed | It is periodic in position and something is adding a speed-dependent effect | This block cannot cancel that; look at friction or damping |
| The frequency seems to be out by a large factor | It was configured in hertz rather than cycles per input unit | Recompute against the input’s units |
| The arrays went to zero after setting the order from an application | Setting the order clears all three arrays and offset |
Write order first |
input reads zero on a trace |
You are looking at a disabled cycle — the block zeroes its own input | Enable it before judging the link |
The controller behaves strangely after writing a large order |
It was written past the array length, which reads out of bounds | Keep order below the array length; restart the controller |
| The output has a constant bias | offset is non-zero |
Set it to 0 unless you meant it |
| The correction cannot be switched off without losing the fit | Set gain to 0 — the coefficients are kept |
|
| A non-numeric input produced a non-numeric output that then cleared | Expected: the block holds no state | Fix the source |
| You need this on several axes | Not possible — this block is single channel | Use one instance per axis |
A starting point for a cogging correction on a motor with 12 poles, before the amplitudes are fitted:
enable = true
order = 2
gain = 0.0
offset = 0.0
frequency = 0, 12, 24
amplitude = 0, 0, 0
phase = 0, 0, 0
Element 0 is left at zero throughout because it is ignored. Fit the amplitudes
with Tuning steps 2 and 3, then raise gain.
Limits and errors
| Limit | Set by | What happens | Reported |
|---|---|---|---|
order below the array length |
Nothing | Not checked. A larger value reads past the end of all three arrays, which is undefined and can crash or produce nonsense. Discover the length by reading amplitude back |
Not reported |
| Element 0 | Fixed | Ignored in all three arrays. Harmonics start at element 1 | Not reported |
order = 0 |
Fixed | The output is zero | Not reported; isEnabled still reads true |
output |
Nothing | Unbounded — the sum of the amplitudes times the gain, plus the offset. Limit it downstream if the consumer needs a bound | Not reported |
frequency units |
Fixed | Cycles per unit of input, not hertz | Not reported |
| Disabled behaviour | Fixed | Output zero, not a pass-through, and input is zeroed too |
Not reported |
| Non-numeric input | Nothing | Produces a non-numeric output. Stateless, so it recovers immediately | Not reported |
| Channel count | Fixed | One channel per instance, always | Not reported |
The block raises no errors or warnings and logs nothing. Every failure above shows as a value on a trace, not as a message.
Verified against motorcortex-control3 3.30.0 (bc348fd).