Concept — One-Shot Inverse Control
FR24: Inverse Control solved simultaneously with cycle equations
❌ Approche Traditionnelle
1. Fixer valve → Simuler
2. Mesurer superheat
3. Ajuster valve
4. Répéter (optimisation externe)
→ Lent, coûteux, non garanti
✅ Approche One-Shot (Entropyk)
1. Définir contrainte: superheat = 5K
2. Lier à variable: valve position
3. Valve devient inconnue du solveur
4. Résolution simultanée (1 appel)
→ Rapide, garanti, élégant
Vecteur de résidus étendu
rtotal = [ rcycle, rconstraint ]T = 0
rconstraint = superheatmesuré − superheatcible
Mapping — Contrainte → Variable de Contrôle
📐 Constraint
superheat_control
target: 5.0 K
link_constraint_to_control()
🎚 BoundedVar
valve_position
[0.1, 1.0]
✓ Résolu
valve = 38%
SH = 5.02 K
Validation des Degrés de Liberté (DoF)
Équations
9
composants: 8
contraintes: +1
=
Inconnues
9
états bords: 8
contrôles: +1
✓ Système bien posé — validate_inverse_control_dof() = Ok
Équilibré
n_eqs == n_unknowns
Résolvable
Sur-contraint
n_eqs > n_unknowns
Erreur
Sous-contraint
n_eqs < n_unknowns
Warning
Équations du système étendu
📦 Équations du cycle (8 éq.)
| Composant | Équation | État |
| Compresseur | r₁(P,h) = 0 | 2 éq. |
| Condenseur | r₂(P,h) = 0 | 2 éq. |
| EXV | r₃(P,h) = 0 | 2 éq. |
| Évaporateur | r₄(P,h) = 0 | 2 éq. |
📐 Équations de contrainte (+1 éq.)
| Type | Équation | Valeur |
| Superheat | r_c = SH − 5.0 | 5.02 − 5.0 |
| Jacobian | ∂r_c/∂valve | ≈ 1.0 |
| State idx | 2·edges + i | idx = 8 |
Convergence — Newton-Raphson
Valeurs au point de fonctionnement
Contrainte Superheat
IDsuperheat_control
OutputSuperheat(evaporator)
Target5.0 K
Mesuré5.02 K
Résidu0.02 K
Satisfait✓
Variable de Contrôle
IDvalve_position
Initial50.0%
Final38.0%
Bounds[10%, 100%]
SaturéNon
State idx8
Solveur Newton-Raphson
Itérations7
Tolérance1e-8
‖r‖ final3.2e-9
MéthodeOne-Shot
Temps12 ms
DoF Validation
Edges4 (×2 = 8)
Controls+1
Total unknowns9
Components4 (×2 = 8)
Constraints+1
Total equations9
Balance9 = 9 ✓
API Rust — Utilisation
// ══════════════════════════════════════════════════════════════════════
// Story 5.3: Residual Embedding for Inverse Control
// ══════════════════════════════════════════════════════════════════════
use entropyk_solver::inverse::{
Constraint, ConstraintId, ComponentOutput,
BoundedVariable, BoundedVariableId,
};
// 1. Définir la contrainte: superheat = 5K
let constraint = Constraint::new(
ConstraintId::new("superheat_control"),
ComponentOutput::Superheat { component_id: "evaporator".into() },
5.0, // target: 5 Kelvin
);
system.add_constraint(constraint)?;
// 2. Définir la variable de contrôle bornée
let control = BoundedVariable::new(
BoundedVariableId::new("valve_position"),
0.5, 0.1, 1.0, // init, min, max
)?;
system.add_bounded_variable(control)?;
// 3. Lier contrainte → contrôle (One-Shot!)
system.link_constraint_to_control(
&ConstraintId::new("superheat_control"),
&BoundedVariableId::new("valve_position"),
)?;
// 4. Valider DoF + Finalize
system.validate_inverse_control_dof()?;
system.finalize()?;
// 5. Résoudre (One-Shot)
let result = NewtonRaphson::new().solve(&system)?;
// 6. Résultat
let valve = system.get_bounded_variable(&BoundedVariableId::new("valve_position")).unwrap();
println!("Valve: {:.1}% SH: {:.2} K", valve.value()*100.0, sh);
API — Méthodes System
| Méthode | Description | Retour |
| add_constraint(c) | Ajoute une contrainte | Result<(), ConstraintError> |
| add_bounded_variable(v) | Ajoute variable bornée | Result<(), BoundedVariableError> |
| link_constraint_to_control(cid, vid) | Lie contrainte → contrôle | Result<(), DoFError> |
| unlink_constraint(cid) | Supprime le lien | Option<BoundedVariableId> |
| validate_inverse_control_dof() | Valide éq == inconnues | Result<(), DoFError> |
| control_variable_state_index(id) | Index vecteur d'état | Option<usize> |
| full_state_vector_len() | Longueur totale | usize |
| compute_constraint_residuals(...) | Calcule résidus contraintes | usize |
| compute_inverse_control_jacobian(...) | Jacobian ∂r/∂control | Vec<(row,col,val)> |