aboutsummaryrefslogtreecommitdiffstats
path: root/klippy/extras/shaper_calibrate.py
diff options
context:
space:
mode:
authorDmitry Butyugin <dmbutyugin@google.com>2021-01-29 19:21:04 +0100
committerKevinOConnor <kevin@koconnor.net>2021-03-20 13:24:43 -0400
commit73a39370ad98dad866d80ee0e67808f4ca137875 (patch)
treeaaf3784683a2441fc29cd64badec754cfbafd107 /klippy/extras/shaper_calibrate.py
parent8c369b54aba2bf064dbe6fa67860fecf1415be43 (diff)
downloadkutter-73a39370ad98dad866d80ee0e67808f4ca137875.tar.gz
kutter-73a39370ad98dad866d80ee0e67808f4ca137875.tar.xz
kutter-73a39370ad98dad866d80ee0e67808f4ca137875.zip
shaper_calibrate: Estimate max_accel to avoid excessive smoothing
Signed-off-by: Dmitry Butyugin <dmbutyugin@google.com>
Diffstat (limited to 'klippy/extras/shaper_calibrate.py')
-rw-r--r--klippy/extras/shaper_calibrate.py42
1 files changed, 34 insertions, 8 deletions
diff --git a/klippy/extras/shaper_calibrate.py b/klippy/extras/shaper_calibrate.py
index bf4c5746..8e7bb8e6 100644
--- a/klippy/extras/shaper_calibrate.py
+++ b/klippy/extras/shaper_calibrate.py
@@ -97,10 +97,8 @@ def get_3hump_ei_shaper(shaper_freq, damping_ratio):
T = [0., .5*t_d, t_d, 1.5*t_d, 2.*t_d]
return (A, T)
-def get_shaper_smoothing(shaper):
- # Smoothing calculation params
- HALF_ACCEL = 2500.
- SCV = 5.
+def get_shaper_smoothing(shaper, accel=5000, scv=5.):
+ half_accel = accel * .5
A, T = shaper
inv_D = 1. / sum(A)
@@ -113,8 +111,8 @@ def get_shaper_smoothing(shaper):
for i in range(n):
if T[i] >= ts:
# Calculate offset for one of the axes
- offset_90 += A[i] * (SCV + HALF_ACCEL * (T[i]-ts)) * (T[i]-ts)
- offset_180 += A[i] * HALF_ACCEL * (T[i]-ts)**2
+ offset_90 += A[i] * (scv + half_accel * (T[i]-ts)) * (T[i]-ts)
+ offset_180 += A[i] * half_accel * (T[i]-ts)**2
offset_90 *= inv_D * math.sqrt(2.)
offset_180 *= inv_D
return max(offset_90, offset_180)
@@ -164,7 +162,7 @@ class CalibrationData:
CalibrationResult = collections.namedtuple(
'CalibrationResult',
- ('name', 'freq', 'vals', 'vibrs', 'smoothing', 'score'))
+ ('name', 'freq', 'vals', 'vibrs', 'smoothing', 'score', 'max_accel'))
class ShaperCalibrate:
def __init__(self, printer):
@@ -333,6 +331,7 @@ class ShaperCalibrate:
shaper_vals = np.maximum(shaper_vals, vals)
if vibrations > shaper_vibrations:
shaper_vibrations = vibrations
+ max_accel = self.find_shaper_max_accel(shaper)
# 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
@@ -341,7 +340,7 @@ class ShaperCalibrate:
CalibrationResult(
name=shaper_cfg.name, freq=test_freq, vals=shaper_vals,
vibrs=shaper_vibrations, smoothing=shaper_smoothing,
- score=shaper_score))
+ score=shaper_score, max_accel=max_accel))
if best_res is None or best_res.vibrs > results[-1].vibrs:
# The current frequency is better for the shaper.
best_res = results[-1]
@@ -353,6 +352,30 @@ class ShaperCalibrate:
selected = res
return selected
+ def _bisect(self, func):
+ left = right = 1.
+ while not func(left):
+ right = left
+ left *= .5
+ if right == left:
+ while func(right):
+ right *= 2.
+ while right - left > 1e-8:
+ middle = (left + right) * .5
+ if func(middle):
+ left = middle
+ else:
+ right = middle
+ return left
+
+ def find_shaper_max_accel(self, shaper):
+ # 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: get_shaper_smoothing(
+ shaper, test_accel) <= TARGET_SMOOTHING)
+ return max_accel
+
def find_best_shaper(self, calibration_data, max_smoothing, logger=None):
best_shaper = None
all_shapers = []
@@ -364,6 +387,9 @@ class ShaperCalibrate:
"(vibrations = %.1f%%, smoothing ~= %.3f)" % (
shaper.name, shaper.freq, shaper.vibrs * 100.,
shaper.smoothing))
+ logger("To avoid too much smoothing with '%s', suggested "
+ "max_accel <= %.0f mm/sec^2" % (
+ shaper.name, round(shaper.max_accel / 100.) * 100.))
all_shapers.append(shaper)
if (best_shaper is None or shaper.score * 1.2 < best_shaper.score or
(shaper.score * 1.1 < best_shaper.score and