mirror of https://github.com/Desuuuu/klipper.git
shaper_calibrate: Estimate max_accel to avoid excessive smoothing
Signed-off-by: Dmitry Butyugin <dmbutyugin@google.com>
This commit is contained in:
parent
8c369b54ab
commit
73a39370ad
|
@ -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]
|
T = [0., .5*t_d, t_d, 1.5*t_d, 2.*t_d]
|
||||||
return (A, T)
|
return (A, T)
|
||||||
|
|
||||||
def get_shaper_smoothing(shaper):
|
def get_shaper_smoothing(shaper, accel=5000, scv=5.):
|
||||||
# Smoothing calculation params
|
half_accel = accel * .5
|
||||||
HALF_ACCEL = 2500.
|
|
||||||
SCV = 5.
|
|
||||||
|
|
||||||
A, T = shaper
|
A, T = shaper
|
||||||
inv_D = 1. / sum(A)
|
inv_D = 1. / sum(A)
|
||||||
|
@ -113,8 +111,8 @@ def get_shaper_smoothing(shaper):
|
||||||
for i in range(n):
|
for i in range(n):
|
||||||
if T[i] >= ts:
|
if T[i] >= ts:
|
||||||
# Calculate offset for one of the axes
|
# Calculate offset for one of the axes
|
||||||
offset_90 += A[i] * (SCV + HALF_ACCEL * (T[i]-ts)) * (T[i]-ts)
|
offset_90 += A[i] * (scv + half_accel * (T[i]-ts)) * (T[i]-ts)
|
||||||
offset_180 += A[i] * HALF_ACCEL * (T[i]-ts)**2
|
offset_180 += A[i] * half_accel * (T[i]-ts)**2
|
||||||
offset_90 *= inv_D * math.sqrt(2.)
|
offset_90 *= inv_D * math.sqrt(2.)
|
||||||
offset_180 *= inv_D
|
offset_180 *= inv_D
|
||||||
return max(offset_90, offset_180)
|
return max(offset_90, offset_180)
|
||||||
|
@ -164,7 +162,7 @@ class CalibrationData:
|
||||||
|
|
||||||
CalibrationResult = collections.namedtuple(
|
CalibrationResult = collections.namedtuple(
|
||||||
'CalibrationResult',
|
'CalibrationResult',
|
||||||
('name', 'freq', 'vals', 'vibrs', 'smoothing', 'score'))
|
('name', 'freq', 'vals', 'vibrs', 'smoothing', 'score', 'max_accel'))
|
||||||
|
|
||||||
class ShaperCalibrate:
|
class ShaperCalibrate:
|
||||||
def __init__(self, printer):
|
def __init__(self, printer):
|
||||||
|
@ -333,6 +331,7 @@ class ShaperCalibrate:
|
||||||
shaper_vals = np.maximum(shaper_vals, vals)
|
shaper_vals = np.maximum(shaper_vals, vals)
|
||||||
if vibrations > shaper_vibrations:
|
if vibrations > shaper_vibrations:
|
||||||
shaper_vibrations = vibrations
|
shaper_vibrations = vibrations
|
||||||
|
max_accel = self.find_shaper_max_accel(shaper)
|
||||||
# The score trying to minimize vibrations, but also accounting
|
# The score trying to minimize vibrations, but also accounting
|
||||||
# the growth of smoothing. The formula itself does not have any
|
# the growth of smoothing. The formula itself does not have any
|
||||||
# special meaning, it simply shows good results on real user data
|
# special meaning, it simply shows good results on real user data
|
||||||
|
@ -341,7 +340,7 @@ class ShaperCalibrate:
|
||||||
CalibrationResult(
|
CalibrationResult(
|
||||||
name=shaper_cfg.name, freq=test_freq, vals=shaper_vals,
|
name=shaper_cfg.name, freq=test_freq, vals=shaper_vals,
|
||||||
vibrs=shaper_vibrations, smoothing=shaper_smoothing,
|
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:
|
if best_res is None or best_res.vibrs > results[-1].vibrs:
|
||||||
# The current frequency is better for the shaper.
|
# The current frequency is better for the shaper.
|
||||||
best_res = results[-1]
|
best_res = results[-1]
|
||||||
|
@ -353,6 +352,30 @@ class ShaperCalibrate:
|
||||||
selected = res
|
selected = res
|
||||||
return selected
|
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):
|
def find_best_shaper(self, calibration_data, max_smoothing, logger=None):
|
||||||
best_shaper = None
|
best_shaper = None
|
||||||
all_shapers = []
|
all_shapers = []
|
||||||
|
@ -364,6 +387,9 @@ class ShaperCalibrate:
|
||||||
"(vibrations = %.1f%%, smoothing ~= %.3f)" % (
|
"(vibrations = %.1f%%, smoothing ~= %.3f)" % (
|
||||||
shaper.name, shaper.freq, shaper.vibrs * 100.,
|
shaper.name, shaper.freq, shaper.vibrs * 100.,
|
||||||
shaper.smoothing))
|
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)
|
all_shapers.append(shaper)
|
||||||
if (best_shaper is None or shaper.score * 1.2 < best_shaper.score or
|
if (best_shaper is None or shaper.score * 1.2 < best_shaper.score or
|
||||||
(shaper.score * 1.1 < best_shaper.score and
|
(shaper.score * 1.1 < best_shaper.score and
|
||||||
|
|
|
@ -100,9 +100,10 @@ def plot_freq_response(lognames, calibration_data, shapers,
|
||||||
ax2.set_ylabel('Shaper vibration reduction (ratio)')
|
ax2.set_ylabel('Shaper vibration reduction (ratio)')
|
||||||
best_shaper_vals = None
|
best_shaper_vals = None
|
||||||
for shaper in shapers:
|
for shaper in shapers:
|
||||||
label = "%s (%.1f Hz, vibr=%.1f%%, sm~=%.2f)" % (
|
label = "%s (%.1f Hz, vibr=%.1f%%, sm~=%.2f, accel<=%.f)" % (
|
||||||
shaper.name.upper(), shaper.freq,
|
shaper.name.upper(), shaper.freq,
|
||||||
shaper.vibrs * 100., shaper.smoothing)
|
shaper.vibrs * 100., shaper.smoothing,
|
||||||
|
round(shaper.max_accel / 100.) * 100.)
|
||||||
linestyle = 'dotted'
|
linestyle = 'dotted'
|
||||||
if shaper.name == selected_shaper:
|
if shaper.name == selected_shaper:
|
||||||
linestyle = 'dashdot'
|
linestyle = 'dashdot'
|
||||||
|
|
Loading…
Reference in New Issue