What input shaping is
Input shaping is a pre-filter applied to the stepper motor velocity commands before they reach the motor. The goal is to suppress mechanical vibrations excited by motion. The technique was developed by Singer and Seering (MIT, 1990) and is now standard in 3D printer firmwares.
The signal chain
The motion planner outputs a velocity step: the stepper ISR receives a target velocity and must reach it instantly. In the ideal case, the motor follows the command perfectly. In reality, the mechanical system — belt, pulley, frame — has a resonant frequency. A velocity step excites that resonance, producing ringing (ghosting) on the printed part.
The input shaper sits between the planner and the step generator. It convolves the velocity step with a short FIR pulse train (the "shaper"):
The pulse amplitudes and times are chosen so that the residual vibration at the target frequency is exactly zero. The filter is causal () and normalized (), so the total displacement is unchanged — the move simply takes longer to complete.
Zero-vibration condition
A second-order mechanical resonance responds to an impulse with a decaying sinusoid. Two impulses, spaced by exactly half the resonant period and weighted appropriately, produce sinusoids that cancel at the resonant frequency. A three-impulse shaper (ZVD, MZV, EI) adds a third pulse to make the cancellation robust against damping ratio uncertainty.
| Shaper | Pulses | Time spread | Notch depth | Damping robustness |
|---|---|---|---|---|
| ZV | 2 | 0.5 periods | Deep | Low |
| MZV | 3 | 1.0 periods | Deep | Moderate |
| ZVD | 3 | 1.0 periods | Deeper | Moderate |
| EI | 3 | 1.5 periods | Broad, deep | High |
The deeper the notch, the lower the remaining vibration at the target frequency. The broader the notch, the more frequencies it covers — useful when the resonance is not a sharp peak. The cost is a longer shaped move.
In the firmware
The shaper is not a continuous-time filter. It operates in the step ISR, which runs every step event. The shaper stores a queue of upcoming step timestamps; each incoming step is delayed and amplitude-scaled according to the shaper's pulse train. The step ISR overhead is proportional to the number of pulses. The Core One firmware limits each axis to 10 pulses.
Single-stage filter per axis
The stock firmware applies one input shaper per logical axis. On the Core One, the factory defaults are MZV at 60 Hz for X and MZV at 48 Hz for Y. Each shaper is a 3-pulse FIR filter that places a single deep notch at its target frequency.
Motor sweep measurements on a Core One show two distinct resonance clusters:
| Configuration | Frequency | Remaining vibrations | Suppression |
|---|---|---|---|
| Factory MZV X@60, Y@48 | — | 0.209 | 79.1% |
| Best single-shaper (ZVD@57) | 57 Hz | 0.159 | 84.1% |
| Best single-shaper (EI@56) | 56 Hz | 0.144 | 85.6% |
A single shaper cannot place deep notches at both clusters simultaneously. A ZVD or EI shaper tuned between the two peaks partially suppresses both but leaves significant residual at each.
Crosstalk in CoreXY kinematics
In CoreXY, the kinematic mixing matrix maps logical axis moves to motor steps:
| Move direction | Motor A steps | Motor B steps |
|---|---|---|
| +X | +1 | −1 |
| +Y | +1 | +1 |
Every logical X move drives both motors with opposite sign; every Y move drives both with the same sign. A vibration excited on motor A projects onto both X and Y. A vibration excited on motor B also projects onto both axes. The firmware cannot isolate a single motor's vibration to a single logical axis.
Motor sweep data — driving one motor at a time while measuring X and Y response — shows the crosstalk directly:
Motor A sweep (driving motor A, measuring X/Y response):
- Peak X response: 65 Hz, gain = 4.86
- Peak Y response: 65 Hz, gain = 2.03
Motor B sweep (driving motor B, measuring X/Y response):
- Peak Y response: 42 Hz, gain = 3.72
- Peak X response: 44 Hz, gain = 2.01
Driving motor A excites both axes at ~65 Hz. Driving motor B excites both axes at ~42 Hz. The stock firmware's single-shaper-per-axis approach damps one motor's resonance on one axis but leaves the coupled resonance from the other motor largely unfiltered.
The charts show the motor sweep data. Motor A's primary resonance cluster sits at 55–67 Hz. Motor B's primary resonance cluster sits at 33–45 Hz. On both motors, the "wrong-axis" response (crosstalk) is roughly 40–50% of the "correct-axis" response at peak.
A single filter spanning both peaks
A single shaper tuned between the two peaks covers both clusters with a broader, shallower notch. The chart below shows the vibration reduction (VR) transfer function for each shaper — the factor by which the shaper attenuates vibration at each frequency. A deep notch reaches near zero; a shallow notch does not.
The factory configuration uses MZV at 60 Hz (X) and 48 Hz (Y). Because CoreXY mixes both motors into both axes, using different frequencies on X and Y creates direction-dependent residuals — a 45° move excites both motors and sees neither shaper at full strength.
A same-shaper approach — one frequency for both axes — eliminates direction dependence. The best single shaper found from the sweep data is ZVD at 57 Hz or EI at 56 Hz:
| Shaper | 42 Hz VR | 65 Hz VR | Worst-case residual |
|---|---|---|---|
| Factory MZV X@60 | 0.339 | 0.064 | 0.339 |
| Factory MZV Y@48 | 0.126 | 0.145 | 0.145 |
| ZVD@57 (same both axes) | 0.143 | 0.040 | 0.143 |
| EI@56 (same both axes) | 0.092 | 0.014 | 0.092 |
The broader EI notch performs better than ZVD, but a single shaper cannot reach the deep suppression of a notch centered on each peak. At 42 Hz — motor B's primary resonance — even the best single shaper leaves 9% of the vibration. At 65 Hz — motor A's primary resonance — it leaves 1.4%. The 42 Hz peak is the limiting factor.
The chart below shows the shaped spectrum: the raw vibration gain multiplied by the shaper's VR at each frequency. The shaded areas are the vibrations that remain after shaping.
The fundamental problem: a single FIR shaper places one deep notch. Two distinct resonance clusters require two notches.
Cascaded second-order shaper
The community firmware adds a cascaded (second-order) input shaper: each axis gets a primary filter for one resonance cluster and a cascade filter for the other cluster. The two filters are convolved into a single FIR pulse train, so the step ISR overhead is unchanged.
The cascade search over the measured data finds:
| Configuration | Pulses | Remaining vibrations | Suppression |
|---|---|---|---|
| Factory MZV 60/48 | 3+3 | 0.209 | 79.1% |
| Best single-shaper | 3 | 0.144 | 85.6% |
| ZV@40 + ZVD@64 | 6 | 0.058 | 94.2% |
| ZVD@37 + EI@61 | 9 | 0.032 | 96.8% |
The cascaded shaper places independent notches at both resonance clusters (~42 Hz from motor B and ~65 Hz from motor A). The chart below compares the shaped spectrum for the factory configuration, the best single shaper, and the cascaded shaper. The 9-pulse ZVD+EI cascade reduces remaining vibrations by a factor of 6.5 compared to the factory configuration, and by a factor of 4.5 compared to the best single-shaper configuration.
Each shaper type has a fixed pulse count and total duration:
| Shaper type | Pulses | Total duration (× period) | Description |
|---|---|---|---|
| ZV | 2 | 0.5 | Minimal, narrow notch |
| MZV | 3 | 1.0 | Default Prusa, moderate notch |
| ZVD | 3 | 1.0 | Deeper notch than MZV |
| EI | 3 | 1.5 | Broader notch, longer duration |
A cascade of two shapers multiplies the pulse count: ZVD (3) × EI (3) = 9 pulses. The Core One firmware allows up to 10 pulses per axis, so a 9-pulse cascade fits within the budget. A 6-pulse ZV+ZVD cascade (2 × 3) leaves more headroom.
The implementation convolves two shapers into one pulse train:
void create_cascaded_input_shaper_pulses(
input_shaper_pulses_t &is_pulses,
const input_shaper::AxisConfig &primary_config,
const std::optional<input_shaper::AxisConfig> &cascade_config) {
input_shaper::Shaper shaper1 = input_shaper::get(
primary_config.damping_ratio, primary_config.frequency,
primary_config.vibration_reduction, primary_config.type);
if (!cascade_config.has_value() || cascade_config->type == Type::null) {
// No cascade — use the primary shaper alone
init_input_shaper_pulses(shaper1.a, shaper1.t, shaper1.num_pulses, &is_pulses);
return;
}
input_shaper::Shaper shaper2 = input_shaper::get(
cascade_config->damping_ratio, cascade_config->frequency,
cascade_config->vibration_reduction, cascade_config->type);
// Convolve: combined pulse at (t1_i + t2_j) has amplitude (a1_i * a2_j)
for (int i = 0; i < n1; ++i) {
for (int j = 0; j < n2; ++j) {
combined_a[idx] = shaper1.a[i] * shaper2.a[j];
combined_t[idx] = shaper1.t[i] + shaper2.t[j];
++idx;
}
}
}
The cascade configuration is stored alongside the primary configuration in input_shaper::Config:
struct Config {
std::optional<AxisConfig> axis[3];
std::optional<AxisConfig> cascade[3]; ///< Cascade second shaper per axis
std::optional<WeightAdjustConfig> weight_adjust_y;
};
And set via the M593 gcode with new cascade parameters (ST, SF, SD, SV):
M593 X ST ZVD SF 45.0 ST ZVD SF 51.2 ; X primary 45 Hz, cascade 51.2 Hz
The axis swap bug (now fixed upstream)
For over a year, input shaping on the Core One was effectively broken due to a bug in set_logical_axis_config_internal(): the X and Y shaper parameters were swapped. The second call (for Y) overwrote the results of the first call with a reversed axis mapping, causing the X shaper to be applied to Y and vice versa.
This was fixed in v6.5.3 (commit 97f968a8c), and a related calibration bug (M1959 vibrating A/B motors instead of X/Y) was fixed in v6.5.6 (commit 434fd8f67, BFW-8536).
Manual resonance finder
The PR includes a "Motor Vibration" wizard (screen_motor_vibration.cpp) accessible from the Control menu. It drives the stepper motors at a user-selected frequency and amplitude while an attached accelerometer measures the response. This lets users manually sweep frequencies to find both the primary and coupled resonances for each axis — the data needed to configure the cascade filters.
History and status
-
Sep 2024Issue #4732 opened: layer shifts with input shaping enabled. Long-running investigation (BFW-7519).
-
Dec 2024Issue #4573 opened: "Impossible print — layer shifts" with input shaping. Linked to "Avoid Crossing Perimeters" (BFW-7030).
-
May 2025v6.5.3: Input shaper axis assignment bug fixed on CoreXY — X and Y shapers no longer swapped.
-
Jul 2025v6.5.6 / BFW-8536: Input shaper calibration fixed for CoreXY — M1959 now vibrates X/Y motors instead of A/B.
-
Jun 2026Community PR #26: Cascaded input shaper and manual resonance finder. Calibration workflow not yet streamlined.
References
- Community edition PR #26: Input Shaper improvements + manual resonance finder — cascaded input shaper, manual resonance finder screen
- Stock firmware commit 97f968a8c: Fix input shaper axis assignment for CoreXY — fixed the X/Y swap in v6.5.3
- Stock firmware commit 434fd8f67: Fix input shaper calibration for CoreXY printers — fixed M1959 vibrating A/B instead of X/Y in v6.5.6
- Issue #4732: Input Shaper increases likelihood of layer shifts — BFW-7519, the long-running layer shift investigation
- Issue #4573: Impossible print - layer shifts — BFW-7030, layer shifts with "Avoid Crossing Perimeters"
- Firmware v6.5.3 release notes
- Firmware v6.5.6 release notes
Research Notes
Motor sweep measurements were performed by driving motor A or motor B at a fixed frequency and measuring the X/Y accelerometer response. Two measurement sets exist: one from the center of the bed (2026-06-09), one from a validated position (raw_validated01). Both show the same two-cluster structure: motor A dominant at ~65 Hz, motor B dominant at ~42 Hz.
The "remaining vibrations" metric is a raw weighted sum: sum of shaped gains divided by sum of original gains, pessimized over damping ratios ζ = [0.05, 0.10, 0.15]. This differs from the stock Klipper/Prusa metric which uses a thresholded sum (ignoring gains below a floor). The raw metric is more informative for cascaded shapers because deep cascades push all peaks below typical thresholds, making thresholded metrics uninformative.
The 6-pulse ZV+ZVD cascade is the most compact viable option (≤ MAX_PULSES = 10 per axis, but 6 pulses leaves more headroom). The 9-pulse ZVD+EI cascade gives the best suppression but uses more of the pulse budget.
The factory configuration uses different frequencies for X and Y (60/48 Hz). Because CoreXY kinematics couple both motors to both axes, using different shapers on X and Y creates direction-dependent residuals. The same-shaper approach (one frequency for both axes) eliminates this direction-dependence.
Prusa Research has not publicly addressed the crosstalk problem. The layer shift issues (#4732, #4573) were partially mitigated by the axis swap fix in v6.5.3, but the underlying crosstalk from two distinct motor resonance clusters remains unaddressed in upstream firmware.