@vessel-dsp/compiler 0.0.0-stage → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +118 -2
- package/dist/bake.d.ts +38 -0
- package/dist/bake.d.ts.map +1 -0
- package/dist/bake.js +101 -0
- package/dist/bake.js.map +1 -0
- package/dist/bbd-clock.d.ts +171 -0
- package/dist/bbd-clock.d.ts.map +1 -0
- package/dist/bbd-clock.js +1750 -0
- package/dist/bbd-clock.js.map +1 -0
- package/dist/block-row.d.ts +51 -0
- package/dist/block-row.d.ts.map +1 -0
- package/dist/block-row.js +17 -0
- package/dist/block-row.js.map +1 -0
- package/dist/bypass.d.ts +3 -0
- package/dist/bypass.d.ts.map +1 -0
- package/dist/bypass.js +228 -0
- package/dist/bypass.js.map +1 -0
- package/dist/compile.d.ts +24 -0
- package/dist/compile.d.ts.map +1 -0
- package/dist/compile.js +348 -0
- package/dist/compile.js.map +1 -0
- package/dist/converter-scale.d.ts +14 -0
- package/dist/converter-scale.d.ts.map +1 -0
- package/dist/converter-scale.js +133 -0
- package/dist/converter-scale.js.map +1 -0
- package/dist/couple.d.ts +28 -0
- package/dist/couple.d.ts.map +1 -0
- package/dist/couple.js +567 -0
- package/dist/couple.js.map +1 -0
- package/dist/dangling-active-terminal.d.ts +47 -0
- package/dist/dangling-active-terminal.d.ts.map +1 -0
- package/dist/dangling-active-terminal.js +542 -0
- package/dist/dangling-active-terminal.js.map +1 -0
- package/dist/declared-program.d.ts +23 -0
- package/dist/declared-program.d.ts.map +1 -0
- package/dist/declared-program.js +387 -0
- package/dist/declared-program.js.map +1 -0
- package/dist/denomination.d.ts +48 -0
- package/dist/denomination.d.ts.map +1 -0
- package/dist/denomination.js +27 -0
- package/dist/denomination.js.map +1 -0
- package/dist/device-laws.d.ts +237 -0
- package/dist/device-laws.d.ts.map +1 -0
- package/dist/device-laws.js +3513 -0
- package/dist/device-laws.js.map +1 -0
- package/dist/diagnostics.d.ts +13 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +19 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/emit.d.ts +8 -0
- package/dist/emit.d.ts.map +1 -0
- package/dist/emit.js +43 -0
- package/dist/emit.js.map +1 -0
- package/dist/errors.d.ts +22 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +39 -0
- package/dist/errors.js.map +1 -0
- package/dist/firmware-class.d.ts +69 -0
- package/dist/firmware-class.d.ts.map +1 -0
- package/dist/firmware-class.js +20 -0
- package/dist/firmware-class.js.map +1 -0
- package/dist/fixtures/circuits.d.ts +1742 -0
- package/dist/fixtures/circuits.d.ts.map +1 -0
- package/dist/fixtures/circuits.js +13896 -0
- package/dist/fixtures/circuits.js.map +1 -0
- package/dist/fixtures/expected.d.ts +261 -0
- package/dist/fixtures/expected.d.ts.map +1 -0
- package/dist/fixtures/expected.js +315 -0
- package/dist/fixtures/expected.js.map +1 -0
- package/dist/fixtures/index.d.ts +4 -0
- package/dist/fixtures/index.d.ts.map +1 -0
- package/dist/fixtures/index.js +8 -0
- package/dist/fixtures/index.js.map +1 -0
- package/dist/fixtures/registry.d.ts +52 -0
- package/dist/fixtures/registry.d.ts.map +1 -0
- package/dist/fixtures/registry.js +341 -0
- package/dist/fixtures/registry.js.map +1 -0
- package/dist/generic-tube-fit.d.ts +12 -0
- package/dist/generic-tube-fit.d.ts.map +1 -0
- package/dist/generic-tube-fit.js +45 -0
- package/dist/generic-tube-fit.js.map +1 -0
- package/dist/grounded-clock-supply.d.ts +13 -0
- package/dist/grounded-clock-supply.d.ts.map +1 -0
- package/dist/grounded-clock-supply.js +45 -0
- package/dist/grounded-clock-supply.js.map +1 -0
- package/dist/identify.d.ts +50 -0
- package/dist/identify.d.ts.map +1 -0
- package/dist/identify.js +319 -0
- package/dist/identify.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/inert-controls.d.ts +15 -0
- package/dist/inert-controls.d.ts.map +1 -0
- package/dist/inert-controls.js +266 -0
- package/dist/inert-controls.js.map +1 -0
- package/dist/latch-seed.d.ts +53 -0
- package/dist/latch-seed.d.ts.map +1 -0
- package/dist/latch-seed.js +257 -0
- package/dist/latch-seed.js.map +1 -0
- package/dist/link.d.ts +7 -0
- package/dist/link.d.ts.map +1 -0
- package/dist/link.js +270 -0
- package/dist/link.js.map +1 -0
- package/dist/lower.d.ts +79 -0
- package/dist/lower.d.ts.map +1 -0
- package/dist/lower.js +1855 -0
- package/dist/lower.js.map +1 -0
- package/dist/netlist.d.ts +79 -0
- package/dist/netlist.d.ts.map +1 -0
- package/dist/netlist.js +4746 -0
- package/dist/netlist.js.map +1 -0
- package/dist/non-executable-clock-drivers.d.ts +8 -0
- package/dist/non-executable-clock-drivers.d.ts.map +1 -0
- package/dist/non-executable-clock-drivers.js +33 -0
- package/dist/non-executable-clock-drivers.js.map +1 -0
- package/dist/open-category.d.ts +98 -0
- package/dist/open-category.d.ts.map +1 -0
- package/dist/open-category.js +111 -0
- package/dist/open-category.js.map +1 -0
- package/dist/over-driven-node.d.ts +33 -0
- package/dist/over-driven-node.d.ts.map +1 -0
- package/dist/over-driven-node.js +188 -0
- package/dist/over-driven-node.js.map +1 -0
- package/dist/part-catalog.d.ts +15 -0
- package/dist/part-catalog.d.ts.map +1 -0
- package/dist/part-catalog.js +6712 -0
- package/dist/part-catalog.js.map +1 -0
- package/dist/part-number.d.ts +32 -0
- package/dist/part-number.d.ts.map +1 -0
- package/dist/part-number.js +80 -0
- package/dist/part-number.js.map +1 -0
- package/dist/partition.d.ts +7 -0
- package/dist/partition.d.ts.map +1 -0
- package/dist/partition.js +242 -0
- package/dist/partition.js.map +1 -0
- package/dist/port-full-scale.d.ts +70 -0
- package/dist/port-full-scale.d.ts.map +1 -0
- package/dist/port-full-scale.js +235 -0
- package/dist/port-full-scale.js.map +1 -0
- package/dist/pot-orientation.d.ts +114 -0
- package/dist/pot-orientation.d.ts.map +1 -0
- package/dist/pot-orientation.js +551 -0
- package/dist/pot-orientation.js.map +1 -0
- package/dist/power-domain-control.d.ts +40 -0
- package/dist/power-domain-control.d.ts.map +1 -0
- package/dist/power-domain-control.js +142 -0
- package/dist/power-domain-control.js.map +1 -0
- package/dist/proxy-declaration.d.ts +121 -0
- package/dist/proxy-declaration.d.ts.map +1 -0
- package/dist/proxy-declaration.js +50 -0
- package/dist/proxy-declaration.js.map +1 -0
- package/dist/registry.d.ts +323 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +192 -0
- package/dist/registry.js.map +1 -0
- package/dist/sparse-schedule.d.ts +65 -0
- package/dist/sparse-schedule.d.ts.map +1 -0
- package/dist/sparse-schedule.js +421 -0
- package/dist/sparse-schedule.js.map +1 -0
- package/dist/speaker-load.d.ts +38 -0
- package/dist/speaker-load.d.ts.map +1 -0
- package/dist/speaker-load.js +97 -0
- package/dist/speaker-load.js.map +1 -0
- package/dist/stage-coverage.d.ts +21 -0
- package/dist/stage-coverage.d.ts.map +1 -0
- package/dist/stage-coverage.js +124 -0
- package/dist/stage-coverage.js.map +1 -0
- package/dist/stamp-partition.d.ts +314 -0
- package/dist/stamp-partition.d.ts.map +1 -0
- package/dist/stamp-partition.js +472 -0
- package/dist/stamp-partition.js.map +1 -0
- package/dist/supply-reference.d.ts +19 -0
- package/dist/supply-reference.d.ts.map +1 -0
- package/dist/supply-reference.js +66 -0
- package/dist/supply-reference.js.map +1 -0
- package/dist/supply-short.d.ts +32 -0
- package/dist/supply-short.d.ts.map +1 -0
- package/dist/supply-short.js +118 -0
- package/dist/supply-short.js.map +1 -0
- package/dist/supply-stamps.d.ts +51 -0
- package/dist/supply-stamps.d.ts.map +1 -0
- package/dist/supply-stamps.js +363 -0
- package/dist/supply-stamps.js.map +1 -0
- package/dist/terminal-role.d.ts +109 -0
- package/dist/terminal-role.d.ts.map +1 -0
- package/dist/terminal-role.js +46 -0
- package/dist/terminal-role.js.map +1 -0
- package/dist/terminal-roles.d.ts +59 -0
- package/dist/terminal-roles.d.ts.map +1 -0
- package/dist/terminal-roles.js +92 -0
- package/dist/terminal-roles.js.map +1 -0
- package/dist/transformer.d.ts +181 -0
- package/dist/transformer.d.ts.map +1 -0
- package/dist/transformer.js +476 -0
- package/dist/transformer.js.map +1 -0
- package/dist/types.d.ts +3157 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +11 -0
- package/dist/types.js.map +1 -0
- package/dist/unbounded-operating-point.d.ts +35 -0
- package/dist/unbounded-operating-point.d.ts.map +1 -0
- package/dist/unbounded-operating-point.js +181 -0
- package/dist/unbounded-operating-point.js.map +1 -0
- package/dist/unexecuted-region.d.ts +3 -0
- package/dist/unexecuted-region.d.ts.map +1 -0
- package/dist/unexecuted-region.js +122 -0
- package/dist/unexecuted-region.js.map +1 -0
- package/dist/unimplemented-control-role.d.ts +3 -0
- package/dist/unimplemented-control-role.d.ts.map +1 -0
- package/dist/unimplemented-control-role.js +61 -0
- package/dist/unimplemented-control-role.js.map +1 -0
- package/dist/unreachable-output.d.ts +3 -0
- package/dist/unreachable-output.d.ts.map +1 -0
- package/dist/unreachable-output.js +97 -0
- package/dist/unreachable-output.js.map +1 -0
- package/dist/unreadable-terminal-role.d.ts +67 -0
- package/dist/unreadable-terminal-role.d.ts.map +1 -0
- package/dist/unreadable-terminal-role.js +409 -0
- package/dist/unreadable-terminal-role.js.map +1 -0
- package/dist/unverified-pinout.d.ts +27 -0
- package/dist/unverified-pinout.d.ts.map +1 -0
- package/dist/unverified-pinout.js +121 -0
- package/dist/unverified-pinout.js.map +1 -0
- package/package.json +75 -5
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
import { stampAuxRows, stampNodeValue, stampShape, } from "./stamp-partition.js";
|
|
2
|
+
/**
|
|
3
|
+
* Every matrix entry a stamp can write, over-approximated as the full square over the stamp's
|
|
4
|
+
* own terminals.
|
|
5
|
+
*
|
|
6
|
+
* Read off the shape table in `stamp-partition.ts` rather than restated here. `terminalNodes`
|
|
7
|
+
* lets a kind narrow the set -- only `vccs` does, to its output pair -- and `terminalsDropGround`
|
|
8
|
+
* lets it drop ground, which `vccs` also does and nothing else may, because `schedulePattern`
|
|
9
|
+
* removes row 0 globally but keeps column 0.
|
|
10
|
+
*
|
|
11
|
+
* Order is not significant: the caller expands these into every (row, column) pair and collects
|
|
12
|
+
* them in a `Set`.
|
|
13
|
+
*/
|
|
14
|
+
export function stampTerminals(stamp, nodeCount) {
|
|
15
|
+
const shape = stampShape(stamp);
|
|
16
|
+
const fields = shape.terminalNodes ?? shape.nodes;
|
|
17
|
+
const rows = [
|
|
18
|
+
...stampAuxRows(stamp, nodeCount),
|
|
19
|
+
...fields.map((field) => stampNodeValue(stamp, field)),
|
|
20
|
+
];
|
|
21
|
+
return shape.terminalsDropGround ? rows.filter((row) => row !== 0) : rows;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Entries that are provably nonzero at every control position and every Newton iterate,
|
|
25
|
+
* and are therefore the only ones allowed to be pivots.
|
|
26
|
+
*
|
|
27
|
+
* **Two conditions, and both are load-bearing. An entry belongs here only when the stamp
|
|
28
|
+
* writes it (a) in the direction being claimed and (b) on every iterate.** Marking an entry
|
|
29
|
+
* the stamp leaves zero does not produce a wrong answer -- the runtime's pivot guard catches
|
|
30
|
+
* the collapse and re-solves densely -- but it produces a *silently dense* block, which is
|
|
31
|
+
* worse than a slow one because nothing reports it. Measured 2026-09-18 on the shipping
|
|
32
|
+
* console: `boss-ch-1` gave its schedule up inside `prepare()` and ran 100x100 dense for the
|
|
33
|
+
* whole session (12.8x real time), `boss-ce-5` tripped the guard on half its iterations and
|
|
34
|
+
* paid for the schedule *and* the dense solve (6.6x), and `boss-ce-2`, `boss-ce-2b`,
|
|
35
|
+
* `boss-dm-2` and `boss-dd-3b` abandoned within their first 64 audio iterations. Every one of
|
|
36
|
+
* those traced back to an entry marked here that the owning stamp cannot guarantee. See
|
|
37
|
+
* `thoughts/shared/2026-09-18-sparse-schedule-runtime-audit.md`.
|
|
38
|
+
*
|
|
39
|
+
* So `pair()` is for symmetric writes only. A stamp that writes `matrix[row][column]` and not
|
|
40
|
+
* its transpose -- every controlled-source coupling in this file's device set does exactly
|
|
41
|
+
* that -- marks the one entry with `eligible.add`, or marks nothing when the value can vanish.
|
|
42
|
+
*
|
|
43
|
+
* **What this does NOT establish is that an eligible pivot is numerically usable.** Every node
|
|
44
|
+
* diagonal is listed below because the runtime adds `gmin` to it, which is true and nearly
|
|
45
|
+
* useless: a pivot of 1e-12 against entries of order 1e2 is a growth factor of 1e14, and dense
|
|
46
|
+
* partial pivoting would never choose it. That is a separate, open defect (`boss-aw-2` fails to
|
|
47
|
+
* converge on the sparse path and converges in four iterations densely), and it cannot be fixed
|
|
48
|
+
* from the pattern alone -- it needs the pivot search to see magnitudes. Recorded in §6 of the
|
|
49
|
+
* audit above.
|
|
50
|
+
*/
|
|
51
|
+
export function provablyNonzeroEntries(block, size) {
|
|
52
|
+
const eligible = new Set();
|
|
53
|
+
for (let node = 0; node < block.nodeCount; node += 1) {
|
|
54
|
+
eligible.add(node * size + node);
|
|
55
|
+
}
|
|
56
|
+
/** For entries a stamp writes in BOTH directions on every iterate, and only those. */
|
|
57
|
+
const pair = (row, column) => {
|
|
58
|
+
eligible.add(row * size + column);
|
|
59
|
+
eligible.add(column * size + row);
|
|
60
|
+
};
|
|
61
|
+
const auxRow = (sourceIndex, offset = 0) => block.nodeCount + sourceIndex + offset;
|
|
62
|
+
for (const stamp of block.stamps) {
|
|
63
|
+
switch (stamp.kind) {
|
|
64
|
+
// **The three by-inspection cases, and they were the largest omission.** A resistor's
|
|
65
|
+
// conductance is `g > 0` at every control position and every iterate; a capacitor's
|
|
66
|
+
// trapezoidal companion is `2C/dt`; an inductor's is `dt/2L` (scaled by `1/(1+Rk)`
|
|
67
|
+
// when a winding resistance is declared, which is still strictly positive). None can
|
|
68
|
+
// vanish, so all four entries of each pair are provable by inspection rather than by
|
|
69
|
+
// analysis.
|
|
70
|
+
//
|
|
71
|
+
// Their absence is why ~74% of every packet's pivot candidates read as "unproven" --
|
|
72
|
+
// 407 of 544 on `mxr-carbon-copy` and **185 of 268 on healthy `marshall-jtm45`** --
|
|
73
|
+
// which left Markowitz choosing from a quarter of its real options everywhere, and
|
|
74
|
+
// forced 10 unproven pivots on carbon-copy that then failed 144,188 times.
|
|
75
|
+
case "conductance":
|
|
76
|
+
case "capacitor":
|
|
77
|
+
case "inductor": {
|
|
78
|
+
const { a, b } = stamp;
|
|
79
|
+
if (a === b) {
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
pair(a, a);
|
|
83
|
+
pair(b, b);
|
|
84
|
+
pair(a, b);
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
case "dc-source":
|
|
88
|
+
case "ac-source": {
|
|
89
|
+
if (stamp.positive === stamp.negative) {
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
const row = auxRow(stamp.sourceIndex);
|
|
93
|
+
pair(row, stamp.positive);
|
|
94
|
+
pair(row, stamp.negative);
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
case "logic-divider": {
|
|
98
|
+
if (stamp.qNode === stamp.gndNode) {
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
const row = auxRow(stamp.sourceIndex);
|
|
102
|
+
pair(row, stamp.qNode);
|
|
103
|
+
pair(row, stamp.gndNode);
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
case "analog-switch": {
|
|
107
|
+
// **The channel only.** `g = gOff + (gOn - gOff) * sigmoid` is bounded below by
|
|
108
|
+
// `gOff = 1/offOhms > 0` at every control voltage, and `stampConductance` writes
|
|
109
|
+
// all four of its cells, so the channel pair is provable.
|
|
110
|
+
//
|
|
111
|
+
// The gate couplings are not, on both counts. `coupling = dg/dvCtrl * (vA - vB)`
|
|
112
|
+
// is written into `matrix[a][control]` and `matrix[b][control]` and **never their
|
|
113
|
+
// transposes**, and it is exactly zero twice over: the sigmoid derivative
|
|
114
|
+
// underflows once the gate is more than ~8 V past threshold (which is where a
|
|
115
|
+
// CMOS switch spends all of its time), and `vA - vB` is zero across a closed
|
|
116
|
+
// switch feeding a settled node. `boss-dd-3b` pivoted on `(node23, node6)` and
|
|
117
|
+
// abandoned its schedule 27 iterations into the operating point.
|
|
118
|
+
if (stamp.a !== stamp.b) {
|
|
119
|
+
pair(stamp.a, stamp.b);
|
|
120
|
+
}
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
case "compandor": {
|
|
124
|
+
// **Nothing is provable here.** `(sumNode, cellIn)` carries `-gCell`, where
|
|
125
|
+
// `gCell` is the *envelope* state: zero until the rectifier's capacitor has
|
|
126
|
+
// charged, which on a fresh `prepare()` is every iterate of the operating point
|
|
127
|
+
// and the first few hundred samples after it. It is also written one way only.
|
|
128
|
+
// `mxr-carbon-copy` and `electro-harmonix-deluxe-memory-man` carry two of these
|
|
129
|
+
// each on their dominant block.
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
case "clock-driver": {
|
|
133
|
+
// **The phase rows and their own diagonals; NOT the supply couplings.**
|
|
134
|
+
//
|
|
135
|
+
// Each phase row is an ideal source row for one output pin: `matrix[row][cpN] +=
|
|
136
|
+
// 1`, `matrix[cpN][row] += 1`, `matrix[row][row] -= 1`. All three are
|
|
137
|
+
// unconditional, the first two are symmetric, and an aux row belongs to exactly
|
|
138
|
+
// one stamp, so nothing else can cancel the -1 on its diagonal. That diagonal is
|
|
139
|
+
// the best pivot in the block and was previously not listed at all.
|
|
140
|
+
//
|
|
141
|
+
// The supply couplings are the opposite of provable. `couple(theta < 0.5 ? vdd :
|
|
142
|
+
// gnd, row1, 1.0)` writes ONE of the two pins per iterate, into `matrix[row][pin]`
|
|
143
|
+
// and never the transpose. Both were listed, so at any instant at least half of
|
|
144
|
+
// what was marked was zero, and the alternation guaranteed that a pivot chosen on
|
|
145
|
+
// one phase collapsed on the next. This is what `boss-ch-1` (aux10, node2),
|
|
146
|
+
// `boss-ce-5` (aux4, node1), `boss-ce-2` (node2, aux5 -- a transpose that no
|
|
147
|
+
// stamp ever writes) and `boss-dm-2` (node1, aux7) each pivoted on.
|
|
148
|
+
//
|
|
149
|
+
// The *pattern* still needs both pins, and still has them: `stampTerminals` reads
|
|
150
|
+
// the shape table, which is a different question from what may be a pivot. The
|
|
151
|
+
// bug the old comment here describes -- a pattern missing a cell the stamp writes
|
|
152
|
+
// -- is real and is not this set's job to prevent.
|
|
153
|
+
const row1 = auxRow(stamp.sourceIndex);
|
|
154
|
+
pair(row1, stamp.cp1);
|
|
155
|
+
eligible.add(row1 * size + row1);
|
|
156
|
+
const row2 = auxRow(stamp.sourceIndex, 1);
|
|
157
|
+
pair(row2, stamp.cp2);
|
|
158
|
+
eligible.add(row2 * size + row2);
|
|
159
|
+
const row3 = auxRow(stamp.sourceIndex, 2);
|
|
160
|
+
pair(row3, stamp.vgg);
|
|
161
|
+
eligible.add(row3 * size + row3);
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
case "comparator": {
|
|
165
|
+
// **The pull-down only.** `gCell = gOn * sigma + gOff` is bounded below by
|
|
166
|
+
// `gOff = 1/floatOhms > 0` and goes through `stampConductance`, so it is
|
|
167
|
+
// symmetric and cannot vanish.
|
|
168
|
+
//
|
|
169
|
+
// The input couplings carry `gControl = gOn * dsigma * (vOut - vVee)`, written
|
|
170
|
+
// into the output and vee rows only, never the transpose, and zero whenever the
|
|
171
|
+
// comparator is saturated -- which for a comparator is its entire working life,
|
|
172
|
+
// the linear band being a few millivolts wide. `moogerfooger-mf-102` carries four.
|
|
173
|
+
if (stamp.output !== stamp.vee) {
|
|
174
|
+
pair(stamp.output, stamp.vee);
|
|
175
|
+
}
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
case "transformer": {
|
|
179
|
+
const nodes = [
|
|
180
|
+
stamp.primaryPlus,
|
|
181
|
+
stamp.primaryMinus,
|
|
182
|
+
stamp.secondaryPlus,
|
|
183
|
+
stamp.secondaryMinus,
|
|
184
|
+
];
|
|
185
|
+
if (new Set(nodes).size !== 4) {
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
const row = block.nodeCount + stamp.sourceIndex;
|
|
189
|
+
pair(row, stamp.primaryPlus);
|
|
190
|
+
pair(row, stamp.primaryMinus);
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
case "input-source":
|
|
194
|
+
case "macro-audio-source":
|
|
195
|
+
pair(auxRow(stamp.sourceIndex), stamp.node);
|
|
196
|
+
break;
|
|
197
|
+
case "ideal-opamp":
|
|
198
|
+
eligible.add(stamp.output * size + auxRow(stamp.sourceIndex));
|
|
199
|
+
break;
|
|
200
|
+
case "vccs": {
|
|
201
|
+
const gm = stamp.transconductance;
|
|
202
|
+
if (gm !== 0) {
|
|
203
|
+
if (stamp.outP !== 0) {
|
|
204
|
+
if (stamp.inP !== 0)
|
|
205
|
+
eligible.add(stamp.outP * size + stamp.inP);
|
|
206
|
+
if (stamp.inN !== 0)
|
|
207
|
+
eligible.add(stamp.outP * size + stamp.inN);
|
|
208
|
+
}
|
|
209
|
+
if (stamp.outN !== 0) {
|
|
210
|
+
if (stamp.inP !== 0)
|
|
211
|
+
eligible.add(stamp.outN * size + stamp.inP);
|
|
212
|
+
if (stamp.inN !== 0)
|
|
213
|
+
eligible.add(stamp.outN * size + stamp.inN);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
case "ota": {
|
|
219
|
+
if (stamp.bias !== stamp.vee) {
|
|
220
|
+
pair(stamp.bias, stamp.vee);
|
|
221
|
+
}
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
default:
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return eligible;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* The block's structural pattern: every entry any stamp can write, plus the gmin diagonals,
|
|
232
|
+
* with ground-pin overwrite applied.
|
|
233
|
+
*/
|
|
234
|
+
export function schedulePattern(block, size) {
|
|
235
|
+
const pattern = new Set();
|
|
236
|
+
for (const stamp of block.stamps) {
|
|
237
|
+
const terminals = stampTerminals(stamp, block.nodeCount);
|
|
238
|
+
for (const row of terminals) {
|
|
239
|
+
for (const column of terminals) {
|
|
240
|
+
pattern.add(row * size + column);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
for (let node = 1; node < block.nodeCount; node += 1) {
|
|
245
|
+
pattern.add(node * size + node);
|
|
246
|
+
}
|
|
247
|
+
for (let column = 0; column < size; column += 1) {
|
|
248
|
+
pattern.delete(column);
|
|
249
|
+
}
|
|
250
|
+
pattern.add(0);
|
|
251
|
+
return pattern;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Work out the elimination order and emit its opcode stream.
|
|
255
|
+
*
|
|
256
|
+
* Returns null when the pattern cannot be eliminated at all (a structurally singular block).
|
|
257
|
+
*/
|
|
258
|
+
export function computeSparseSchedule(block) {
|
|
259
|
+
const size = block.nodeCount + block.auxCount;
|
|
260
|
+
if (size === 0) {
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
const pattern = schedulePattern(block, size);
|
|
264
|
+
const eligible = provablyNonzeroEntries(block, size);
|
|
265
|
+
const rows = Array.from({ length: size }, () => new Set());
|
|
266
|
+
const columns = Array.from({ length: size }, () => new Set());
|
|
267
|
+
for (const key of pattern) {
|
|
268
|
+
const row = Math.floor(key / size);
|
|
269
|
+
rows[row]?.add(key % size);
|
|
270
|
+
columns[key % size]?.add(row);
|
|
271
|
+
}
|
|
272
|
+
const doneRow = new Set();
|
|
273
|
+
const doneColumn = new Set();
|
|
274
|
+
const pivots = [];
|
|
275
|
+
let unprovenPivots = 0;
|
|
276
|
+
for (let step = 0; step < size; step += 1) {
|
|
277
|
+
let bestRow = -1;
|
|
278
|
+
let bestColumn = -1;
|
|
279
|
+
let bestKey = Infinity;
|
|
280
|
+
let bestProven = false;
|
|
281
|
+
for (let row = 0; row < size; row += 1) {
|
|
282
|
+
if (doneRow.has(row)) {
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
let rowCount = 0;
|
|
286
|
+
for (const column of rows[row]) {
|
|
287
|
+
if (!doneColumn.has(column)) {
|
|
288
|
+
rowCount += 1;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (rowCount === 0) {
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
for (const column of rows[row]) {
|
|
295
|
+
if (doneColumn.has(column)) {
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
let columnCount = 0;
|
|
299
|
+
for (const other of columns[column]) {
|
|
300
|
+
if (!doneRow.has(other)) {
|
|
301
|
+
columnCount += 1;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
const key = (rowCount - 1) * (columnCount - 1) * 2 + (row === column ? 0 : 1);
|
|
305
|
+
const proven = eligible.has(row * size + column);
|
|
306
|
+
if (proven && !bestProven) {
|
|
307
|
+
bestProven = true;
|
|
308
|
+
bestKey = key;
|
|
309
|
+
bestRow = row;
|
|
310
|
+
bestColumn = column;
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
if (!proven && bestProven) {
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
if (key < bestKey) {
|
|
317
|
+
bestKey = key;
|
|
318
|
+
bestRow = row;
|
|
319
|
+
bestColumn = column;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if (bestRow < 0) {
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
if (!bestProven) {
|
|
327
|
+
unprovenPivots += 1;
|
|
328
|
+
}
|
|
329
|
+
const pivotRow = [...rows[bestRow]].filter((column) => !doneColumn.has(column) && column !== bestColumn);
|
|
330
|
+
const pivotColumn = [...columns[bestColumn]].filter((row) => !doneRow.has(row) && row !== bestRow);
|
|
331
|
+
for (const row of pivotColumn) {
|
|
332
|
+
for (const column of pivotRow) {
|
|
333
|
+
if (!rows[row].has(column)) {
|
|
334
|
+
rows[row]?.add(column);
|
|
335
|
+
columns[column]?.add(row);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
pivots.push({ row: bestRow, column: bestColumn });
|
|
340
|
+
doneRow.add(bestRow);
|
|
341
|
+
doneColumn.add(bestColumn);
|
|
342
|
+
}
|
|
343
|
+
if (pivots.length !== size) {
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
const slotOf = new Map();
|
|
347
|
+
const gatherRow = [];
|
|
348
|
+
const gatherColumn = [];
|
|
349
|
+
for (let row = 0; row < size; row += 1) {
|
|
350
|
+
for (const column of rows[row]) {
|
|
351
|
+
slotOf.set(row * size + column, gatherRow.length);
|
|
352
|
+
gatherRow.push(row);
|
|
353
|
+
gatherColumn.push(column);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
const slot = (row, column) => {
|
|
357
|
+
const found = slotOf.get(row * size + column);
|
|
358
|
+
if (found === undefined) {
|
|
359
|
+
throw new Error(`sparse schedule has no slot for entry (${row}, ${column})`);
|
|
360
|
+
}
|
|
361
|
+
return found;
|
|
362
|
+
};
|
|
363
|
+
const liveRows = Array.from({ length: size }, () => new Set());
|
|
364
|
+
const liveColumns = Array.from({ length: size }, () => new Set());
|
|
365
|
+
for (const key of pattern) {
|
|
366
|
+
const row = Math.floor(key / size);
|
|
367
|
+
liveRows[row]?.add(key % size);
|
|
368
|
+
liveColumns[key % size]?.add(row);
|
|
369
|
+
}
|
|
370
|
+
const eliminatedRow = new Set();
|
|
371
|
+
const eliminatedColumn = new Set();
|
|
372
|
+
const ops = [];
|
|
373
|
+
let factorCount = 0;
|
|
374
|
+
let sparseOps = 0;
|
|
375
|
+
for (const pivot of pivots) {
|
|
376
|
+
ops.push(6, slot(pivot.row, pivot.column), 0, 0);
|
|
377
|
+
const pivotRow = [...liveRows[pivot.row]].filter((column) => !eliminatedColumn.has(column) && column !== pivot.column);
|
|
378
|
+
const pivotColumn = [...liveColumns[pivot.column]].filter((row) => !eliminatedRow.has(row) && row !== pivot.row);
|
|
379
|
+
for (const row of pivotColumn) {
|
|
380
|
+
const factor = factorCount;
|
|
381
|
+
factorCount += 1;
|
|
382
|
+
ops.push(0, factor, slot(row, pivot.column), slot(pivot.row, pivot.column));
|
|
383
|
+
for (const column of pivotRow) {
|
|
384
|
+
if (!liveRows[row].has(column)) {
|
|
385
|
+
liveRows[row]?.add(column);
|
|
386
|
+
liveColumns[column]?.add(row);
|
|
387
|
+
}
|
|
388
|
+
ops.push(1, slot(row, column), factor, slot(pivot.row, column));
|
|
389
|
+
sparseOps += 1;
|
|
390
|
+
}
|
|
391
|
+
ops.push(2, row, factor, pivot.row);
|
|
392
|
+
sparseOps += 1;
|
|
393
|
+
}
|
|
394
|
+
eliminatedRow.add(pivot.row);
|
|
395
|
+
eliminatedColumn.add(pivot.column);
|
|
396
|
+
}
|
|
397
|
+
for (let step = pivots.length - 1; step >= 0; step -= 1) {
|
|
398
|
+
const pivot = pivots[step];
|
|
399
|
+
ops.push(3, pivot.row, 0, 0);
|
|
400
|
+
for (let later = step + 1; later < pivots.length; later += 1) {
|
|
401
|
+
const column = pivots[later].column;
|
|
402
|
+
if (liveRows[pivot.row].has(column)) {
|
|
403
|
+
ops.push(4, slot(pivot.row, column), column, 0);
|
|
404
|
+
sparseOps += 1;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
ops.push(5, pivot.column, slot(pivot.row, pivot.column), 0);
|
|
408
|
+
}
|
|
409
|
+
return {
|
|
410
|
+
ops,
|
|
411
|
+
slots: gatherRow.length,
|
|
412
|
+
factorCount,
|
|
413
|
+
gatherRow,
|
|
414
|
+
gatherColumn,
|
|
415
|
+
size,
|
|
416
|
+
sparseOps,
|
|
417
|
+
denseOps: (size * size * size - size) / 3,
|
|
418
|
+
unprovenPivots,
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
//# sourceMappingURL=sparse-schedule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sparse-schedule.js","sourceRoot":"","sources":["../src/sparse-schedule.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export type SpeakerOnePort = {
|
|
2
|
+
readonly reOhms: number;
|
|
3
|
+
readonly leHenries: number;
|
|
4
|
+
readonly motionalOhms: number;
|
|
5
|
+
readonly motionalHenries: number;
|
|
6
|
+
readonly motionalFarads: number;
|
|
7
|
+
/** What the whole network was scaled by, for the warning to quote. */
|
|
8
|
+
readonly nominalOhms: number;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* The generic driver's one-port, impedance-scaled to a declared nominal impedance.
|
|
12
|
+
*
|
|
13
|
+
* A 16 ohm driver is not a different curve from an 8 ohm one, it is the same curve twice as high:
|
|
14
|
+
* scaling `Re`, `Rmot` and `Lmot` by `k` and dividing `Cmot` by `k` multiplies the impedance by `k`
|
|
15
|
+
* at every frequency and leaves the resonance and its Q exactly where they were. That is exact for
|
|
16
|
+
* the electrical one-port, which is what makes one seed profile usable for the corpus's 8 and 16
|
|
17
|
+
* ohm jacks without inventing a second driver.
|
|
18
|
+
*/
|
|
19
|
+
export declare function speakerOnePort(nominalOhms: number): SpeakerOnePort;
|
|
20
|
+
/**
|
|
21
|
+
* `Z` of the one-port at a frequency, complex.
|
|
22
|
+
*
|
|
23
|
+
* Series `Re + jwLe`, then the three motional elements in parallel. Kept here beside the element
|
|
24
|
+
* values so a check cannot drift from the thing it checks.
|
|
25
|
+
*
|
|
26
|
+
* **Complex, not a magnitude, because a divider needs the phase.** Reflecting this through a
|
|
27
|
+
* transformer and dividing against a power stage's output impedance with magnitudes alone is wrong
|
|
28
|
+
* wherever the load is reactive: measured on `report-speaker-load.ts`'s fixture, a scalar divider
|
|
29
|
+
* agrees at resonance and at the impedance minimum -- both nearly real -- and is 14.7% off at 5 kHz,
|
|
30
|
+
* where the voice-coil inductance dominates.
|
|
31
|
+
*/
|
|
32
|
+
export declare function speakerImpedance(port: SpeakerOnePort, frequencyHz: number): {
|
|
33
|
+
readonly re: number;
|
|
34
|
+
readonly im: number;
|
|
35
|
+
};
|
|
36
|
+
/** `|Z|` of the one-port, from {@link speakerImpedance}. */
|
|
37
|
+
export declare function speakerImpedanceMagnitude(port: SpeakerOnePort, frequencyHz: number): number;
|
|
38
|
+
//# sourceMappingURL=speaker-load.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"speaker-load.d.ts","sourceRoot":"","sources":["../src/speaker-load.ts"],"names":[],"mappings":"AA+CA,MAAM,MAAM,cAAc,GAAG;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,sEAAsE;IACtE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,cAAc,CAclE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAC/B,IAAI,EAAE,cAAc,EACpB,WAAW,EAAE,MAAM,GACjB;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAU9C;AAED,4DAA4D;AAC5D,wBAAgB,yBAAyB,CACxC,IAAI,EAAE,cAAc,EACpB,WAAW,EAAE,MAAM,GACjB,MAAM,CAGR"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Stage B: a speaker as a linear one-port, instead of a resistor.
|
|
2
|
+
//
|
|
3
|
+
// Stage A terminated an output transformer's secondary with the jack's declared nominal impedance,
|
|
4
|
+
// which made the plate load line real. A real driver is not a resistor: its impedance rises to a
|
|
5
|
+
// peak at cone resonance and climbs again with voice-coil inductance, and the power tubes see that
|
|
6
|
+
// curve rather than a flat 8 or 16 ohms.
|
|
7
|
+
//
|
|
8
|
+
// The standard linear equivalent, and the one `speakerThieleSmallSpiceReferenceDeck()` already
|
|
9
|
+
// emits so its curve is the acceptance test:
|
|
10
|
+
//
|
|
11
|
+
// Re --- Le --- ( Rmot || Lmot || Cmot ) --- return
|
|
12
|
+
//
|
|
13
|
+
// Rmot = Bl^2 / Rms Cmot = Mms / Bl^2 Lmot = Cms * Bl^2 Rms = 2*pi*fs*Mms / Qms
|
|
14
|
+
//
|
|
15
|
+
// Five plain elements over two extra nodes. No new operator, no Newton cost -- every one of them is
|
|
16
|
+
// linear, and the v2 runtime already stamps resistors, inductors and capacitors.
|
|
17
|
+
//
|
|
18
|
+
// **This is a generic driver, never a named one, and that is a deliberate decision rather than a
|
|
19
|
+
// shortcut.** No corpus packet identifies its driver in a form that resolves: the five that §5
|
|
20
|
+
// credits with driver identity all declare prose (`SpeakerModel: "Celestion T4437"`, `SpeakerSet:
|
|
21
|
+
// "two 8 ohm 12 inch speakers in parallel"`). Matching the first to a `celestion-blue-alnico-8`
|
|
22
|
+
// profile is a name inference this pipeline forbids, and the other two name no driver at all. So
|
|
23
|
+
// the choice is a generic profile or no Stage B, and every application of it carries a
|
|
24
|
+
// `generic-speaker-profile` warning naming the jack, so a render can never be quoted as *this
|
|
25
|
+
// amp's* speaker.
|
|
26
|
+
//
|
|
27
|
+
// The numbers below are the `celestion-vintage-30-8` seed from
|
|
28
|
+
// `src/web/assets/cab-mic-profiles.vdsp`, which v1 names as its own default profile. Transcribed
|
|
29
|
+
// rather than imported, because the v2 compiler may not read `src/web` -- the same reason
|
|
30
|
+
// `GENERIC_TRIODE` holds a 12AX7 fit as data here. Its own record states
|
|
31
|
+
// `sourceConfidence: official-basic-aggregate-physical-seed` and says the full T-S row is a
|
|
32
|
+
// "non-factory consensus seed for runtime-load development, not a promotion-grade exact driver
|
|
33
|
+
// revision claim". That bound travels with anything this produces: it is the *shape* of a real
|
|
34
|
+
// driver's impedance, not a measurement of one.
|
|
35
|
+
/** The one generic driver, as its source states it. 8 ohm nominal. */
|
|
36
|
+
const GENERIC_DRIVER = {
|
|
37
|
+
nominalOhms: 8,
|
|
38
|
+
reOhms: 7.3,
|
|
39
|
+
leHenries: 0.00045,
|
|
40
|
+
fsHz: 75,
|
|
41
|
+
qms: 4.88,
|
|
42
|
+
mmsKg: 0.0331,
|
|
43
|
+
cmsMetersPerNewton: 0.00013604724221864757,
|
|
44
|
+
blTeslaMeters: 13.1,
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* The generic driver's one-port, impedance-scaled to a declared nominal impedance.
|
|
48
|
+
*
|
|
49
|
+
* A 16 ohm driver is not a different curve from an 8 ohm one, it is the same curve twice as high:
|
|
50
|
+
* scaling `Re`, `Rmot` and `Lmot` by `k` and dividing `Cmot` by `k` multiplies the impedance by `k`
|
|
51
|
+
* at every frequency and leaves the resonance and its Q exactly where they were. That is exact for
|
|
52
|
+
* the electrical one-port, which is what makes one seed profile usable for the corpus's 8 and 16
|
|
53
|
+
* ohm jacks without inventing a second driver.
|
|
54
|
+
*/
|
|
55
|
+
export function speakerOnePort(nominalOhms) {
|
|
56
|
+
const k = nominalOhms / GENERIC_DRIVER.nominalOhms;
|
|
57
|
+
const rms = (2 * Math.PI * GENERIC_DRIVER.fsHz * GENERIC_DRIVER.mmsKg) /
|
|
58
|
+
GENERIC_DRIVER.qms;
|
|
59
|
+
const motor = GENERIC_DRIVER.blTeslaMeters * GENERIC_DRIVER.blTeslaMeters;
|
|
60
|
+
return {
|
|
61
|
+
reOhms: GENERIC_DRIVER.reOhms * k,
|
|
62
|
+
leHenries: GENERIC_DRIVER.leHenries * k,
|
|
63
|
+
motionalOhms: (motor / rms) * k,
|
|
64
|
+
motionalHenries: GENERIC_DRIVER.cmsMetersPerNewton * motor * k,
|
|
65
|
+
motionalFarads: GENERIC_DRIVER.mmsKg / motor / k,
|
|
66
|
+
nominalOhms,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* `Z` of the one-port at a frequency, complex.
|
|
71
|
+
*
|
|
72
|
+
* Series `Re + jwLe`, then the three motional elements in parallel. Kept here beside the element
|
|
73
|
+
* values so a check cannot drift from the thing it checks.
|
|
74
|
+
*
|
|
75
|
+
* **Complex, not a magnitude, because a divider needs the phase.** Reflecting this through a
|
|
76
|
+
* transformer and dividing against a power stage's output impedance with magnitudes alone is wrong
|
|
77
|
+
* wherever the load is reactive: measured on `report-speaker-load.ts`'s fixture, a scalar divider
|
|
78
|
+
* agrees at resonance and at the impedance minimum -- both nearly real -- and is 14.7% off at 5 kHz,
|
|
79
|
+
* where the voice-coil inductance dominates.
|
|
80
|
+
*/
|
|
81
|
+
export function speakerImpedance(port, frequencyHz) {
|
|
82
|
+
const w = 2 * Math.PI * frequencyHz;
|
|
83
|
+
const gr = 1 / port.motionalOhms;
|
|
84
|
+
const bl = w === 0 ? Number.POSITIVE_INFINITY : -1 / (w * port.motionalHenries);
|
|
85
|
+
const bc = w * port.motionalFarads;
|
|
86
|
+
const b = bl === Number.POSITIVE_INFINITY ? Number.POSITIVE_INFINITY : bl + bc;
|
|
87
|
+
const denom = gr * gr + b * b;
|
|
88
|
+
const zr = denom === 0 || !Number.isFinite(b) ? 0 : gr / denom;
|
|
89
|
+
const zi = denom === 0 || !Number.isFinite(b) ? 0 : -b / denom;
|
|
90
|
+
return { re: port.reOhms + zr, im: w * port.leHenries + zi };
|
|
91
|
+
}
|
|
92
|
+
/** `|Z|` of the one-port, from {@link speakerImpedance}. */
|
|
93
|
+
export function speakerImpedanceMagnitude(port, frequencyHz) {
|
|
94
|
+
const z = speakerImpedance(port, frequencyHz);
|
|
95
|
+
return Math.hypot(z.re, z.im);
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=speaker-load.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"speaker-load.js","sourceRoot":"","sources":["../src/speaker-load.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type Block, type Ports, type Program } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Read from the lowered stamps, the same discipline as `supply-reference.ts` and
|
|
4
|
+
* `port-full-scale.ts`.
|
|
5
|
+
*
|
|
6
|
+
* The distinctions available from a program, and nothing finer:
|
|
7
|
+
*
|
|
8
|
+
* - `speaker-electrical` — the output port sits on a winding of a transformer declaring a `ratio`,
|
|
9
|
+
* so it *is* the speaker terminal. **Position, not load quality**: whether a speaker is
|
|
10
|
+
* modelled across it is a different question, answered by Stage A of the output-stage plan and
|
|
11
|
+
* its §4.6 table. An earlier draft here split this by "is something resistive across the node",
|
|
12
|
+
* and `fender-bassman` showed why that fails -- a 27 kOhm network element sits on its secondary
|
|
13
|
+
* and no test at this stage can tell that from an 8 Ohm driver without guessing from magnitude.
|
|
14
|
+
* - `preamp` — no output transformer at all, but the program declares a high-voltage supply
|
|
15
|
+
* winding (`voltsHv`), which only an amp has. `mesa-boogie-mark-v` lands here: its packet hands
|
|
16
|
+
* the transformer and speaker to a companion fixture, so its render is a preamp level.
|
|
17
|
+
* - `instrument` — everything else, which is every pedal: a pedal does not claim to be further
|
|
18
|
+
* along the chain than the instrument feeding it.
|
|
19
|
+
*/
|
|
20
|
+
export declare function stageCoverage(blocks: readonly Block[], ports: Ports): Program["stageCoverage"];
|
|
21
|
+
//# sourceMappingURL=stage-coverage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stage-coverage.d.ts","sourceRoot":"","sources":["../src/stage-coverage.ts"],"names":[],"mappings":"AAeA,OAAO,EAAU,KAAK,KAAK,EAAe,KAAK,KAAK,EAAE,KAAK,OAAO,EAAE,MAAM,SAAS,CAAC;AAEpF;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAC5B,MAAM,EAAE,SAAS,KAAK,EAAE,EACxB,KAAK,EAAE,KAAK,GACV,OAAO,CAAC,eAAe,CAAC,CAyF1B"}
|