Update simulation preset and UI template
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -358,6 +358,10 @@
|
||||
.sweep-table .cell-ok { color: #166534; font-weight: 600; }
|
||||
.sweep-table .cell-bad { color: #b91c1c; }
|
||||
.sweep-table .cell-null { color: #94a3b8; }
|
||||
/* Constraint proximity highlights — override row stripes */
|
||||
.sweep-table td.cell-limit-met { background: #dcfce7 !important; } /* green — met target */
|
||||
.sweep-table td.cell-limit-near { background: #fef9c3 !important; } /* yellow — near limit */
|
||||
.sweep-table td.cell-limit-over { background: #fed7aa !important; } /* orange — over limit */
|
||||
|
||||
/* ---- Spinner ---- */
|
||||
.spinner {
|
||||
@@ -616,6 +620,13 @@
|
||||
<tbody id="sweep-table-body"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style="padding:6px 14px 10px;font-size:11px;color:#64748b;display:flex;gap:16px;align-items:center">
|
||||
<span>P_out shading:</span>
|
||||
<span><span style="display:inline-block;width:12px;height:12px;background:#dcfce7;border:1px solid #86efac;vertical-align:middle;margin-right:4px"></span>Met target</span>
|
||||
<span><span style="display:inline-block;width:12px;height:12px;background:#fef9c3;border:1px solid #d4b800;vertical-align:middle;margin-right:4px"></span>Near limit (>90%)</span>
|
||||
<span><span style="display:inline-block;width:12px;height:12px;background:#fed7aa;border:1px solid #c2590a;vertical-align:middle;margin-right:4px"></span>Over limit</span>
|
||||
<span style="color:#94a3b8">Near/over applies to: B, Vs, Ip, Is, P_out</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div><!-- /right-col -->
|
||||
@@ -1003,6 +1014,14 @@ async function runSweep() {
|
||||
}
|
||||
|
||||
sweepData = data;
|
||||
// Stash constraint limits so updateTable can shade near-limit cells
|
||||
sweepData._constraints = {
|
||||
B_max_T: parseFloat(document.getElementById('con-B').value) || Infinity,
|
||||
Vs_max: parseFloat(document.getElementById('con-Vs').value) || Infinity,
|
||||
Ip_max: parseFloat(document.getElementById('con-Ip').value) || Infinity,
|
||||
Is_max: parseFloat(document.getElementById('con-Is').value) || Infinity,
|
||||
P_out_max_W: parseFloat(document.getElementById('con-Pout').value) || Infinity,
|
||||
};
|
||||
setMsg(msg, 'ok', `Done — ${data.rows.length} operating points computed.`);
|
||||
|
||||
// Populate frequency dropdown
|
||||
@@ -1187,7 +1206,6 @@ const _TABLE_COLS = [
|
||||
{ key: 'freq_hz', label: 'freq (Hz)' },
|
||||
{ key: 'Z_load_R', label: 'R (Ω)' },
|
||||
{ key: 'Z_load_X', label: 'X (Ω)' },
|
||||
{ key: 'met_target', label: 'met' },
|
||||
{ key: 'primary_tap', label: 'P tap' },
|
||||
{ key: 'secondary_tap', label: 'S tap' },
|
||||
{ key: 'Vp_rms', label: 'Vp (V)' },
|
||||
@@ -1214,11 +1232,6 @@ function fmtCell(key, val, row) {
|
||||
if (key === '_T_rise') { val = row ? row._T_rise : null; }
|
||||
if (key === '_T_copper') { val = row ? row._T_copper : null; }
|
||||
if (val === null || val === undefined) return '<span class="cell-null">—</span>';
|
||||
if (key === 'met_target') {
|
||||
return val
|
||||
? '<span class="cell-ok">YES</span>'
|
||||
: '<span class="cell-bad">NO</span>';
|
||||
}
|
||||
if (key === 'efficiency' && typeof val === 'number') {
|
||||
return (val * 100).toFixed(2) + '%';
|
||||
}
|
||||
@@ -1228,6 +1241,35 @@ function fmtCell(key, val, row) {
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an object mapping column key → 'over' | 'near' | null for a row,
|
||||
* based on how close each value is to its constraint limit.
|
||||
*
|
||||
* 'over' = value exceeds the limit
|
||||
* 'near' = value is within NEAR_THRESHOLD of the limit (ratio > 0.9)
|
||||
* null = fine
|
||||
*/
|
||||
const _LIMIT_NEAR_THRESHOLD = 0.90; // flag cell when value/limit > this
|
||||
|
||||
function limitingCells(row, constraints) {
|
||||
if (!constraints) return {};
|
||||
const result = {};
|
||||
|
||||
function check(colKey, value, limit) {
|
||||
if (value == null || !isFinite(limit) || limit <= 0) return;
|
||||
const ratio = value / limit;
|
||||
if (ratio > 1.0) result[colKey] = 'over';
|
||||
else if (ratio > _LIMIT_NEAR_THRESHOLD) result[colKey] = 'near';
|
||||
}
|
||||
|
||||
check('B_peak_T', row.B_peak_T, constraints.B_max_T);
|
||||
check('Vs_rms', row.Vs_rms, constraints.Vs_max);
|
||||
check('Ip_rms', row.Ip_rms, constraints.Ip_max);
|
||||
check('Is_rms', row.Is_rms, constraints.Is_max);
|
||||
check('P_out_W', row.P_out_W, constraints.P_out_max_W);
|
||||
return result;
|
||||
}
|
||||
|
||||
function updateTable(rows, T_rise, T_copper) {
|
||||
document.getElementById('table-card').style.display = 'block';
|
||||
|
||||
@@ -1239,12 +1281,24 @@ function updateTable(rows, T_rise, T_copper) {
|
||||
|
||||
const thead = document.getElementById('sweep-table-head');
|
||||
const tbody = document.getElementById('sweep-table-body');
|
||||
const constraints = sweepData && sweepData._constraints;
|
||||
|
||||
thead.innerHTML = '<tr>' + _TABLE_COLS.map(c => `<th>${c.label}</th>`).join('') + '</tr>';
|
||||
|
||||
tbody.innerHTML = rows.map(r =>
|
||||
'<tr>' + _TABLE_COLS.map(c => `<td>${fmtCell(c.key, r[c.key], r)}</td>`).join('') + '</tr>'
|
||||
).join('');
|
||||
tbody.innerHTML = rows.map(r => {
|
||||
const limits = limitingCells(r, constraints);
|
||||
const cells = _TABLE_COLS.map(c => {
|
||||
const lvl = limits[c.key];
|
||||
// P_out_W gets green when the optimizer met its target (and isn't near/over a limit)
|
||||
const metGreen = c.key === 'P_out_W' && r.met_target && !lvl;
|
||||
const cls = lvl === 'over' ? ' class="cell-limit-over"'
|
||||
: lvl === 'near' ? ' class="cell-limit-near"'
|
||||
: metGreen ? ' class="cell-limit-met"'
|
||||
: '';
|
||||
return `<td${cls}>${fmtCell(c.key, r[c.key], r)}</td>`;
|
||||
});
|
||||
return '<tr>' + cells.join('') + '</tr>';
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function triggerCsvDownload() {
|
||||
|
||||
Reference in New Issue
Block a user