Skip to content

Commit

Permalink
added proper use of damping ratio and SCV to compute shaper recommend…
Browse files Browse the repository at this point in the history
…ations
  • Loading branch information
Frix-x committed Feb 19, 2024
1 parent b42e377 commit 80c8da6
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 20 deletions.
10 changes: 8 additions & 2 deletions K-ShakeTune/K-SnT_axis.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ gcode:
{% set max_freq = params.FREQ_END|default(133.3)|float %}
{% set hz_per_sec = params.HZ_PER_SEC|default(1)|float %}
{% set axis = params.AXIS|default("all")|string|lower %}
{% set scv = params.SCV|default(None) %}
{% set max_sm = params.MAX_SMOOTHING|default(None) %}
{% set keep_results = params.KEEP_N_RESULTS|default(3)|int %}
{% set keep_csv = params.KEEP_CSV|default(True) %}

Expand All @@ -25,13 +27,17 @@ gcode:
{ action_raise_error("AXIS selection invalid. Should be either all, x or y!") }
{% endif %}

{% if scv is None %}
{% set scv = printer.toolhead.square_corner_velocity %}
{% endif %}

{% if X %}
TEST_RESONANCES AXIS=X OUTPUT=raw_data NAME=x FREQ_START={min_freq} FREQ_END={max_freq} HZ_PER_SEC={hz_per_sec}
M400

RESPOND MSG="X axis frequency profile generation..."
RESPOND MSG="This may take some time (1-3min)"
RUN_SHELL_COMMAND CMD=shaketune PARAMS="--type shaper {% if keep_csv %}--keep_csv{% endif %}"
RUN_SHELL_COMMAND CMD=shaketune PARAMS="--type shaper --scv {scv} {% if max_sm is not None %}--max_smoothing {max_sm}{% endif %} {% if keep_csv %}--keep_csv{% endif %}"
{% endif %}

{% if Y %}
Expand All @@ -40,7 +46,7 @@ gcode:

RESPOND MSG="Y axis frequency profile generation..."
RESPOND MSG="This may take some time (1-3min)"
RUN_SHELL_COMMAND CMD=shaketune PARAMS="--type shaper {% if keep_csv %}--keep_csv{% endif %}"
RUN_SHELL_COMMAND CMD=shaketune PARAMS="--type shaper --scv {scv} {% if max_sm is not None %}--max_smoothing {max_sm}{% endif %} {% if keep_csv %}--keep_csv{% endif %}"
{% endif %}

M400
Expand Down
33 changes: 23 additions & 10 deletions K-ShakeTune/scripts/graph_shaper.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,22 @@
# Computation
######################################################################

# Find the best shaper parameters using Klipper's official algorithm selection
def calibrate_shaper(datas, max_smoothing):
# Find the best shaper parameters using Klipper's official algorithm selection with
# a proper precomputed damping ratio (zeta) and using the configured printer SQV value
def calibrate_shaper(datas, max_smoothing, scv, max_freq):
helper = shaper_calibrate.ShaperCalibrate(printer=None)
calibration_data = helper.process_accelerometer_data(datas)
calibration_data.normalize_to_frequencies()

shaper, all_shapers = helper.find_best_shaper(calibration_data, max_smoothing, print_with_c_locale)
fr, zeta, _ = compute_mechanical_parameters(calibration_data.psd_sum, calibration_data.freq_bins)

print_with_c_locale("Recommended shaper is %s @ %.1f Hz" % (shaper.name, shaper.freq))
print_with_c_locale("Axis has a main resonant frequency at %.1fHz with an estimated damping ratio of %.3f" % (fr, zeta))
shaper, all_shapers = helper.find_best_shaper(
calibration_data, shapers=None, damping_ratio=zeta,
scv=scv, shaper_freqs=None, max_smoothing=max_smoothing,
test_damping_ratios=None, max_freq=max_freq,
logger=print_with_c_locale)

print_with_c_locale("\n-> Recommended shaper is %s @ %.1f Hz (when using a square corner velocity of %.1f and a computed damping ratio of %.3f)" % (shaper.name.upper(), shaper.freq, scv, zeta))

return shaper.name, all_shapers, calibration_data, fr, zeta

Expand Down Expand Up @@ -198,7 +203,7 @@ def plot_spectrogram(ax, t, bins, pdata, peaks, max_freq):
# Startup and main routines
######################################################################

def shaper_calibration(lognames, klipperdir="~/klipper", max_smoothing=None, max_freq=200.):
def shaper_calibration(lognames, klipperdir="~/klipper", max_smoothing=None, scv=5. , max_freq=200.):
set_locale()
global shaper_calibrate
shaper_calibrate = setup_klipper_import(klipperdir)
Expand All @@ -209,7 +214,7 @@ def shaper_calibration(lognames, klipperdir="~/klipper", max_smoothing=None, max
print_with_c_locale("Warning: incorrect number of .csv files detected. Only the first one will be used!")

# Compute shapers, PSD outputs and spectrogram
performance_shaper, shapers, calibration_data, fr, zeta = calibrate_shaper(datas[0], max_smoothing)
performance_shaper, shapers, calibration_data, fr, zeta = calibrate_shaper(datas[0], max_smoothing, scv, max_freq)
pdata, bins, t = compute_spectrogram(datas[0])
del datas

Expand All @@ -231,7 +236,7 @@ def shaper_calibration(lognames, klipperdir="~/klipper", max_smoothing=None, max
# Print the peaks info in the console
peak_freqs_formated = ["{:.1f}".format(f) for f in peaks_freqs]
num_peaks_above_effect_threshold = np.sum(calibration_data.psd_sum[peaks] > peaks_threshold[1])
print_with_c_locale("Peaks detected on the graph: %d @ %s Hz (%d above effect threshold)" % (num_peaks, ", ".join(map(str, peak_freqs_formated)), num_peaks_above_effect_threshold))
print_with_c_locale("\nPeaks detected on the graph: %d @ %s Hz (%d above effect threshold)" % (num_peaks, ", ".join(map(str, peak_freqs_formated)), num_peaks_above_effect_threshold))

# Create graph layout
fig, (ax1, ax2) = plt.subplots(2, 1, gridspec_kw={
Expand All @@ -245,17 +250,23 @@ def shaper_calibration(lognames, klipperdir="~/klipper", max_smoothing=None, max
})
fig.set_size_inches(8.3, 11.6)

# Add title
# Add a title with some test info
title_line1 = "INPUT SHAPER CALIBRATION TOOL"
fig.text(0.12, 0.965, title_line1, ha='left', va='bottom', fontsize=20, color=KLIPPAIN_COLORS['purple'], weight='bold')
try:
filename_parts = (lognames[0].split('/')[-1]).split('_')
dt = datetime.strptime(f"{filename_parts[1]} {filename_parts[2]}", "%Y%m%d %H%M%S")
title_line2 = dt.strftime('%x %X') + ' -- ' + filename_parts[3].upper().split('.')[0] + ' axis'
title_line3 = '| Square corner velocity: ' + str(scv) + 'mm/s'
title_line4 = '| Max allowed smoothing: ' + str(max_smoothing)
except:
print_with_c_locale("Warning: CSV filename look to be different than expected (%s)" % (lognames[0]))
title_line2 = lognames[0].split('/')[-1]
title_line3 = ''
title_line4 = ''
fig.text(0.12, 0.957, title_line2, ha='left', va='top', fontsize=16, color=KLIPPAIN_COLORS['dark_purple'])
fig.text(0.58, 0.960, title_line3, ha='left', va='top', fontsize=10, color=KLIPPAIN_COLORS['dark_purple'])
fig.text(0.58, 0.946, title_line4, ha='left', va='top', fontsize=10, color=KLIPPAIN_COLORS['dark_purple'])

# Plot the graphs
plot_freq_response(ax1, calibration_data, shapers, performance_shaper, peaks, peaks_freqs, peaks_threshold, fr, zeta, max_freq)
Expand Down Expand Up @@ -284,6 +295,8 @@ def main():
help="maximum frequency to graph")
opts.add_option("-s", "--max_smoothing", type="float", default=None,
help="maximum shaper smoothing to allow")
opts.add_option("--scv", "--square_corner_velocity", type="float",
dest="scv", default=5., help="square corner velocity")
opts.add_option("-k", "--klipper_dir", type="string", dest="klipperdir",
default="~/klipper", help="main klipper directory")
options, args = opts.parse_args()
Expand All @@ -294,7 +307,7 @@ def main():
if options.max_smoothing is not None and options.max_smoothing < 0.05:
opts.error("Too small max_smoothing specified (must be at least 0.05)")

fig = shaper_calibration(args, options.klipperdir, options.max_smoothing, options.max_freq)
fig = shaper_calibration(args, options.klipperdir, options.max_smoothing, options.scv, options.max_freq)
fig.savefig(options.output, dpi=150)


Expand Down
10 changes: 7 additions & 3 deletions K-ShakeTune/scripts/is_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def create_belts_graph(keep_csv):
return


def create_shaper_graph(keep_csv):
def create_shaper_graph(keep_csv, max_smoothing, scv):
current_date = datetime.now().strftime('%Y%m%d_%H%M%S')

# Get all the files and sort them based on last modified time to select the most recent one
Expand All @@ -120,7 +120,7 @@ def create_shaper_graph(keep_csv):
time.sleep(2)

# Generate the shaper graph and its name
fig = shaper_calibration([new_file], KLIPPER_FOLDER)
fig = shaper_calibration([new_file], KLIPPER_FOLDER, max_smoothing=max_smoothing, scv=scv)
png_filename = os.path.join(RESULTS_FOLDER, RESULTS_SUBFOLDERS[1], f'resonances_{current_date}_{axis}.png')
fig.savefig(png_filename, dpi=150)

Expand Down Expand Up @@ -263,6 +263,10 @@ def main():
help="number of results to keep in the result folder after each run of the script")
opts.add_option("-c", "--keep_csv", action="store_true", default=False, dest="keep_csv",
help="weither or not to keep the CSV files alongside the PNG graphs image results")
opts.add_option("--scv", "--square_corner_velocity", type="float", dest="scv", default=5.,
help="square corner velocity used to compute max accel for axis shapers graphs")
opts.add_option("--max_smoothing", type="float", dest="max_smoothing", default=None,
help="maximum shaper smoothing to allow")
options, args = opts.parse_args()

if options.type is None:
Expand All @@ -282,7 +286,7 @@ def main():
create_belts_graph(keep_csv=options.keep_csv)
print(f"Belt graph created. You will find the results in {RESULTS_FOLDER}/{RESULTS_SUBFOLDERS[0]}")
elif graph_mode.lower() == 'shaper':
axis = create_shaper_graph(keep_csv=options.keep_csv)
axis = create_shaper_graph(keep_csv=options.keep_csv, max_smoothing=options.max_smoothing, scv=options.scv)
print(f"{axis} input shaper graph created. You will find the results in {RESULTS_FOLDER}/{RESULTS_SUBFOLDERS[1]}")
elif graph_mode.lower() == 'vibrations':
create_vibrations_graph(axis_name=options.axis_name, accel=options.accel_used, chip_name=options.chip_name, keep_csv=options.keep_csv)
Expand Down
12 changes: 7 additions & 5 deletions docs/macros/axis_tuning.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Then, call the `AXES_SHAPER_CALIBRATION` macro and look for the graphs in the re
|FREQ_END|133|Maximum excitation frequency|
|HZ_PER_SEC|1|Number of Hz per seconds for the test|
|AXIS|"all"|Axis you want to test in the list of "all", "X" or "Y"|
|SCV|printer square corner velocity|Square corner velocity you want to use to calculate shaper recommendations. Using higher SCV values usually results in more smoothing and lower maximum accelerations|
|MAX_SMOOTHING|None|Max smoothing allowed when calculating shaper recommendations|
|KEEP_N_RESULTS|3|Total number of results to keep in the result folder after running the test. The older results are automatically cleaned up|
|KEEP_CSV|True|Weither or not to keep the CSV data file alonside the PNG graphs|

Expand All @@ -39,13 +41,13 @@ For setting your Input Shaping filters, rely on the auto-computed values display
* `MZV` is usually the top pick for well-adjusted machines. It's a good compromise for low remaining vibrations while still allowing pretty good acceleration values. Keep in mind, `MZV` is only recommended by Klipper on good graphs.
* `EI` can be used as a fallback for challenging graphs. But first, try to fix your mechanical issues before using it: almost every printer should be able to run `MZV` instead.
* `2HUMP_EI` and `3HUMP_EI` are last-resort choices. Usually, they lead to a high level of smoothing in order to suppress the ringing while also using relatively low acceleration values. If they pop up as suggestions, it's likely your machine has underlying mechanical issues (that lead to pretty bad or "wide" graphs).
- **Recommended Acceleration** (`accel<=...`): This isn't a standalone figure. It's essential to also consider the `vibr` and `sm` values as it's a compromise between the three. They will give you the percentage of remaining vibrations and the smoothing after Input Shaping, when using the recommended acceleration. Nothing will prevent you from using higher acceleration values; they are not a limit. However, when doing so, Input Shaping may not be able to suppress all the ringing on your parts. Finally, keep in mind that high acceleration values are not useful at all if there is still a high level of remaining vibrations: you should address any mechanical issues first.
- **The remaining vibrations** (`vibr`): This directly correlates with ringing. It correspond to the total value of the blue "after shaper" signal. Ideally, you want a filter with minimal or zero vibrations.
- **Recommended Acceleration** (`accel<=...`): This isn't a standalone figure. It's essential to also consider the `vibr` and `sm` values as it's a compromise between the three. They will give you the percentage of remaining vibrations and the smoothing after Input Shaping, when using the recommended acceleration. Nothing will prevent you from using higher acceleration values; they are not a limit. However, in this case, Input Shaping may not be able to suppress all the ringing on your parts, and more smoothing will occur. Finally, keep in mind that high acceleration values are not useful at all if there is still a high level of remaining vibrations: you should address any mechanical issues first.
- **The remaining vibrations** (`vibr`): This directly correlates with ringing. It correspond to the total value of the "after shaper" signal. Ideally, you want a filter with minimal remaining vibrations.
- **Shaper recommendations**: This script will give you some tailored recommendations based on your graphs. Pick the one that suit your needs:
* The "performance" shaper is Klipper's original suggestion that is good for high acceleration while also sometimes allowing a little bit of remaining vibrations. Use it if your goal is speed printing and you don't care much about some remaining ringing.
* The "performance" shaper is Klipper's original suggestion, which is good for high acceleration, but sometimes allows a little residual vibration while minimizing smoothing. Use it if your goal is speed printing and you don't care much about some remaining ringing.
* The "low vibration" shaper aims for the lowest level of remaining vibration to ensure the best print quality with minimal ringing. This should be the best bet for most users.
* Sometimes, only a single recommendation called "best" shaper is presented. This means that either no suitable "low vibration" shaper was found (due to a high level of vibration or with too much smoothing) or because the "performance" shaper is also the one with the lowest vibration level.
- **Damping Ratio**: Displayed at the end, this estimatation is only reliable when the graph shows a distinct, standalone and clean peak. On a well tuned machine, setting the damping ratio (instead of Klipper's 0.1 default value) can further reduce the ringing at high accelerations and with higher square corner velocities.
* Sometimes only a single recommendation is given as the "best" shaper. This means that either no suitable "low vibration" shaper was found (due to a high level of residual vibration or too much smoothing), or that the "performance" shaper is also the one with the lowest vibration level.
- **Damping Ratio**: Displayed at the end, this is an estimate based on your data that is used to improve the shaper recommendations for your machine. Defining it in the `[input_shaper]` section (instead of Klipper's default value of 0.1) can further reduce ringing at high accelerations and higher square corner velocities.

Then, add to your configuration:
```
Expand Down

0 comments on commit 80c8da6

Please sign in to comment.