Spaces:
Running on Zero
Running on Zero
| """Actuator allocation and fault detection tools.""" | |
| from __future__ import annotations | |
| from typing import Any | |
| import numpy as np | |
| from controlai_agent.registry import registry | |
| from controlai_agent.verifier import verifier | |
| def minimum_norm_control_allocation(B: list[float], desired_tau: float) -> dict[str, Any]: | |
| B_vec = np.array(B, dtype=float) | |
| b_norm_sq = float(np.dot(B_vec, B_vec)) | |
| u = (desired_tau / b_norm_sq) * B_vec | |
| v_report = verifier.verify_allocation(B_vec, u, desired_tau) | |
| return { | |
| "u": u.tolist(), | |
| "achieved_tau": float(np.dot(B_vec, u)), | |
| "norm_u": float(np.linalg.norm(u)), | |
| "verification": v_report, | |
| } | |
| def actuator_fault_isolation(B: list[float], command: list[float], measured_tau: float) -> dict[str, Any]: | |
| B_vec = np.array(B, dtype=float) | |
| u_vec = np.array(command, dtype=float) | |
| expected_tau = float(np.dot(B_vec, u_vec)) | |
| residual = float(measured_tau - expected_tau) | |
| # Candidate loss fractions assuming actuator i failed | |
| candidate_losses = [] | |
| for i in range(len(B_vec)): | |
| denom = B_vec[i] * u_vec[i] | |
| loss_fraction = float(-residual / denom) if abs(denom) > 1e-9 else None | |
| candidate_losses.append(loss_fraction) | |
| return { | |
| "expected_tau": expected_tau, | |
| "measured_tau": measured_tau, | |
| "torque_residual": residual, | |
| "is_fault_detected": abs(residual) > 1e-4, | |
| "candidate_actuator_loss_fractions": candidate_losses, | |
| } | |