|
|
|
@@ -40,6 +40,7 @@ matplotlib.use('Agg')
|
|
|
|
PEAKS_DETECTION_THRESHOLD = 0.05
|
|
|
|
PEAKS_DETECTION_THRESHOLD = 0.05
|
|
|
|
PEAKS_EFFECT_THRESHOLD = 0.12
|
|
|
|
PEAKS_EFFECT_THRESHOLD = 0.12
|
|
|
|
SPECTROGRAM_LOW_PERCENTILE_FILTER = 5
|
|
|
|
SPECTROGRAM_LOW_PERCENTILE_FILTER = 5
|
|
|
|
|
|
|
|
MAX_SMOOTHING = 0.1
|
|
|
|
|
|
|
|
|
|
|
|
KLIPPAIN_COLORS = {
|
|
|
|
KLIPPAIN_COLORS = {
|
|
|
|
"purple": "#70088C",
|
|
|
|
"purple": "#70088C",
|
|
|
|
@@ -163,7 +164,7 @@ def detect_peaks(psd, freqs, window_size=5, vicinity=3):
|
|
|
|
# Graphing
|
|
|
|
# Graphing
|
|
|
|
######################################################################
|
|
|
|
######################################################################
|
|
|
|
|
|
|
|
|
|
|
|
def plot_freq_response_with_damping(ax, calibration_data, shapers, selected_shaper, fr, zeta, max_freq):
|
|
|
|
def plot_freq_response_with_damping(ax, calibration_data, shapers, performance_shaper, fr, zeta, max_freq):
|
|
|
|
freqs = calibration_data.freq_bins
|
|
|
|
freqs = calibration_data.freq_bins
|
|
|
|
psd = calibration_data.psd_sum[freqs <= max_freq]
|
|
|
|
psd = calibration_data.psd_sum[freqs <= max_freq]
|
|
|
|
px = calibration_data.psd_x[freqs <= max_freq]
|
|
|
|
px = calibration_data.psd_x[freqs <= max_freq]
|
|
|
|
@@ -193,30 +194,50 @@ def plot_freq_response_with_damping(ax, calibration_data, shapers, selected_shap
|
|
|
|
ax2 = ax.twinx()
|
|
|
|
ax2 = ax.twinx()
|
|
|
|
ax2.yaxis.set_visible(False)
|
|
|
|
ax2.yaxis.set_visible(False)
|
|
|
|
|
|
|
|
|
|
|
|
best_shaper_vals = None
|
|
|
|
lowvib_shaper_vibrs = float('inf')
|
|
|
|
no_vibr_shaper = None
|
|
|
|
lowvib_shaper = None
|
|
|
|
no_vibr_shaper_freq = None
|
|
|
|
lowvib_shaper_freq = None
|
|
|
|
no_vibr_shaper_accel = 0
|
|
|
|
lowvib_shaper_accel = 0
|
|
|
|
|
|
|
|
|
|
|
|
# Draw the shappers curves and add their specific parameters in the legend
|
|
|
|
# Draw the shappers curves and add their specific parameters in the legend
|
|
|
|
# This adds also a way to find the best shaper with 0% of vibrations (to be printed in the legend later)
|
|
|
|
# This adds also a way to find the best shaper with a low level of vibrations (with a resonable level of smoothing)
|
|
|
|
for shaper in shapers:
|
|
|
|
for shaper in shapers:
|
|
|
|
shaper_max_accel = round(shaper.max_accel / 100.) * 100.
|
|
|
|
shaper_max_accel = round(shaper.max_accel / 100.) * 100.
|
|
|
|
label = "%s (%.1f Hz, vibr=%.1f%%, sm~=%.2f, accel<=%.f)" % (
|
|
|
|
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,
|
|
|
|
shaper_max_accel)
|
|
|
|
shaper_max_accel)
|
|
|
|
linestyle = 'dotted'
|
|
|
|
ax2.plot(freqs, shaper.vals, label=label, linestyle='dotted')
|
|
|
|
if shaper.name == selected_shaper:
|
|
|
|
|
|
|
|
linestyle = 'dashdot'
|
|
|
|
# Get the performance shaper
|
|
|
|
selected_shaper_freq = shaper.freq
|
|
|
|
if shaper.name == performance_shaper:
|
|
|
|
best_shaper_vals = shaper.vals
|
|
|
|
performance_shaper_freq = shaper.freq
|
|
|
|
if (shaper.vibrs * 100 == 0.) and (shaper_max_accel > no_vibr_shaper_accel):
|
|
|
|
performance_shaper_vibr = shaper.vibrs * 100.
|
|
|
|
no_vibr_shaper_accel = shaper_max_accel
|
|
|
|
performance_shaper_vals = shaper.vals
|
|
|
|
no_vibr_shaper = shaper.name
|
|
|
|
|
|
|
|
no_vibr_shaper_freq = shaper.freq
|
|
|
|
# Get the low vibration shaper
|
|
|
|
ax2.plot(freqs, shaper.vals, label=label, linestyle=linestyle)
|
|
|
|
if (shaper.vibrs * 100 < lowvib_shaper_vibrs or (shaper.vibrs * 100 == lowvib_shaper_vibrs and shaper_max_accel > lowvib_shaper_accel)) and shaper.smoothing < MAX_SMOOTHING:
|
|
|
|
ax.plot(freqs, psd * best_shaper_vals, label='With %s applied' % (selected_shaper.upper()), color='cyan')
|
|
|
|
lowvib_shaper_accel = shaper_max_accel
|
|
|
|
|
|
|
|
lowvib_shaper = shaper.name
|
|
|
|
|
|
|
|
lowvib_shaper_freq = shaper.freq
|
|
|
|
|
|
|
|
lowvib_shaper_vibrs = shaper.vibrs * 100
|
|
|
|
|
|
|
|
lowvib_shaper_vals = shaper.vals
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# User recommendations are added to the legend: one is Klipper's original suggestion that is usually good for performances
|
|
|
|
|
|
|
|
# and the other one is the custom "low vibration" recommendation that looks for a suitable shaper that doesn't have excessive
|
|
|
|
|
|
|
|
# smoothing and that have a lower vibration level. If both recommendation are the same shaper, or if no suitable "low
|
|
|
|
|
|
|
|
# vibration" shaper is found, then only a single line as the "best shaper" recommendation is added to the legend
|
|
|
|
|
|
|
|
if lowvib_shaper != None and lowvib_shaper != performance_shaper and lowvib_shaper_vibrs <= performance_shaper_vibr:
|
|
|
|
|
|
|
|
ax2.plot([], [], ' ', label="Recommended performance shaper: %s @ %.1f Hz" % (performance_shaper.upper(), performance_shaper_freq))
|
|
|
|
|
|
|
|
ax.plot(freqs, psd * performance_shaper_vals, label='With %s applied' % (performance_shaper.upper()), color='cyan')
|
|
|
|
|
|
|
|
ax2.plot([], [], ' ', label="Recommended low vibrations shaper: %s @ %.1f Hz" % (lowvib_shaper.upper(), lowvib_shaper_freq))
|
|
|
|
|
|
|
|
ax.plot(freqs, psd * lowvib_shaper_vals, label='With %s applied' % (lowvib_shaper.upper()), color='lime')
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
ax2.plot([], [], ' ', label="Recommended best shaper: %s @ %.1f Hz" % (performance_shaper.upper(), performance_shaper_freq))
|
|
|
|
|
|
|
|
ax.plot(freqs, psd * performance_shaper_vals, label='With %s applied' % (performance_shaper.upper()), color='cyan')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# And the estimated damping ratio is finally added at the end of the legend
|
|
|
|
|
|
|
|
ax2.plot([], [], ' ', label="Estimated damping ratio (ζ): %.3f" % (zeta))
|
|
|
|
|
|
|
|
|
|
|
|
# Draw the detected peaks and name them
|
|
|
|
# Draw the detected peaks and name them
|
|
|
|
# This also draw the detection threshold and warning threshold (aka "effect zone")
|
|
|
|
# This also draw the detection threshold and warning threshold (aka "effect zone")
|
|
|
|
@@ -240,10 +261,6 @@ def plot_freq_response_with_damping(ax, calibration_data, shapers, selected_shap
|
|
|
|
ax.fill_between(freqs, 0, peaks_warning_threshold, color='green', alpha=0.15, label='Relax Region')
|
|
|
|
ax.fill_between(freqs, 0, peaks_warning_threshold, color='green', alpha=0.15, label='Relax Region')
|
|
|
|
ax.fill_between(freqs, peaks_warning_threshold, peaks_effect_threshold, color='orange', alpha=0.2, label='Warning Region')
|
|
|
|
ax.fill_between(freqs, peaks_warning_threshold, peaks_effect_threshold, color='orange', alpha=0.2, label='Warning Region')
|
|
|
|
|
|
|
|
|
|
|
|
# Final user recommendations added to the legend with an added 0% vibration shaper and the estimated damping ratio over stock Klipper's algorithms
|
|
|
|
|
|
|
|
ax2.plot([], [], ' ', label="Recommended shaper: %s @ %.1f Hz" % (selected_shaper.upper(), selected_shaper_freq))
|
|
|
|
|
|
|
|
ax2.plot([], [], ' ', label="Recommended low vibrations shaper: %s @ %.1f Hz" % (no_vibr_shaper.upper(), no_vibr_shaper_freq))
|
|
|
|
|
|
|
|
ax2.plot([], [], ' ', label="Estimated damping ratio (ζ): %.3f" % (zeta))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Add the main resonant frequency and damping ratio of the axis to the graph title
|
|
|
|
# Add the main resonant frequency and damping ratio of the axis to the graph title
|
|
|
|
ax.set_title("Axis Frequency Profile (ω0=%.1fHz, ζ=%.3f)" % (fr, zeta), fontsize=14, color=KLIPPAIN_COLORS['dark_orange'], weight='bold')
|
|
|
|
ax.set_title("Axis Frequency Profile (ω0=%.1fHz, ζ=%.3f)" % (fr, zeta), fontsize=14, color=KLIPPAIN_COLORS['dark_orange'], weight='bold')
|
|
|
|
@@ -315,7 +332,7 @@ def shaper_calibration(lognames, klipperdir="~/klipper", max_smoothing=None, max
|
|
|
|
datas = [parse_log(fn) for fn in lognames]
|
|
|
|
datas = [parse_log(fn) for fn in lognames]
|
|
|
|
|
|
|
|
|
|
|
|
# Calibrate shaper and generate outputs
|
|
|
|
# Calibrate shaper and generate outputs
|
|
|
|
selected_shaper, shapers, calibration_data, fr, zeta = calibrate_shaper_with_damping(datas, max_smoothing)
|
|
|
|
performance_shaper, shapers, calibration_data, fr, zeta = calibrate_shaper_with_damping(datas, max_smoothing)
|
|
|
|
|
|
|
|
|
|
|
|
fig = matplotlib.pyplot.figure()
|
|
|
|
fig = matplotlib.pyplot.figure()
|
|
|
|
gs = matplotlib.gridspec.GridSpec(2, 1, height_ratios=[4, 3])
|
|
|
|
gs = matplotlib.gridspec.GridSpec(2, 1, height_ratios=[4, 3])
|
|
|
|
@@ -335,7 +352,7 @@ def shaper_calibration(lognames, klipperdir="~/klipper", max_smoothing=None, max
|
|
|
|
fig.text(0.12, 0.957, title_line2, ha='left', va='top', fontsize=16, color=KLIPPAIN_COLORS['dark_purple'])
|
|
|
|
fig.text(0.12, 0.957, title_line2, ha='left', va='top', fontsize=16, color=KLIPPAIN_COLORS['dark_purple'])
|
|
|
|
|
|
|
|
|
|
|
|
# Plot the graphs
|
|
|
|
# Plot the graphs
|
|
|
|
peaks = plot_freq_response_with_damping(ax1, calibration_data, shapers, selected_shaper, fr, zeta, max_freq)
|
|
|
|
peaks = plot_freq_response_with_damping(ax1, calibration_data, shapers, performance_shaper, fr, zeta, max_freq)
|
|
|
|
plot_spectrogram(ax2, datas[0], peaks, max_freq)
|
|
|
|
plot_spectrogram(ax2, datas[0], peaks, max_freq)
|
|
|
|
|
|
|
|
|
|
|
|
fig.set_size_inches(8.3, 11.6)
|
|
|
|
fig.set_size_inches(8.3, 11.6)
|
|
|
|
|