77 """Plot controller run data."""
78 fig = plt.figure(figsize=(16, 12))
79 gs = GridSpec(4, 2, figure=fig, hspace=0.3, wspace=0.3)
81 time = data[
"timestamp"]
84 ax1 = fig.add_subplot(gs[0, 0])
85 ax1.plot(time, data[
"F_ref"] / 1000,
'b--', label=
'F_ref', linewidth=2)
86 ax1.plot(time, data[
"F"] / 1000,
'r-', label=
'F_hat', linewidth=1.5)
87 ax1.set_xlabel(
'Time [s]')
88 ax1.set_ylabel(
'Thrust [kN]')
89 ax1.set_title(
'Thrust Tracking')
91 ax1.grid(
True, alpha=0.3)
94 ax2 = fig.add_subplot(gs[0, 1])
95 ax2.plot(time, data[
"MR_ref"],
'b--', label=
'MR_ref', linewidth=2)
96 ax2.plot(time, data[
"MR"],
'r-', label=
'MR_hat', linewidth=1.5)
97 ax2.set_xlabel(
'Time [s]')
98 ax2.set_ylabel(
'Mixture Ratio (O/F)')
99 ax2.set_title(
'Mixture Ratio')
101 ax2.grid(
True, alpha=0.3)
104 ax3 = fig.add_subplot(gs[1, 0])
105 ax3.plot(time, data[
"P_copv"] / 1e6,
'b-', label=
'P_copv', linewidth=1.5)
106 ax3.plot(time, data[
"P_reg"] / 1e6,
'g-', label=
'P_reg', linewidth=1.5)
107 ax3.set_xlabel(
'Time [s]')
108 ax3.set_ylabel(
'Pressure [MPa]')
109 ax3.set_title(
'COPV and Regulator Pressures')
111 ax3.grid(
True, alpha=0.3)
114 ax4 = fig.add_subplot(gs[1, 1])
115 ax4.plot(time, data[
"P_u_fuel"] / 1e6,
'b-', label=
'P_u_fuel', linewidth=1.5)
116 ax4.plot(time, data[
"P_u_ox"] / 1e6,
'r-', label=
'P_u_ox', linewidth=1.5)
117 ax4.set_xlabel(
'Time [s]')
118 ax4.set_ylabel(
'Pressure [MPa]')
119 ax4.set_title(
'Ullage Pressures')
121 ax4.grid(
True, alpha=0.3)
124 ax5 = fig.add_subplot(gs[2, 0])
125 ax5.plot(time, data[
"P_d_fuel"] / 1e6,
'b-', label=
'P_d_fuel', linewidth=1.5)
126 ax5.plot(time, data[
"P_d_ox"] / 1e6,
'r-', label=
'P_d_ox', linewidth=1.5)
127 ax5.plot(time, data[
"P_ch"] / 1e6,
'g-', label=
'P_ch', linewidth=1.5)
128 ax5.set_xlabel(
'Time [s]')
129 ax5.set_ylabel(
'Pressure [MPa]')
130 ax5.set_title(
'Feed and Chamber Pressures')
132 ax5.grid(
True, alpha=0.3)
135 ax6 = fig.add_subplot(gs[2, 1])
136 ax6.plot(time, data[
"duty_F"],
'b-', label=
'duty_F', linewidth=1.5)
137 ax6.plot(time, data[
"duty_O"],
'r-', label=
'duty_O', linewidth=1.5)
138 ax6.set_xlabel(
'Time [s]')
139 ax6.set_ylabel(
'Duty Cycle [0-1]')
140 ax6.set_title(
'Solenoid Duty Cycles')
141 ax6.set_ylim([-0.1, 1.1])
143 ax6.grid(
True, alpha=0.3)
146 ax7 = fig.add_subplot(gs[3, :])
147 constraint_keys = [k
for k
in data.keys()
if k.startswith(
"constraint_")]
149 for key
in constraint_keys:
150 constraint_name = key[len(
"constraint_"):]
151 ax7.plot(time, data[key], label=constraint_name, linewidth=1.5, alpha=0.7)
152 ax7.axhline(y=0, color=
'k', linestyle=
'--', linewidth=1, alpha=0.5)
153 ax7.set_xlabel(
'Time [s]')
154 ax7.set_ylabel(
'Constraint Margin (positive = violation)')
155 ax7.set_title(
'Constraint Margins')
156 ax7.legend(ncol=3, fontsize=8)
157 ax7.grid(
True, alpha=0.3)
159 ax7.text(0.5, 0.5,
'No constraint data', ha=
'center', va=
'center', transform=ax7.transAxes)
160 ax7.set_title(
'Constraint Margins')
162 plt.suptitle(
'Controller Run Analysis', fontsize=16, y=0.995)
165 plt.savefig(output_file, dpi=150, bbox_inches=
'tight')
166 print(f
"Plot saved to {output_file}")