diff --git a/presets/sim.json b/presets/sim.json
index b81391b..6ba4224 100644
--- a/presets/sim.json
+++ b/presets/sim.json
@@ -1,6 +1,6 @@
{
"points": {
- "frequencies": "256\n870\n3140\n8900\n12000\n16000\n22000\n33000\n45000",
+ "frequencies": "256\n512\n1024\n3140\n8900\n12000\n16000\n22000\n33000\n45000",
"loads": "10\n50\n100\n200\n600\n2000",
"target_power_W": 25,
"power_tol_pct": 2,
diff --git a/templates/index.html b/templates/index.html
index 112428b..dc67f01 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -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 @@
+
+ P_out shading:
+ Met target
+ Near limit (>90%)
+ Over limit
+ Near/over applies to: B, Vs, Ip, Is, P_out
+
@@ -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 '—';
- if (key === 'met_target') {
- return val
- ? 'YES'
- : 'NO';
- }
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 = '' + _TABLE_COLS.map(c => `| ${c.label} | `).join('') + '
';
- tbody.innerHTML = rows.map(r =>
- '' + _TABLE_COLS.map(c => `| ${fmtCell(c.key, r[c.key], r)} | `).join('') + '
'
- ).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 `${fmtCell(c.key, r[c.key], r)} | `;
+ });
+ return '' + cells.join('') + '
';
+ }).join('');
}
function triggerCsvDownload() {