747 lines
34 KiB
HTML
747 lines
34 KiB
HTML
<!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: 100vh;
|
||
padding: 40px 20px 80px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
|
||
h1 {
|
||
font-size: 1.5rem;
|
||
font-weight: 700;
|
||
color: var(--cyan);
|
||
margin-bottom: 4px;
|
||
letter-spacing: -.5px;
|
||
}
|
||
|
||
.sub { font-size: .82rem; color: var(--dim); margin-bottom: 40px; }
|
||
|
||
.page {
|
||
width: 100%;
|
||
max-width: 1080px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 28px;
|
||
}
|
||
|
||
section { width: 100%; }
|
||
|
||
section h2 {
|
||
font-size: .75rem;
|
||
text-transform: uppercase;
|
||
letter-spacing: .1em;
|
||
color: var(--dim);
|
||
font-weight: 600;
|
||
border-bottom: 1px solid var(--border);
|
||
padding-bottom: 8px;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.legend {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 18px;
|
||
justify-content: center;
|
||
margin-bottom: 36px;
|
||
}
|
||
|
||
.leg {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 7px;
|
||
font-size: .74rem;
|
||
color: var(--dim);
|
||
}
|
||
|
||
.leg-dot {
|
||
width: 11px;
|
||
height: 11px;
|
||
border-radius: 3px;
|
||
border: 2px solid;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.flow-diagram {
|
||
border: 2px solid var(--cyan);
|
||
border-radius: 14px;
|
||
background: var(--cyan-bg);
|
||
padding: 28px 24px 32px;
|
||
position: relative;
|
||
}
|
||
|
||
.flow-diagram > .blabel {
|
||
position: absolute;
|
||
top: -13px;
|
||
left: 22px;
|
||
background: var(--bg);
|
||
padding: 0 10px;
|
||
font-size: .72rem;
|
||
font-weight: 600;
|
||
color: var(--cyan);
|
||
letter-spacing: .07em;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.node {
|
||
border: 2px solid var(--border);
|
||
border-radius: 10px;
|
||
background: var(--surface);
|
||
padding: 12px 16px;
|
||
text-align: center;
|
||
min-width: 90px;
|
||
cursor: default;
|
||
transition: transform .18s, box-shadow .18s;
|
||
}
|
||
|
||
.node:hover {
|
||
transform: translateY(-3px);
|
||
box-shadow: 0 8px 24px rgba(0, 0, 0, .5);
|
||
}
|
||
|
||
.node .nm { font-size: .8rem; font-weight: 600; }
|
||
.node .ty { font-size: .62rem; color: var(--dim); margin-top: 2px; font-family: 'JetBrains Mono', monospace; }
|
||
.node .vals { font-size: .6rem; font-family: 'JetBrains Mono', monospace; color: var(--cyan); margin-top: 4px; 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: 48px;
|
||
}
|
||
|
||
.arr-line {
|
||
width: 100%;
|
||
height: 2px;
|
||
background: linear-gradient(90deg, var(--border), var(--dim));
|
||
position: relative;
|
||
}
|
||
|
||
.arr-line::after {
|
||
content: '';
|
||
position: absolute;
|
||
right: -1px;
|
||
top: -4px;
|
||
border: 5px solid transparent;
|
||
border-left-color: var(--dim);
|
||
}
|
||
|
||
.arr-lbl {
|
||
font-size: .58rem;
|
||
color: var(--dim);
|
||
font-family: 'JetBrains Mono', monospace;
|
||
margin-top: 3px;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.info-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||
gap: 14px;
|
||
}
|
||
|
||
.icard {
|
||
border: 1px solid var(--border);
|
||
border-radius: 10px;
|
||
background: var(--surface);
|
||
padding: 14px;
|
||
}
|
||
|
||
.icard h3 {
|
||
font-size: .7rem;
|
||
font-weight: 600;
|
||
text-transform: uppercase;
|
||
letter-spacing: .08em;
|
||
color: var(--dim);
|
||
border-bottom: 1px solid var(--border);
|
||
padding-bottom: 7px;
|
||
margin-bottom: 9px;
|
||
}
|
||
|
||
.irow {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
font-size: .75rem;
|
||
padding: 3px 0;
|
||
}
|
||
|
||
.irow .k { color: var(--dim); }
|
||
.irow .v { font-family: 'JetBrains Mono', monospace; font-size: .7rem; }
|
||
|
||
.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: 1px solid var(--border);
|
||
border-radius: 10px;
|
||
padding: 18px 20px;
|
||
}
|
||
|
||
.eq-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
font-size: .75rem;
|
||
}
|
||
|
||
.eq-table th {
|
||
text-align: left;
|
||
font-weight: 600;
|
||
font-size: .68rem;
|
||
color: var(--dim);
|
||
text-transform: uppercase;
|
||
letter-spacing: .07em;
|
||
padding: 0 8px 10px;
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
|
||
.eq-table td {
|
||
padding: 5px 8px;
|
||
font-family: 'JetBrains Mono', monospace;
|
||
font-size: .7rem;
|
||
}
|
||
|
||
.eq-table tr:not(:last-child) td { border-bottom: 1px solid rgba(48, 54, 61, .5); }
|
||
.eq-table .cat { color: var(--dim); font-family: 'Inter', sans-serif; font-size: .72rem; }
|
||
.eq-table .formula { color: var(--cyan); }
|
||
.eq-table .result { color: var(--green); text-align: right; }
|
||
|
||
pre {
|
||
background: var(--surface);
|
||
border: 1px solid var(--border);
|
||
border-radius: 10px;
|
||
padding: 18px;
|
||
font-family: 'JetBrains Mono', monospace;
|
||
font-size: .72rem;
|
||
line-height: 1.7;
|
||
overflow-x: auto;
|
||
}
|
||
|
||
.status-badge {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 5px;
|
||
padding: 4px 10px;
|
||
border-radius: 100px;
|
||
font-size: .68rem;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.status-badge.ok {
|
||
background: var(--green-bg);
|
||
color: var(--green);
|
||
border: 1px solid rgba(63, 185, 80, .3);
|
||
}
|
||
|
||
.status-badge.warn {
|
||
background: rgba(227, 179, 65, .1);
|
||
color: var(--yellow);
|
||
border: 1px solid rgba(227, 179, 65, .3);
|
||
}
|
||
|
||
.status-badge.error {
|
||
background: rgba(248, 81, 73, .1);
|
||
color: var(--red);
|
||
border: 1px solid rgba(248, 81, 73, .3);
|
||
}
|
||
|
||
.dof-box {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 20px;
|
||
padding: 20px;
|
||
background: var(--surface);
|
||
border: 1px solid var(--border);
|
||
border-radius: 10px;
|
||
}
|
||
|
||
.dof-side {
|
||
text-align: center;
|
||
min-width: 150px;
|
||
}
|
||
|
||
.dof-side .title {
|
||
font-size: .7rem;
|
||
color: var(--dim);
|
||
text-transform: uppercase;
|
||
letter-spacing: .08em;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.dof-side .count {
|
||
font-size: 2rem;
|
||
font-weight: 700;
|
||
font-family: 'JetBrains Mono', monospace;
|
||
}
|
||
|
||
.dof-side .detail {
|
||
font-size: .65rem;
|
||
color: var(--dim);
|
||
font-family: 'JetBrains Mono', monospace;
|
||
margin-top: 4px;
|
||
}
|
||
|
||
.dof-equals { font-size: 1.5rem; color: var(--green); }
|
||
|
||
.mapping-box {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 24px;
|
||
padding: 24px;
|
||
background: var(--surface);
|
||
border: 1px solid var(--border);
|
||
border-radius: 10px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.mapping-arrow {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 4px;
|
||
}
|
||
|
||
.mapping-arrow svg { width: 80px; height: 40px; }
|
||
.mapping-arrow .lbl { font-size: .6rem; color: var(--cyan); font-family: 'JetBrains Mono', monospace; }
|
||
|
||
.conv-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(60px, 1fr));
|
||
gap: 6px;
|
||
}
|
||
|
||
.conv-cell {
|
||
background: var(--surface);
|
||
border: 1px solid var(--border);
|
||
border-radius: 6px;
|
||
padding: 8px;
|
||
text-align: center;
|
||
}
|
||
|
||
.conv-cell .iter { font-size: .55rem; color: var(--dim); }
|
||
.conv-cell .val { font-size: .7rem; font-family: 'JetBrains Mono', monospace; color: var(--cyan); margin-top: 2px; }
|
||
.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% + 8px);
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
background: #1c2128;
|
||
border: 1px solid var(--border);
|
||
color: var(--text);
|
||
font-size: .68rem;
|
||
font-family: 'JetBrains Mono', monospace;
|
||
padding: 6px 10px;
|
||
border-radius: 6px;
|
||
white-space: pre;
|
||
z-index: 100;
|
||
pointer-events: none;
|
||
box-shadow: 0 8px 24px 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>
|