"""Plot pid-results.csv. Tested with matplotlib 3.6.3; labels are shared in JA/EN.""" import csv from collections import defaultdict import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt plt.rcParams.update({'font.size': 14}) rows=defaultdict(list) with open('pid-results.csv') as source: for row in csv.DictReader(source): rows[row['scenario']].append({k: float(v) for k,v in row.items() if k!='scenario'}) fig, axes=plt.subplots(2, 1, figsize=(10, 7), sharex=True) styles=['-', '--', '-.', ':'] for (name, data), style in zip(rows.items(), styles): for ax, key in zip(axes, ['output', 'control']): ax.plot([r['time_s'] for r in data], [r[key] for r in data], style, label=name, linewidth=2) data=rows['nominal'] axes[0].plot([r['time_s'] for r in data], [r['target'] for r in data], color='black', linewidth=1, label='target') axes[0].set_ylabel('Output (normalized)');axes[1].set_ylabel('Control (normalized)') axes[1].set_xlabel('Time (s)') for ax in axes: ax.grid(alpha=.3); ax.legend(loc='best', fontsize=12) fig.suptitle('PID simulation: Kp=3, Ki=2, Kd=1; dt=0.005 s; 2,401 samples/case') fig.tight_layout() fig.savefig('pid-response.svg', metadata={'Description':'Simulation of a normalized second-order plant, with measurement delay and saturation; not hardware measurements.'}) from pathlib import Path p=Path("pid-response.svg") s=p.read_text().replace("", s.index("PID simulation with delay and saturationOutput and control from 0 to 12 seconds; target changes from 1 to 0.4 at 6 seconds. Conditional integration reduces windup under a 0.8 control limit.'+s[pos:] p.write_text(s)