aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/graph_accelerometer.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/graph_accelerometer.py')
-rwxr-xr-xscripts/graph_accelerometer.py224
1 files changed, 145 insertions, 79 deletions
diff --git a/scripts/graph_accelerometer.py b/scripts/graph_accelerometer.py
index 84b31311..7286c041 100755
--- a/scripts/graph_accelerometer.py
+++ b/scripts/graph_accelerometer.py
@@ -8,59 +8,73 @@
import importlib, optparse, os, sys
from textwrap import wrap
import numpy as np, matplotlib
-sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)),
- '..', 'klippy'))
-shaper_calibrate = importlib.import_module('.shaper_calibrate', 'extras')
-MAX_TITLE_LENGTH=65
+sys.path.append(
+ os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", "klippy")
+)
+shaper_calibrate = importlib.import_module(".shaper_calibrate", "extras")
+
+MAX_TITLE_LENGTH = 65
+
def parse_log(logname, opts):
with open(logname) as f:
for header in f:
- if header.startswith('#'):
+ if header.startswith("#"):
continue
- if header.startswith('freq,psd_x,psd_y,psd_z,psd_xyz'):
+ if header.startswith("freq,psd_x,psd_y,psd_z,psd_xyz"):
# Processed power spectral density file
break
# Raw accelerometer data
- return np.loadtxt(logname, comments='#', delimiter=',')
+ return np.loadtxt(logname, comments="#", delimiter=",")
# Parse power spectral density data
- data = np.loadtxt(logname, skiprows=1, comments='#', delimiter=',')
+ data = np.loadtxt(logname, skiprows=1, comments="#", delimiter=",")
calibration_data = shaper_calibrate.CalibrationData(
- freq_bins=data[:,0], psd_sum=data[:,4],
- psd_x=data[:,1], psd_y=data[:,2], psd_z=data[:,3])
+ freq_bins=data[:, 0],
+ psd_sum=data[:, 4],
+ psd_x=data[:, 1],
+ psd_y=data[:, 2],
+ psd_z=data[:, 3],
+ )
calibration_data.set_numpy(np)
return calibration_data
+
######################################################################
# Raw accelerometer graphing
######################################################################
+
def plot_accel(datas, lognames):
fig, axes = matplotlib.pyplot.subplots(nrows=3, sharex=True)
- axes[0].set_title("\n".join(wrap(
- "Accelerometer data (%s)" % (', '.join(lognames)), MAX_TITLE_LENGTH)))
- axis_names = ['x', 'y', 'z']
+ axes[0].set_title(
+ "\n".join(
+ wrap("Accelerometer data (%s)" % (", ".join(lognames)), MAX_TITLE_LENGTH)
+ )
+ )
+ axis_names = ["x", "y", "z"]
for data, logname in zip(datas, lognames):
if isinstance(data, shaper_calibrate.CalibrationData):
- raise error("Cannot plot raw accelerometer data using the processed"
- " resonances, raw_data input is required")
+ raise error(
+ "Cannot plot raw accelerometer data using the processed"
+ " resonances, raw_data input is required"
+ )
first_time = data[0, 0]
- times = data[:,0] - first_time
+ times = data[:, 0] - first_time
for i in range(len(axis_names)):
- avg = data[:,i+1].mean()
- adata = data[:,i+1] - data[:,i+1].mean()
+ avg = data[:, i + 1].mean()
+ adata = data[:, i + 1] - data[:, i + 1].mean()
ax = axes[i]
- label = '\n'.join(wrap(logname, 60)) + ' (%+.3f mm/s^2)' % (-avg,)
+ label = "\n".join(wrap(logname, 60)) + " (%+.3f mm/s^2)" % (-avg,)
ax.plot(times, adata, alpha=0.8, label=label)
- axes[-1].set_xlabel('Time (s)')
+ axes[-1].set_xlabel("Time (s)")
fontP = matplotlib.font_manager.FontProperties()
- fontP.set_size('x-small')
+ fontP.set_size("x-small")
for i in range(len(axis_names)):
ax = axes[i]
ax.grid(True)
- ax.legend(loc='best', prop=fontP)
- ax.set_ylabel('%s accel' % (axis_names[i],))
+ ax.legend(loc="best", prop=fontP)
+ ax.set_ylabel("%s accel" % (axis_names[i],))
fig.tight_layout()
return fig
@@ -69,6 +83,7 @@ def plot_accel(datas, lognames):
# Frequency graphing
######################################################################
+
# Calculate estimated "power spectral density"
def calc_freq_response(data, max_freq):
if isinstance(data, shaper_calibrate.CalibrationData):
@@ -76,29 +91,41 @@ def calc_freq_response(data, max_freq):
helper = shaper_calibrate.ShaperCalibrate(printer=None)
return helper.process_accelerometer_data(data)
+
def calc_specgram(data, axis):
if isinstance(data, shaper_calibrate.CalibrationData):
- raise error("Cannot calculate the spectrogram using the processed"
- " resonances, raw_data input is required")
+ raise error(
+ "Cannot calculate the spectrogram using the processed"
+ " resonances, raw_data input is required"
+ )
N = data.shape[0]
- Fs = N / (data[-1,0] - data[0,0])
+ Fs = N / (data[-1, 0] - data[0, 0])
# Round up to a power of 2 for faster FFT
- M = 1 << int(.5 * Fs - 1).bit_length()
- window = np.kaiser(M, 6.)
+ M = 1 << int(0.5 * Fs - 1).bit_length()
+ window = np.kaiser(M, 6.0)
+
def _specgram(x):
return matplotlib.mlab.specgram(
- x, Fs=Fs, NFFT=M, noverlap=M//2, window=window,
- mode='psd', detrend='mean', scale_by_freq=False)
+ x,
+ Fs=Fs,
+ NFFT=M,
+ noverlap=M // 2,
+ window=window,
+ mode="psd",
+ detrend="mean",
+ scale_by_freq=False,
+ )
- d = {'x': data[:,1], 'y': data[:,2], 'z': data[:,3]}
- if axis != 'all':
+ d = {"x": data[:, 1], "y": data[:, 2], "z": data[:, 3]}
+ if axis != "all":
pdata, bins, t = _specgram(d[axis])
else:
- pdata, bins, t = _specgram(d['x'])
- for ax in 'yz':
+ pdata, bins, t = _specgram(d["x"])
+ for ax in "yz":
pdata += _specgram(d[ax])[0]
return pdata, bins, t
+
def plot_frequency(datas, lognames, max_freq):
calibration_data = calc_freq_response(datas[0], max_freq)
for data in datas[1:]:
@@ -111,33 +138,37 @@ def plot_frequency(datas, lognames, max_freq):
freqs = freqs[freqs <= max_freq]
fig, ax = matplotlib.pyplot.subplots()
- ax.set_title("\n".join(wrap(
- "Frequency response (%s)" % (', '.join(lognames)), MAX_TITLE_LENGTH)))
- ax.set_xlabel('Frequency (Hz)')
- ax.set_ylabel('Power spectral density')
+ ax.set_title(
+ "\n".join(
+ wrap("Frequency response (%s)" % (", ".join(lognames)), MAX_TITLE_LENGTH)
+ )
+ )
+ ax.set_xlabel("Frequency (Hz)")
+ ax.set_ylabel("Power spectral density")
- ax.plot(freqs, psd, label='X+Y+Z', alpha=0.6)
- ax.plot(freqs, px, label='X', alpha=0.6)
- ax.plot(freqs, py, label='Y', alpha=0.6)
- ax.plot(freqs, pz, label='Z', alpha=0.6)
+ ax.plot(freqs, psd, label="X+Y+Z", alpha=0.6)
+ ax.plot(freqs, px, label="X", alpha=0.6)
+ ax.plot(freqs, py, label="Y", alpha=0.6)
+ ax.plot(freqs, pz, label="Z", alpha=0.6)
ax.xaxis.set_minor_locator(matplotlib.ticker.AutoMinorLocator())
ax.yaxis.set_minor_locator(matplotlib.ticker.AutoMinorLocator())
- ax.grid(which='major', color='grey')
- ax.grid(which='minor', color='lightgrey')
- ax.ticklabel_format(axis='y', style='scientific', scilimits=(0,0))
+ ax.grid(which="major", color="grey")
+ ax.grid(which="minor", color="lightgrey")
+ ax.ticklabel_format(axis="y", style="scientific", scilimits=(0, 0))
fontP = matplotlib.font_manager.FontProperties()
- fontP.set_size('x-small')
- ax.legend(loc='best', prop=fontP)
+ fontP.set_size("x-small")
+ ax.legend(loc="best", prop=fontP)
fig.tight_layout()
return fig
+
def plot_compare_frequency(datas, lognames, max_freq, axis):
fig, ax = matplotlib.pyplot.subplots()
- ax.set_title('Frequency responses comparison')
- ax.set_xlabel('Frequency (Hz)')
- ax.set_ylabel('Power spectral density')
+ ax.set_title("Frequency responses comparison")
+ ax.set_xlabel("Frequency (Hz)")
+ ax.set_ylabel("Power spectral density")
for data, logname in zip(datas, lognames):
calibration_data = calc_freq_response(data, max_freq)
@@ -148,32 +179,36 @@ def plot_compare_frequency(datas, lognames, max_freq, axis):
ax.xaxis.set_minor_locator(matplotlib.ticker.AutoMinorLocator())
ax.yaxis.set_minor_locator(matplotlib.ticker.AutoMinorLocator())
- ax.grid(which='major', color='grey')
- ax.grid(which='minor', color='lightgrey')
+ ax.grid(which="major", color="grey")
+ ax.grid(which="minor", color="lightgrey")
fontP = matplotlib.font_manager.FontProperties()
- fontP.set_size('x-small')
- ax.legend(loc='best', prop=fontP)
+ fontP.set_size("x-small")
+ ax.legend(loc="best", prop=fontP)
fig.tight_layout()
return fig
+
# Plot data in a "spectrogram colormap"
def plot_specgram(data, logname, max_freq, axis):
pdata, bins, t = calc_specgram(data, axis)
fig, ax = matplotlib.pyplot.subplots()
- ax.set_title("\n".join(wrap("Spectrogram %s (%s)" % (axis, logname),
- MAX_TITLE_LENGTH)))
+ ax.set_title(
+ "\n".join(wrap("Spectrogram %s (%s)" % (axis, logname), MAX_TITLE_LENGTH))
+ )
ax.pcolormesh(t, bins, pdata, norm=matplotlib.colors.LogNorm())
- ax.set_ylim([0., max_freq])
- ax.set_ylabel('frequency (hz)')
- ax.set_xlabel('Time (s)')
+ ax.set_ylim([0.0, max_freq])
+ ax.set_ylabel("frequency (hz)")
+ ax.set_xlabel("Time (s)")
fig.tight_layout()
return fig
+
######################################################################
# CSV output
######################################################################
+
def write_frequency_response(datas, output):
helper = shaper_calibrate.ShaperCalibrate(printer=None)
calibration_data = helper.process_accelerometer_data(datas[0])
@@ -181,6 +216,7 @@ def write_frequency_response(datas, output):
calibration_data.add_data(helper.process_accelerometer_data(data))
helper.save_calibration_data(output, calibration_data)
+
def write_specgram(psd, freq_bins, time, output):
M = freq_bins.shape[0]
with open(output, "w") as csvfile:
@@ -190,46 +226,76 @@ def write_specgram(psd, freq_bins, time, output):
csvfile.write("\n")
for i in range(M):
csvfile.write("%.1f" % (freq_bins[i],))
- for value in psd[i,:]:
+ for value in psd[i, :]:
csvfile.write(",%.6e" % (value,))
csvfile.write("\n")
+
######################################################################
# Startup
######################################################################
+
def is_csv_output(output):
- return output and os.path.splitext(output)[1].lower() == '.csv'
+ return output and os.path.splitext(output)[1].lower() == ".csv"
+
def setup_matplotlib(output):
global matplotlib
if is_csv_output(output):
# Only mlab may be necessary with CSV output
import matplotlib.mlab
+
return
if output:
- matplotlib.rcParams.update({'figure.autolayout': True})
- matplotlib.use('Agg')
+ matplotlib.rcParams.update({"figure.autolayout": True})
+ matplotlib.use("Agg")
import matplotlib.pyplot, matplotlib.dates, matplotlib.font_manager
import matplotlib.ticker
+
def main():
# Parse command-line arguments
usage = "%prog [options] <raw logs>"
opts = optparse.OptionParser(usage)
- opts.add_option("-o", "--output", type="string", dest="output",
- default=None, help="filename of output graph")
- opts.add_option("-f", "--max_freq", type="float", default=200.,
- help="maximum frequency to graph")
- opts.add_option("-r", "--raw", action="store_true",
- help="graph raw accelerometer data")
- opts.add_option("-c", "--compare", action="store_true",
- help="graph comparison of power spectral density "
- "between different accelerometer data files")
- opts.add_option("-s", "--specgram", action="store_true",
- help="graph spectrogram of accelerometer data")
- opts.add_option("-a", type="string", dest="axis", default="all",
- help="axis to graph (one of 'all', 'x', 'y', or 'z')")
+ opts.add_option(
+ "-o",
+ "--output",
+ type="string",
+ dest="output",
+ default=None,
+ help="filename of output graph",
+ )
+ opts.add_option(
+ "-f",
+ "--max_freq",
+ type="float",
+ default=200.0,
+ help="maximum frequency to graph",
+ )
+ opts.add_option(
+ "-r", "--raw", action="store_true", help="graph raw accelerometer data"
+ )
+ opts.add_option(
+ "-c",
+ "--compare",
+ action="store_true",
+ help="graph comparison of power spectral density "
+ "between different accelerometer data files",
+ )
+ opts.add_option(
+ "-s",
+ "--specgram",
+ action="store_true",
+ help="graph spectrogram of accelerometer data",
+ )
+ opts.add_option(
+ "-a",
+ type="string",
+ dest="axis",
+ default="all",
+ help="axis to graph (one of 'all', 'x', 'y', or 'z')",
+ )
options, args = opts.parse_args()
if len(args) < 1:
opts.error("Incorrect number of arguments")
@@ -261,8 +327,7 @@ def main():
opts.error("Only 1 input is supported in specgram mode")
fig = plot_specgram(datas[0], args[0], options.max_freq, options.axis)
elif options.compare:
- fig = plot_compare_frequency(datas, args, options.max_freq,
- options.axis)
+ fig = plot_compare_frequency(datas, args, options.max_freq, options.axis)
else:
fig = plot_frequency(datas, args, options.max_freq)
@@ -273,5 +338,6 @@ def main():
fig.set_size_inches(8, 6)
fig.savefig(options.output)
-if __name__ == '__main__':
+
+if __name__ == "__main__":
main()