aboutsummaryrefslogtreecommitdiffstats
path: root/klippy/extras/shaper_calibrate.py
diff options
context:
space:
mode:
Diffstat (limited to 'klippy/extras/shaper_calibrate.py')
-rw-r--r--klippy/extras/shaper_calibrate.py52
1 files changed, 37 insertions, 15 deletions
diff --git a/klippy/extras/shaper_calibrate.py b/klippy/extras/shaper_calibrate.py
index af77845c..f3bfd8d2 100644
--- a/klippy/extras/shaper_calibrate.py
+++ b/klippy/extras/shaper_calibrate.py
@@ -1,6 +1,6 @@
# Automatic calibration of input shapers
#
-# Copyright (C) 2020 Dmitry Butyugin <dmbutyugin@google.com>
+# Copyright (C) 2020-2024 Dmitry Butyugin <dmbutyugin@google.com>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
import collections, importlib, logging, math, multiprocessing, traceback
@@ -227,34 +227,49 @@ class ShaperCalibrate:
offset_180 *= inv_D
return max(offset_90, offset_180)
- def fit_shaper(self, shaper_cfg, calibration_data, max_smoothing):
+ def fit_shaper(self, shaper_cfg, calibration_data, shaper_freqs,
+ damping_ratio, scv, max_smoothing, test_damping_ratios,
+ max_freq):
np = self.numpy
- test_freqs = np.arange(shaper_cfg.min_freq, MAX_SHAPER_FREQ, .2)
+ damping_ratio = damping_ratio or shaper_defs.DEFAULT_DAMPING_RATIO
+ test_damping_ratios = test_damping_ratios or TEST_DAMPING_RATIOS
+
+ if not shaper_freqs:
+ shaper_freqs = (None, None, None)
+ if isinstance(shaper_freqs, tuple):
+ freq_end = shaper_freqs[1] or MAX_SHAPER_FREQ
+ freq_start = min(shaper_freqs[0] or shaper_cfg.min_freq,
+ freq_end - 1e-7)
+ freq_step = shaper_freqs[2] or .2
+ test_freqs = np.arange(freq_start, freq_end, freq_step)
+ else:
+ test_freqs = np.array(shaper_freqs)
+
+ max_freq = max(max_freq or MAX_FREQ, test_freqs.max())
freq_bins = calibration_data.freq_bins
- psd = calibration_data.psd_sum[freq_bins <= MAX_FREQ]
- freq_bins = freq_bins[freq_bins <= MAX_FREQ]
+ psd = calibration_data.psd_sum[freq_bins <= max_freq]
+ freq_bins = freq_bins[freq_bins <= max_freq]
best_res = None
results = []
for test_freq in test_freqs[::-1]:
shaper_vibrations = 0.
shaper_vals = np.zeros(shape=freq_bins.shape)
- shaper = shaper_cfg.init_func(
- test_freq, shaper_defs.DEFAULT_DAMPING_RATIO)
- shaper_smoothing = self._get_shaper_smoothing(shaper)
+ shaper = shaper_cfg.init_func(test_freq, damping_ratio)
+ shaper_smoothing = self._get_shaper_smoothing(shaper, scv=scv)
if max_smoothing and shaper_smoothing > max_smoothing and best_res:
return best_res
# Exact damping ratio of the printer is unknown, pessimizing
# remaining vibrations over possible damping values
- for dr in TEST_DAMPING_RATIOS:
+ for dr in test_damping_ratios:
vibrations, vals = self._estimate_remaining_vibrations(
shaper, dr, freq_bins, psd)
shaper_vals = np.maximum(shaper_vals, vals)
if vibrations > shaper_vibrations:
shaper_vibrations = vibrations
- max_accel = self.find_shaper_max_accel(shaper)
+ max_accel = self.find_shaper_max_accel(shaper, scv)
# The score trying to minimize vibrations, but also accounting
# the growth of smoothing. The formula itself does not have any
# special meaning, it simply shows good results on real user data
@@ -278,6 +293,8 @@ class ShaperCalibrate:
def _bisect(self, func):
left = right = 1.
+ if not func(1e-9):
+ return 0.
while not func(left):
right = left
left *= .5
@@ -292,22 +309,27 @@ class ShaperCalibrate:
right = middle
return left
- def find_shaper_max_accel(self, shaper):
+ def find_shaper_max_accel(self, shaper, scv):
# Just some empirically chosen value which produces good projections
# for max_accel without much smoothing
TARGET_SMOOTHING = 0.12
max_accel = self._bisect(lambda test_accel: self._get_shaper_smoothing(
- shaper, test_accel) <= TARGET_SMOOTHING)
+ shaper, test_accel, scv) <= TARGET_SMOOTHING)
return max_accel
- def find_best_shaper(self, calibration_data, max_smoothing, logger=None):
+ def find_best_shaper(self, calibration_data, shapers=None,
+ damping_ratio=None, scv=None, shaper_freqs=None,
+ max_smoothing=None, test_damping_ratios=None,
+ max_freq=None, logger=None):
best_shaper = None
all_shapers = []
+ shapers = shapers or AUTOTUNE_SHAPERS
for shaper_cfg in shaper_defs.INPUT_SHAPERS:
- if shaper_cfg.name not in AUTOTUNE_SHAPERS:
+ if shaper_cfg.name not in shapers:
continue
shaper = self.background_process_exec(self.fit_shaper, (
- shaper_cfg, calibration_data, max_smoothing))
+ shaper_cfg, calibration_data, shaper_freqs, damping_ratio,
+ scv, max_smoothing, test_damping_ratios, max_freq))
if logger is not None:
logger("Fitted shaper '%s' frequency = %.1f Hz "
"(vibrations = %.1f%%, smoothing ~= %.3f)" % (