Non-linear pressure advance

I recently discovered nonlinear pressure advance through the Kalico fork and became interested in implementing a more sophisticated PA algorithm for Klipper.

Taking inspiration from the nonlinear PA implementation in @dmbutyugin’s repository, I’ve developed my own implementation that adds nonlinear correction methods

The implementation introduces 5 different nonlinear methods:

  1. Linear (default) - Standard Klipper behavior

  2. Tanh - Hyperbolic tangent with saturation at high velocities

  3. Exp - Exponential response for quick transitions

  4. Recip - Reciprocal function for gradual saturation

  5. Sigmoid - S-curve response for smooth transitions

New Configuration Parameters

[extruder]
pressure_advance_method: tanh        # Algorithm selection
pressure_advance_offset: 0.3         # Nonlinear correction magnitude (-1.0 to 1.0)
pressure_advance_linv: 50.0          # Velocity normalization factor (0.001 to 1000.0)

G-code Commands

# Set nonlinear PA parameters
SET_PRESSURE_ADVANCE ADVANCE=0.05 METHOD=tanh OFFSET=0.3 LINV=50

Technical Approach

The implementation works by:

  1. Computing smoothed velocity through time integration over the smoothing window

  2. Applying the selected (non)linear function to the normalized velocity

  3. Adding the (non)linear correction to the base position

The mathematical foundation:

position = base + (linear_pa(v) || nonlinear_pa(v))

:warning: This is where I need your help! :warning:

While I believe the algorithm is mathematically sound, I haven’t conducted extensive print testing yet. I’m particularly concerned about:

  1. Implementation correctness - Are there edge cases I missed?

  2. Performance impact - Does the additional computation significantly affect print performance?

  3. Memory management - Is the PA parameter cleanup logic robust?

Implementation Details

The complete implementation is available in my GitHub fork:

Repository: GitHub - loss-and-quick/klipper at feat/nonlinear-pa

I’m excited about the potential of this enhancement but want to make sure it’s implemented correctly and safely before broader testing. Any feedback, concerns, or suggestions would be greatly appreciated!

5 Likes

General comments:

  • It is preferable to do iterative changes, piece by piece.
  • Do not mix the refactoring with functional changes.

It is harder to grasp. Just imagine, if Kevin, for example, with comparable changes in the raw line count, just squashes it: Centralize host motion flushing by KevinOConnor · Pull Request #7014 · Klipper3d/klipper · GitHub
This is a part of the task: write commits and change the code in a way that would be readable to others.

About the motion subsystem, general rule - there should be no speed jumps or infinite something. This is part of the reason why there is an integration logic - to smooth.

About the performance, I would suggest you do the testing with the Klipper batch mode:
At least like that:

# It is enough to disable not used things, make a dummy MCU dict (just compile your MCU)
# Also set G28 at the start of the file, or SET_POSITION...
time python3 klippy/klippy.py rp2040_printer.cfg -a /tmp/klippy_uds -i ./Cube_0.1mm_PLA_19m36s.gcode -d out/klipper.dict -o /tmp/dummy.serial

That will give you a rough idea of how fast/slow it is.

About the testing, you can take a look at:

# Record the data:
./scripts/motan/data_logger.py ~/printer_data/comms/klippy.sock /tmp/stepcompress_patched
# View the data:
./scripts/motan/motan_graph.py -g '[["deviation(angle(mt6826s),stepq(stepper_x))"],["deviation(angle(mt6826s),kin(stepper_x))"],["adxl345(adxl345,x)"],["adxl345(adxl345,y)"],["derivative(stepq(stepper_x))"],["step_phase(tmc5160 stepper_x)"]]' ./stepcompress_patched -s 0 -d 10

Also, it could help you:

Hope that helps.

1 Like