@vessel-dsp/compiler 0.0.0-stage → 0.2.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 +314 -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 +344 -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 +3497 -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 +1721 -0
- package/dist/fixtures/circuits.d.ts.map +1 -0
- package/dist/fixtures/circuits.js +13404 -0
- package/dist/fixtures/circuits.js.map +1 -0
- package/dist/fixtures/expected.d.ts +257 -0
- package/dist/fixtures/expected.d.ts.map +1 -0
- package/dist/fixtures/expected.js +311 -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 +7 -0
- package/dist/part-catalog.d.ts.map +1 -0
- package/dist/part-catalog.js +6639 -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,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **What a terminal IS — typed, with per-terminal evidence.**
|
|
3
|
+
*
|
|
4
|
+
* **The defect:** 1260 terminals across the corpus's open devices carry `role: pin`. One value.
|
|
5
|
+
* `vinl` is indistinguishable from `A0`, `SUM` from `VCC`. It is the fourth instance of the
|
|
6
|
+
* missing-field defect and the worst of them, because the first three blocked a classification, a
|
|
7
|
+
* declaration and an ownership claim while **this one blocks a MEASUREMENT**: the fidelity
|
|
8
|
+
* counterfactual must bridge a device's audio-bearing terminals, cannot tell which those are, and
|
|
9
|
+
* therefore bridges all of them — a DRAM's address bus included — giving an upper bound (37) where
|
|
10
|
+
* a number was wanted.
|
|
11
|
+
*
|
|
12
|
+
* **The remediation is a pattern this repository already trusts, not a new design.** The triode
|
|
13
|
+
* registry carries per-parameter `source` citations plus an entry-level
|
|
14
|
+
* `terminalProfileEvidenceStatus`; `CLAUDE.md` names it the provenance template for the whole
|
|
15
|
+
* registry. This is that template extended to the classes that never got it.
|
|
16
|
+
*/
|
|
17
|
+
export type TerminalRole =
|
|
18
|
+
/** Carries signal. The only role the audio-path counterfactual may bridge. */
|
|
19
|
+
"audio" | "supply" | "ground"
|
|
20
|
+
/** Address lines: a bus, never a signal path. */
|
|
21
|
+
| "address"
|
|
22
|
+
/** Data lines, parallel or serial. */
|
|
23
|
+
| "data" | "clock"
|
|
24
|
+
/** Mode, enable, reset, chip-select: a parameter stream, not audio. */
|
|
25
|
+
| "control"
|
|
26
|
+
/**
|
|
27
|
+
* **Added because the corpus forces it.** A DAC's `VREF` sets full-scale output: it is neither a
|
|
28
|
+
* supply rail nor a signal, and calling it either loses the distinction that makes it useful.
|
|
29
|
+
* `RKM14L492-103F` in `boss-dd-2` and `boss-dsd-3` carries one.
|
|
30
|
+
*/
|
|
31
|
+
| "reference";
|
|
32
|
+
/**
|
|
33
|
+
* **How a role is known. Two kinds, and the second is deliberately weaker.**
|
|
34
|
+
*
|
|
35
|
+
* `direct-source` is the strong kind: a datasheet pinout, a service-note terminal map, or the
|
|
36
|
+
* packet's own declared node role (for `supply`/`ground`, cited to the node ledger) — the way the
|
|
37
|
+
* triode registry cites a Koren coefficient.
|
|
38
|
+
*
|
|
39
|
+
* **`packet-validated-shell` is circumstantial and is named so it reads that way**: it is not the
|
|
40
|
+
* source document saying what a terminal is, it is *our own packet's deck* having pushed a signal
|
|
41
|
+
* through it. It buys the shells that have **no part number at all** —
|
|
42
|
+
* `boss-st-2:ANALOG_INPUT_SUPPORT` can never have a datasheet — at the price of being admissible
|
|
43
|
+
* for exactly one role.
|
|
44
|
+
*
|
|
45
|
+
* **It is asymmetric, and the direction is the unwelcome one.** A deck can only ever ADD an audio
|
|
46
|
+
* terminal, never remove one, so this kind can move a device from `drops` to `stays` and never the
|
|
47
|
+
* reverse. A ceiling that improves because of it is a bug, not a result.
|
|
48
|
+
*/
|
|
49
|
+
export type TerminalRoleEvidenceKind = "direct-source" | "packet-validated-shell";
|
|
50
|
+
/**
|
|
51
|
+
* **A role and the evidence for it. Both required — a role without evidence is refused.**
|
|
52
|
+
*
|
|
53
|
+
* **The banned inference is reading the pin's NAME.** `vinl` looking like audio and `A0` looking
|
|
54
|
+
* like an address is exactly the substring classification `CLAUDE.md` forbids, and it is forbidden
|
|
55
|
+
* because **a pin name is a label, not a fact**. It is also how this corpus already went wrong once:
|
|
56
|
+
* four tremolo optocouplers are wired from their terminals' *names*, one of the two surviving name
|
|
57
|
+
* vocabularies.
|
|
58
|
+
*/
|
|
59
|
+
export type TerminalRoleEvidence = {
|
|
60
|
+
readonly kind: "direct-source";
|
|
61
|
+
readonly role: TerminalRole;
|
|
62
|
+
/** The cited authority: a datasheet pinout, a service-note terminal map, a node ledger. */
|
|
63
|
+
readonly source: string;
|
|
64
|
+
} | {
|
|
65
|
+
/**
|
|
66
|
+
* **Admissible for `audio` and nothing else.** Address, data and clock are not evidenceable
|
|
67
|
+
* this way at all: a deck that drives a bus line proves nothing about what the line carries,
|
|
68
|
+
* and supply/ground need no deck because the packet already declares them.
|
|
69
|
+
*/
|
|
70
|
+
readonly kind: "packet-validated-shell";
|
|
71
|
+
readonly role: "audio";
|
|
72
|
+
/** The packet-local deck, by path. It must exist and must have passed. */
|
|
73
|
+
readonly deck: string;
|
|
74
|
+
/**
|
|
75
|
+
* **The specific path through this terminal that the deck exercises**, as the deck's own
|
|
76
|
+
* driven node and probed node. "The deck covers this component" is NOT this field: the
|
|
77
|
+
* claim is that signal passes through *this terminal*, and a component-level citation
|
|
78
|
+
* cannot support a per-terminal claim.
|
|
79
|
+
*/
|
|
80
|
+
readonly signalPath: string;
|
|
81
|
+
};
|
|
82
|
+
/** Strong or circumstantial. Reported wherever a populated profile is summarised. */
|
|
83
|
+
export declare function evidenceStrength(e: TerminalRoleEvidence): "source" | "circumstantial";
|
|
84
|
+
/**
|
|
85
|
+
* **`unpopulated` is a first-class state and a CORRECT outcome**, not a gap. If a role cannot be
|
|
86
|
+
* evidenced it stays unpopulated, and a consumer must handle that rather than guess.
|
|
87
|
+
*/
|
|
88
|
+
export type TerminalProfile = {
|
|
89
|
+
readonly status: "unpopulated";
|
|
90
|
+
readonly reason: string;
|
|
91
|
+
} | {
|
|
92
|
+
readonly status: "populated";
|
|
93
|
+
/** Keyed by the terminal's declared name. */
|
|
94
|
+
readonly terminals: Readonly<Record<string, TerminalRoleEvidence>>;
|
|
95
|
+
};
|
|
96
|
+
export declare function validateTerminalProfile(p: TerminalProfile): readonly string[];
|
|
97
|
+
/**
|
|
98
|
+
* **The terminals the audio-path counterfactual may bridge.**
|
|
99
|
+
*
|
|
100
|
+
* **Returns `null` when the profile is unpopulated**, and the caller must then fall back to
|
|
101
|
+
* bridging everything and **report its result as an upper bound** — which is exactly what the
|
|
102
|
+
* ceiling of 37 is today. The distinction between "measured" and "bounded" lives here.
|
|
103
|
+
*
|
|
104
|
+
* **A device needs at least TWO audio terminals to bridge anything.** One audio pin connects
|
|
105
|
+
* nothing, which is why an R2R ladder with eleven data lines and a single `SUM` should leave the
|
|
106
|
+
* audio path once its profile is populated.
|
|
107
|
+
*/
|
|
108
|
+
export declare function audioTerminals(p: TerminalProfile | undefined): readonly string[] | null;
|
|
109
|
+
//# sourceMappingURL=terminal-role.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal-role.d.ts","sourceRoot":"","sources":["../src/terminal-role.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,YAAY;AACvB,8EAA8E;AAC5E,OAAO,GACP,QAAQ,GACR,QAAQ;AACV,iDAAiD;GAC/C,SAAS;AACX,sCAAsC;GACpC,MAAM,GACN,OAAO;AACT,uEAAuE;GACrE,SAAS;AACX;;;;GAIG;GACD,WAAW,CAAC;AAEf;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,wBAAwB,GAAG,eAAe,GAAG,wBAAwB,CAAC;AAElF;;;;;;;;GAQG;AACH,MAAM,MAAM,oBAAoB,GAC7B;IACA,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,2FAA2F;IAC3F,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACvB,GACD;IACA;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;IACxC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEL,qFAAqF;AACrF,wBAAgB,gBAAgB,CAC/B,CAAC,EAAE,oBAAoB,GACrB,QAAQ,GAAG,gBAAgB,CAE7B;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,GACxB;IAAE,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC3D;IACA,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,6CAA6C;IAC7C,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAC;CAClE,CAAC;AAEL,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,eAAe,GAAG,SAAS,MAAM,EAAE,CA8B7E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,eAAe,GAAG,SAAS,GAAG,SAAS,MAAM,EAAE,GAAG,IAAI,CAKvF"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** Strong or circumstantial. Reported wherever a populated profile is summarised. */
|
|
2
|
+
export function evidenceStrength(e) {
|
|
3
|
+
return e.kind === "direct-source" ? "source" : "circumstantial";
|
|
4
|
+
}
|
|
5
|
+
export function validateTerminalProfile(p) {
|
|
6
|
+
if (p.status === "unpopulated")
|
|
7
|
+
return p.reason.trim() === ""
|
|
8
|
+
? ["`unpopulated` must say why -- an unexplained absence is indistinguishable from an oversight"]
|
|
9
|
+
: [];
|
|
10
|
+
const out = [];
|
|
11
|
+
for (const [name, e] of Object.entries(p.terminals)) {
|
|
12
|
+
if (e.kind === "direct-source") {
|
|
13
|
+
if (e.source.trim() === "")
|
|
14
|
+
out.push(`terminal "${name}" declares role \`${e.role}\` with no source -- A ROLE ASSIGNED WITHOUT EVIDENCE IS REFUSED. Cite a datasheet pinout, a service-note terminal map, or the packet's declared node role.`);
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
// Checked at runtime as well as in the types: registry entries are authored as data and can
|
|
18
|
+
// reach this function from JSON, where the union's discrimination buys nothing.
|
|
19
|
+
if (e.role !== "audio")
|
|
20
|
+
out.push(`terminal "${name}" claims role \`${e.role}\` from \`packet-validated-shell\` -- REFUSED. That kind evidences \`audio\` and nothing else: address, data and clock are not evidenceable from a deck at all, and supply/ground are already evidenced by the packet's declared node role.`);
|
|
21
|
+
if (e.deck.trim() === "")
|
|
22
|
+
out.push(`terminal "${name}" claims \`packet-validated-shell\` with no deck -- REFUSED. Name the packet-local deck that passed.`);
|
|
23
|
+
if (e.signalPath.trim() === "")
|
|
24
|
+
out.push(`terminal "${name}" claims \`packet-validated-shell\` with no signal path -- REFUSED. "The deck covers this component" cannot support a per-terminal claim; name the driven node and the probed node.`);
|
|
25
|
+
}
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* **The terminals the audio-path counterfactual may bridge.**
|
|
30
|
+
*
|
|
31
|
+
* **Returns `null` when the profile is unpopulated**, and the caller must then fall back to
|
|
32
|
+
* bridging everything and **report its result as an upper bound** — which is exactly what the
|
|
33
|
+
* ceiling of 37 is today. The distinction between "measured" and "bounded" lives here.
|
|
34
|
+
*
|
|
35
|
+
* **A device needs at least TWO audio terminals to bridge anything.** One audio pin connects
|
|
36
|
+
* nothing, which is why an R2R ladder with eleven data lines and a single `SUM` should leave the
|
|
37
|
+
* audio path once its profile is populated.
|
|
38
|
+
*/
|
|
39
|
+
export function audioTerminals(p) {
|
|
40
|
+
if (p === undefined || p.status === "unpopulated")
|
|
41
|
+
return null;
|
|
42
|
+
return Object.entries(p.terminals)
|
|
43
|
+
.filter(([, e]) => e.role === "audio")
|
|
44
|
+
.map(([name]) => name);
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=terminal-role.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal-role.js","sourceRoot":"","sources":["../src/terminal-role.ts"],"names":[],"mappings":"AAyFA,qFAAqF;AACrF,MAAM,UAAU,gBAAgB,CAC/B,CAAuB;IAEvB,OAAO,CAAC,CAAC,IAAI,KAAK,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,gBAAgB,CAAC;AACjE,CAAC;AAcD,MAAM,UAAU,uBAAuB,CAAC,CAAkB;IACzD,IAAI,CAAC,CAAC,MAAM,KAAK,aAAa;QAC7B,OAAO,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE;YAC5B,CAAC,CAAC,CAAC,6FAA6F,CAAC;YACjG,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC;QACrD,IAAI,CAAC,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;YAChC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE;gBACzB,GAAG,CAAC,IAAI,CACP,aAAa,IAAI,qBAAqB,CAAC,CAAC,IAAI,6JAA6J,CACzM,CAAC;YACH,SAAS;QACV,CAAC;QACD,4FAA4F;QAC5F,gFAAgF;QAChF,IAAK,CAAC,CAAC,IAAqB,KAAK,OAAO;YACvC,GAAG,CAAC,IAAI,CACP,aAAa,IAAI,mBAAmB,CAAC,CAAC,IAAI,6OAA6O,CACvR,CAAC;QACH,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;YACvB,GAAG,CAAC,IAAI,CACP,aAAa,IAAI,sGAAsG,CACvH,CAAC;QACH,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE;YAC7B,GAAG,CAAC,IAAI,CACP,aAAa,IAAI,qLAAqL,CACtM,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,CAA8B;IAC5D,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,KAAK,aAAa;QAAE,OAAO,IAAI,CAAC;IAC/D,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;SAChC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC;SACrC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a supply names the terminal it drives, and the terminal it returns through.
|
|
3
|
+
*
|
|
4
|
+
* **These were two pairs, not one, until 2026-09-01.** `device-laws.ts` (stage 3, building the
|
|
5
|
+
* drive/return node sets that decide whether a jack contact engages onto a stranded supply
|
|
6
|
+
* node) accepted `{positive, hot, plus}` / `{negative, return}`. `lower.ts` (stage 5, choosing
|
|
7
|
+
* which end of a supply a stamp drives) accepted those plus `{line, anode, +}` /
|
|
8
|
+
* `{cathode, minus, neutral}`. Same question, two answers, three tokens apart -- so a supply
|
|
9
|
+
* declaring `line` was a drive terminal when lowering and invisible to stage 3, which decides
|
|
10
|
+
* jack engagement.
|
|
11
|
+
*
|
|
12
|
+
* Resolved as the **union**, because both stages are asking which end is which and the wider
|
|
13
|
+
* vocabulary is the more complete answer to that question, not a laxer one.
|
|
14
|
+
*
|
|
15
|
+
* **Measured before merging, so this is a consolidation and not a behaviour change.** Across
|
|
16
|
+
* all 142 corpus packets, only five role tokens appear on a `voltage-source` at all:
|
|
17
|
+
* `positive` (46), `negative` (45), `hot` (1), `return` (1) and `midpoint` (1). None of the six
|
|
18
|
+
* divergent tokens occurs, so no packet's classification moves. The divergence was latent, and
|
|
19
|
+
* the point of merging it now is that the next packet spelling a rail `line` gets one answer
|
|
20
|
+
* instead of two.
|
|
21
|
+
*
|
|
22
|
+
* `midpoint` is deliberately in neither set: a centre tap is not a drive end or a return end,
|
|
23
|
+
* and the stages that consult these are asking about polarity.
|
|
24
|
+
*/
|
|
25
|
+
export declare const supplyDriveRoles: ReadonlySet<string>;
|
|
26
|
+
/**
|
|
27
|
+
* Role tokens that name a terminal's **position or its winding half, and deliberately carry no
|
|
28
|
+
* electrode evidence** — so a resolver that cannot orient a device from them has read the
|
|
29
|
+
* document correctly rather than failed to.
|
|
30
|
+
*
|
|
31
|
+
* **Why this set exists.** Four asymmetric-device resolvers in `lower.ts` fall back to
|
|
32
|
+
* declaration order when they cannot read a role, and that fallback serves two situations one
|
|
33
|
+
* predicate could not previously tell apart: a document of bare lugs, which carries no
|
|
34
|
+
* orientation evidence and where declaration order is all there is, and a document that *named*
|
|
35
|
+
* its terminals in a spelling the resolver does not know, where declaration order is a guess.
|
|
36
|
+
* The first is correct and must stay silent; the second is the silent-mis-wiring class the
|
|
37
|
+
* 2026-09-02 census measured. This set is the escape hatch that separates them.
|
|
38
|
+
*
|
|
39
|
+
* Every entry is named as exactly this case by a resolver's own docstring already, and each is
|
|
40
|
+
* corpus-evidenced: `diodeTerminals` says it "falls back to declaration order for `a,b` and bare
|
|
41
|
+
* **`a`/`b` removed 2026-09-03, because a diode is not a symmetric device.** They were here for
|
|
42
|
+
* "a diode's bare `a`/`b` lugs, which carry no orientation evidence" -- and that reading is wrong
|
|
43
|
+
* in a way a mutation study caught: reversing such a diode moves the program, so declaration
|
|
44
|
+
* order is not "the document's intended reading", it is a guess this set was suppressing the
|
|
45
|
+
* warning about. What remains is genuinely symmetric: the two ends of a winding, where either
|
|
46
|
+
* order is the same circuit.
|
|
47
|
+
*
|
|
48
|
+
* The older note read: `diodeTerminals` says "falls back to declaration order for `a,b` and bare
|
|
49
|
+
* "`ac_a`/`ac_b` and `heater_a`/`heater_b` are symmetric windings that name no polarity ... so
|
|
50
|
+
* both fall back to declaration order" (`fender-5f1-champ`'s filament bus and `hiwatt-dr103`'s
|
|
51
|
+
* heater bus). Nothing here feeds a resolver, so adding a token changes no wiring — it only
|
|
52
|
+
* declares that this spelling's fallback was intended.
|
|
53
|
+
*
|
|
54
|
+
* A `lugN` or bare `pinN` needs no entry: `terminalRoleToken` already folds a bare pin number to
|
|
55
|
+
* `null`, and a `lug1`/`lug3` names a pot's track end, which `potTerminals` resolves by its own
|
|
56
|
+
* quiet-distance rule rather than by orientation.
|
|
57
|
+
*/
|
|
58
|
+
export declare const orientationFreeRoles: ReadonlySet<string>;
|
|
59
|
+
//# sourceMappingURL=terminal-roles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal-roles.d.ts","sourceRoot":"","sources":["../src/terminal-roles.ts"],"names":[],"mappings":"AAsBA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,MAAM,CAO/C,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,oBAAoB,EAAE,WAAW,CAAC,MAAM,CAKnD,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// Terminal-role vocabularies shared by more than one stage.
|
|
2
|
+
//
|
|
3
|
+
// **Why this file exists.** The corpus spells one terminal many ways, and the design rule is
|
|
4
|
+
// refuse rather than guess, so every stage that has to recognise a role carries a closed set of
|
|
5
|
+
// the spellings it accepts. That is correct. What is not correct is two stages carrying their
|
|
6
|
+
// *own* closed set for the *same* question, because the two then drift: the sets below were
|
|
7
|
+
// found defined twice, under the same names, in different files, and two of them had already
|
|
8
|
+
// diverged by three tokens each.
|
|
9
|
+
//
|
|
10
|
+
// The rule this file establishes: **a role vocabulary consulted by more than one stage lives
|
|
11
|
+
// here, once.** A vocabulary only one stage reads stays with that stage -- it cannot drift
|
|
12
|
+
// against anything. This is phase 1 of R1 in
|
|
13
|
+
// `thoughts/shared/plans/archive/2026-08-31-v2-complexity-reduction-plan.md`, and it is deliberately
|
|
14
|
+
// the half that needs nothing from `@vessel-dsp/core`: consolidating duplication that already
|
|
15
|
+
// exists inside this repository. Canonicalising the spellings themselves, upstream, is the
|
|
16
|
+
// other half and is still gated on the core parser contract.
|
|
17
|
+
//
|
|
18
|
+
// Nothing here is a substring or regex test. Every set is compared as whole values against
|
|
19
|
+
// tokens `terminalRoleToken` has already folded (case dropped, separators stripped, a leading
|
|
20
|
+
// `pinN` removed), which is what keeps this on the right side of the repository's rule against
|
|
21
|
+
// reading authored prose.
|
|
22
|
+
/**
|
|
23
|
+
* How a supply names the terminal it drives, and the terminal it returns through.
|
|
24
|
+
*
|
|
25
|
+
* **These were two pairs, not one, until 2026-09-01.** `device-laws.ts` (stage 3, building the
|
|
26
|
+
* drive/return node sets that decide whether a jack contact engages onto a stranded supply
|
|
27
|
+
* node) accepted `{positive, hot, plus}` / `{negative, return}`. `lower.ts` (stage 5, choosing
|
|
28
|
+
* which end of a supply a stamp drives) accepted those plus `{line, anode, +}` /
|
|
29
|
+
* `{cathode, minus, neutral}`. Same question, two answers, three tokens apart -- so a supply
|
|
30
|
+
* declaring `line` was a drive terminal when lowering and invisible to stage 3, which decides
|
|
31
|
+
* jack engagement.
|
|
32
|
+
*
|
|
33
|
+
* Resolved as the **union**, because both stages are asking which end is which and the wider
|
|
34
|
+
* vocabulary is the more complete answer to that question, not a laxer one.
|
|
35
|
+
*
|
|
36
|
+
* **Measured before merging, so this is a consolidation and not a behaviour change.** Across
|
|
37
|
+
* all 142 corpus packets, only five role tokens appear on a `voltage-source` at all:
|
|
38
|
+
* `positive` (46), `negative` (45), `hot` (1), `return` (1) and `midpoint` (1). None of the six
|
|
39
|
+
* divergent tokens occurs, so no packet's classification moves. The divergence was latent, and
|
|
40
|
+
* the point of merging it now is that the next packet spelling a rail `line` gets one answer
|
|
41
|
+
* instead of two.
|
|
42
|
+
*
|
|
43
|
+
* `midpoint` is deliberately in neither set: a centre tap is not a drive end or a return end,
|
|
44
|
+
* and the stages that consult these are asking about polarity.
|
|
45
|
+
*/
|
|
46
|
+
export const supplyDriveRoles = new Set([
|
|
47
|
+
"positive",
|
|
48
|
+
"plus",
|
|
49
|
+
"hot",
|
|
50
|
+
"line",
|
|
51
|
+
"anode",
|
|
52
|
+
"+",
|
|
53
|
+
]);
|
|
54
|
+
/**
|
|
55
|
+
* Role tokens that name a terminal's **position or its winding half, and deliberately carry no
|
|
56
|
+
* electrode evidence** — so a resolver that cannot orient a device from them has read the
|
|
57
|
+
* document correctly rather than failed to.
|
|
58
|
+
*
|
|
59
|
+
* **Why this set exists.** Four asymmetric-device resolvers in `lower.ts` fall back to
|
|
60
|
+
* declaration order when they cannot read a role, and that fallback serves two situations one
|
|
61
|
+
* predicate could not previously tell apart: a document of bare lugs, which carries no
|
|
62
|
+
* orientation evidence and where declaration order is all there is, and a document that *named*
|
|
63
|
+
* its terminals in a spelling the resolver does not know, where declaration order is a guess.
|
|
64
|
+
* The first is correct and must stay silent; the second is the silent-mis-wiring class the
|
|
65
|
+
* 2026-09-02 census measured. This set is the escape hatch that separates them.
|
|
66
|
+
*
|
|
67
|
+
* Every entry is named as exactly this case by a resolver's own docstring already, and each is
|
|
68
|
+
* corpus-evidenced: `diodeTerminals` says it "falls back to declaration order for `a,b` and bare
|
|
69
|
+
* **`a`/`b` removed 2026-09-03, because a diode is not a symmetric device.** They were here for
|
|
70
|
+
* "a diode's bare `a`/`b` lugs, which carry no orientation evidence" -- and that reading is wrong
|
|
71
|
+
* in a way a mutation study caught: reversing such a diode moves the program, so declaration
|
|
72
|
+
* order is not "the document's intended reading", it is a guess this set was suppressing the
|
|
73
|
+
* warning about. What remains is genuinely symmetric: the two ends of a winding, where either
|
|
74
|
+
* order is the same circuit.
|
|
75
|
+
*
|
|
76
|
+
* The older note read: `diodeTerminals` says "falls back to declaration order for `a,b` and bare
|
|
77
|
+
* "`ac_a`/`ac_b` and `heater_a`/`heater_b` are symmetric windings that name no polarity ... so
|
|
78
|
+
* both fall back to declaration order" (`fender-5f1-champ`'s filament bus and `hiwatt-dr103`'s
|
|
79
|
+
* heater bus). Nothing here feeds a resolver, so adding a token changes no wiring — it only
|
|
80
|
+
* declares that this spelling's fallback was intended.
|
|
81
|
+
*
|
|
82
|
+
* A `lugN` or bare `pinN` needs no entry: `terminalRoleToken` already folds a bare pin number to
|
|
83
|
+
* `null`, and a `lug1`/`lug3` names a pot's track end, which `potTerminals` resolves by its own
|
|
84
|
+
* quiet-distance rule rather than by orientation.
|
|
85
|
+
*/
|
|
86
|
+
export const orientationFreeRoles = new Set([
|
|
87
|
+
"aca",
|
|
88
|
+
"acb",
|
|
89
|
+
"heatera",
|
|
90
|
+
"heaterb",
|
|
91
|
+
]);
|
|
92
|
+
//# sourceMappingURL=terminal-roles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal-roles.js","sourceRoot":"","sources":["../src/terminal-roles.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,EAAE;AACF,6FAA6F;AAC7F,gGAAgG;AAChG,8FAA8F;AAC9F,4FAA4F;AAC5F,6FAA6F;AAC7F,iCAAiC;AACjC,EAAE;AACF,6FAA6F;AAC7F,2FAA2F;AAC3F,6CAA6C;AAC7C,qGAAqG;AACrG,8FAA8F;AAC9F,2FAA2F;AAC3F,6DAA6D;AAC7D,EAAE;AACF,2FAA2F;AAC3F,8FAA8F;AAC9F,+FAA+F;AAC/F,0BAA0B;AAE1B;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAwB,IAAI,GAAG,CAAC;IAC5D,UAAU;IACV,MAAM;IACN,KAAK;IACL,MAAM;IACN,OAAO;IACP,GAAG;CACH,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAwB,IAAI,GAAG,CAAC;IAChE,KAAK;IACL,KAAK;IACL,SAAS;IACT,SAAS;CACT,CAAC,CAAC"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { type Device, type DeviceLaw, type NodeId } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* How many `(device, terminal)` references touch each node across the whole netlist.
|
|
4
|
+
*
|
|
5
|
+
* Existence evidence, not a corpus-wide cost: `transformerWindings` is the only reader, and
|
|
6
|
+
* only when its own terminal grouping turns up a winding with a single, unpaired end. A node
|
|
7
|
+
* this stage never asks about -- ground, or any node two ordinary components share -- costs
|
|
8
|
+
* nothing extra to have counted.
|
|
9
|
+
*/
|
|
10
|
+
export declare function nodeOccurrenceCounts(devices: readonly Device[]): Map<NodeId, number>;
|
|
11
|
+
/**
|
|
12
|
+
* A transformer's windings, as coupled pairs against its primary.
|
|
13
|
+
*
|
|
14
|
+
* **Positional order was silently wrong on 45 of the corpus's 55 transformers.** This read
|
|
15
|
+
* `device.nodes` as exactly `[primary+, primary-, secondary+, secondary-]` and dropped every
|
|
16
|
+
* terminal past the fourth without a word. Only 10 transformers have four terminals; the rest
|
|
17
|
+
* have five to thirteen. `tycobrahe-octavia` is the compiled case: its `T1` is
|
|
18
|
+
* `[primarya, primaryb, secondarya, secondaryct, secondaryb, shieldnc]`, so the old reading
|
|
19
|
+
* coupled `(secondarya, secondaryct)` — **half the secondary** — and left `secondaryb` driven by
|
|
20
|
+
* nothing. Since `secondarya` and `secondaryb` each feed a diode anode with the centre tap
|
|
21
|
+
* grounded, that is a full-wave rectifier reduced to half-wave, which is the difference between
|
|
22
|
+
* an octave-up pedal and a fuzz.
|
|
23
|
+
*
|
|
24
|
+
* Grouping is by **terminal-role token compared whole** against the closed table below, never by
|
|
25
|
+
* substring or by position. A role this table does not name is a refusal rather than a guess: a
|
|
26
|
+
* winding assembled from tokens nobody has checked would silently couple the wrong pair, which is
|
|
27
|
+
* the failure this replaces.
|
|
28
|
+
*
|
|
29
|
+
* A centre tap splits its winding into two halves in series. Each half carries half the turns, so
|
|
30
|
+
* its primary-to-half ratio is **twice** the declared one — the declared `Ratio` is read as
|
|
31
|
+
* primary-to-*full*-winding, which is the conventional statement for a tapped secondary and is
|
|
32
|
+
* documented here because the source cannot say which it meant.
|
|
33
|
+
*
|
|
34
|
+
* **One declared ratio is applied to every secondary.** `declaredRatio` is exact for a single
|
|
35
|
+
* secondary, tapped or not, whose halves genuinely share a ratio -- which is every transformer
|
|
36
|
+
* that reaches the coupled path, because a ratio is only ever derived for a transformer whose
|
|
37
|
+
* primary carries signal.
|
|
38
|
+
*
|
|
39
|
+
* ## Driven windings: a power transformer needs no primary
|
|
40
|
+
*
|
|
41
|
+
* **A transformer the source specifies by its winding voltages is lowered as one `ac-source` per
|
|
42
|
+
* winding, and its primary is not modelled at all.** Decided 2026-08-14 after measuring the amp
|
|
43
|
+
* corpus; `netlist.ts`'s `transformerWindingVolts` carries the argument for why the primary side
|
|
44
|
+
* is not needed and this function is where that is executed.
|
|
45
|
+
*
|
|
46
|
+
* The physics: the B+ rail comes from the HV secondary through the rectifier and the filter
|
|
47
|
+
* network, and a cap-input rectifier's behaviour is fixed by the secondary RMS, the rectifier
|
|
48
|
+
* drop and the load. The primary is the mains side, and nothing downstream of it is audio. So a
|
|
49
|
+
* winding whose own RMS the source states can be driven directly, and the mains number the
|
|
50
|
+
* previous formulation demanded -- unstateable for the multi-tap primaries this corpus is full of
|
|
51
|
+
* -- drops out.
|
|
52
|
+
*
|
|
53
|
+
* **What this models that the coupled form did not.** `vox-ac15-top-boost` declares no supply
|
|
54
|
+
* component at all: under the coupled form its power transformer's primary would be driven by
|
|
55
|
+
* nothing and its B+ would solve to zero, a wrong answer that renders. A driven winding asserts
|
|
56
|
+
* the voltage the source states regardless of what the mains side of the document contains.
|
|
57
|
+
*
|
|
58
|
+
* **What this does not model, plainly.** A real transformer sags: winding resistance, leakage
|
|
59
|
+
* inductance and core loss make B+ fall as the power tubes draw, and that sag is part of how an
|
|
60
|
+
* amp sounds. **No source in this corpus states any of those**, so none of them is modelled and
|
|
61
|
+
* none is guessed. The series impedance is `SUPPLY_SOURCE_OHMS`, the repository's existing
|
|
62
|
+
* one-ohm default for every supply, carried on the law -- it is there so an ideal source cannot
|
|
63
|
+
* deliver unbounded current into a rectifier, and it is **not** a winding resistance: a real HV
|
|
64
|
+
* winding is tens to hundreds of ohms. Read a B+ from this model as the no-load rail. Likewise
|
|
65
|
+
* there is no cross-winding coupling (loading the HV winding does not disturb the heaters) and
|
|
66
|
+
* nothing on the mains side can switch the amp off any more, because there is no longer a path
|
|
67
|
+
* from the mains inlet to the secondaries; the standby switch, which sits after the rectifier,
|
|
68
|
+
* is unaffected.
|
|
69
|
+
*
|
|
70
|
+
* **The centre tap is two sources about the tap, not one across the winding.** A `370-0-370`
|
|
71
|
+
* winding with the tap grounded gets `V(a) - V(tap) = E` and `V(tap) - V(b) = E`, so `a` and `b`
|
|
72
|
+
* swing in antiphase about the tap at 370 V RMS each -- which is what makes the full-wave
|
|
73
|
+
* rectifier downstream full-wave. One 740 V source across `a`-`b` would leave the tap
|
|
74
|
+
* undetermined and the rectifier fed wrongly. The pairing is the same one the coupled form
|
|
75
|
+
* already uses, and the stated voltage is per half by the corpus's own convention, so it is
|
|
76
|
+
* applied to each half directly and never doubled.
|
|
77
|
+
*
|
|
78
|
+
* **Every winding must have a voltage if any does.** A transformer on this path has no ratio to
|
|
79
|
+
* fall back on by construction, so a winding with no typed voltage is refused by name rather than
|
|
80
|
+
* silently dropped or defaulted -- `fender-bassman` and `marshall-jtm45` both state their
|
|
81
|
+
* rectifier-heater winding only as prose ("assumed from GZ34 heater, unprinted on selected
|
|
82
|
+
* schematic"), and that is a source gap to report, not a number to invent.
|
|
83
|
+
*
|
|
84
|
+
* **A tapped primary swaps which winding is the shared reference, added 2026-08-14.** Three
|
|
85
|
+
* amp output transformers (`fender-5e3-deluxe-tweed`, `marshall-jtm45`, `vox-ac30-top-boost`)
|
|
86
|
+
* declare a **centre-tapped primary** -- the ordinary push-pull shape, plate-to-plate with the
|
|
87
|
+
* centre tap at B+ -- which the original code refused outright: "no single reference winding".
|
|
88
|
+
* That refusal is still correct for a primary tapped *and* carrying no other complete winding to
|
|
89
|
+
* pivot on, but a push-pull output transformer always has one: the secondary. Every winding on
|
|
90
|
+
* one core shares the same volts-per-turn, so if `declaredRatio = Vprimary_full / Vsecondary_full`
|
|
91
|
+
* (exactly what the impedance-pair rung above already derives), then for a centre tap splitting
|
|
92
|
+
* the primary into two equal halves:
|
|
93
|
+
*
|
|
94
|
+
* V(half) = V(primary_full) / 2
|
|
95
|
+
* V(secondary_full) = V(primary_full) / declaredRatio = (2 * V(half)) / declaredRatio
|
|
96
|
+
* => V(secondary_full) = (2 / declaredRatio) * V(half)
|
|
97
|
+
*
|
|
98
|
+
* So stamping the secondary as the shared reference and each primary half as a winding coupled
|
|
99
|
+
* to it needs `2 / declaredRatio` per half -- applied directly, not doubled again. Verified
|
|
100
|
+
* against `fender-5e3-deluxe-tweed`'s own numbers: `declaredRatio = sqrt(8000/8) ≈ 31.62`,
|
|
101
|
+
* swapped ratio `2/31.62 ≈ 0.0632`, and `0.0632 * 15.81 = 1` confirms the round trip
|
|
102
|
+
* (`1/0.0632 ≈ 15.81 = declaredRatio/2`, the per-half ratio the un-swapped direction would have
|
|
103
|
+
* used).
|
|
104
|
+
*
|
|
105
|
+
* The swap needs **exactly one** other complete, untapped winding to pivot on; zero or several is
|
|
106
|
+
* refused rather than guessed. It cannot arise on the driven path, which models no primary.
|
|
107
|
+
*
|
|
108
|
+
* **A winding with only one declared end is dropped if connectivity says it is dangling, and
|
|
109
|
+
* refused by name otherwise -- also 2026-08-14.** `vox-ac30-top-boost`'s output transformer
|
|
110
|
+
* declares a `secondary_8` terminal beside its typed, wired `secondary_16` -- "8 Ω alternate
|
|
111
|
+
* source-visible tap" in the source's own words, a second impedance tap on the same core with no
|
|
112
|
+
* companion end of its own. Its node touches no other component anywhere in the document (checked
|
|
113
|
+
* against `nodeOccurrenceCounts`, connectivity rather than a spelling), so nothing this stage
|
|
114
|
+
* could stamp for it would change the solved circuit, and it is dropped exactly as `shieldnc`
|
|
115
|
+
* already is. This is deliberately **not** a blanket rule for the `secondary8`/`secondary_8`
|
|
116
|
+
* spelling: a future packet that actually wires an alternate tap to a load has a node other
|
|
117
|
+
* components touch, and that packet refuses by name instead -- a real multi-tap secondary in use
|
|
118
|
+
* is a different device law this stage does not have, not a winding to silently drop.
|
|
119
|
+
*/
|
|
120
|
+
export type LoweredWinding = {
|
|
121
|
+
readonly kind: "coupled";
|
|
122
|
+
readonly primaryPlus: number;
|
|
123
|
+
readonly primaryMinus: number;
|
|
124
|
+
readonly plus: number;
|
|
125
|
+
readonly minus: number;
|
|
126
|
+
readonly turnsRatio: number;
|
|
127
|
+
} | {
|
|
128
|
+
readonly kind: "driven";
|
|
129
|
+
readonly plus: number;
|
|
130
|
+
readonly minus: number;
|
|
131
|
+
readonly amplitudeVolts: number;
|
|
132
|
+
readonly frequencyHz: number;
|
|
133
|
+
readonly sourceOhms: number;
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Nodes where a transformer meets a **selector switch** and nothing else.
|
|
137
|
+
*
|
|
138
|
+
* Connectivity, never a spelling: a node qualifies when the devices touching it are one
|
|
139
|
+
* transformer and one or more plain `switch`es, with no third kind. An output transformer's
|
|
140
|
+
* impedance selector is exactly that shape -- `hiwatt-dr103`'s `SW_IMPEDANCE_SELECTOR` has one
|
|
141
|
+
* `common` and three throws, each throw sharing a node with one secondary tap of
|
|
142
|
+
* `T_OUTPUT_TH7549_2`.
|
|
143
|
+
*
|
|
144
|
+
* **`switch` and not `selector`, deliberately, and this is the whole boundary of this rule.** This
|
|
145
|
+
* repository already models a real 1-of-N selector as its own device kind: `selector` stamps every
|
|
146
|
+
* throw of every pole and lets a control decide which conducts, resolving its position from a
|
|
147
|
+
* declared `Options:` list against `Position:`. That is the right answer for an ohms selector -- it
|
|
148
|
+
* makes the taps *switchable*, so the reflected load changes with the selection, which is the half
|
|
149
|
+
* that matters for power-stage distortion.
|
|
150
|
+
*
|
|
151
|
+
* These two packets do not reach it: they declare `kind: switch` with a `SelectedState: 16 ohms`
|
|
152
|
+
* property rather than the `Options`/`Position` pair the classifier reads. So this rule is the
|
|
153
|
+
* narrow, exact thing that can be said meanwhile -- an unselected throw is open, and an open
|
|
154
|
+
* secondary contributes nothing -- and it **stops applying by construction** the moment a packet
|
|
155
|
+
* declares its selector properly, because a `selector` is not a `switch` and this predicate counts
|
|
156
|
+
* only the latter. It cannot defeat the better model; it is superseded by it.
|
|
157
|
+
*/
|
|
158
|
+
export declare function selectorTapNodes(devices: readonly Device[]): ReadonlySet<NodeId>;
|
|
159
|
+
/**
|
|
160
|
+
* The coils this transformer declares, reduced to the pairs of nodes a stamp needs.
|
|
161
|
+
*
|
|
162
|
+
* **Read, not reconstructed.** Until `@vessel-dsp/core@0.6.35` a transformer's terminals gave no
|
|
163
|
+
* statement of which coil each belonged to, so this stage grouped them with a 110-entry table
|
|
164
|
+
* keyed on folded terminal spellings -- `primaryplus`, `hvreda345vac`, `powertubeheatercenter0v`.
|
|
165
|
+
* That table covered the corpus because it was written from the corpus, one packet at a time, and
|
|
166
|
+
* a transformer nobody had transcribed yet arrived as a refusal naming a winding class instead of
|
|
167
|
+
* the real fault, which was that the document never said what its coils were.
|
|
168
|
+
*
|
|
169
|
+
* Everything the table encoded beyond the grouping stays where it was:
|
|
170
|
+
*
|
|
171
|
+
* - **`end: a|b|tap` is coil order plus each terminal's own role.** The ends are the terminals
|
|
172
|
+
* whose declared role is `winding`; a `windingTap` sits physically where the list puts it.
|
|
173
|
+
* - **`end: unconnected` was never winding structure.** A tap the document wires to nothing is a
|
|
174
|
+
* connectivity fact, read from `terminalOccurrences` below exactly as before.
|
|
175
|
+
* - **`end: selectable` likewise.** Which mains tap is live is a property of the selector switch,
|
|
176
|
+
* and the refusal below still names that switch rather than the transformer.
|
|
177
|
+
*/
|
|
178
|
+
export declare function transformerWindings(device: Device, law: Extract<DeviceLaw, {
|
|
179
|
+
kind: "transformer";
|
|
180
|
+
}>, terminalOccurrences: ReadonlyMap<NodeId, number>, selectorTaps: ReadonlySet<NodeId>): readonly LoweredWinding[];
|
|
181
|
+
//# sourceMappingURL=transformer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transformer.d.ts","sourceRoot":"","sources":["../src/transformer.ts"],"names":[],"mappings":"AAaA,OAAO,EAAU,KAAK,MAAM,EAAE,KAAK,SAAS,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAE3E;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAQpF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4GG;AACH,MAAM,MAAM,cAAc,GACvB;IACA,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC3B,GACD;IACA,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEL;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,WAAW,CAAC,MAAM,CAAC,CA6BhF;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CAClC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,OAAO,CAAC,SAAS,EAAE;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC,EAChD,mBAAmB,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EAChD,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,GAC/B,SAAS,cAAc,EAAE,CA4M3B"}
|