import%20marimo%0A%0A__generated_with%20%3D%20%220.23.16%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20Learning%20MPC%20Weights%20for%20DC%20Motor%20Speed%20Control%0A%0A%20%20%20%20A%20model%20predictive%20controller%20balances%20speed%20tracking%20against%20large%20or%0A%20%20%20%20rapidly%20changing%20motor-voltage%20commands.%20Here%2C%20the%20upper%20problem%20learns%0A%20%20%20%20two%20control-cost%20weights%20from%20an%20expert%20response%2C%20while%20the%20lower%20problem%0A%20%20%20%20computes%20the%20corresponding%20constrained%20motor%20trajectory.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20from%20pathlib%20import%20Path%0A%0A%20%20%20%20import%20cvxpy%20as%20cp%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%20%20%20%20import%20numpy%20as%20np%0A%0A%20%20%20%20from%20blvpy%20import%20BilevelProblem%2C%20LowerProblem%0A%0A%20%20%20%20plt.style.use(Path(__file__).resolve().parents%5B1%5D%20%2F%20%22_shared%22%20%2F%20%22zhlatex.mplstyle%22)%0A%20%20%20%20return%20BilevelProblem%2C%20LowerProblem%2C%20Path%2C%20cp%2C%20mo%2C%20np%2C%20plt%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Bilevel%20formulation%0A%0A%20%20%20%20Let%20%24x(t)%3D(%5Comega(t)%2Ci(t))%24%20contain%20shaft%20speed%20and%20armature%20current%2C%20and%20let%0A%20%20%20%20%24u(t)%24%20be%20the%20applied%20voltage.%20The%20motor%20dynamics%20are%20discretized%20as%0A%20%20%20%20%24x(t%2B1)%3DAx(t)%2BBu(t)%24.%20For%20fixed%20voltage-effort%20and%20voltage-slew%20weights%0A%20%20%20%20%24%5Cdelta%2C%5Ceta%3E0%24%2C%20one%20MPC%20update%20solves%0A%0A%20%20%20%20%5C%5B%0A%20%20%20%20%5Cbegin%7Barray%7D%7Bll%7D%0A%20%20%20%20S(%5Cdelta%2C%5Ceta)%3D%5Cmathop%7B%5Cmathrm%7Bargmin%7D%7D_%7Bx%2Cu%7D%0A%20%20%20%20%20%20%26%20%5Cdisplaystyle%0A%20%20%20%20%20%20%20%20%5Csum_%7Bt%3D1%7D%5E%7BN%7D(%5Comega(t)-1)%5E2%0A%20%20%20%20%20%20%20%20%2B0.04%5Csum_%7Bt%3D1%7D%5E%7BN%7D(i(t)-0.1)%5E2%20%5C%5C%0A%20%20%20%20%20%20%26%20%5Cdisplaystyle%5Cquad%0A%20%20%20%20%20%20%20%20%2B%5Cdelta%5Csum_%7Bt%3D0%7D%5E%7BN-1%7D(u(t)-0.2)%5E2%0A%20%20%20%20%20%20%20%20%2B%5Ceta%5Csum_%7Bt%3D0%7D%5E%7BN-1%7D(u(t)-u(t-1))%5E2%0A%20%20%20%20%20%20%20%20%2B5(%5Comega(N)-1)%5E2%20%5C%5C%0A%20%20%20%20%5Cmathop%7B%5Cmathrm%7Bsubject%5C%20to%7D%7D%0A%20%20%20%20%20%20%26%20x(0)%3D(0%2C0)%2C%5Cqquad%20x(t%2B1)%3DAx(t)%2BBu(t)%2C%5C%5C%0A%20%20%20%20%20%20%26%20%7Cu(t)%7C%5Cleq2%2C%5Cqquad%20%7Ci(t)%7C%5Cleq0.5%2C%5C%5C%0A%20%20%20%20%20%20%26%20-0.05%5Cleq%5Comega(t)%5Cleq1.25%2C%0A%20%20%20%20%5Cend%7Barray%7D%0A%20%20%20%20%5C%5D%0A%0A%20%20%20%20with%20previous%20input%20%24u(-1)%3D0%24.%20Given%20expert%20samples%0A%20%20%20%20%24(%5Chat%7Bx%7D%2C%5Chat%7Bu%7D)%24%2C%20the%20upper%20problem%20is%0A%0A%20%20%20%20%5C%5B%0A%20%20%20%20%5Cbegin%7Barray%7D%7Bll%7D%0A%20%20%20%20%5Cmathop%7B%5Cmathrm%7Bminimize%7D%7D_%7B%5Cdelta%2C%5Ceta%2Cx%2Cu%7D%0A%20%20%20%20%20%20%26%20%5ClVert%20x-%5Chat%7Bx%7D%5CrVert_F%5E2%0A%20%20%20%20%20%20%20%20%2B0.1%5ClVert%20u-%5Chat%7Bu%7D%5CrVert_2%5E2%5C%5C%0A%20%20%20%20%5Cmathop%7B%5Cmathrm%7Bsubject%5C%20to%7D%7D%0A%20%20%20%20%20%20%26%200.01%5Cleq%5Cdelta%5Cleq1%2C%5C%5C%0A%20%20%20%20%20%20%26%200.01%5Cleq%5Ceta%5Cleq1%2C%5C%5C%0A%20%20%20%20%20%20%26%20(x%2Cu)%5Cin%20S(%5Cdelta%2C%5Ceta).%0A%20%20%20%20%5Cend%7Barray%7D%0A%20%20%20%20%5C%5D%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Synthetic%20instance%0A%0A%20%20%20%20We%20use%20a%2024-step%20horizon%20with%20sample%20time%20%240.05%24%2C%20target%20equilibrium%0A%20%20%20%20%24(%5Comega%2Ci%2Cu)%3D(1%2C0.1%2C0.2)%24%2C%20normalized%20motor%20constants%2C%20and%20operating%0A%20%20%20%20limits.%20The%20exact%20synthetic%20expert%20response%20uses%0A%20%20%20%20hidden%20weights%20%24(%5Cdelta%5E%7B%5Crm%20E%7D%2C%5Ceta%5E%7B%5Crm%20E%7D)%3D(0.035%2C0.16)%24.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(np)%3A%0A%20%20%20%20J%20%3D%200.01%0A%20%20%20%20b%20%3D%200.01%0A%20%20%20%20K_t%20%3D%200.1%0A%20%20%20%20K_e%20%3D%200.1%0A%20%20%20%20L%20%3D%200.5%0A%20%20%20%20R%20%3D%201.0%0A%20%20%20%20sample_time%20%3D%200.05%0A%20%20%20%20A%20%3D%20np.eye(2)%20%2B%20sample_time%20*%20np.array(%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B-b%20%2F%20J%2C%20K_t%20%2F%20J%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B-K_e%20%2F%20L%2C%20-R%20%2F%20L%5D%2C%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20)%0A%20%20%20%20B%20%3D%20sample_time%20*%20np.array(%5B0.0%2C%201.0%20%2F%20L%5D)%0A%0A%20%20%20%20N%20%3D%2024%0A%20%20%20%20x_initial%20%3D%20np.zeros(2)%0A%20%20%20%20u_previous%20%3D%200.0%0A%20%20%20%20x_reference%20%3D%20np.array(%5B1.0%2C%200.1%5D)%0A%20%20%20%20u_reference%20%3D%200.2%0A%20%20%20%20u_max%20%3D%202.0%0A%20%20%20%20i_max%20%3D%200.5%0A%20%20%20%20omega_min%20%3D%20-0.05%0A%20%20%20%20omega_max%20%3D%201.25%0A%20%20%20%20current_weight%20%3D%200.04%0A%20%20%20%20terminal_weight%20%3D%205.0%0A%20%20%20%20expert_delta%20%3D%200.035%0A%20%20%20%20expert_eta%20%3D%200.16%0A%20%20%20%20baseline_delta%20%3D%200.5%0A%20%20%20%20baseline_eta%20%3D%200.5%0A%20%20%20%20delta_bounds%20%3D%20(0.01%2C%201.0)%0A%20%20%20%20eta_bounds%20%3D%20(0.01%2C%201.0)%0A%0A%20%20%20%20assert%20np.allclose(x_reference%2C%20A%20%40%20x_reference%20%2B%20B%20*%20u_reference)%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20A%2C%0A%20%20%20%20%20%20%20%20B%2C%0A%20%20%20%20%20%20%20%20J%2C%0A%20%20%20%20%20%20%20%20N%2C%0A%20%20%20%20%20%20%20%20baseline_delta%2C%0A%20%20%20%20%20%20%20%20baseline_eta%2C%0A%20%20%20%20%20%20%20%20current_weight%2C%0A%20%20%20%20%20%20%20%20delta_bounds%2C%0A%20%20%20%20%20%20%20%20eta_bounds%2C%0A%20%20%20%20%20%20%20%20expert_delta%2C%0A%20%20%20%20%20%20%20%20expert_eta%2C%0A%20%20%20%20%20%20%20%20i_max%2C%0A%20%20%20%20%20%20%20%20omega_max%2C%0A%20%20%20%20%20%20%20%20omega_min%2C%0A%20%20%20%20%20%20%20%20sample_time%2C%0A%20%20%20%20%20%20%20%20terminal_weight%2C%0A%20%20%20%20%20%20%20%20u_max%2C%0A%20%20%20%20%20%20%20%20u_previous%2C%0A%20%20%20%20%20%20%20%20u_reference%2C%0A%20%20%20%20%20%20%20%20x_initial%2C%0A%20%20%20%20%20%20%20%20x_reference%2C%0A%20%20%20%20)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Expert%20and%20untuned%20responses%0A%0A%20%20%20%20Independent%20CVXPY%20solves%20generate%20the%20expert%20trajectory%20and%20the%20untuned%0A%20%20%20%20baseline%20by%20fixing%20their%20MPC%20weights.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20A%2C%0A%20%20%20%20B%2C%0A%20%20%20%20N%2C%0A%20%20%20%20cp%2C%0A%20%20%20%20current_weight%2C%0A%20%20%20%20expert_delta%2C%0A%20%20%20%20expert_eta%2C%0A%20%20%20%20i_max%2C%0A%20%20%20%20np%2C%0A%20%20%20%20omega_max%2C%0A%20%20%20%20omega_min%2C%0A%20%20%20%20terminal_weight%2C%0A%20%20%20%20u_max%2C%0A%20%20%20%20u_previous%2C%0A%20%20%20%20u_reference%2C%0A%20%20%20%20x_initial%2C%0A%20%20%20%20x_reference%2C%0A)%3A%0A%20%20%20%20def%20solve_fixed_mpc(fixed_delta%2C%20fixed_eta%2C%20x_initial_mpc%2C%20u_previous_mpc)%3A%0A%20%20%20%20%20%20%20%20_x%20%3D%20cp.Variable((2%2C%20N%20%2B%201))%0A%20%20%20%20%20%20%20%20_u%20%3D%20cp.Variable(N)%0A%20%20%20%20%20%20%20%20_u_change%20%3D%20cp.diff(cp.hstack(%5Bu_previous_mpc%2C%20_u%5D))%0A%20%20%20%20%20%20%20%20_cost%20%3D%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20cp.sum_squares(_x%5B0%2C%201%3A%5D%20-%20x_reference%5B0%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%2B%20current_weight%20*%20cp.sum_squares(_x%5B1%2C%201%3A%5D%20-%20x_reference%5B1%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%2B%20fixed_delta%20*%20cp.sum_squares(_u%20-%20u_reference)%0A%20%20%20%20%20%20%20%20%20%20%20%20%2B%20fixed_eta%20*%20cp.sum_squares(_u_change)%0A%20%20%20%20%20%20%20%20%20%20%20%20%2B%20terminal_weight%20*%20cp.square(_x%5B0%2C%20-1%5D%20-%20x_reference%5B0%5D)%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20_x_next%20%3D%20A%20%40%20_x%5B%3A%2C%20%3A-1%5D%20%2B%20cp.outer(B%2C%20_u)%0A%20%20%20%20%20%20%20%20_problem%20%3D%20cp.Problem(%0A%20%20%20%20%20%20%20%20%20%20%20%20cp.Minimize(_cost)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_x%5B%3A%2C%200%5D%20%3D%3D%20x_initial_mpc%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_x%5B%3A%2C%201%3A%5D%20%3D%3D%20_x_next%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cp.abs(_u)%20%3C%3D%20u_max%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cp.abs(_x%5B1%2C%20%3A%5D)%20%3C%3D%20i_max%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_x%5B0%2C%20%3A%5D%20%3E%3D%20omega_min%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_x%5B0%2C%20%3A%5D%20%3C%3D%20omega_max%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20_problem.solve(%0A%20%20%20%20%20%20%20%20%20%20%20%20solver%3Dcp.CLARABEL%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20tol_gap_abs%3D1e-10%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20tol_gap_rel%3D1e-10%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20tol_feas%3D1e-10%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20assert%20_problem.status%20%3D%3D%20cp.OPTIMAL%0A%20%20%20%20%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20np.asarray(_x.value%2C%20dtype%3Dfloat)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20np.asarray(_u.value%2C%20dtype%3Dfloat)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20float(_problem.value)%2C%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20x_hat%2C%20u_hat%2C%20expert_lower_objective%20%3D%20solve_fixed_mpc(%0A%20%20%20%20%20%20%20%20fixed_delta%3Dexpert_delta%2C%0A%20%20%20%20%20%20%20%20fixed_eta%3Dexpert_eta%2C%0A%20%20%20%20%20%20%20%20x_initial_mpc%3Dx_initial%2C%0A%20%20%20%20%20%20%20%20u_previous_mpc%3Du_previous%2C%0A%20%20%20%20)%0A%20%20%20%20return%20expert_lower_objective%2C%20solve_fixed_mpc%2C%20u_hat%2C%20x_hat%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Specify%20and%20solve%20the%20bilevel%20model%0A%0A%20%20%20%20%60delta%60%20and%20%60eta%60%20are%20upper-level%20variables%20and%20parameters%20of%20the%20lower%20MPC%0A%20%20%20%20problem.%20We%20initialize%20them%20and%20the%20trajectory%20from%20the%20feasible%20untuned%0A%20%20%20%20baseline.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20A%2C%0A%20%20%20%20B%2C%0A%20%20%20%20BilevelProblem%2C%0A%20%20%20%20LowerProblem%2C%0A%20%20%20%20N%2C%0A%20%20%20%20baseline_delta%2C%0A%20%20%20%20baseline_eta%2C%0A%20%20%20%20cp%2C%0A%20%20%20%20current_weight%2C%0A%20%20%20%20delta_bounds%2C%0A%20%20%20%20eta_bounds%2C%0A%20%20%20%20i_max%2C%0A%20%20%20%20omega_max%2C%0A%20%20%20%20omega_min%2C%0A%20%20%20%20solve_fixed_mpc%2C%0A%20%20%20%20terminal_weight%2C%0A%20%20%20%20u_hat%2C%0A%20%20%20%20u_max%2C%0A%20%20%20%20u_previous%2C%0A%20%20%20%20u_reference%2C%0A%20%20%20%20x_hat%2C%0A%20%20%20%20x_initial%2C%0A%20%20%20%20x_reference%2C%0A)%3A%0A%20%20%20%20x_baseline%2C%20u_baseline%2C%20baseline_lower_objective%20%3D%20solve_fixed_mpc(%0A%20%20%20%20%20%20%20%20baseline_delta%2C%0A%20%20%20%20%20%20%20%20baseline_eta%2C%0A%20%20%20%20%20%20%20%20x_initial%2C%0A%20%20%20%20%20%20%20%20u_previous%2C%0A%20%20%20%20)%0A%0A%20%20%20%20delta%20%3D%20cp.Variable(%0A%20%20%20%20%20%20%20%20nonneg%3DTrue%2C%0A%20%20%20%20%20%20%20%20bounds%3D%5Bdelta_bounds%5B0%5D%2C%20delta_bounds%5B1%5D%5D%2C%0A%20%20%20%20%20%20%20%20name%3D%22delta%22%2C%0A%20%20%20%20)%0A%20%20%20%20eta%20%3D%20cp.Variable(%0A%20%20%20%20%20%20%20%20nonneg%3DTrue%2C%0A%20%20%20%20%20%20%20%20bounds%3D%5Beta_bounds%5B0%5D%2C%20eta_bounds%5B1%5D%5D%2C%0A%20%20%20%20%20%20%20%20name%3D%22eta%22%2C%0A%20%20%20%20)%0A%20%20%20%20x%20%3D%20cp.Variable((2%2C%20N%20%2B%201)%2C%20name%3D%22x%22)%0A%20%20%20%20u%20%3D%20cp.Variable(N%2C%20name%3D%22u%22)%0A%0A%20%20%20%20delta.value%20%3D%20baseline_delta%0A%20%20%20%20eta.value%20%3D%20baseline_eta%0A%20%20%20%20x.value%20%3D%20x_baseline%0A%20%20%20%20u.value%20%3D%20u_baseline%0A%0A%20%20%20%20u_change%20%3D%20cp.diff(cp.hstack(%5Bu_previous%2C%20u%5D))%0A%20%20%20%20mpc_objective%20%3D%20(%0A%20%20%20%20%20%20%20%20cp.sum_squares(x%5B0%2C%201%3A%5D%20-%20x_reference%5B0%5D)%0A%20%20%20%20%20%20%20%20%2B%20current_weight%20*%20cp.sum_squares(x%5B1%2C%201%3A%5D%20-%20x_reference%5B1%5D)%0A%20%20%20%20%20%20%20%20%2B%20delta%20*%20cp.sum_squares(u%20-%20u_reference)%0A%20%20%20%20%20%20%20%20%2B%20eta%20*%20cp.sum_squares(u_change)%0A%20%20%20%20%20%20%20%20%2B%20terminal_weight%20*%20cp.square(x%5B0%2C%20-1%5D%20-%20x_reference%5B0%5D)%0A%20%20%20%20)%0A%20%20%20%20x_next%20%3D%20A%20%40%20x%5B%3A%2C%20%3A-1%5D%20%2B%20cp.outer(B%2C%20u)%0A%20%20%20%20controller%20%3D%20LowerProblem(%0A%20%20%20%20%20%20%20%20cp.Minimize(mpc_objective)%2C%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20x%5B%3A%2C%200%5D%20%3D%3D%20x_initial%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20x%5B%3A%2C%201%3A%5D%20%3D%3D%20x_next%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20cp.abs(u)%20%3C%3D%20u_max%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20cp.abs(x%5B1%2C%20%3A%5D)%20%3C%3D%20i_max%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20x%5B0%2C%20%3A%5D%20%3E%3D%20omega_min%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20x%5B0%2C%20%3A%5D%20%3C%3D%20omega_max%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20parameters%3D%5Bdelta%2C%20eta%5D%2C%0A%20%20%20%20)%0A%20%20%20%20imitation_loss%20%3D%20cp.sum_squares(x%20-%20x_hat)%20%2B%200.1%20*%20cp.sum_squares(u%20-%20u_hat)%0A%20%20%20%20problem%20%3D%20BilevelProblem(cp.Minimize(imitation_loss)%2C%20controller)%0A%0A%20%20%20%20assert%20problem.is_dblp()%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20baseline_lower_objective%2C%0A%20%20%20%20%20%20%20%20delta%2C%0A%20%20%20%20%20%20%20%20eta%2C%0A%20%20%20%20%20%20%20%20problem%2C%0A%20%20%20%20%20%20%20%20u%2C%0A%20%20%20%20%20%20%20%20u_baseline%2C%0A%20%20%20%20%20%20%20%20x%2C%0A%20%20%20%20%20%20%20%20x_baseline%2C%0A%20%20%20%20)%0A%0A%0A%40app.cell%0Adef%20_(problem)%3A%0A%20%20%20%20epsilon_target%20%3D%201e-5%0A%20%20%20%20result%20%3D%20problem.solve(%0A%20%20%20%20%20%20%20%20epsilon_initial%3D1e-2%2C%0A%20%20%20%20%20%20%20%20epsilon_target%3Depsilon_target%2C%0A%20%20%20%20%20%20%20%20solver_options%3D%7B%22tol%22%3A%201e-10%2C%20%22max_iter%22%3A%203000%7D%2C%0A%20%20%20%20%20%20%20%20verbose%3DFalse%2C%0A%20%20%20%20)%0A%20%20%20%20diagnostics%20%3D%20problem.gap_diagnostics(result)%0A%20%20%20%20return%20diagnostics%2C%20epsilon_target%2C%20result%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Independent%20learned-weight%20reference%0A%0A%20%20%20%20A%20final%20CVXPY%20solve%20fixes%20the%20learned%20weights%20and%20independently%20checks%20the%0A%20%20%20%20recovered%20trajectory%20and%20lower%20objective.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(delta%2C%20eta%2C%20solve_fixed_mpc%2C%20u_previous%2C%20x_initial)%3A%0A%20%20%20%20learned_delta%20%3D%20float(delta.value)%0A%20%20%20%20learned_eta%20%3D%20float(eta.value)%0A%20%20%20%20x_independent%2C%20u_independent%2C%20reference_lower_objective%20%3D%20solve_fixed_mpc(%0A%20%20%20%20%20%20%20%20learned_delta%2C%0A%20%20%20%20%20%20%20%20learned_eta%2C%0A%20%20%20%20%20%20%20%20x_initial%2C%0A%20%20%20%20%20%20%20%20u_previous%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20learned_delta%2C%0A%20%20%20%20%20%20%20%20learned_eta%2C%0A%20%20%20%20%20%20%20%20reference_lower_objective%2C%0A%20%20%20%20%20%20%20%20u_independent%2C%0A%20%20%20%20%20%20%20%20x_independent%2C%0A%20%20%20%20)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(%0A%20%20%20%20A%2C%0A%20%20%20%20B%2C%0A%20%20%20%20baseline_delta%2C%0A%20%20%20%20baseline_eta%2C%0A%20%20%20%20baseline_lower_objective%2C%0A%20%20%20%20delta_bounds%2C%0A%20%20%20%20diagnostics%2C%0A%20%20%20%20epsilon_target%2C%0A%20%20%20%20eta_bounds%2C%0A%20%20%20%20expert_delta%2C%0A%20%20%20%20expert_eta%2C%0A%20%20%20%20expert_lower_objective%2C%0A%20%20%20%20i_max%2C%0A%20%20%20%20learned_delta%2C%0A%20%20%20%20learned_eta%2C%0A%20%20%20%20mo%2C%0A%20%20%20%20np%2C%0A%20%20%20%20omega_max%2C%0A%20%20%20%20omega_min%2C%0A%20%20%20%20reference_lower_objective%2C%0A%20%20%20%20result%2C%0A%20%20%20%20u%2C%0A%20%20%20%20u_baseline%2C%0A%20%20%20%20u_hat%2C%0A%20%20%20%20u_independent%2C%0A%20%20%20%20u_max%2C%0A%20%20%20%20x%2C%0A%20%20%20%20x_baseline%2C%0A%20%20%20%20x_hat%2C%0A%20%20%20%20x_independent%2C%0A)%3A%0A%20%20%20%20x_learned%20%3D%20np.asarray(x.value%2C%20dtype%3Dfloat)%0A%20%20%20%20u_learned%20%3D%20np.asarray(u.value%2C%20dtype%3Dfloat)%0A%20%20%20%20baseline_imitation_loss%20%3D%20float(np.sum(np.square(x_baseline%20-%20x_hat))%20%2B%200.1%20*%20np.sum(np.square(u_baseline%20-%20u_hat)))%0A%20%20%20%20learned_imitation_loss%20%3D%20float(np.sum(np.square(x_learned%20-%20x_hat))%20%2B%200.1%20*%20np.sum(np.square(u_learned%20-%20u_hat)))%0A%20%20%20%20x_learned_next%20%3D%20A%20%40%20x_learned%5B%3A%2C%20%3A-1%5D%20%2B%20B.reshape(2%2C%201)%20*%20u_learned.reshape(1%2C%20-1)%0A%20%20%20%20dynamics_residual%20%3D%20x_learned%5B%3A%2C%201%3A%5D%20-%20x_learned_next%0A%0A%20%20%20%20assert%20result.succeeded%2C%20result.message%0A%20%20%20%20assert%20np.isfinite(result.objective)%0A%20%20%20%20assert%20np.isclose(result.final_epsilon%2C%20epsilon_target%2C%20rtol%3D0.0%2C%20atol%3D1e-15)%0A%20%20%20%20assert%20result.residuals.max_violation%20%3C%3D%202e-7%0A%20%20%20%20assert%20result.complementarity%20%3C%3D%201.1%20*%20epsilon_target%0A%20%20%20%20assert%20abs(diagnostics.source_gap)%20%3C%3D%201.1%20*%20epsilon_target%0A%20%20%20%20assert%20delta_bounds%5B0%5D%20%3C%3D%20learned_delta%20%3C%3D%20delta_bounds%5B1%5D%0A%20%20%20%20assert%20eta_bounds%5B0%5D%20%3C%3D%20learned_eta%20%3C%3D%20eta_bounds%5B1%5D%0A%20%20%20%20assert%20abs(learned_delta%20-%20expert_delta)%20%3C%3D%201e-5%0A%20%20%20%20assert%20abs(learned_eta%20-%20expert_eta)%20%3C%3D%201e-5%0A%20%20%20%20assert%20np.max(np.abs(dynamics_residual))%20%3C%3D%201e-7%0A%20%20%20%20assert%20np.max(np.abs(u_learned))%20%3C%3D%20u_max%20%2B%201e-7%0A%20%20%20%20assert%20np.max(np.abs(x_learned%5B1%2C%20%3A%5D))%20%3C%3D%20i_max%20%2B%201e-7%0A%20%20%20%20assert%20np.min(x_learned%5B0%2C%20%3A%5D)%20%3E%3D%20omega_min%20-%201e-7%0A%20%20%20%20assert%20np.max(x_learned%5B0%2C%20%3A%5D)%20%3C%3D%20omega_max%20%2B%201e-7%0A%20%20%20%20assert%20np.allclose(x_learned%2C%20x_independent%2C%20atol%3D1e-5)%0A%20%20%20%20assert%20np.allclose(u_learned%2C%20u_independent%2C%20atol%3D1e-5)%0A%20%20%20%20assert%20abs(reference_lower_objective%20-%20expert_lower_objective)%20%3C%3D%201e-5%0A%20%20%20%20assert%20learned_imitation_loss%20%3C%3D%201e-8%0A%20%20%20%20assert%20learned_imitation_loss%20%3C%3D%201e-6%20*%20baseline_imitation_loss%0A%0A%20%20%20%20_baseline_weights%20%3D%20f%22(%7Bbaseline_delta%3A.3f%7D%2C%20%7Bbaseline_eta%3A.3f%7D)%22%0A%20%20%20%20_expert_weights%20%3D%20f%22(%7Bexpert_delta%3A.3f%7D%2C%20%7Bexpert_eta%3A.3f%7D)%22%0A%20%20%20%20_learned_weights%20%3D%20f%22(%7Blearned_delta%3A.6f%7D%2C%20%7Blearned_eta%3A.6f%7D)%22%0A%0A%20%20%20%20mo.md(rf%22%22%22%0A%20%20%20%20%23%23%20Result%0A%0A%20%20%20%20%7C%20quantity%20%7C%20value%20%7C%0A%20%20%20%20%7C%20---%20%7C%20---%3A%20%7C%0A%20%20%20%20%7C%20status%20%7C%20%60%7Bresult.status%7D%60%20%7C%0A%20%20%20%20%7C%20baseline%20weights%20%24(%5Cdelta%2C%5Ceta)%24%20%7C%20%7B_baseline_weights%7D%20%7C%0A%20%20%20%20%7C%20expert%20weights%20%24(%5Cdelta%5E%7B%7B%5Crm%20E%7D%7D%2C%5Ceta%5E%7B%7B%5Crm%20E%7D%7D)%24%20%7C%20%7B_expert_weights%7D%20%7C%0A%20%20%20%20%7C%20learned%20weights%20%24(%5Cdelta%5E%5Cstar%2C%5Ceta%5E%5Cstar)%24%20%7C%20%7B_learned_weights%7D%20%7C%0A%20%20%20%20%7C%20baseline%20imitation%20loss%20%7C%20%7Bbaseline_imitation_loss%3A.6f%7D%20%7C%0A%20%20%20%20%7C%20learned%20imitation%20loss%20%7C%20%7Blearned_imitation_loss%3A.3e%7D%20%7C%0A%20%20%20%20%7C%20baseline%20lower%20objective%20%7C%20%7Bbaseline_lower_objective%3A.6f%7D%20%7C%0A%20%20%20%20%7C%20learned%20fixed-weight%20lower%20objective%20%7C%20%7Breference_lower_objective%3A.6f%7D%20%7C%0A%20%20%20%20%7C%20upper%20objective%20%7C%20%7Bfloat(result.objective)%3A.3e%7D%20%7C%0A%20%20%20%20%7C%20final%20epsilon%20%7C%20%7Bresult.final_epsilon%3A.3e%7D%20%7C%0A%20%20%20%20%7C%20maximum%20lifted%20residual%20%7C%20%7Bresult.residuals.max_violation%3A.3e%7D%20%7C%0A%20%20%20%20%7C%20complementarity%20%7C%20%7Bresult.complementarity%3A.3e%7D%20%7C%0A%20%20%20%20%7C%20source%20gap%20%7C%20%7Bdiagnostics.source_gap%3A.3e%7D%20%7C%0A%0A%20%20%20%20BLVPY%20recovers%20both%20hidden%20weights%20and%20reduces%20the%20trajectory-matching%20loss%0A%20%20%20%20from%20%7Bbaseline_imitation_loss%3A.3f%7D%20to%20essentially%20zero.%20The%20independent%0A%20%20%20%20fixed-weight%20MPC%20solve%20reproduces%20the%20learned%20state%20and%20voltage%20sequences.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Receding-horizon%20validation%0A%0A%20%20%20%20To%20validate%20closed-loop%20MPC%2C%20we%20repeat%20the%20controller%20for%2036%20samples%2C%0A%20%20%20%20applying%20only%20the%20first%20voltage%20from%20each%20fresh%2024-step%20solve.%20Independent%0A%20%20%20%20CVXPY%20rollouts%20compare%20the%20expert%2C%20untuned%2C%20and%20learned%20weights.%20An%0A%20%20%20%20unannounced%20load-torque%20pulse%20acts%20from%20%240.6%24%20to%20%240.8%24%20seconds%2C%20so%20each%0A%20%20%20%20controller%20must%20correct%20after%20observing%20the%20disturbed%20motor%20state.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20A%2C%0A%20%20%20%20B%2C%0A%20%20%20%20J%2C%0A%20%20%20%20baseline_delta%2C%0A%20%20%20%20baseline_eta%2C%0A%20%20%20%20expert_delta%2C%0A%20%20%20%20expert_eta%2C%0A%20%20%20%20i_max%2C%0A%20%20%20%20learned_delta%2C%0A%20%20%20%20learned_eta%2C%0A%20%20%20%20np%2C%0A%20%20%20%20omega_max%2C%0A%20%20%20%20omega_min%2C%0A%20%20%20%20sample_time%2C%0A%20%20%20%20solve_fixed_mpc%2C%0A%20%20%20%20u_max%2C%0A%20%20%20%20u_previous%2C%0A%20%20%20%20x_initial%2C%0A%20%20%20%20x_reference%2C%0A)%3A%0A%20%20%20%20rollout_steps%20%3D%2036%0A%20%20%20%20rollout_time%20%3D%20sample_time%20*%20np.arange(rollout_steps%20%2B%201)%0A%20%20%20%20rollout_input_time%20%3D%20rollout_time%5B%3A-1%5D%0A%20%20%20%20disturbance_start%20%3D%200.6%0A%20%20%20%20disturbance_end%20%3D%200.8%0A%20%20%20%20load_torque%20%3D%20np.zeros(rollout_steps)%0A%20%20%20%20load_torque%5B(rollout_input_time%20%3E%3D%20disturbance_start)%20%26%20(rollout_input_time%20%3C%20disturbance_end)%5D%20%3D%200.012%0A%20%20%20%20load_disturbance_vector%20%3D%20np.array(%5B-sample_time%20%2F%20J%2C%200.0%5D)%0A%0A%20%20%20%20def%20rollout_mpc(fixed_delta%2C%20fixed_eta)%3A%0A%20%20%20%20%20%20%20%20_x%20%3D%20np.zeros((2%2C%20rollout_steps%20%2B%201))%0A%20%20%20%20%20%20%20%20_u%20%3D%20np.zeros(rollout_steps)%0A%20%20%20%20%20%20%20%20_x%5B%3A%2C%200%5D%20%3D%20x_initial%0A%20%20%20%20%20%20%20%20_u_previous%20%3D%20u_previous%0A%20%20%20%20%20%20%20%20for%20_step%20in%20range(rollout_steps)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_%2C%20_u_plan%2C%20_%20%3D%20solve_fixed_mpc(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fixed_delta%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fixed_eta%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_x%5B%3A%2C%20_step%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_u_previous%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20_u%5B_step%5D%20%3D%20_u_plan%5B0%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20_x%5B%3A%2C%20_step%20%2B%201%5D%20%3D%20A%20%40%20_x%5B%3A%2C%20_step%5D%20%2B%20B%20*%20_u%5B_step%5D%20%2B%20load_disturbance_vector%20*%20load_torque%5B_step%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20_u_previous%20%3D%20_u%5B_step%5D%0A%20%20%20%20%20%20%20%20return%20_x%2C%20_u%0A%0A%20%20%20%20x_expert_rollout%2C%20u_expert_rollout%20%3D%20rollout_mpc(expert_delta%2C%20expert_eta)%0A%20%20%20%20x_baseline_rollout%2C%20u_baseline_rollout%20%3D%20rollout_mpc(baseline_delta%2C%20baseline_eta)%0A%20%20%20%20x_learned_rollout%2C%20u_learned_rollout%20%3D%20rollout_mpc(learned_delta%2C%20learned_eta)%0A%20%20%20%20baseline_tracking_mse%20%3D%20float(np.mean(np.square(x_baseline_rollout%5B0%2C%20%3A%5D%20-%20x_reference%5B0%5D)))%0A%20%20%20%20learned_tracking_mse%20%3D%20float(np.mean(np.square(x_learned_rollout%5B0%2C%20%3A%5D%20-%20x_reference%5B0%5D)))%0A%0A%20%20%20%20assert%20np.max(np.abs(x_learned_rollout%20-%20x_expert_rollout))%20%3C%3D%201e-4%0A%20%20%20%20assert%20np.max(np.abs(u_learned_rollout%20-%20u_expert_rollout))%20%3C%3D%201e-4%0A%20%20%20%20assert%20learned_tracking_mse%20%3C%3D%200.9%20*%20baseline_tracking_mse%0A%20%20%20%20assert%20abs(x_learned_rollout%5B0%2C%20-1%5D%20-%20x_reference%5B0%5D)%20%3C%3D%201e-3%0A%20%20%20%20assert%20np.max(np.abs(u_learned_rollout))%20%3C%3D%20u_max%20%2B%201e-7%0A%20%20%20%20assert%20np.max(np.abs(x_learned_rollout%5B1%2C%20%3A%5D))%20%3C%3D%20i_max%20%2B%201e-7%0A%20%20%20%20assert%20np.min(x_learned_rollout%5B0%2C%20%3A%5D)%20%3E%3D%20omega_min%20-%201e-7%0A%20%20%20%20assert%20np.max(x_learned_rollout%5B0%2C%20%3A%5D)%20%3C%3D%20omega_max%20%2B%201e-7%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20baseline_tracking_mse%2C%0A%20%20%20%20%20%20%20%20disturbance_end%2C%0A%20%20%20%20%20%20%20%20disturbance_start%2C%0A%20%20%20%20%20%20%20%20learned_tracking_mse%2C%0A%20%20%20%20%20%20%20%20u_baseline_rollout%2C%0A%20%20%20%20%20%20%20%20u_expert_rollout%2C%0A%20%20%20%20%20%20%20%20u_learned_rollout%2C%0A%20%20%20%20%20%20%20%20x_baseline_rollout%2C%0A%20%20%20%20%20%20%20%20x_expert_rollout%2C%0A%20%20%20%20%20%20%20%20x_learned_rollout%2C%0A%20%20%20%20)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(baseline_tracking_mse%2C%20learned_tracking_mse%2C%20mo)%3A%0A%20%20%20%20tracking_improvement%20%3D%20100.0%20*%20(baseline_tracking_mse%20-%20learned_tracking_mse)%20%2F%20baseline_tracking_mse%0A%20%20%20%20mo.md(rf%22%22%22%0A%20%20%20%20%23%23%20Closed-loop%20interpretation%0A%0A%20%20%20%20The%20learned%20trajectory%20overlaps%20the%20expert%2C%20reducing%20speed-tracking%20MSE%20by%0A%20%20%20%20%7Btracking_improvement%3A.1f%7D%25%20relative%20to%20the%20untuned%20controller.%0A%20%20%20%20The%20initial%20plan%20is%20the%20single%2024-step%20expert%20trajectory%20used%0A%20%20%20%20for%20training%20and%20does%20not%20anticipate%20the%20shaded%20load-torque%20pulse.%20The%0A%20%20%20%20closed-loop%20controllers%20replan%20after%20the%20resulting%20speed%20drop.%20Horizontal%0A%20%20%20%20lines%20mark%20the%20targets%20and%20operating%20limits.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(%0A%20%20%20%20N%2C%0A%20%20%20%20Path%2C%0A%20%20%20%20disturbance_end%2C%0A%20%20%20%20disturbance_start%2C%0A%20%20%20%20i_max%2C%0A%20%20%20%20np%2C%0A%20%20%20%20omega_max%2C%0A%20%20%20%20omega_min%2C%0A%20%20%20%20plt%2C%0A%20%20%20%20sample_time%2C%0A%20%20%20%20u_baseline_rollout%2C%0A%20%20%20%20u_expert_rollout%2C%0A%20%20%20%20u_hat%2C%0A%20%20%20%20u_learned_rollout%2C%0A%20%20%20%20u_max%2C%0A%20%20%20%20u_reference%2C%0A%20%20%20%20x_baseline_rollout%2C%0A%20%20%20%20x_expert_rollout%2C%0A%20%20%20%20x_hat%2C%0A%20%20%20%20x_learned_rollout%2C%0A%20%20%20%20x_reference%2C%0A)%3A%0A%20%20%20%20control_figure%2C%20control_axes%20%3D%20plt.subplots(%0A%20%20%20%20%20%20%20%203%2C%0A%20%20%20%20%20%20%20%201%2C%0A%20%20%20%20%20%20%20%20figsize%3D(7.4%2C%207.2)%2C%0A%20%20%20%20%20%20%20%20sharex%3DTrue%2C%0A%20%20%20%20%20%20%20%20layout%3D%22constrained%22%2C%0A%20%20%20%20)%0A%20%20%20%20prediction_index%20%3D%20np.arange(N%20%2B%201)%0A%20%20%20%20prediction_input_index%20%3D%20prediction_index%5B%3A-1%5D%0A%20%20%20%20rollout_index%20%3D%20np.arange(x_baseline_rollout.shape%5B1%5D)%0A%20%20%20%20rollout_input_index%20%3D%20np.arange(u_baseline_rollout.size)%0A%20%20%20%20disturbance_start_index%20%3D%20round(disturbance_start%20%2F%20sample_time)%0A%20%20%20%20disturbance_end_index%20%3D%20round(disturbance_end%20%2F%20sample_time)%0A%0A%20%20%20%20def%20draw_state_comparison(axis%2C%20x_index)%3A%0A%20%20%20%20%20%20%20%20axis.plot(%0A%20%20%20%20%20%20%20%20%20%20%20%20prediction_index%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20x_hat%5Bx_index%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20color%3D%22C2%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20linestyle%3D%22-.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20linewidth%3D1.0%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20marker%3D%22x%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20markersize%3D4.0%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20markevery%3D3%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20zorder%3D5%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20label%3D%22Demonstration%22%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20axis.plot(%0A%20%20%20%20%20%20%20%20%20%20%20%20rollout_index%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20x_baseline_rollout%5Bx_index%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20color%3D%22C1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20linestyle%3D%22%3A%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20linewidth%3D2.0%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20label%3D%22Untuned%22%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20axis.plot(%0A%20%20%20%20%20%20%20%20%20%20%20%20rollout_index%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20x_learned_rollout%5Bx_index%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20color%3D%22C0%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20linewidth%3D2.2%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20label%3D%22Learned%22%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20axis.plot(%0A%20%20%20%20%20%20%20%20%20%20%20%20rollout_index%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20x_expert_rollout%5Bx_index%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20color%3D%22black%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20linestyle%3D%22--%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20linewidth%3D1.1%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20marker%3D%22o%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20markersize%3D3.5%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20markerfacecolor%3D%22white%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20markevery%3D4%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20label%3D%22Expert%22%2C%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20draw_state_comparison(control_axes%5B0%5D%2C%200)%0A%20%20%20%20control_axes%5B0%5D.axhline(x_reference%5B0%5D%2C%20color%3D%220.4%22%2C%20linestyle%3D%22--%22%2C%20linewidth%3D0.8)%0A%20%20%20%20control_axes%5B0%5D.axhline(omega_min%2C%20color%3D%220.65%22%2C%20linestyle%3D%22-.%22%2C%20linewidth%3D0.8)%0A%20%20%20%20control_axes%5B0%5D.axhline(omega_max%2C%20color%3D%220.65%22%2C%20linestyle%3D%22-.%22%2C%20linewidth%3D0.8)%0A%20%20%20%20control_axes%5B0%5D.set(ylabel%3Dr%22%24%5Comega(t)%24%22%2C%20ylim%3D(-0.1%2C%201.32))%0A%20%20%20%20control_axes%5B0%5D.legend(%0A%20%20%20%20%20%20%20%20ncol%3D4%2C%0A%20%20%20%20%20%20%20%20frameon%3DFalse%2C%0A%20%20%20%20%20%20%20%20fontsize%3D12%2C%0A%20%20%20%20%20%20%20%20loc%3D%22lower%20center%22%2C%0A%20%20%20%20%20%20%20%20bbox_to_anchor%3D(0.5%2C%201.0)%2C%0A%20%20%20%20)%0A%0A%20%20%20%20draw_state_comparison(control_axes%5B1%5D%2C%201)%0A%20%20%20%20control_axes%5B1%5D.axhline(x_reference%5B1%5D%2C%20color%3D%220.4%22%2C%20linestyle%3D%22--%22%2C%20linewidth%3D0.8)%0A%20%20%20%20control_axes%5B1%5D.axhline(-i_max%2C%20color%3D%220.65%22%2C%20linestyle%3D%22-.%22%2C%20linewidth%3D0.8)%0A%20%20%20%20control_axes%5B1%5D.axhline(i_max%2C%20color%3D%220.65%22%2C%20linestyle%3D%22-.%22%2C%20linewidth%3D0.8)%0A%20%20%20%20control_axes%5B1%5D.set(ylabel%3Dr%22%24i(t)%24%22%2C%20ylim%3D(-0.55%2C%200.55))%0A%0A%20%20%20%20control_axes%5B2%5D.step(%0A%20%20%20%20%20%20%20%20prediction_input_index%2C%0A%20%20%20%20%20%20%20%20u_hat%2C%0A%20%20%20%20%20%20%20%20where%3D%22post%22%2C%0A%20%20%20%20%20%20%20%20color%3D%22C2%22%2C%0A%20%20%20%20%20%20%20%20linestyle%3D%22-.%22%2C%0A%20%20%20%20%20%20%20%20linewidth%3D1.0%2C%0A%20%20%20%20%20%20%20%20marker%3D%22x%22%2C%0A%20%20%20%20%20%20%20%20markersize%3D4.0%2C%0A%20%20%20%20%20%20%20%20markevery%3D3%2C%0A%20%20%20%20%20%20%20%20zorder%3D5%2C%0A%20%20%20%20)%0A%20%20%20%20control_axes%5B2%5D.step(%0A%20%20%20%20%20%20%20%20rollout_input_index%2C%0A%20%20%20%20%20%20%20%20u_baseline_rollout%2C%0A%20%20%20%20%20%20%20%20where%3D%22post%22%2C%0A%20%20%20%20%20%20%20%20color%3D%22C1%22%2C%0A%20%20%20%20%20%20%20%20linestyle%3D%22%3A%22%2C%0A%20%20%20%20%20%20%20%20linewidth%3D2.0%2C%0A%20%20%20%20)%0A%20%20%20%20control_axes%5B2%5D.step(%0A%20%20%20%20%20%20%20%20rollout_input_index%2C%0A%20%20%20%20%20%20%20%20u_learned_rollout%2C%0A%20%20%20%20%20%20%20%20where%3D%22post%22%2C%0A%20%20%20%20%20%20%20%20color%3D%22C0%22%2C%0A%20%20%20%20%20%20%20%20linewidth%3D2.2%2C%0A%20%20%20%20)%0A%20%20%20%20control_axes%5B2%5D.step(%0A%20%20%20%20%20%20%20%20rollout_input_index%2C%0A%20%20%20%20%20%20%20%20u_expert_rollout%2C%0A%20%20%20%20%20%20%20%20where%3D%22post%22%2C%0A%20%20%20%20%20%20%20%20color%3D%22black%22%2C%0A%20%20%20%20%20%20%20%20linestyle%3D%22--%22%2C%0A%20%20%20%20%20%20%20%20linewidth%3D1.1%2C%0A%20%20%20%20%20%20%20%20marker%3D%22o%22%2C%0A%20%20%20%20%20%20%20%20markersize%3D3.5%2C%0A%20%20%20%20%20%20%20%20markerfacecolor%3D%22white%22%2C%0A%20%20%20%20%20%20%20%20markevery%3D4%2C%0A%20%20%20%20)%0A%20%20%20%20control_axes%5B2%5D.axhline(u_reference%2C%20color%3D%220.4%22%2C%20linestyle%3D%22--%22%2C%20linewidth%3D0.8)%0A%20%20%20%20control_axes%5B2%5D.axhline(-u_max%2C%20color%3D%220.65%22%2C%20linestyle%3D%22-.%22%2C%20linewidth%3D0.8)%0A%20%20%20%20control_axes%5B2%5D.axhline(u_max%2C%20color%3D%220.65%22%2C%20linestyle%3D%22-.%22%2C%20linewidth%3D0.8)%0A%20%20%20%20control_axes%5B2%5D.set(%0A%20%20%20%20%20%20%20%20xlabel%3D%22%24t%24%22%2C%0A%20%20%20%20%20%20%20%20ylabel%3Dr%22%24u(t)%24%22%2C%0A%20%20%20%20%20%20%20%20xlim%3D(rollout_index%5B0%5D%2C%20rollout_index%5B-1%5D)%2C%0A%20%20%20%20%20%20%20%20ylim%3D(-2.12%2C%202.12)%2C%0A%20%20%20%20)%0A%0A%20%20%20%20for%20_axis%20in%20control_axes%3A%0A%20%20%20%20%20%20%20%20_axis.axvspan(%0A%20%20%20%20%20%20%20%20%20%20%20%20disturbance_start_index%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20disturbance_end_index%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20color%3D%220.88%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20alpha%3D0.7%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20zorder%3D0%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20_axis.grid(alpha%3D0.2%2C%20linewidth%3D0.6)%0A%0A%20%20%20%20control_axes%5B0%5D.text(%0A%20%20%20%20%20%20%20%200.5%20*%20(disturbance_start_index%20%2B%20disturbance_end_index)%2C%0A%20%20%20%20%20%20%20%201.18%2C%0A%20%20%20%20%20%20%20%20%22Load%20torque%22%2C%0A%20%20%20%20%20%20%20%20ha%3D%22center%22%2C%0A%20%20%20%20%20%20%20%20va%3D%22center%22%2C%0A%20%20%20%20%20%20%20%20fontsize%3D8.5%2C%0A%20%20%20%20%20%20%20%20color%3D%220.35%22%2C%0A%20%20%20%20)%0A%0A%20%20%20%20figure_dir%20%3D%20Path(__file__).resolve().parent%20%2F%20%22figures%22%0A%20%20%20%20figure_dir.mkdir(parents%3DTrue%2C%20exist_ok%3DTrue)%0A%20%20%20%20figure_path%20%3D%20figure_dir%20%2F%20%22dc_motor_mpc_tuning.pdf%22%0A%20%20%20%20control_figure.savefig(figure_path%2C%20bbox_inches%3D%22tight%22)%0A%20%20%20%20plt.show()%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
4d58850c35b1926326c9bd64a345c901