Transformation
Transformation is the conversion stage between an actuator’s engineering units and a drive’s raw units.8 minute read
Transformation is the conversion stage between an actuator’s engineering
units and a drive’s raw units. It converts setpoints going out, converts and
conditions measurements coming back, and holds the gear ratio that relates the
two sides.
It contains a transducer, and on the measurement side a linearisation table, an IIR filter and a low-pass filter, applied in that order.
flowchart LR
i1(["inputSoftwareSide"]) --> B["Transformation"]
i2(["inputHardwareSide"]) --> B
p1(["gearRatio"]) --> B
p2(["referenceLoadSide"]) --> B
B --> o1(["outputSoftwareSide"])
B --> o2(["outputHardwareSide"])
B --> s1(["transducer"])
B --> s2(["actualFilter, actualLP1Filter"])
B --> s3(["actualLinearizeLookup"])
Almost everything you configure is in the sub-trees. The sensor resolution and referencing are under
transducer; the measurement filtering is underactualLP1FilterandactualFilter; the linearisation table is underactualLinearizeLookup. This block itself has only two parameters.
The filtered measurement and its velocity are not published. The block computes both and passes them to its parent in software, but neither appears in the tree — so you can see
outputSoftwareSidebefore the low-pass, and you cannot see the result after it.
gearRatioof 0 is not refused and produces an invalid measurement path. Never write 0 to it.
Not every instance has every sub-tree. The linearisation table is created only for a block that converts one way, towards software; a block that converts both ways does not have it. If
actualLinearizeLookupis missing from your tree, that is why.actualFilterandactualLP1Filterare present on every block that has a measurement side at all, whichever direction it converts.
The measurement chain
The measurement side runs in a fixed order:
inputHardwareSide → transducer → actualLinearizeLookup → actualFilter → actualLP1Filter
(one-way blocks only) (IIR) (low-pass)
outputSoftwareSide is published after actualFilter and before
actualLP1Filter, so the leaf you can trace shows the IIR’s effect but not
the low-pass’s.
actualFilter is a full IIR of up to order 6 — two notches plus a
low-pass — and it is the right place for a structural resonance or a
mains-frequency pickup, because it acts on the measurement before
actualLP1Filter derives a velocity from it. It is pass-through by default
(order 1, num[0] = den[0] = 1), so an unconfigured block conditions nothing
here.
A switched-off
actualFilteris a bypass, not a mute. On its own anIIRFilteroutputs zero when it is disabled, whenorderis 0, or whenden[0]is 0 — and a measured position that reads zero is far worse than an unfiltered one. This block therefore guards it: whenever the filter is not actually filtering, the unfiltered measurement is passed to the low-pass instead. You can disableactualFiltersafely.
Signals
Inputs
| Path | Unit | Range | Description |
|---|---|---|---|
inputSoftwareSide |
actuator unit | unbounded | The setpoint to send to the drive. Multiplied by gearRatio, then converted to raw units. |
inputHardwareSide |
ticks | unbounded | The raw sensor reading. Converted to actuator units, then divided by gearRatio. |
Outputs
| Path | Unit | Description |
|---|---|---|
outputSoftwareSide |
actuator unit | Where the machine is, in actuator units. On a both-ways instance this is unfiltered; on a measurement-only instance it has been through the linearisation table and the IIR filter. Either way it has not been through the low-pass. |
outputHardwareSide |
ticks | The setpoint for the drive. |
Parameters
| Path | Unit | Default | Range | Effect |
|---|---|---|---|---|
gearRatio |
ticks-side unit per actuator unit | see below | non-zero | Multiplies the outgoing setpoint and divides the incoming measurement. A 0 is not refused and makes the measurement path invalid. |
referenceLoadSide |
actuator unit | 0.0 | unbounded | The position used when referencing. This is in actuator units, while the transducer’s own reference parameters below are in motor-side units — do not confuse the two. |
Both are persistent and survive a controller restart.
The parameters that matter most are in the sub-trees:
| Path | Effect |
|---|---|
transducer/ticksPerRevolution, …/gainNum, …/gainDen |
The sensor conversion. See the Transducer page. |
transducer/offset, transducer/referencing/… |
Referencing. |
actualLP1Filter/omega |
The measurement low-pass cut-off, in radians per second. |
actualFilter/… |
The IIR filter’s numerator and denominator — used as a notch, typically. Measurement-only instances. |
actualLinearizeLookup/x, …/y, …/numPoints |
The sensor linearisation table, six points. Measurement-only instances. |
Setup
- Set up the transducer first —
transducer/ticksPerRevolutionand the two gain factors. Verify it on its own before touching this block. - Set
gearRatiofrom the drivetrain between the sensor and the actuator’s output. Never write 0. - Move the machine a known distance by hand and confirm
outputSoftwareSidechanges by that amount in actuator units. This checks the transducer and the gear ratio together. - Set
actualLP1Filter/omega— go to Tuning. - If your instance has one, set the linearisation table under
actualLinearizeLookupfrom measurements of the sensor’s error. - If your instance has one, set the IIR filter under
actualFilterto notch out any structural frequency you need removed. Leave it as a pass-through until you know you need it. - Set
referenceLoadSideand reference the machine, remembering this value is in actuator units.
Tuning
- Get the conversion exactly right before any filtering. A gain error looks like a scaling problem at every speed; a filter problem only appears when things move.
- Verify the conversion over a long move, not a short one.
- Set
actualLP1Filter/omegafrom the noise on your measurement and the bandwidth your control loop needs. Lower removes more noise and adds more lag. - You cannot see the low-pass’s output in the tree, so judge it by its effect on the loop rather than by watching the signal: too low a cut-off shows as sluggish or oscillatory position control.
- Use the IIR filter for a specific structural frequency, not for general smoothing — that is the low-pass’s job. Design it as a discrete-time filter and enter the coefficients directly.
- Set the linearisation table only after the gain and offset are right. It corrects the shape of the sensor’s error, not its scale.
- Re-check everything after a task-rate change: the low-pass cut-off is in radians per second and does not move, but the IIR coefficients are discrete-time and do depend on the rate.
The block corrects the low-pass’s lag by one sample before handing the result on, which is why the measurement the controller sees is less delayed than the filter alone would give.
| Symptom | Cause | Action |
|---|---|---|
| The measurement is invalid | gearRatio is 0, which is not refused |
Set a non-zero ratio |
| The measurement is proportionally wrong | The gear ratio or the transducer conversion | Check the transducer alone first, then the ratio |
| The machine moves the wrong way | A sign error in the gear ratio or the transducer gain | Use a negative value on one of them, not both |
| The setpoint and the measurement disagree by a constant | The transducer offset, or referencing has not been done | Reference the machine |
| I cannot see the filtered measurement | It is not published | Judge the filter by its effect on the control loop |
actualLinearizeLookup is missing from my tree |
Your instance converts both ways, and only measurement-only instances have it | Nothing — it is fixed when the controller is built |
actualFilter is missing |
Same reason | Nothing |
| The measurement is noisy | actualLP1Filter/omega is too high |
Lower it, and accept more lag |
| Position control became sluggish or unstable | actualLP1Filter/omega is too low for the loop |
Raise it |
| The IIR filter did nothing after a task-rate change | Its coefficients are discrete-time and depend on the rate | Recalculate and re-enter them |
| Referencing put the machine in the wrong place | referenceLoadSide is in actuator units, unlike the transducer’s own reference |
Check which one you set |
| The drive stopped responding after referencing | The transducer holds its output until the positions agree | See the Transducer page |
| I need to bypass the conversion | Not possible — there is no enable, and the two sides are in different units | Set gearRatio to 1 and check the transducer |
A starting point for a direct-driven axis:
gearRatio = 1.0
referenceLoadSide = 0.0
actualLP1Filter/omega = 200.0
transducer/… = <see the Transducer page>
Limits and errors
| Limit | Set by | What happens | Reported |
|---|---|---|---|
| Conversion | gearRatio and the transducer |
The setpoint is multiplied by the ratio, the measurement divided by it | outputSoftwareSide, outputHardwareSide |
gearRatio of 0 |
Not checked | The measurement path becomes invalid | Not reported |
| Values that are not numbers | Nothing | Not checked at this level. The sub-modules behave differently: the lookup freezes, the filters propagate | Not reported |
| Measurement filtering | The three sub-trees | Linearisation, then the IIR filter, then the low-pass — but only a measurement-only instance has the linearisation table | Not reported |
actualFilter switched off |
Guarded by this block | The unfiltered measurement is passed to the low-pass. A bare IIRFilter would output 0 here |
The filter’s own isEnabled |
| Filtered outputs | Fixed | Computed and not published. The filtered measurement and its velocity go to the parent in software only | Not applicable |
| Filter lag | Fixed | The block advances the filtered signal by one sample using the filter’s own derivative, recovering most of the low-pass’s delay | Not reported |
referenceLoadSide units |
Fixed | Actuator units, unlike the transducer’s own reference parameters | Not reported |
| Sub-modules present | Fixed at build time | Depends on which directions the instance converts | Not reported |
| Enable | None | There is no enable, disable or isEnabled, despite what older documentation said | Not applicable |
| Channel count | Fixed | One axis per instance, always | Not reported |
This block logs nothing itself. The transducer below it logs during referencing. Every other condition above shows as a value on a trace, or not at all.
Verified against motorcortex-control3 3.30.0 (bc348fd).