Regression in dynamic PA

Commit 29724a7 moved the PA constant from being a property of the move to a property of the extruder. This broke dynamic changes to the pressure advance constant during printing, for example to reduce the constant during overhangs or bridges to account for the lack of backpressure which tends to make these features sag. I reported this a long time ago, incorrectly using the GitHub issue tracker; the reason I’m raising it again now is that an Orca Slicer developer has been in touch with me trying to implement dynamic PA adjustment per-feature, and I had to tell them it presently does not work, because any runtime change to the advance constant will be unsynchronized with the moves it was intended to go with, and in practice will be off in time by an amount that depends in complex ways on when flushes happen, how deep the planner move queue and trapq move queues are, etc.

In addition to breaking timing, the change also potentially causes crashes if PA is changed during print. This is because, unlike before where the change got smoothed out by smooth time, now the change is instantaneous. This produces jump discontinuities which the itersolver can blow up on.

I would like to propose that 29724a7 be reverted. I don’t really understand the motivation for it to begin with. It should be fine for each extruder stepper to have its own PA setting, but that needs to be copied into the trapq at the time a move is generated with that extruder stepper as the active one. If the intent is really to allow more than one extruder stepper to be active at once, with different PA values for each, then each needs its own trapq; they cannot share the trapq like they are doing now.

Link back to the original issue report on GH: Apparent regression in variable PA · Issue #6338 · Klipper3d/klipper · GitHub

Hi there, thank you for bringing this issue to my attention, as I’ve seen some unintended consequences when trying to apply dynamic PA adjustments for continuous features indeed.

The PR currently in development can be found here: Enhancement: Adaptive Pressure advance by igiannakas · Pull Request #5609 · SoftFever/OrcaSlicer · GitHub

To give you some background, the feature aims to not only adjust the PA for specific features, but model the behaviour of the extrusion system more thoroughly using flow speed, acceleration and PA samples to extrapolate an ideal PA value using statistical modelling.

This model can then be used to derive a PA value that is right for the extrusion profile at hand (layer heights, speeds, line widths and accelerations). This is an evolution of the dynamic PA per feature and aims to remove the “hard coded” nature of the previous approach to a specific set of accelerations, speeds, flow rates and layer heights.

Some users have had great success with this feature, especially when speeds vary greatly and with nozzles or extrusion systems that behave non linearly when pressure increases in the nozzle.

I definitely agree with the point that Pressure Advance can depend on the velocity (of an extruder), and there is a value in adapting the PA to the velocity. However, regarding the point of that commit:

  • It is not a mere regression. This modification allows one to set different PA values for different extruder motors, which is a must for IDEX printer (for dual and mirror modes printing) and for mixing hotends like Cyclops, and perhaps in other instances. So we cannot just revert it.
  • Dynamic adjustment of PA in the slicer seems to be a wrong place, in my opinion. It would be similar to implementing Input Shaping in slicer - definitely possible, but very fragile, since both require the knowledge of the actual velocities of the moves, and the slicer cannot 100% accurately reconstruct the behavior and the motion planning of the firmware, and any run-time modifications will make these adjustments fall apart (e.g. changing feed rate from 100%).

So a potentially better approach would be for us to come up with the non-linear pressure model and implement it in the firmware, and then the user would tune the relevant parameters of that model, enter them in the slicer as a part of filament start gcode, and then the firmware would be using these parameters to compute PA in real-time. A shameless plug here: I had implemented a non-linear PA support in my experimental branch earlier (python, c). Admittedly what I have there is just a proof of concept, and what’s lacking is good PA models and the process of tuning their parameters (though if you are interested, I can share an OpenOffice spreadsheet that can be used to tune parameters for the 2 already available models). However, plugging a different non-linear model should be very easy, so if you feel like it, you could give it a try and experiment with it (or if you do have some very promising models already, I could also try putting them there). Unlike some other features, I have reasonably high hopes that if it proves to work well, it can be integrated into the Klipper mainline, with so many features available now that can benefit from non-linear PA models. If for some reason that doesn’t work for you, as I mentioned before, reworking PA parameters propagation such that changing them does not result in flushing of the move queue would be fairly non-trivial endeavor.

Also an open question is what the PA should actually depend on. Extruder velocity is likely one of them. Dependency of the PA on acceleration was reported e.g. previously somewhere in this thread, but honestly what was unclear to me at the time is whether the PA actually depends on the acceleration, or that, perhaps, the default smooth_time = 0.04 in Klipper is too high for modern hotends and printers, and first thing to test would be to reducing it and checking whether the dependency of PA on acceleration would go away.

I’m not aware of any defects like the above. If you have found a defect like that, please attach a Klipper log file from the event (make sure you are running unmodified Klipper code, issue an M112 immediately after the event, and attach the full unmodified log here).

-Kevin

Actually, after some thoughts, I realized that it should not be that difficult to implement dynamic adjustment of pressure advance. I pushed the code to this branch @igiannakas in case you want to give it a try. This should work pretty much as mainline Klipper without any changes, just the commands SET_PRESSURE_ADVANCE ADVANCE=... will take effect on the next gcode commands and will not flush the move queue (note that modifying smooth time via SET_PRESSURE_ADVANCE SMOOTH_TIME=... will flush the queue, so better not do it during the printing).

Here’s an example of using it, obtained with motan tool (you can see the PA changing mid-moves without flushing the move queue except the last 2 moves where smooth_time is also changed). Edit: in case the chart is confusing, ‘extruder position’ and ‘extruder velocity’ (in blue) are the extruder stepper position and velocity after the PA is applied (so these are the true commanded positions and velocities), and ‘extruder x position’ and ‘extruder x velocity’ (in orange) are the corresponding position and velocity of the extruder from the trapezoidal move planner before any PA (or smoothing) is applied.

for the following sequence:

GCode
SET_PRESSURE_ADVANCE ADVANCE=0.1
; Home and extrusion moves
G28
G1 X20 Y20 Z10 F6000
G1 E2 F600
G1 X25 Y25 E2.5 F6000

G1 X30 Y30 E3.0

; Update pressure advance for primary extruder
SET_PRESSURE_ADVANCE ADVANCE=0.01
G1 X35 Y35 E3.5

; Update pressure advance for primary extruder
SET_PRESSURE_ADVANCE ADVANCE=0.05
G1 X40 Y40 E4.0 F3000

; Update smooth_time
SET_PRESSURE_ADVANCE SMOOTH_TIME=0.01
G1 X45 Y45 E4.5 F6000

; Updating both smooth_time and pressure advance
SET_PRESSURE_ADVANCE SMOOTH_TIME=0.03 ADVANCE=0.1
G1 X50 Y50 E5.0

@dmbutyugin
Indeed the best approach would be to create a non linear model in klipper. This is the best way, as klipper is fully aware of the toolhead velocities at any point in time, as well as the commanded nozzle flow.

The slicer implementation is an approximation & stop gap in lieu of doing that - partly cause I am not skilled enough to code this in klipper and partly because I am simply evolving an existing idea which is good enough - PA by extrusion role that has been around for a while.

Also from my tests and from the community in the PR it seems to be a step up from existing behaviour - not ideal by any means, but an improvement nonetheless.

Interpolation wise, I coded a 3 dimensional PCHIP interpolator as the “new thing” here - this should ideally be the targeted model to use if ever implemented in klipper itself, as it doesn’t suffer from oscillations and it can approximate without any error/deviation the PA value when the input parameters in the model match the user given ones during calibration (I’m explaining more on the model in the pr above). Most other interpolation models will have inherently a deviation from the calibrated values (like cubic, log, power regression models etc)

I’ll check out the Pr above - that sounds fantastic! For my benefit, does it behave the same way as the old klipper behaviour (and danger klipper) or is this new? Ie what should I expect as a result? :slight_smile:

For reference, the only artefacts I’ve noted when using dynamic PA in the slicer is in overhangs & specifically if I adjust PA midway through an extrusion to emit a different PA value for a slower overhanging region, like the below (using mainline klipper).

If I adjust PA at the start of the extrusion, the print is perfect but the overhangs could be a bit better as the Pa is too low for them then. It’s the current compromise using slicer based PA adjustments.

@dmbutyugin does your PR aim to address this artefact when changing Pa during an extrusion move?

Ps. All tests above were done with mainline klipper, V2.4 350 with G2E extruder at 3k accel external, 4k internal perimeters and 10k infill. Revo CHT nozzle which has very good flow control actually so my PA flattens out very quickly after about 100mm/sec

FWIW, I think one does not exclude the other - we could have both non-linear PA and the ability to adjust the pressure advance without stopping the toolhead, this is why I put together this change to address the latter. And my hope is that this may unblock the experiments on non-linear PA, even if done initially through slicer, so that we can collect more data and statistics and then add an already fleshed out model to Klipper when we understand things better. Even then, there could be cases when the PA (non-linear) model may need to be adjusted mid-print, e.g. for overhangs and maybe elsewhere.

I’m unsure what folks did in danger klipper - I know they took some of my patches, but the branch they took them from does not support dynamic adjustment of the PA, and I do not know what they implemented to support it (there are many branches to skim through). I’m not 100% certain what the old behavior was either, but this change allows one to change the pressure advance between the moves with the same or different velocities, and the extruder position will be adjusted smoothly between these two moves according to the new PA values. So, SET_PRESSURE_ADVANCE affects only the subsequent G0/G1 moves starting from the next directly after it, does not affect earlier moves, and does not change the toolhead kinematics (e.g. does not stop it, which would cause a blob). So, I think this is the best possible behavior that we can do. Also, I attached the chart and the corresponding gcode, so you can see for yourself. E.g. the dynamic adjustments of PA here seem to work as expected:

SET_PRESSURE_ADVANCE ADVANCE=0.1
...
G1 X30 Y30 E3.0 F6000
SET_PRESSURE_ADVANCE ADVANCE=0.01
G1 X35 Y35 E3.5 F6000
SET_PRESSURE_ADVANCE ADVANCE=0.05
G1 X40 Y40 E4.0 F3000

In this case the toolhead simply decelerates from 100 mm/s to 50 mm/s on the last move, but the extruder works through the PA changes throughout the moves (near their boundaries based on smooth_time configured).

I’m not sure I understood the issue you are describing and the desired effect. Note that you cannot change pa ‘during an extrusion move’, because G0/G1 and SET_PRESSURE_ADVANCE are different commands, and the latter cannot take effect mid-move. However, you can simply split a single G1 into several commands with the same velocity and extrusion factor and insert a SET_PRESSURE_ADVANCE command somewhere in between them as appropriate, and it should work.

@dmbutyugin thank you for taking time to reply to me :slight_smile:

That is great to hear :slight_smile: I’ll continue working on the Orca slicer PR and hopefully we validate the concept when more users use it and tweak and fine tune before determining whether a klipper change would be beneficial, thank you!

This seems to be the fix for exactly the issue I was facing when adjusting PA for overhangs. Let me try to be a bit more succinct on what was happening in the scenario above:

Step 1: Orca sets an internal GCODE marker to instruct the built in GCODE post processor to evaluate the PA at the start of the new feature - external wall, internal wall, infill etc
Step 2: The post processor, to determine the appropriate PA, uses the feature acceleration and volumetric flow rate (which is a proxy for speed at the same layer height) and runs it through the 3D PCHIP interpolator. A new PA value is derived.
Step 3: The PA command is emitted right before the upcomming feature begins printing - so usually right before the seam (and before the first G1 X Y E command for that feature)
Step 4: If an overhang is encountered, Orca would split the G1 move to allow for speed adjustment prior to the overhang. Here I have a choice - adjust PA for the new speed and flow or not.

Scenario 1: If I adjusted the PA value immediately before the overhang G1 X Y E move, I got with mainline klipper a wall artefact like the above picture. It appeared like momentary over extrusion or stutter (hard to tell at print speed though)

Scenario 2: If I don’t adjust the PA value for the overhang G1 X Y E move, there is no artefact; however as this feature would ideally need a higher PA so it is ever so slightly “bulging”

Please note that these tests were done with mainline klipper a few weeks ago, not your new branch.

What I was trying to understand was whether the changes in your branch would address this limitation. It sounds like it will, as the extruder would transition to the new PA value with no “stutter” so this issue should be resolved.

In any case once my current print is done I’ll pull the change and test it out.

Hope I’m making sense? :slight_smile:

PS. Why dont you grab the PR build and also give it a spin? I’d love for more feedback in the approach! Currently the code adjusts PA for every feature change (external/internal walls/bridge/infill etc) and for fully overhanging perimeters but NOT for partly overhanging perimeters due to the issue described above. It uses acceleration and volumetric flow speed as the variables to interpolate the right PA for an arbitrary acceleration and speed.

I’ll push a new build soon that also adjusts for partly overhanging perimeters to test with your klipper changes.

OK, thanks for the explanation of the issue, I think my new code should work fine with this scenario. As for the current mainline behavior, Klipper cannot really change the extruder PA while extruding, as this would require an immediate change in the extruder position, and would result in stepcompress errors. In order to avoid this problem altogether, when PA is changing, Klipper flushes its internal move queue and effectively makes the toolhead stop. Then the extruder does not have to change position on the PA change - since the velocity is 0, PA adjustment of position is also 0 regardless of the value of advance coefficient. Then Klipper continues printing with the new PA value. So the PA value changes exactly where needed, however, due to momentary stop of the toolhead (the pause lasts ~ smooth_time seconds) you are likely to get a blob in this spot, so this kind of defeats the purpose of the dynamic PA feature. If I were to take a wild guess, perhaps Danger Klipper simply removed that move queue flushing, but then the PA will be applied at some random point in time (typically before it was actually supposed to take effect) and if you change the PA too much, you are very likely to run into stepcompress errors (and timer too close errors are also possible).

Thank you for the offer, but I’m not currently using Orca slicer, so it is a bit of work to set things up, and I did waste quite a bit of efforts in the past on non-linear PA already. I will likely take a look at it some time in the future, but I hope to see more real-life tests first.

And thanks for providing a brief overview of your models. For comparison, the two non-linear models I have implemented earlier just do an interpolation between two PA values, essentially, with PA(extruder_velocity == 0) > PA(extruder_velocity → infinity), using one of the two smooth functions I came up with. FWIW, I did not observe the dependency on the acceleration, but I did not study that too much. So, for my understanding, in your first post here you indicated the parameters such as smooth_time, acceleration and velocity. What is ‘LH=0.2’ and what are the shapers that you are using and what their maximum recommended accelerations are? This is for me to put the tests into perspective and to understand the observed effects better.

this is exactly why dynamic PA works in the PR when starting a new feature - as the speed is 0 or close to 0 and there is no extrusion happening - thank you for confirming my observations!!

Which is exactly the artefact I was seeing on the wall above! This correlates perfectly - and also matches the 0.01 smooth time I use (since the artefact size is small).

So I’ve tested several variables to figure out what has the highest impact on PA -

  1. Print Speed
  2. Acceleration
  3. Layer height (LH)

The conclusion was that acceleration and nozzle flow over time (volumetric flow speed) is what impacts it the most. The jury is out whether it is nozzle flow or speed, but by testing with the same speed across different layer heights the PA was quite different.

So I’m currently using volumetric flow speed (mm3/s) and acceleration. The former is equivalent to print speed if printing with the same line width and layer height but it appears that this can help adjust PA if using drastically different line widths and layer heights too.

The tests are here:

Speed - constant accel:

Both speed and acceleration had a big impact on ideal PA value.

Then it was proposed by Softfever and a couple of other users to explore whether volumetric flow speed is a better variable instead of speed. I run some tests with varying layer heights to emulate higher flows with the same speed and indeed there was a very similar corelation to speed.

So concluded on volumetric flow speed and acceleration as the two primary levers for now.

Higher Accel - varying speeds:

Sorry discourse only allows me 1 pic per post.

Thanks, so just to clarify, when saying ‘speed’ in the context of PA, I always meant ‘extruder velocity’ and not the toolhead (and extruder velocity is linearly proportional to the volumetric flow due to constant filament cross-section pi * r^2). I suppose this was not really obvious the way I wrote it, so I just wanted to clarify that. And the models I’ve implemented (as well as ‘velocity’ term calculation for non-linear PA) use the extruder velocity, not the toolhead velocity, which is affected by the extrusion width, layer height, toolhead speed and any flow rate adjustments applied.

OK, so I understood what LH was in your tests, and the extrusion width was probably ~0.4mm? So the only remaining question I have is about input shapers - they can greatly affect the quality of the angles by smoothing them. So I’d like to understand what was used in the tests to understand if input shapers could affect the tests to some degree or not.

@dmbutyugin Perfect, so we are aligned on the speed front - we both used the same or equivalent variable :slight_smile: Extrusion width was 0.42mm due to the slic3r flow math it should really be slightly higher than the nozzle width, hence that is the minimum I typically use.

On the shaper front I’m using the below:

[input_shaper]
shaper_freq_x: 73.0
shaper_type_x: ei
shaper_freq_y: 50.2
shaper_type_y: ei
damping_ratio_x: 0.056
damping_ratio_y: 0.052

I’m using EI instead of MZV as I don’t want any ringing on the prints and also using the same shaper on X & Y for probably superstitious reasons - just for both axis to have the same shaper (probably unnecessary).

Below graphs from shake tune - reasonably clean overall, for the size of the printer, I think.

And Y:

PA tests were done with 5 SCV, 0.01 smooth time (I don’t touch this in the PA adjustment as well).

OK, thanks for the data points! I think your PA tests at 3K accel make sense, but at 10K the tests are not really illustrative - this is way above the capabilities of the printer to reproduce fine details, like sharp corners. So by adjusting (reducing) PA at high accelerations you can attempt to compensate for corner smoothing from input shaping by insufficient PA, but I’d say this is not a ‘PA acceleration dependency’ in the common sense, just compensating one defect with another one. It would be more interesting and telling to compare, for example, 2K and 4K accelerations, especially if you use MZV 42 Hz for Y axis, since this will be a 2x change of acceleration, but both values well within the mechanical capabilities of the printer.

Ok that makes sense - I’ll run the tests with 1-2-4k acceleration and MZV and see if it makes a difference. The smoothing effect I hadn’t considered. Thank you for pointing this out!!!

The model in the orca Pr doesn’t care for it anyway / if only one acceleration is provided it uses that model only.

Also thank you for getting involved in this - it’s great to get more insight into how klipper functions so I don’t waste time and don’t go down wrong rabbit holes :slight_smile:

Sure, I was more talking about interpreting the results of the tests (and tuning the model, for that matter). However, in real printing one could use different accelerations: for example, for one of my printers I have a recommendation to use ~7.5K acceleration, and in practice I use 5K for external perimeters and top/bottom surfaces (for better details and finish), 7K for other extruding moves, and 10K for travel. So, understanding how acceleration affects the PA can be very useful to see if it needs to be adjusted with acceleration.

And as for the choice of smooth_time = 0.01s, I think it is not bad at all. However, I had a theory or a hunch, if you will, that it should be close to the ‘input shaper smooth time’, or basically the duration of the input shaper(s). In your case for Y axis you have EI @50.2 Hz, and that one has a duration of 1 / 50.2 ~= 0.02 s (and ~0.014s for X axis). So, if you have an opportunity, you could also check how the test turns out with smooth_time = 0.015 s and smooth_time = 0.02 s, especially as you are changing the acceleration values.

So, all in all, thanks for your tests and investigations, and I’m looking forward for your tests of the new branch. If the testing shows that it works well, I’ll open the PR and, hopefully, we can get it merged.