scripts: Small improvements for input shaper and accelerometer scripts

Signed-off-by: Dmitry Butyugin <dmbutyugin@google.com>
This commit is contained in:
Dmitry Butyugin 2020-12-05 23:48:03 +01:00 committed by KevinOConnor
parent f84a570dde
commit 5ccc17042c
2 changed files with 46 additions and 27 deletions

View File

@ -7,11 +7,14 @@
# This file may be distributed under the terms of the GNU GPLv3 license. # This file may be distributed under the terms of the GNU GPLv3 license.
from __future__ import print_function from __future__ import print_function
import optparse, os, sys import optparse, os, sys
from textwrap import wrap
import numpy as np, matplotlib import numpy as np, matplotlib
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)),
'..', 'klippy', 'extras')) '..', 'klippy', 'extras'))
from shaper_calibrate import CalibrationData, ShaperCalibrate from shaper_calibrate import CalibrationData, ShaperCalibrate
MAX_TITLE_LENGTH=65
def parse_log(logname): def parse_log(logname):
with open(logname) as f: with open(logname) as f:
for header in f: for header in f:
@ -61,7 +64,7 @@ def calibrate_shaper(datas, csv_output):
# Plot frequency response and suggested input shapers # Plot frequency response and suggested input shapers
###################################################################### ######################################################################
def plot_freq_response(calibration_data, shapers_vals, def plot_freq_response(lognames, calibration_data, shapers_vals,
selected_shaper, max_freq): selected_shaper, 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]
@ -83,10 +86,8 @@ def plot_freq_response(calibration_data, shapers_vals,
ax.plot(freqs, py, label='Y', color='green') ax.plot(freqs, py, label='Y', color='green')
ax.plot(freqs, pz, label='Z', color='blue') ax.plot(freqs, pz, label='Z', color='blue')
if shapers_vals: title = "Frequency response and shapers (%s)" % (', '.join(lognames))
ax.set_title("Frequency response and shapers") ax.set_title("\n".join(wrap(title, MAX_TITLE_LENGTH)))
else:
ax.set_title("Frequency response")
ax.xaxis.set_minor_locator(matplotlib.ticker.AutoMinorLocator()) ax.xaxis.set_minor_locator(matplotlib.ticker.AutoMinorLocator())
ax.yaxis.set_minor_locator(matplotlib.ticker.AutoMinorLocator()) ax.yaxis.set_minor_locator(matplotlib.ticker.AutoMinorLocator())
ax.xaxis.set_minor_locator(matplotlib.ticker.AutoMinorLocator()) ax.xaxis.set_minor_locator(matplotlib.ticker.AutoMinorLocator())
@ -94,23 +95,25 @@ def plot_freq_response(calibration_data, shapers_vals,
ax.ticklabel_format(axis='y', style='scientific', scilimits=(0,0)) ax.ticklabel_format(axis='y', style='scientific', scilimits=(0,0))
ax.grid(which='major', color='grey') ax.grid(which='major', color='grey')
ax.grid(which='minor', color='lightgrey') ax.grid(which='minor', color='lightgrey')
ax.legend(loc='upper right', prop=fontP)
if shapers_vals: ax2 = ax.twinx()
ax2 = ax.twinx() ax2.set_ylabel('Shaper vibration reduction (ratio)')
ax2.set_ylabel('Shaper vibration reduction (ratio)') best_shaper_vals = None
best_shaper_vals = None for name, freq, vals in shapers_vals:
for name, freq, vals in shapers_vals: label = "%s (%.1f Hz)" % (name.upper(), freq)
label = "%s (%.1f Hz)" % (name.upper(), freq) linestyle = 'dotted'
linestyle = 'dotted' if name == selected_shaper:
if name == selected_shaper: linestyle = 'dashdot'
label += ' (selected)' best_shaper_vals = vals
linestyle = 'dashdot' ax2.plot(freqs, vals, label=label, linestyle=linestyle)
best_shaper_vals = vals ax.plot(freqs, psd * best_shaper_vals,
ax2.plot(freqs, vals, label=label, linestyle=linestyle) label='After\nshaper', color='cyan')
ax.plot(freqs, psd * best_shaper_vals, # A hack to add a human-readable shaper recommendation to legend
label='After\nshaper', color='cyan') ax2.plot([], [], ' ',
ax2.legend(loc='upper left', prop=fontP) label="Recommended shaper: %s" % (selected_shaper.upper()))
ax.legend(loc='upper left', prop=fontP)
ax2.legend(loc='upper right', prop=fontP)
fig.tight_layout() fig.tight_layout()
return fig return fig
@ -152,7 +155,7 @@ def main():
# Draw graph # Draw graph
setup_matplotlib(options.output is not None) setup_matplotlib(options.output is not None)
fig = plot_freq_response(calibration_data, shapers_vals, fig = plot_freq_response(args, calibration_data, shapers_vals,
selected_shaper, options.max_freq) selected_shaper, options.max_freq)
# Show graph # Show graph

View File

@ -12,10 +12,20 @@ sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)),
'..', 'klippy', 'extras')) '..', 'klippy', 'extras'))
from shaper_calibrate import ShaperCalibrate from shaper_calibrate import ShaperCalibrate
MAX_TITLE_LENGTH=80 MAX_TITLE_LENGTH=65
def parse_log(logname): def parse_log(logname, opts):
return np.loadtxt(logname, comments='#', delimiter=',') with open(logname) as f:
for header in f:
if not header.startswith('#'):
break
if not header.startswith('freq,psd_x,psd_y,psd_z,psd_xyz'):
# Raw accelerometer data
return np.loadtxt(logname, comments='#', delimiter=',')
# Power spectral density data or shaper calibration data
opts.error("File %s does not contain raw accelerometer data and therefore "
"is not supported by graph_accelerometer.py script. Please use "
"calibrate_shaper.py script to process it instead." % (logname,))
###################################################################### ######################################################################
# Raw accelerometer graphing # Raw accelerometer graphing
@ -185,7 +195,7 @@ def setup_matplotlib(output):
def main(): def main():
# Parse command-line arguments # Parse command-line arguments
usage = "%prog [options] <logs>" usage = "%prog [options] <raw logs>"
opts = optparse.OptionParser(usage) opts = optparse.OptionParser(usage)
opts.add_option("-o", "--output", type="string", dest="output", opts.add_option("-o", "--output", type="string", dest="output",
default=None, help="filename of output graph") default=None, help="filename of output graph")
@ -205,7 +215,7 @@ def main():
opts.error("Incorrect number of arguments") opts.error("Incorrect number of arguments")
# Parse data # Parse data
datas = [parse_log(fn) for fn in args] datas = [parse_log(fn, opts) for fn in args]
setup_matplotlib(options.output) setup_matplotlib(options.output)
@ -215,6 +225,8 @@ def main():
if options.compare: if options.compare:
opts.error("comparison mode is not supported with csv output") opts.error("comparison mode is not supported with csv output")
if options.specgram: if options.specgram:
if len(args) > 1:
opts.error("Only 1 input is supported in specgram mode")
pdata, bins, t = calc_specgram(datas[0], options.axis) pdata, bins, t = calc_specgram(datas[0], options.axis)
write_specgram(pdata, bins, t, options.output) write_specgram(pdata, bins, t, options.output)
else: else:
@ -223,8 +235,12 @@ def main():
# Draw graph # Draw graph
if options.raw: if options.raw:
if len(args) > 1:
opts.error("Only 1 input is supported in raw mode")
fig = plot_accel(datas[0], args[0]) fig = plot_accel(datas[0], args[0])
elif options.specgram: elif options.specgram:
if len(args) > 1:
opts.error("Only 1 input is supported in specgram mode")
fig = plot_specgram(datas[0], args[0], options.max_freq, options.axis) fig = plot_specgram(datas[0], args[0], options.max_freq, options.axis)
elif options.compare: elif options.compare:
fig = plot_compare_frequency(datas, args, options.max_freq) fig = plot_compare_frequency(datas, args, options.max_freq)