@@ -0,0 +1,746 @@
<!DOCTYPE html>
< html lang = "fr" >
< head >
< meta charset = "UTF-8" / >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" / >
< title > Entropyk — Contrôle Inverse One-Shot< / title >
< style >
@ import url ( 'https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap' ) ;
: root {
--bg : #0d1117 ;
--surface : #161b22 ;
--border : #30363d ;
--text : #e6edf3 ;
--dim : #7d8590 ;
--cyan : #39d0d8 ;
--cyan-bg : rgba ( 57 , 208 , 216 , .06 ) ;
--green : #3fb950 ;
--green-bg : rgba ( 63 , 185 , 80 , .06 ) ;
--orange : #f0883e ;
--orange-bg : rgba ( 240 , 136 , 62 , .06 ) ;
--blue : #58a6ff ;
--blue-bg : rgba ( 88 , 166 , 255 , .06 ) ;
--purple : #bc8cff ;
--purple-bg : rgba ( 188 , 140 , 255 , .06 ) ;
--red : #f85149 ;
--yellow : #e3b341 ;
--pink : #ff7eb6 ;
}
* { box-sizing : border-box ; margin : 0 ; padding : 0 ; }
body {
background : var ( - - bg ) ;
color : var ( - - text ) ;
font-family : 'Inter' , sans-serif ;
min-height : 100 vh ;
padding : 40 px 20 px 80 px ;
display : flex ;
flex-direction : column ;
align-items : center ;
}
h1 {
font-size : 1.5 rem ;
font-weight : 700 ;
color : var ( - - cyan ) ;
margin-bottom : 4 px ;
letter-spacing : -.5 px ;
}
. sub { font-size : .82 rem ; color : var ( - - dim ) ; margin-bottom : 40 px ; }
. page {
width : 100 % ;
max-width : 1080 px ;
display : flex ;
flex-direction : column ;
gap : 28 px ;
}
section { width : 100 % ; }
section h2 {
font-size : .75 rem ;
text-transform : uppercase ;
letter-spacing : .1 em ;
color : var ( - - dim ) ;
font-weight : 600 ;
border-bottom : 1 px solid var ( - - border ) ;
padding-bottom : 8 px ;
margin-bottom : 16 px ;
}
. legend {
display : flex ;
flex-wrap : wrap ;
gap : 18 px ;
justify-content : center ;
margin-bottom : 36 px ;
}
. leg {
display : flex ;
align-items : center ;
gap : 7 px ;
font-size : .74 rem ;
color : var ( - - dim ) ;
}
. leg-dot {
width : 11 px ;
height : 11 px ;
border-radius : 3 px ;
border : 2 px solid ;
flex-shrink : 0 ;
}
. flow-diagram {
border : 2 px solid var ( - - cyan ) ;
border-radius : 14 px ;
background : var ( - - cyan - bg ) ;
padding : 28 px 24 px 32 px ;
position : relative ;
}
. flow-diagram > . blabel {
position : absolute ;
top : -13 px ;
left : 22 px ;
background : var ( - - bg ) ;
padding : 0 10 px ;
font-size : .72 rem ;
font-weight : 600 ;
color : var ( - - cyan ) ;
letter-spacing : .07 em ;
text-transform : uppercase ;
}
. node {
border : 2 px solid var ( - - border ) ;
border-radius : 10 px ;
background : var ( - - surface ) ;
padding : 12 px 16 px ;
text-align : center ;
min-width : 90 px ;
cursor : default ;
transition : transform .18 s , box-shadow .18 s ;
}
. node : hover {
transform : translateY ( -3 px ) ;
box-shadow : 0 8 px 24 px rgba ( 0 , 0 , 0 , .5 ) ;
}
. node . nm { font-size : .8 rem ; font-weight : 600 ; }
. node . ty { font-size : .62 rem ; color : var ( - - dim ) ; margin-top : 2 px ; font-family : 'JetBrains Mono' , monospace ; }
. node . vals { font-size : .6 rem ; font-family : 'JetBrains Mono' , monospace ; color : var ( - - cyan ) ; margin-top : 4 px ; line-height : 1.5 ; }
. node . constraint { border-color : var ( - - purple ) ; background : var ( - - purple - bg ) ; }
. node . control { border-color : var ( - - orange ) ; background : var ( - - orange - bg ) ; }
. node . component { border-color : var ( - - blue ) ; background : var ( - - blue - bg ) ; }
. node . result { border-color : var ( - - green ) ; background : var ( - - green - bg ) ; }
. arr {
display : flex ;
flex-direction : column ;
align-items : center ;
min-width : 48 px ;
}
. arr-line {
width : 100 % ;
height : 2 px ;
background : linear-gradient ( 90 deg , var ( - - border ) , var ( - - dim ) ) ;
position : relative ;
}
. arr-line :: after {
content : '' ;
position : absolute ;
right : -1 px ;
top : -4 px ;
border : 5 px solid transparent ;
border-left-color : var ( - - dim ) ;
}
. arr-lbl {
font-size : .58 rem ;
color : var ( - - dim ) ;
font-family : 'JetBrains Mono' , monospace ;
margin-top : 3 px ;
white-space : nowrap ;
}
. info-grid {
display : grid ;
grid-template-columns : repeat ( auto - fit , minmax ( 220 px , 1 fr ) ) ;
gap : 14 px ;
}
. icard {
border : 1 px solid var ( - - border ) ;
border-radius : 10 px ;
background : var ( - - surface ) ;
padding : 14 px ;
}
. icard h3 {
font-size : .7 rem ;
font-weight : 600 ;
text-transform : uppercase ;
letter-spacing : .08 em ;
color : var ( - - dim ) ;
border-bottom : 1 px solid var ( - - border ) ;
padding-bottom : 7 px ;
margin-bottom : 9 px ;
}
. irow {
display : flex ;
justify-content : space-between ;
align-items : center ;
font-size : .75 rem ;
padding : 3 px 0 ;
}
. irow . k { color : var ( - - dim ) ; }
. irow . v { font-family : 'JetBrains Mono' , monospace ; font-size : .7 rem ; }
. v . g { color : var ( - - green ) ; }
. v . c { color : var ( - - cyan ) ; }
. v . o { color : var ( - - orange ) ; }
. v . b { color : var ( - - blue ) ; }
. v . p { color : var ( - - purple ) ; }
. v . r { color : var ( - - red ) ; }
. eq-box {
background : var ( - - surface ) ;
border : 1 px solid var ( - - border ) ;
border-radius : 10 px ;
padding : 18 px 20 px ;
}
. eq-table {
width : 100 % ;
border-collapse : collapse ;
font-size : .75 rem ;
}
. eq-table th {
text-align : left ;
font-weight : 600 ;
font-size : .68 rem ;
color : var ( - - dim ) ;
text-transform : uppercase ;
letter-spacing : .07 em ;
padding : 0 8 px 10 px ;
border-bottom : 1 px solid var ( - - border ) ;
}
. eq-table td {
padding : 5 px 8 px ;
font-family : 'JetBrains Mono' , monospace ;
font-size : .7 rem ;
}
. eq-table tr : not ( : last-child ) td { border-bottom : 1 px solid rgba ( 48 , 54 , 61 , .5 ) ; }
. eq-table . cat { color : var ( - - dim ) ; font-family : 'Inter' , sans-serif ; font-size : .72 rem ; }
. eq-table . formula { color : var ( - - cyan ) ; }
. eq-table . result { color : var ( - - green ) ; text-align : right ; }
pre {
background : var ( - - surface ) ;
border : 1 px solid var ( - - border ) ;
border-radius : 10 px ;
padding : 18 px ;
font-family : 'JetBrains Mono' , monospace ;
font-size : .72 rem ;
line-height : 1.7 ;
overflow-x : auto ;
}
. status-badge {
display : inline-flex ;
align-items : center ;
gap : 5 px ;
padding : 4 px 10 px ;
border-radius : 100 px ;
font-size : .68 rem ;
font-weight : 600 ;
}
. status-badge . ok {
background : var ( - - green - bg ) ;
color : var ( - - green ) ;
border : 1 px solid rgba ( 63 , 185 , 80 , .3 ) ;
}
. status-badge . warn {
background : rgba ( 227 , 179 , 65 , .1 ) ;
color : var ( - - yellow ) ;
border : 1 px solid rgba ( 227 , 179 , 65 , .3 ) ;
}
. status-badge . error {
background : rgba ( 248 , 81 , 73 , .1 ) ;
color : var ( - - red ) ;
border : 1 px solid rgba ( 248 , 81 , 73 , .3 ) ;
}
. dof-box {
display : flex ;
align-items : center ;
justify-content : center ;
gap : 20 px ;
padding : 20 px ;
background : var ( - - surface ) ;
border : 1 px solid var ( - - border ) ;
border-radius : 10 px ;
}
. dof-side {
text-align : center ;
min-width : 150 px ;
}
. dof-side . title {
font-size : .7 rem ;
color : var ( - - dim ) ;
text-transform : uppercase ;
letter-spacing : .08 em ;
margin-bottom : 8 px ;
}
. dof-side . count {
font-size : 2 rem ;
font-weight : 700 ;
font-family : 'JetBrains Mono' , monospace ;
}
. dof-side . detail {
font-size : .65 rem ;
color : var ( - - dim ) ;
font-family : 'JetBrains Mono' , monospace ;
margin-top : 4 px ;
}
. dof-equals { font-size : 1.5 rem ; color : var ( - - green ) ; }
. mapping-box {
display : flex ;
align-items : center ;
justify-content : center ;
gap : 24 px ;
padding : 24 px ;
background : var ( - - surface ) ;
border : 1 px solid var ( - - border ) ;
border-radius : 10 px ;
flex-wrap : wrap ;
}
. mapping-arrow {
display : flex ;
flex-direction : column ;
align-items : center ;
gap : 4 px ;
}
. mapping-arrow svg { width : 80 px ; height : 40 px ; }
. mapping-arrow . lbl { font-size : .6 rem ; color : var ( - - cyan ) ; font-family : 'JetBrains Mono' , monospace ; }
. conv-grid {
display : grid ;
grid-template-columns : repeat ( auto - fill , minmax ( 60 px , 1 fr ) ) ;
gap : 6 px ;
}
. conv-cell {
background : var ( - - surface ) ;
border : 1 px solid var ( - - border ) ;
border-radius : 6 px ;
padding : 8 px ;
text-align : center ;
}
. conv-cell . iter { font-size : .55 rem ; color : var ( - - dim ) ; }
. conv-cell . val { font-size : .7 rem ; font-family : 'JetBrains Mono' , monospace ; color : var ( - - cyan ) ; margin-top : 2 px ; }
. conv-cell . active { border-color : var ( - - green ) ; background : var ( - - green - bg ) ; }
. conv-cell . active . val { color : var ( - - green ) ; }
[ data-tip ] { position : relative ; }
[ data-tip ] : hover :: after {
content : attr ( data - tip ) ;
position : absolute ;
bottom : calc ( 100 % + 8 px ) ;
left : 50 % ;
transform : translateX ( -50 % ) ;
background : #1c2128 ;
border : 1 px solid var ( - - border ) ;
color : var ( - - text ) ;
font-size : .68 rem ;
font-family : 'JetBrains Mono' , monospace ;
padding : 6 px 10 px ;
border-radius : 6 px ;
white-space : pre ;
z-index : 100 ;
pointer-events : none ;
box-shadow : 0 8 px 24 px rgba ( 0 , 0 , 0 , .5 ) ;
}
< / style >
< / head >
< body >
< h1 > 🎯 Entropyk — Contrôle Inverse One-Shot< / h1 >
< p class = "sub" > Superheat control avec valve d'expansion — Story 5.3: Residual Embedding< / p >
< div class = "legend" >
< div class = "leg" > < div class = "leg-dot" style = "border-color:var(--purple)" > < / div > Constraint< / div >
< div class = "leg" > < div class = "leg-dot" style = "border-color:var(--orange)" > < / div > BoundedVariable< / div >
< div class = "leg" > < div class = "leg-dot" style = "border-color:var(--cyan)" > < / div > Lien One-Shot< / div >
< div class = "leg" > < div class = "leg-dot" style = "border-color:var(--green)" > < / div > Résultat< / div >
< / div >
< div class = "page" >
<!-- ═══ CONCEPT ═══ -->
< section >
< h2 > Concept — One-Shot Inverse Control< / h2 >
< div class = "flow-diagram" >
< span class = "blabel" > FR24: Inverse Control solved simultaneously with cycle equations< / span >
< div style = "display:flex;align-items:stretch;gap:24px;justify-content:center;flex-wrap:wrap;" >
< div style = "flex:1;min-width:280px;background:rgba(248,81,73,.05);border:1px solid rgba(248,81,73,.2);border-radius:10px;padding:16px;" >
< div style = "font-size:.75rem;font-weight:600;color:var(--red);margin-bottom:12px;text-transform:uppercase;letter-spacing:.08em;" >
❌ Approche Traditionnelle
< / div >
< div style = "font-size:.72rem;color:var(--dim);line-height:1.8;" >
< div > 1. Fixer valve → Simuler< / div >
< div > 2. Mesurer superheat< / div >
< div > 3. Ajuster valve< / div >
< div > 4. < span style = "color:var(--red)" > Répéter (optimisation externe)< / span > < / div >
< div style = "border-top:1px solid var(--border);padding-top:8px;margin-top:8px;" >
< span style = "color:var(--red)" > → Lent, coûteux, non garanti< / span >
< / div >
< / div >
< / div >
< div style = "flex:1;min-width:280px;background:var(--green-bg);border:1px solid rgba(63,185,80,.3);border-radius:10px;padding:16px;" >
< div style = "font-size:.75rem;font-weight:600;color:var(--green);margin-bottom:12px;text-transform:uppercase;letter-spacing:.08em;" >
✅ Approche One-Shot (Entropyk)
< / div >
< div style = "font-size:.72rem;color:var(--dim);line-height:1.8;" >
< div > 1. Définir contrainte: superheat = 5K< / div >
< div > 2. Lier à variable: valve position< / div >
< div > 3. < span style = "color:var(--cyan)" > Valve devient inconnue du solveur< / span > < / div >
< div > 4. < span style = "color:var(--green)" > Résolution simultanée (1 appel)< / span > < / div >
< div style = "border-top:1px solid rgba(63,185,80,.3);padding-top:8px;margin-top:8px;" >
< span style = "color:var(--green)" > → Rapide, garanti, élégant< / span >
< / div >
< / div >
< / div >
< / div >
< div style = "margin-top:20px;padding:16px;background:var(--bg);border-radius:8px;text-align:center;" >
< div style = "font-size:.7rem;color:var(--dim);margin-bottom:8px;" > Vecteur de résidus étendu< / div >
< div style = "font-family:'JetBrains Mono',monospace;font-size:.85rem;color:var(--cyan);" >
r< sub > total< / sub > = [ r< sub > cycle< / sub > , r< sub > constraint< / sub > ]< sup > T< / sup > = 0
< / div >
< div style = "font-size:.65rem;color:var(--dim);margin-top:8px;" >
r< sub > constraint< / sub > = superheat< sub > mesuré< / sub > − superheat< sub > cible< / sub >
< / div >
< / div >
< / div >
< / section >
<!-- ═══ MAPPING ═══ -->
< section >
< h2 > Mapping — Contrainte → Variable de Contrôle< / h2 >
< div class = "mapping-box" >
< div class = "node constraint" data-tip = "Constraint ID: superheat_control Output: Superheat(evaporator) Target: 5.0 K" >
< div class = "nm" > 📐 Constraint< / div >
< div class = "ty" > superheat_control< / div >
< div class = "vals" > target: 5.0 K< / div >
< / div >
< div class = "mapping-arrow" >
< svg viewBox = "0 0 80 40" >
< defs >
< linearGradient id = "linkGrad" x1 = "0%" y1 = "0%" x2 = "100%" y2 = "0%" >
< stop offset = "0%" style = "stop-color:#bc8cff;stop-opacity:1" / >
< stop offset = "100%" style = "stop-color:#f0883e;stop-opacity:1" / >
< / linearGradient >
< / defs >
< line x1 = "0" y1 = "20" x2 = "70" y2 = "20" stroke = "url(#linkGrad)" stroke-width = "2" stroke-dasharray = "6,3" / >
< polygon points = "70,15 80,20 70,25" fill = "#f0883e" / >
< / svg >
< div class = "lbl" > link_constraint_to_control()< / div >
< / div >
< div class = "node control" data-tip = "BoundedVariable ID: valve_position Value: 0.5 (50%) Bounds: [0.1, 1.0]" >
< div class = "nm" > 🎚 BoundedVar< / div >
< div class = "ty" > valve_position< / div >
< div class = "vals" > [0.1, 1.0]< / div >
< / div >
< div class = "mapping-arrow" >
< svg viewBox = "0 0 60 40" >
< line x1 = "0" y1 = "20" x2 = "50" y2 = "20" stroke = "#7d8590" stroke-width = "2" / >
< polygon points = "50,15 60,20 50,25" fill = "#7d8590" / >
< / svg >
< div class = "lbl" > state[idx]< / div >
< / div >
< div class = "node result" data-tip = "Résultat One-Shot 7 itérations Convergence: 1e-8" >
< div class = "nm" > ✓ Résolu< / div >
< div class = "ty" > valve = 38%< / div >
< div class = "vals" > SH = 5.02 K< / div >
< / div >
< / div >
< / section >
<!-- ═══ DOF ═══ -->
< section >
< h2 > Validation des Degrés de Liberté (DoF)< / h2 >
< div class = "dof-box" >
< div class = "dof-side" >
< div class = "title" > Équations< / div >
< div class = "count" style = "color:var(--blue)" > 9< / div >
< div class = "detail" > composants: 8< br > contraintes: +1< / div >
< / div >
< div class = "dof-equals" > =< / div >
< div class = "dof-side" >
< div class = "title" > Inconnues< / div >
< div class = "count" style = "color:var(--orange)" > 9< / div >
< div class = "detail" > états bords: 8< br > contrôles: +1< / div >
< / div >
< / div >
< div style = "text-align:center;margin-top:12px;" >
< span class = "status-badge ok" > ✓ Système bien posé — validate_inverse_control_dof() = Ok< / span >
< / div >
< div style = "display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-top:16px;" >
< div style = "background:var(--green-bg);border:1px solid rgba(63,185,80,.3);border-radius:8px;padding:12px;text-align:center;" >
< div style = "font-size:.7rem;color:var(--green);font-weight:600;" > Équilibré< / div >
< div style = "font-size:.6rem;color:var(--dim);font-family:'JetBrains Mono',monospace;margin-top:4px;" > n_eqs == n_unknowns< / div >
< div class = "status-badge ok" style = "margin-top:8px;" > Résolvable< / div >
< / div >
< div style = "background:rgba(248,81,73,.05);border:1px solid rgba(248,81,73,.2);border-radius:8px;padding:12px;text-align:center;" >
< div style = "font-size:.7rem;color:var(--red);font-weight:600;" > Sur-contraint< / div >
< div style = "font-size:.6rem;color:var(--dim);font-family:'JetBrains Mono',monospace;margin-top:4px;" > n_eqs > n_unknowns< / div >
< div class = "status-badge error" style = "margin-top:8px;" > Erreur< / div >
< / div >
< div style = "background:rgba(227,179,65,.1);border:1px solid rgba(227,179,65,.3);border-radius:8px;padding:12px;text-align:center;" >
< div style = "font-size:.7rem;color:var(--yellow);font-weight:600;" > Sous-contraint< / div >
< div style = "font-size:.6rem;color:var(--dim);font-family:'JetBrains Mono',monospace;margin-top:4px;" > n_eqs < n_unknowns< / div >
< div class = "status-badge warn" style = "margin-top:8px;" > Warning< / div >
< / div >
< / div >
< / section >
<!-- ═══ ÉQUATIONS ═══ -->
< section >
< h2 > Équations du système étendu< / h2 >
< div style = "display:grid;grid-template-columns:1fr 1fr;gap:16px;" >
< div class = "eq-box" >
< div style = "font-size:.8rem;font-weight:600;color:var(--blue);margin-bottom:12px" > 📦 Équations du cycle (8 éq.)< / div >
< table class = "eq-table" >
< thead > < tr > < th > Composant< / th > < th > Équation< / th > < th > État< / th > < / tr > < / thead >
< tbody >
< tr > < td class = "cat" > Compresseur< / td > < td class = "formula" > r₁(P,h) = 0< / td > < td class = "result" > 2 éq.< / td > < / tr >
< tr > < td class = "cat" > Condenseur< / td > < td class = "formula" > r₂(P,h) = 0< / td > < td class = "result" > 2 éq.< / td > < / tr >
< tr > < td class = "cat" > EXV< / td > < td class = "formula" > r₃(P,h) = 0< / td > < td class = "result" > 2 éq.< / td > < / tr >
< tr > < td class = "cat" > Évaporateur< / td > < td class = "formula" > r₄(P,h) = 0< / td > < td class = "result" > 2 éq.< / td > < / tr >
< / tbody >
< / table >
< / div >
< div class = "eq-box" >
< div style = "font-size:.8rem;font-weight:600;color:var(--purple);margin-bottom:12px" > 📐 Équations de contrainte (+1 éq.)< / div >
< table class = "eq-table" >
< thead > < tr > < th > Type< / th > < th > Équation< / th > < th > Valeur< / th > < / tr > < / thead >
< tbody >
< tr > < td class = "cat" > Superheat< / td > < td class = "formula" > r_c = SH − 5.0< / td > < td class = "result" > 5.02 − 5.0< / td > < / tr >
< tr > < td class = "cat" > Jacobian< / td > < td class = "formula" > ∂r_c/∂valve< / td > < td class = "result" > ≈ 1.0< / td > < / tr >
< tr style = "background:var(--green-bg)" >
< td class = "cat" > State idx< / td > < td class = "formula" > 2·edges + i< / td > < td class = "result" style = "color:var(--green)" > idx = 8< / td >
< / tr >
< / tbody >
< / table >
< / div >
< / div >
< / section >
<!-- ═══ CONVERGENCE ═══ -->
< section >
< h2 > Convergence — Newton-Raphson< / h2 >
< div class = "info-grid" >
< div class = "icard" >
< h3 > Superheat (K)< / h3 >
< div class = "conv-grid" >
< div class = "conv-cell" > < div class = "iter" > i=0< / div > < div class = "val" > 2.30< / div > < / div >
< div class = "conv-cell" > < div class = "iter" > i=1< / div > < div class = "val" > 3.12< / div > < / div >
< div class = "conv-cell" > < div class = "iter" > i=2< / div > < div class = "val" > 3.89< / div > < / div >
< div class = "conv-cell" > < div class = "iter" > i=3< / div > < div class = "val" > 4.41< / div > < / div >
< div class = "conv-cell" > < div class = "iter" > i=4< / div > < div class = "val" > 4.73< / div > < / div >
< div class = "conv-cell" > < div class = "iter" > i=5< / div > < div class = "val" > 4.91< / div > < / div >
< div class = "conv-cell" > < div class = "iter" > i=6< / div > < div class = "val" > 5.01< / div > < / div >
< div class = "conv-cell active" > < div class = "iter" > i=7< / div > < div class = "val" > 5.02< / div > < / div >
< / div >
< / div >
< div class = "icard" >
< h3 > Valve Position (%)< / h3 >
< div class = "conv-grid" >
< div class = "conv-cell" > < div class = "iter" > i=0< / div > < div class = "val" > 50.0< / div > < / div >
< div class = "conv-cell" > < div class = "iter" > i=1< / div > < div class = "val" > 46.2< / div > < / div >
< div class = "conv-cell" > < div class = "iter" > i=2< / div > < div class = "val" > 43.5< / div > < / div >
< div class = "conv-cell" > < div class = "iter" > i=3< / div > < div class = "val" > 41.3< / div > < / div >
< div class = "conv-cell" > < div class = "iter" > i=4< / div > < div class = "val" > 39.8< / div > < / div >
< div class = "conv-cell" > < div class = "iter" > i=5< / div > < div class = "val" > 38.9< / div > < / div >
< div class = "conv-cell" > < div class = "iter" > i=6< / div > < div class = "val" > 38.3< / div > < / div >
< div class = "conv-cell active" > < div class = "iter" > i=7< / div > < div class = "val" > 38.0< / div > < / div >
< / div >
< / div >
< / div >
< / section >
<!-- ═══ VALEURS FINALES ═══ -->
< section >
< h2 > Valeurs au point de fonctionnement< / h2 >
< div class = "info-grid" >
< div class = "icard" >
< h3 > Contrainte Superheat< / h3 >
< div class = "irow" > < span class = "k" > ID< / span > < span class = "v p" > superheat_control< / span > < / div >
< div class = "irow" > < span class = "k" > Output< / span > < span class = "v" > Superheat(evaporator)< / span > < / div >
< div class = "irow" > < span class = "k" > Target< / span > < span class = "v c" > 5.0 K< / span > < / div >
< div class = "irow" > < span class = "k" > Mesuré< / span > < span class = "v g" > 5.02 K< / span > < / div >
< div class = "irow" > < span class = "k" > Résidu< / span > < span class = "v g" > 0.02 K< / span > < / div >
< div class = "irow" > < span class = "k" > Satisfait< / span > < span class = "v g" > ✓< / span > < / div >
< / div >
< div class = "icard" >
< h3 > Variable de Contrôle< / h3 >
< div class = "irow" > < span class = "k" > ID< / span > < span class = "v o" > valve_position< / span > < / div >
< div class = "irow" > < span class = "k" > Initial< / span > < span class = "v" > 50.0%< / span > < / div >
< div class = "irow" > < span class = "k" > Final< / span > < span class = "v g" > 38.0%< / span > < / div >
< div class = "irow" > < span class = "k" > Bounds< / span > < span class = "v" > [10%, 100%]< / span > < / div >
< div class = "irow" > < span class = "k" > Saturé< / span > < span class = "v c" > Non< / span > < / div >
< div class = "irow" > < span class = "k" > State idx< / span > < span class = "v b" > 8< / span > < / div >
< / div >
< div class = "icard" >
< h3 > Solveur Newton-Raphson< / h3 >
< div class = "irow" > < span class = "k" > Itérations< / span > < span class = "v c" > 7< / span > < / div >
< div class = "irow" > < span class = "k" > Tolérance< / span > < span class = "v" > 1e-8< / span > < / div >
< div class = "irow" > < span class = "k" > ‖r‖ final< / span > < span class = "v g" > 3.2e-9< / span > < / div >
< div class = "irow" > < span class = "k" > Méthode< / span > < span class = "v" > One-Shot< / span > < / div >
< div class = "irow" > < span class = "k" > Temps< / span > < span class = "v g" > 12 ms< / span > < / div >
< / div >
< div class = "icard" >
< h3 > DoF Validation< / h3 >
< div class = "irow" > < span class = "k" > Edges< / span > < span class = "v" > 4 (× 2 = 8)< / span > < / div >
< div class = "irow" > < span class = "k" > Controls< / span > < span class = "v o" > +1< / span > < / div >
< div class = "irow" > < span class = "k" > Total unknowns< / span > < span class = "v b" > 9< / span > < / div >
< div class = "irow" > < span class = "k" > Components< / span > < span class = "v" > 4 (× 2 = 8)< / span > < / div >
< div class = "irow" > < span class = "k" > Constraints< / span > < span class = "v p" > +1< / span > < / div >
< div class = "irow" > < span class = "k" > Total equations< / span > < span class = "v b" > 9< / span > < / div >
< div class = "irow" > < span class = "k" > Balance< / span > < span class = "v g" > 9 = 9 ✓< / span > < / div >
< / div >
< / div >
< / section >
<!-- ═══ API RUST ═══ -->
< section >
< h2 > API Rust — Utilisation< / h2 >
< pre style = "color:#d4d4d4" > < span style = "color:#6a9955" > // ══════════════════════════════════════════════════════════════════════< / span >
< span style = "color:#6a9955" > // Story 5.3: Residual Embedding for Inverse Control< / span >
< span style = "color:#6a9955" > // ══════════════════════════════════════════════════════════════════════< / span >
< span style = "color:#569cd6" > use< / span > entropyk_solver::inverse::{
< span style = "color:#4ec9b0" > Constraint< / span > , < span style = "color:#4ec9b0" > ConstraintId< / span > , < span style = "color:#4ec9b0" > ComponentOutput< / span > ,
< span style = "color:#4ec9b0" > BoundedVariable< / span > , < span style = "color:#4ec9b0" > BoundedVariableId< / span > ,
};
< span style = "color:#6a9955" > // 1. Définir la contrainte: superheat = 5K< / span >
< span style = "color:#569cd6" > let< / span > constraint = < span style = "color:#4ec9b0" > Constraint< / span > ::< span style = "color:#dcdcaa" > new< / span > (
< span style = "color:#4ec9b0" > ConstraintId< / span > ::< span style = "color:#dcdcaa" > new< / span > (< span style = "color:#ce9178" > "superheat_control"< / span > ),
< span style = "color:#4ec9b0" > ComponentOutput< / span > ::< span style = "color:#4ec9b0" > Superheat< / span > { component_id: < span style = "color:#ce9178" > "evaporator"< / span > .< span style = "color:#dcdcaa" > into< / span > () },
< span style = "color:#b5cea8" > 5.0< / span > , < span style = "color:#6a9955" > // target: 5 Kelvin< / span >
);
system.< span style = "color:#dcdcaa" > add_constraint< / span > (constraint)?;
< span style = "color:#6a9955" > // 2. Définir la variable de contrôle bornée< / span >
< span style = "color:#569cd6" > let< / span > control = < span style = "color:#4ec9b0" > BoundedVariable< / span > ::< span style = "color:#dcdcaa" > new< / span > (
< span style = "color:#4ec9b0" > BoundedVariableId< / span > ::< span style = "color:#dcdcaa" > new< / span > (< span style = "color:#ce9178" > "valve_position"< / span > ),
< span style = "color:#b5cea8" > 0.5< / span > , < span style = "color:#b5cea8" > 0.1< / span > , < span style = "color:#b5cea8" > 1.0< / span > , < span style = "color:#6a9955" > // init, min, max< / span >
)?;
system.< span style = "color:#dcdcaa" > add_bounded_variable< / span > (control)?;
< span style = "color:#6a9955" > // 3. Lier contrainte → contrôle (One-Shot!)< / span >
system.< span style = "color:#dcdcaa" > link_constraint_to_control< / span > (
< span style = "color:#569cd6" > & < / span > < span style = "color:#4ec9b0" > ConstraintId< / span > ::< span style = "color:#dcdcaa" > new< / span > (< span style = "color:#ce9178" > "superheat_control"< / span > ),
< span style = "color:#569cd6" > & < / span > < span style = "color:#4ec9b0" > BoundedVariableId< / span > ::< span style = "color:#dcdcaa" > new< / span > (< span style = "color:#ce9178" > "valve_position"< / span > ),
)?;
< span style = "color:#6a9955" > // 4. Valider DoF + Finalize< / span >
system.< span style = "color:#dcdcaa" > validate_inverse_control_dof< / span > ()?;
system.< span style = "color:#dcdcaa" > finalize< / span > ()?;
< span style = "color:#6a9955" > // 5. Résoudre (One-Shot)< / span >
< span style = "color:#569cd6" > let< / span > result = < span style = "color:#4ec9b0" > NewtonRaphson< / span > ::< span style = "color:#dcdcaa" > new< / span > ().< span style = "color:#dcdcaa" > solve< / span > (< span style = "color:#569cd6" > & < / span > system)?;
< span style = "color:#6a9955" > // 6. Résultat< / span >
< span style = "color:#569cd6" > let< / span > valve = system.< span style = "color:#dcdcaa" > get_bounded_variable< / span > (< span style = "color:#569cd6" > & < / span > < span style = "color:#4ec9b0" > BoundedVariableId< / span > ::< span style = "color:#dcdcaa" > new< / span > (< span style = "color:#ce9178" > "valve_position"< / span > )).< span style = "color:#dcdcaa" > unwrap< / span > ();
< span style = "color:#dcdcaa" > println!< / span > (< span style = "color:#ce9178" > "Valve: {:.1}% SH: {:.2} K"< / span > , valve.< span style = "color:#dcdcaa" > value< / span > ()< span style = "color:#569cd6" > *< / span > < span style = "color:#b5cea8" > 100.0< / span > , sh);< / pre >
< / section >
<!-- ═══ API MÉTHODES ═══ -->
< section >
< h2 > API — Méthodes System< / h2 >
< div class = "eq-box" >
< table class = "eq-table" >
< thead > < tr > < th > Méthode< / th > < th > Description< / th > < th > Retour< / th > < / tr > < / thead >
< tbody >
< tr > < td class = "formula" > add_constraint(c)< / td > < td class = "cat" > Ajoute une contrainte< / td > < td class = "result" > Result< (), ConstraintError> < / td > < / tr >
< tr > < td class = "formula" > add_bounded_variable(v)< / td > < td class = "cat" > Ajoute variable bornée< / td > < td class = "result" > Result< (), BoundedVariableError> < / td > < / tr >
< tr > < td class = "formula" > link_constraint_to_control(cid, vid)< / td > < td class = "cat" > Lie contrainte → contrôle< / td > < td class = "result" > Result< (), DoFError> < / td > < / tr >
< tr > < td class = "formula" > unlink_constraint(cid)< / td > < td class = "cat" > Supprime le lien< / td > < td class = "result" > Option< BoundedVariableId> < / td > < / tr >
< tr > < td class = "formula" > validate_inverse_control_dof()< / td > < td class = "cat" > Valide éq == inconnues< / td > < td class = "result" > Result< (), DoFError> < / td > < / tr >
< tr > < td class = "formula" > control_variable_state_index(id)< / td > < td class = "cat" > Index vecteur d'état< / td > < td class = "result" > Option< usize> < / td > < / tr >
< tr > < td class = "formula" > full_state_vector_len()< / td > < td class = "cat" > Longueur totale< / td > < td class = "result" > usize< / td > < / tr >
< tr > < td class = "formula" > compute_constraint_residuals(...)< / td > < td class = "cat" > Calcule résidus contraintes< / td > < td class = "result" > usize< / td > < / tr >
< tr > < td class = "formula" > compute_inverse_control_jacobian(...)< / td > < td class = "cat" > Jacobian ∂r/∂control< / td > < td class = "result" > Vec< (row,col,val)> < / td > < / tr >
< / tbody >
< / table >
< / div >
< / section >
< / div >
< script >
document . querySelectorAll ( '.node' ) . forEach ( el => {
el . addEventListener ( 'mouseenter' , ( ) => {
const c = getComputedStyle ( el ) . borderColor ;
el . style . boxShadow = '0 0 0 2px ' + c + ', 0 8px 28px rgba(0,0,0,.5)' ;
} ) ;
el . addEventListener ( 'mouseleave' , ( ) => { el . style . boxShadow = '' ; } ) ;
} ) ;
< / script >
< / body >
< / html >