Transformation

Transformation is the conversion stage between an actuator’s engineering units and a drive’s raw units.
Current release

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 under actualLP1Filter and actualFilter; the linearisation table is under actualLinearizeLookup. 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 outputSoftwareSide before the low-pass, and you cannot see the result after it.

gearRatio of 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 actualLinearizeLookup is missing from your tree, that is why. actualFilter and actualLP1Filter are 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 actualFilter is a bypass, not a mute. On its own an IIRFilter outputs zero when it is disabled, when order is 0, or when den[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 disable actualFilter safely.

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

  1. Set up the transducer first — transducer/ticksPerRevolution and the two gain factors. Verify it on its own before touching this block.
  2. Set gearRatio from the drivetrain between the sensor and the actuator’s output. Never write 0.
  3. Move the machine a known distance by hand and confirm outputSoftwareSide changes by that amount in actuator units. This checks the transducer and the gear ratio together.
  4. Set actualLP1Filter/omega — go to Tuning.
  5. If your instance has one, set the linearisation table under actualLinearizeLookup from measurements of the sensor’s error.
  6. If your instance has one, set the IIR filter under actualFilter to notch out any structural frequency you need removed. Leave it as a pass-through until you know you need it.
  7. Set referenceLoadSide and reference the machine, remembering this value is in actuator units.

Tuning

  1. 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.
  2. Verify the conversion over a long move, not a short one.
  3. Set actualLP1Filter/omega from the noise on your measurement and the bandwidth your control loop needs. Lower removes more noise and adds more lag.
  4. 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.
  5. 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.
  6. Set the linearisation table only after the gain and offset are right. It corrects the shape of the sensor’s error, not its scale.
  7. 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 measurement path: a noisy converted input, the low-pass output, and thecompensated output the block passes on. The compensation recovers most of thedelay the filter adds.

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).