smithkit 0.1.1 → 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.
Files changed (132) hide show
  1. package/README.md +119 -40
  2. package/dist/lib/MarkerMeasurements.d.ts +6 -0
  3. package/dist/lib/MarkerMeasurements.js +22 -0
  4. package/dist/lib/Smith.d.ts +9 -2
  5. package/dist/lib/Smith.js +68 -36
  6. package/dist/lib/SmithFormatter.d.ts +10 -0
  7. package/dist/lib/SmithFormatter.js +19 -0
  8. package/dist/lib/grid/CircleLayerControl.d.ts +15 -0
  9. package/dist/lib/grid/CircleLayerControl.js +40 -0
  10. package/dist/lib/{draw → grid}/ConstCircles.d.ts +4 -6
  11. package/dist/lib/{draw → grid}/ConstCircles.js +2 -2
  12. package/dist/lib/{draw → grid}/ConstQCircles.d.ts +2 -2
  13. package/dist/lib/{draw → grid}/ConstQCircles.js +3 -3
  14. package/dist/lib/{draw → grid}/ConstSwrCircles.d.ts +2 -2
  15. package/dist/lib/{draw → grid}/ConstSwrCircles.js +3 -3
  16. package/dist/lib/grid/GridDefinitions.d.ts +12 -0
  17. package/dist/lib/grid/GridDefinitions.js +138 -0
  18. package/dist/lib/grid/GridGeometry.d.ts +26 -0
  19. package/dist/lib/grid/GridGeometry.js +58 -0
  20. package/dist/lib/grid/GridLabels.d.ts +8 -0
  21. package/dist/lib/grid/GridLabels.js +45 -0
  22. package/dist/lib/grid/GridLayerControl.d.ts +12 -0
  23. package/dist/lib/grid/GridLayerControl.js +39 -0
  24. package/dist/lib/grid/LayerControl.d.ts +6 -0
  25. package/dist/lib/grid/LayerControl.js +16 -0
  26. package/dist/lib/{draw → grid}/SmithGridLayer.d.ts +5 -4
  27. package/dist/lib/{draw → grid}/SmithGridLayer.js +26 -9
  28. package/dist/lib/grid/types.d.ts +1 -1
  29. package/dist/lib/index.d.ts +8 -10
  30. package/dist/lib/index.js +5 -7
  31. package/dist/lib/{draw → interaction}/SmithCursor.d.ts +3 -3
  32. package/dist/lib/{draw → interaction}/SmithCursor.js +6 -6
  33. package/dist/lib/io/Touchstone.d.ts +10 -0
  34. package/dist/lib/io/Touchstone.js +75 -0
  35. package/dist/lib/layers.d.ts +2 -8
  36. package/dist/lib/layers.js +1 -73
  37. package/dist/lib/{complex → math}/Complex.d.ts +1 -0
  38. package/dist/lib/{complex → math}/Complex.js +1 -1
  39. package/dist/lib/math/geometry.d.ts +14 -0
  40. package/dist/lib/measurements.d.ts +2 -4
  41. package/dist/lib/measurements.js +1 -19
  42. package/dist/lib/rf/RfCalculations.d.ts +65 -0
  43. package/dist/lib/rf/RfCalculations.js +161 -0
  44. package/dist/lib/{SmithConstantCircle.d.ts → rf/SmithConstantCircle.d.ts} +2 -3
  45. package/dist/lib/{SmithConstantCircle.js → rf/SmithConstantCircle.js} +3 -4
  46. package/dist/lib/scales/PeripheralScaleDefinitions.d.ts +16 -0
  47. package/dist/lib/scales/PeripheralScaleDefinitions.js +54 -0
  48. package/dist/lib/scales/RadialScaleDefinitions.d.ts +15 -0
  49. package/dist/lib/scales/RadialScaleDefinitions.js +112 -0
  50. package/dist/lib/scales/SmithPeripheralScales.d.ts +4 -2
  51. package/dist/lib/scales/SmithPeripheralScales.js +46 -26
  52. package/dist/lib/scales/SmithScales.d.ts +3 -1
  53. package/dist/lib/scales/SmithScales.js +8 -2
  54. package/dist/lib/svg/LabelLayout.d.ts +17 -0
  55. package/dist/lib/svg/LabelLayout.js +145 -0
  56. package/dist/lib/{draw → svg}/SmithArc.d.ts +1 -1
  57. package/dist/lib/{draw → svg}/SmithCircle.d.ts +1 -1
  58. package/dist/lib/{draw → svg}/SmithLine.d.ts +1 -1
  59. package/dist/lib/{draw → svg}/SmithScaler.d.ts +1 -4
  60. package/dist/lib/{draw → svg}/SmithText.d.ts +1 -1
  61. package/dist/lib/svg/SvgExporter.d.ts +14 -0
  62. package/dist/lib/svg/SvgExporter.js +137 -0
  63. package/dist/lib/{draw → traces}/SmithData.d.ts +24 -35
  64. package/dist/lib/traces/SmithData.js +195 -0
  65. package/dist/lib/{draw → traces}/SmithMarker.d.ts +14 -3
  66. package/dist/lib/traces/SmithMarker.js +237 -0
  67. package/dist/lib/traces/TraceModel.d.ts +31 -0
  68. package/dist/lib/traces/TraceModel.js +123 -0
  69. package/dist/lib/traces/TraceRenderer.d.ts +33 -0
  70. package/dist/lib/traces/TraceRenderer.js +152 -0
  71. package/package.json +4 -1
  72. package/dist/lib/SmithArcsDefs.d.ts +0 -10
  73. package/dist/lib/SmithArcsDefs.js +0 -10
  74. package/dist/lib/components.d.ts +0 -14
  75. package/dist/lib/components.js +0 -26
  76. package/dist/lib/draw/SmithData.js +0 -366
  77. package/dist/lib/draw/SmithMarker.js +0 -122
  78. package/dist/lib/formatting.d.ts +0 -7
  79. package/dist/lib/formatting.js +0 -16
  80. package/dist/lib/grid/definitions.d.ts +0 -3
  81. package/dist/lib/grid/definitions.js +0 -123
  82. package/dist/lib/grid/geometry.d.ts +0 -20
  83. package/dist/lib/grid/geometry.js +0 -55
  84. package/dist/lib/grid/labels.d.ts +0 -3
  85. package/dist/lib/grid/labels.js +0 -41
  86. package/dist/lib/io/touchstone.d.ts +0 -7
  87. package/dist/lib/io/touchstone.js +0 -72
  88. package/dist/lib/math/complexRatio.d.ts +0 -3
  89. package/dist/lib/math/complexRatio.js +0 -30
  90. package/dist/lib/renormalization.d.ts +0 -10
  91. package/dist/lib/renormalization.js +0 -62
  92. package/dist/lib/rf.d.ts +0 -35
  93. package/dist/lib/rf.js +0 -74
  94. package/dist/lib/scales/peripheralScales.d.ts +0 -12
  95. package/dist/lib/scales/peripheralScales.js +0 -49
  96. package/dist/lib/scales/radialScales.d.ts +0 -12
  97. package/dist/lib/scales/radialScales.js +0 -109
  98. package/dist/lib/shapes/Arc.d.ts +0 -6
  99. package/dist/lib/shapes/Circle.d.ts +0 -5
  100. package/dist/lib/shapes/Circle.js +0 -1
  101. package/dist/lib/shapes/Line.d.ts +0 -5
  102. package/dist/lib/shapes/Line.js +0 -1
  103. package/dist/lib/shapes/Point.d.ts +0 -1
  104. package/dist/lib/shapes/Point.js +0 -1
  105. /package/dist/lib/{draw → grid}/ConstConductance.d.ts +0 -0
  106. /package/dist/lib/{draw → grid}/ConstConductance.js +0 -0
  107. /package/dist/lib/{draw → grid}/ConstReactance.d.ts +0 -0
  108. /package/dist/lib/{draw → grid}/ConstReactance.js +0 -0
  109. /package/dist/lib/{draw → grid}/ConstResistance.d.ts +0 -0
  110. /package/dist/lib/{draw → grid}/ConstResistance.js +0 -0
  111. /package/dist/lib/{draw → grid}/ConstSusceptance.d.ts +0 -0
  112. /package/dist/lib/{draw → grid}/ConstSusceptance.js +0 -0
  113. /package/dist/lib/{arcs → grid}/Tick.d.ts +0 -0
  114. /package/dist/lib/{arcs → grid}/Tick.js +0 -0
  115. /package/dist/lib/{draw → interaction}/MouseGesture.d.ts +0 -0
  116. /package/dist/lib/{draw → interaction}/MouseGesture.js +0 -0
  117. /package/dist/lib/{draw/SmithDrawOptions.js → math/geometry.js} +0 -0
  118. /package/dist/lib/{draw → svg}/SmithArc.js +0 -0
  119. /package/dist/lib/{draw → svg}/SmithCircle.js +0 -0
  120. /package/dist/lib/{draw → svg}/SmithDrawOptions.d.ts +0 -0
  121. /package/dist/lib/{shapes/Arc.js → svg/SmithDrawOptions.js} +0 -0
  122. /package/dist/lib/{draw → svg}/SmithGroup.d.ts +0 -0
  123. /package/dist/lib/{draw → svg}/SmithGroup.js +0 -0
  124. /package/dist/lib/{draw → svg}/SmithLine.js +0 -0
  125. /package/dist/lib/{draw → svg}/SmithPath.d.ts +0 -0
  126. /package/dist/lib/{draw → svg}/SmithPath.js +0 -0
  127. /package/dist/lib/{draw → svg}/SmithScaler.js +0 -0
  128. /package/dist/lib/{draw → svg}/SmithShape.d.ts +0 -0
  129. /package/dist/lib/{draw → svg}/SmithShape.js +0 -0
  130. /package/dist/lib/{draw → svg}/SmithSvg.d.ts +0 -0
  131. /package/dist/lib/{draw → svg}/SmithSvg.js +0 -0
  132. /package/dist/lib/{draw → svg}/SmithText.js +0 -0
@@ -0,0 +1,123 @@
1
+ /** Owns validated samples and marker selections without depending on SVG or D3. */
2
+ export class TraceModel {
3
+ samples;
4
+ markers = [];
5
+ markerCount = 0;
6
+ constructor(samples) {
7
+ this.samples = this.copySamples(samples);
8
+ }
9
+ get Samples() {
10
+ return this.samples;
11
+ }
12
+ get Markers() {
13
+ return this.markers.slice();
14
+ }
15
+ addMarker(sampleIndex) {
16
+ this.validateSampleIndex(sampleIndex);
17
+ const marker = { number: ++this.markerCount, selectedPoint: this.samples[sampleIndex] };
18
+ this.markers.push(marker);
19
+ return marker;
20
+ }
21
+ removeMarker(index) {
22
+ const marker = this.markers[index];
23
+ if (marker) {
24
+ this.markers.splice(index, 1);
25
+ }
26
+ return marker;
27
+ }
28
+ getMarker(index) {
29
+ return this.markers[index];
30
+ }
31
+ markerIndex(marker) {
32
+ return this.markers.indexOf(marker);
33
+ }
34
+ markerSampleIndex(index) {
35
+ const marker = this.markers[index];
36
+ return marker ? this.samples.indexOf(marker.selectedPoint) : -1;
37
+ }
38
+ setMarkerSample(index, sampleIndex) {
39
+ const marker = this.markers[index];
40
+ if (!marker) {
41
+ return;
42
+ }
43
+ this.validateSampleIndex(sampleIndex);
44
+ marker.selectedPoint = this.samples[sampleIndex];
45
+ return marker;
46
+ }
47
+ setMarkerFrequency(index, frequencyHz) {
48
+ if (!this.markers[index]) {
49
+ return;
50
+ }
51
+ if (!Number.isFinite(frequencyHz) || frequencyHz < 0) {
52
+ throw new RangeError('Marker frequency must be finite and non-negative.');
53
+ }
54
+ return this.setMarkerSample(index, this.nearestFrequencyIndex(frequencyHz));
55
+ }
56
+ /** Returns false when dragging still selects the same sample. */
57
+ selectNearestPoint(marker, point) {
58
+ if (!this.markers.includes(marker)) {
59
+ return false;
60
+ }
61
+ const sample = this.nearestPoint(point);
62
+ if (sample === marker.selectedPoint) {
63
+ return false;
64
+ }
65
+ marker.selectedPoint = sample;
66
+ return true;
67
+ }
68
+ update(values, strategy) {
69
+ // Validate and copy before mutating either samples or marker selections.
70
+ const samples = this.copySamples(values);
71
+ const selectedIndices = this.markers.map((entry) => this.samples.indexOf(entry.selectedPoint));
72
+ this.samples = samples;
73
+ this.markers.forEach((entry, index) => {
74
+ if (strategy === 'sample-index') {
75
+ entry.selectedPoint = samples[Math.min(selectedIndices[index], samples.length - 1)];
76
+ }
77
+ else if (strategy === 'reflection') {
78
+ entry.selectedPoint = this.nearestPoint(entry.selectedPoint.reflectionCoefficient);
79
+ }
80
+ else {
81
+ entry.selectedPoint = samples[this.nearestFrequencyIndex(entry.selectedPoint.frequencyHz)];
82
+ }
83
+ });
84
+ }
85
+ clear() {
86
+ this.samples = [];
87
+ this.markers = [];
88
+ }
89
+ nearestFrequencyIndex(frequencyHz) {
90
+ let closest = 0;
91
+ let distance = Math.abs(this.samples[0].frequencyHz - frequencyHz);
92
+ for (let i = 1; i < this.samples.length; i++) {
93
+ const nextDistance = Math.abs(this.samples[i].frequencyHz - frequencyHz);
94
+ if (nextDistance < distance) {
95
+ closest = i;
96
+ distance = nextDistance;
97
+ }
98
+ }
99
+ return closest;
100
+ }
101
+ nearestPoint(point) {
102
+ const distance = (sample) => Math.hypot(point[0] - sample.reflectionCoefficient[0], point[1] - sample.reflectionCoefficient[1]);
103
+ return this.samples.reduce((previous, current) => distance(previous) <= distance(current) ? previous : current);
104
+ }
105
+ validateSampleIndex(index) {
106
+ if (!Number.isInteger(index) || index < 0 || index >= this.samples.length) {
107
+ throw new RangeError('Sample index is outside this trace.');
108
+ }
109
+ }
110
+ copySamples(values) {
111
+ if (!values.length ||
112
+ values.some(({ frequencyHz, reflectionCoefficient }) => !Number.isFinite(frequencyHz) ||
113
+ frequencyHz < 0 ||
114
+ reflectionCoefficient.length !== 2 ||
115
+ !reflectionCoefficient.every(Number.isFinite))) {
116
+ throw new RangeError('A dataset requires samples with a non-negative finite frequency and two finite coordinates.');
117
+ }
118
+ return values.map(({ frequencyHz, reflectionCoefficient }) => ({
119
+ frequencyHz,
120
+ reflectionCoefficient: [reflectionCoefficient[0], reflectionCoefficient[1]],
121
+ }));
122
+ }
123
+ }
@@ -0,0 +1,33 @@
1
+ import { SmithGroup } from '../svg/SmithGroup.js';
2
+ import { SmithScaler } from '../svg/SmithScaler.js';
3
+ import type { TraceStyle } from '../measurements.js';
4
+ import type { TraceSamples } from '../samples.js';
5
+ export interface TraceTransform {
6
+ x: number;
7
+ y: number;
8
+ k: number;
9
+ }
10
+ /** Draws a trace; sample validation and marker selection belong to TraceModel. */
11
+ export declare class TraceRenderer {
12
+ private data;
13
+ private color;
14
+ private transform;
15
+ private scaler;
16
+ private style;
17
+ private viewportScale;
18
+ private visible;
19
+ private group;
20
+ constructor(data: TraceSamples, color: string, transform: TraceTransform, container: SmithGroup, scaler: SmithScaler, style?: Partial<TraceStyle>);
21
+ private drawTrace;
22
+ private renderPoints;
23
+ setViewportScale(scale: number): void;
24
+ zoom(transform: TraceTransform): void;
25
+ private zoomDataPoints;
26
+ setColor(color: string): void;
27
+ get Style(): TraceStyle;
28
+ setStyle(options: Partial<TraceStyle>): void;
29
+ private redraw;
30
+ setVisible(visible: boolean): void;
31
+ update(data: TraceSamples): void;
32
+ destroy(): void;
33
+ }
@@ -0,0 +1,152 @@
1
+ import { line } from 'd3';
2
+ import { SmithGroup } from '../svg/SmithGroup.js';
3
+ /** Draws a trace; sample validation and marker selection belong to TraceModel. */
4
+ export class TraceRenderer {
5
+ data;
6
+ color;
7
+ transform;
8
+ scaler;
9
+ style;
10
+ viewportScale = 1;
11
+ visible = true;
12
+ group;
13
+ constructor(data, color, transform, container, scaler, style = {}) {
14
+ this.data = data;
15
+ this.color = color;
16
+ this.transform = transform;
17
+ this.scaler = scaler;
18
+ this.style = {
19
+ mode: style.mode ?? 'points',
20
+ lineWidth: style.lineWidth ?? 2,
21
+ pointRadius: style.pointRadius ?? 2,
22
+ };
23
+ this.group = this.drawTrace(data).attr('pointer-events', 'none');
24
+ container.append(this.group);
25
+ }
26
+ drawTrace(data) {
27
+ const group = new SmithGroup({
28
+ stroke: 'none',
29
+ strokeWidth: 'none',
30
+ fill: this.color,
31
+ });
32
+ group.attr('data-role', 'samples');
33
+ group.attr('data-mode', this.style.mode);
34
+ if (this.style.mode !== 'points') {
35
+ const path = line()
36
+ .x((sample) => this.scaler.x(sample.reflectionCoefficient[0]))
37
+ .y((sample) => this.scaler.y(sample.reflectionCoefficient[1]));
38
+ group.Element.append('path')
39
+ .attr('class', 'trace-line')
40
+ .attr('d', path(data))
41
+ .attr('fill', 'none')
42
+ .attr('stroke', this.color)
43
+ .attr('stroke-width', this.style.lineWidth)
44
+ .attr('vector-effect', 'non-scaling-stroke')
45
+ .attr('stroke-linejoin', 'round')
46
+ .attr('stroke-linecap', 'round');
47
+ }
48
+ if (this.style.mode !== 'line') {
49
+ this.renderPoints(group, data);
50
+ }
51
+ return group;
52
+ }
53
+ renderPoints(group, data) {
54
+ let visible = data;
55
+ if (data.length > 5000) {
56
+ const cells = new Set();
57
+ const cellSize = Math.max(0.5, this.style.pointRadius) / this.viewportScale;
58
+ const extent = this.scaler.x(1);
59
+ const margin = this.style.pointRadius / this.viewportScale;
60
+ visible = data.filter((sample) => {
61
+ const x = this.scaler.x(sample.reflectionCoefficient[0]) * this.transform.k + this.transform.x;
62
+ const y = this.scaler.y(sample.reflectionCoefficient[1]) * this.transform.k + this.transform.y;
63
+ if (x < -margin || y < -margin || x > extent + margin || y > extent + margin) {
64
+ return false;
65
+ }
66
+ const cell = `${Math.floor(x / cellSize)},${Math.floor(y / cellSize)}`;
67
+ if (cells.has(cell)) {
68
+ return false;
69
+ }
70
+ cells.add(cell);
71
+ return true;
72
+ });
73
+ }
74
+ group.Element.selectAll('circle')
75
+ .data(visible)
76
+ .join('circle')
77
+ .attr('cx', (sample) => this.scaler.x(sample.reflectionCoefficient[0]))
78
+ .attr('cy', (sample) => this.scaler.y(sample.reflectionCoefficient[1]))
79
+ .attr('r', this.style.pointRadius / (this.transform.k * this.viewportScale));
80
+ }
81
+ setViewportScale(scale) {
82
+ if (scale === this.viewportScale || !Number.isFinite(scale) || scale <= 0) {
83
+ return;
84
+ }
85
+ this.viewportScale = scale;
86
+ this.zoomDataPoints();
87
+ }
88
+ zoom(transform) {
89
+ this.transform = transform;
90
+ this.zoomDataPoints();
91
+ }
92
+ zoomDataPoints() {
93
+ const k = this.transform.k;
94
+ if (this.style.mode === 'line') {
95
+ return;
96
+ }
97
+ if (this.data.length > 5000) {
98
+ this.renderPoints(this.group, this.data);
99
+ }
100
+ else {
101
+ this.group.Element.selectAll('circle').attr('r', this.style.pointRadius / (k * this.viewportScale));
102
+ }
103
+ }
104
+ setColor(color) {
105
+ this.color = color;
106
+ this.group.attr('fill', color);
107
+ this.group.Element.select('.trace-line').attr('stroke', color);
108
+ }
109
+ get Style() {
110
+ return { ...this.style };
111
+ }
112
+ setStyle(options) {
113
+ const next = {
114
+ mode: options.mode ?? this.style.mode,
115
+ lineWidth: options.lineWidth ?? this.style.lineWidth,
116
+ pointRadius: options.pointRadius ?? this.style.pointRadius,
117
+ };
118
+ if (next.mode === this.style.mode &&
119
+ next.lineWidth === this.style.lineWidth &&
120
+ next.pointRadius === this.style.pointRadius) {
121
+ return;
122
+ }
123
+ const modeChanged = next.mode !== this.style.mode;
124
+ this.style = next;
125
+ if (modeChanged) {
126
+ this.redraw();
127
+ }
128
+ else {
129
+ this.group.Element.select('.trace-line').attr('stroke-width', next.lineWidth);
130
+ this.zoomDataPoints();
131
+ }
132
+ }
133
+ redraw() {
134
+ const group = this.drawTrace(this.data).attr('pointer-events', 'none');
135
+ // Replace in place to retain trace ordering beneath the separate marker layer.
136
+ this.group.Node.replaceWith(group.Node);
137
+ this.group = group;
138
+ this.group.Element.style('display', () => (this.visible ? null : 'none'));
139
+ }
140
+ setVisible(visible) {
141
+ this.visible = visible;
142
+ this.group.Element.style('display', () => (visible ? null : 'none'));
143
+ }
144
+ update(data) {
145
+ this.data = data;
146
+ this.redraw();
147
+ }
148
+ destroy() {
149
+ this.data = [];
150
+ this.group.Element.remove();
151
+ }
152
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smithkit",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Framework-independent, interactive Smith chart library for JavaScript and TypeScript",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -31,10 +31,13 @@
31
31
  "@eslint/js": "^10.0.1",
32
32
  "@playwright/test": "^1.63.0",
33
33
  "@types/node": "^24.0.0",
34
+ "@types/pngjs": "^6.0.5",
34
35
  "@typescript/native": "npm:typescript@^7.0.2",
35
36
  "eslint": "^10.12.0",
36
37
  "eslint-config-prettier": "^10.1.8",
37
38
  "globals": "^17.13.0",
39
+ "pixelmatch": "^8.0.0",
40
+ "pngjs": "^7.0.0",
38
41
  "prettier": "3.9.9",
39
42
  "typescript": "npm:@typescript/typescript6@^6.0.2",
40
43
  "typescript-eslint": "^8.71.0",
@@ -1,10 +0,0 @@
1
- import { createGridDefinitions } from './grid/definitions.js';
2
- import { resistanceLabels, reactanceLabels } from './grid/labels.js';
3
- export { SmithArcEntry } from './grid/types.js';
4
- export type { SmithArcDef, SmithTickDef, SmithTicksShapes, SmithTicksData } from './grid/types.js';
5
- export declare class SmithArcsDefs {
6
- private constructor();
7
- static getData: typeof createGridDefinitions;
8
- static resistanceLabels: typeof resistanceLabels;
9
- static reactanceLabels: typeof reactanceLabels;
10
- }
@@ -1,10 +0,0 @@
1
- import { createGridDefinitions } from './grid/definitions.js';
2
- import { resistanceLabels, reactanceLabels } from './grid/labels.js';
3
- // Compatibility facade; definitions and label rules are independent of SVG rendering.
4
- export { SmithArcEntry } from './grid/types.js';
5
- export class SmithArcsDefs {
6
- constructor() { }
7
- static getData = createGridDefinitions;
8
- static resistanceLabels = resistanceLabels;
9
- static reactanceLabels = reactanceLabels;
10
- }
@@ -1,14 +0,0 @@
1
- /** An ideal series component equivalent to a reactance at one frequency. */
2
- export type ReactiveComponent = {
3
- readonly kind: 'inductor';
4
- readonly inductanceHenries: number;
5
- } | {
6
- readonly kind: 'capacitor';
7
- readonly capacitanceFarads: number;
8
- };
9
- /**
10
- * Convert reactance in ohms at a frequency in Hz to an ideal series L or C.
11
- * Zero frequency, zero reactance, or an unrepresentable component returns undefined.
12
- * Non-finite reactance and negative/non-finite frequency throw RangeError.
13
- */
14
- export declare function reactanceToComponent(reactanceOhms: number, frequencyHz: number): ReactiveComponent | undefined;
@@ -1,26 +0,0 @@
1
- /**
2
- * Convert reactance in ohms at a frequency in Hz to an ideal series L or C.
3
- * Zero frequency, zero reactance, or an unrepresentable component returns undefined.
4
- * Non-finite reactance and negative/non-finite frequency throw RangeError.
5
- */
6
- export function reactanceToComponent(reactanceOhms, frequencyHz) {
7
- if (!Number.isFinite(reactanceOhms)) {
8
- throw new RangeError('Reactance must be finite.');
9
- }
10
- if (!Number.isFinite(frequencyHz) || frequencyHz < 0) {
11
- throw new RangeError('Frequency must be finite and non-negative.');
12
- }
13
- if (frequencyHz === 0 || reactanceOhms === 0) {
14
- return;
15
- }
16
- // Compute in log space so intermediate products/quotients cannot overflow.
17
- const logReactance = Math.log(Math.abs(reactanceOhms));
18
- const logAngularFrequency = Math.log(2 * Math.PI) + Math.log(frequencyHz);
19
- const value = Math.exp((reactanceOhms > 0 ? logReactance : -logReactance) - logAngularFrequency);
20
- if (!Number.isFinite(value) || value === 0) {
21
- return;
22
- }
23
- return reactanceOhms > 0
24
- ? { kind: 'inductor', inductanceHenries: value }
25
- : { kind: 'capacitor', capacitanceFarads: value };
26
- }