smithkit 0.0.0-stage → 0.1.1

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 (101) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +467 -2
  3. package/dist/lib/Smith.d.ts +103 -0
  4. package/dist/lib/Smith.js +562 -0
  5. package/dist/lib/SmithArcsDefs.d.ts +10 -0
  6. package/dist/lib/SmithArcsDefs.js +10 -0
  7. package/dist/lib/SmithConstantCircle.d.ts +62 -0
  8. package/dist/lib/SmithConstantCircle.js +222 -0
  9. package/dist/lib/arcs/Tick.d.ts +33 -0
  10. package/dist/lib/arcs/Tick.js +40 -0
  11. package/dist/lib/complex/Complex.d.ts +130 -0
  12. package/dist/lib/complex/Complex.js +636 -0
  13. package/dist/lib/components.d.ts +14 -0
  14. package/dist/lib/components.js +26 -0
  15. package/dist/lib/draw/ConstCircles.d.ts +63 -0
  16. package/dist/lib/draw/ConstCircles.js +158 -0
  17. package/dist/lib/draw/ConstConductance.d.ts +4 -0
  18. package/dist/lib/draw/ConstConductance.js +6 -0
  19. package/dist/lib/draw/ConstQCircles.d.ts +29 -0
  20. package/dist/lib/draw/ConstQCircles.js +86 -0
  21. package/dist/lib/draw/ConstReactance.d.ts +4 -0
  22. package/dist/lib/draw/ConstReactance.js +6 -0
  23. package/dist/lib/draw/ConstResistance.d.ts +4 -0
  24. package/dist/lib/draw/ConstResistance.js +6 -0
  25. package/dist/lib/draw/ConstSusceptance.d.ts +4 -0
  26. package/dist/lib/draw/ConstSusceptance.js +6 -0
  27. package/dist/lib/draw/ConstSwrCircles.d.ts +29 -0
  28. package/dist/lib/draw/ConstSwrCircles.js +85 -0
  29. package/dist/lib/draw/MouseGesture.d.ts +6 -0
  30. package/dist/lib/draw/MouseGesture.js +26 -0
  31. package/dist/lib/draw/SmithArc.d.ts +10 -0
  32. package/dist/lib/draw/SmithArc.js +26 -0
  33. package/dist/lib/draw/SmithCircle.d.ts +10 -0
  34. package/dist/lib/draw/SmithCircle.js +24 -0
  35. package/dist/lib/draw/SmithCursor.d.ts +49 -0
  36. package/dist/lib/draw/SmithCursor.js +186 -0
  37. package/dist/lib/draw/SmithData.d.ts +66 -0
  38. package/dist/lib/draw/SmithData.js +366 -0
  39. package/dist/lib/draw/SmithDrawOptions.d.ts +5 -0
  40. package/dist/lib/draw/SmithDrawOptions.js +1 -0
  41. package/dist/lib/draw/SmithGridLayer.d.ts +19 -0
  42. package/dist/lib/draw/SmithGridLayer.js +48 -0
  43. package/dist/lib/draw/SmithGroup.d.ts +11 -0
  44. package/dist/lib/draw/SmithGroup.js +31 -0
  45. package/dist/lib/draw/SmithLine.d.ts +11 -0
  46. package/dist/lib/draw/SmithLine.js +27 -0
  47. package/dist/lib/draw/SmithMarker.d.ts +25 -0
  48. package/dist/lib/draw/SmithMarker.js +122 -0
  49. package/dist/lib/draw/SmithPath.d.ts +8 -0
  50. package/dist/lib/draw/SmithPath.js +20 -0
  51. package/dist/lib/draw/SmithScaler.d.ts +19 -0
  52. package/dist/lib/draw/SmithScaler.js +48 -0
  53. package/dist/lib/draw/SmithShape.d.ts +15 -0
  54. package/dist/lib/draw/SmithShape.js +42 -0
  55. package/dist/lib/draw/SmithSvg.d.ts +9 -0
  56. package/dist/lib/draw/SmithSvg.js +27 -0
  57. package/dist/lib/draw/SmithText.d.ts +22 -0
  58. package/dist/lib/draw/SmithText.js +56 -0
  59. package/dist/lib/formatting.d.ts +7 -0
  60. package/dist/lib/formatting.js +16 -0
  61. package/dist/lib/grid/definitions.d.ts +3 -0
  62. package/dist/lib/grid/definitions.js +123 -0
  63. package/dist/lib/grid/geometry.d.ts +20 -0
  64. package/dist/lib/grid/geometry.js +55 -0
  65. package/dist/lib/grid/labels.d.ts +3 -0
  66. package/dist/lib/grid/labels.js +41 -0
  67. package/dist/lib/grid/types.d.ts +30 -0
  68. package/dist/lib/grid/types.js +6 -0
  69. package/dist/lib/index.d.ts +16 -0
  70. package/dist/lib/index.js +9 -0
  71. package/dist/lib/io/touchstone.d.ts +7 -0
  72. package/dist/lib/io/touchstone.js +72 -0
  73. package/dist/lib/layers.d.ts +48 -0
  74. package/dist/lib/layers.js +73 -0
  75. package/dist/lib/math/complexRatio.d.ts +3 -0
  76. package/dist/lib/math/complexRatio.js +30 -0
  77. package/dist/lib/measurements.d.ts +53 -0
  78. package/dist/lib/measurements.js +19 -0
  79. package/dist/lib/renormalization.d.ts +10 -0
  80. package/dist/lib/renormalization.js +62 -0
  81. package/dist/lib/rf.d.ts +35 -0
  82. package/dist/lib/rf.js +74 -0
  83. package/dist/lib/samples.d.ts +6 -0
  84. package/dist/lib/samples.js +1 -0
  85. package/dist/lib/scales/SmithPeripheralScales.d.ts +13 -0
  86. package/dist/lib/scales/SmithPeripheralScales.js +141 -0
  87. package/dist/lib/scales/SmithScales.d.ts +16 -0
  88. package/dist/lib/scales/SmithScales.js +142 -0
  89. package/dist/lib/scales/peripheralScales.d.ts +12 -0
  90. package/dist/lib/scales/peripheralScales.js +49 -0
  91. package/dist/lib/scales/radialScales.d.ts +12 -0
  92. package/dist/lib/scales/radialScales.js +109 -0
  93. package/dist/lib/shapes/Arc.d.ts +6 -0
  94. package/dist/lib/shapes/Arc.js +1 -0
  95. package/dist/lib/shapes/Circle.d.ts +5 -0
  96. package/dist/lib/shapes/Circle.js +1 -0
  97. package/dist/lib/shapes/Line.d.ts +5 -0
  98. package/dist/lib/shapes/Line.js +1 -0
  99. package/dist/lib/shapes/Point.d.ts +1 -0
  100. package/dist/lib/shapes/Point.js +1 -0
  101. package/package.json +76 -4
@@ -0,0 +1,636 @@
1
+ export class Complex {
2
+ realPart;
3
+ imaginaryPart;
4
+ tolerance = Number.EPSILON;
5
+ constructor(re, im) {
6
+ this.realPart = re;
7
+ this.imaginaryPart = im;
8
+ }
9
+ static from(...args) {
10
+ if (args.length === 1) {
11
+ const arg = args[0];
12
+ if (typeof arg === 'number') {
13
+ return new Complex(arg, 0);
14
+ }
15
+ if (typeof arg === 'object' &&
16
+ arg !== null &&
17
+ 're' in arg &&
18
+ 'im' in arg &&
19
+ typeof arg.re === 'number' &&
20
+ typeof arg.im === 'number') {
21
+ return new Complex(arg.re, arg.im);
22
+ }
23
+ if (typeof arg === 'object' &&
24
+ arg !== null &&
25
+ 'r' in arg &&
26
+ 'phi' in arg &&
27
+ typeof arg.r === 'number' &&
28
+ typeof arg.phi === 'number') {
29
+ return Complex.fromPolar(arg.r, arg.phi);
30
+ }
31
+ if (Array.isArray(arg) && arg.length === 2) {
32
+ return new Complex(arg[0], arg[1]);
33
+ }
34
+ }
35
+ if (args.length === 2) {
36
+ const arg0 = args[0];
37
+ const arg1 = args[1];
38
+ if (typeof arg0 === 'number' && typeof arg1 === 'number') {
39
+ return new Complex(arg0, arg1);
40
+ }
41
+ }
42
+ throw new Error('Cannot create complex number, invalid arguments.');
43
+ }
44
+ static fromPolar(r, phi) {
45
+ return new Complex(r * Math.cos(phi), r * Math.sin(phi));
46
+ }
47
+ static one() {
48
+ return new Complex(1, 0);
49
+ }
50
+ static zero() {
51
+ return new Complex(0, 0);
52
+ }
53
+ static get i() {
54
+ return new Complex(0, 1);
55
+ }
56
+ get re() {
57
+ return this.realPart;
58
+ }
59
+ get im() {
60
+ return this.imaginaryPart;
61
+ }
62
+ get epsilon() {
63
+ return this.tolerance;
64
+ }
65
+ set epsilon(e) {
66
+ this.tolerance = e;
67
+ }
68
+ abs() {
69
+ return Complex.abs(this);
70
+ }
71
+ arg() {
72
+ return Complex.arg(this);
73
+ }
74
+ sign() {
75
+ return Complex.sign(this);
76
+ }
77
+ conj() {
78
+ return Complex.conj(this);
79
+ }
80
+ neg() {
81
+ return Complex.neg(this);
82
+ }
83
+ inv() {
84
+ return Complex.inv(this);
85
+ }
86
+ add(v) {
87
+ return Complex.add(this, v);
88
+ }
89
+ sub(v) {
90
+ return Complex.sub(this, v);
91
+ }
92
+ mul(v) {
93
+ return Complex.mul(this, v);
94
+ }
95
+ div(v) {
96
+ return Complex.div(this, v);
97
+ }
98
+ exp() {
99
+ return Complex.exp(this);
100
+ }
101
+ log() {
102
+ return Complex.log(this);
103
+ }
104
+ log2() {
105
+ return Complex.log2(this);
106
+ }
107
+ log10() {
108
+ return Complex.log10(this);
109
+ }
110
+ pow(exponent) {
111
+ return Complex.pow(this, exponent);
112
+ }
113
+ sqrt() {
114
+ return Complex.sqrt(this);
115
+ }
116
+ sin() {
117
+ return Complex.sin(this);
118
+ }
119
+ asin() {
120
+ return Complex.asin(this);
121
+ }
122
+ sinh() {
123
+ return Complex.sinh(this);
124
+ }
125
+ asinh() {
126
+ return Complex.asinh(this);
127
+ }
128
+ cos() {
129
+ return Complex.cos(this);
130
+ }
131
+ acos() {
132
+ return Complex.acos(this);
133
+ }
134
+ cosh() {
135
+ return Complex.cosh(this);
136
+ }
137
+ acosh() {
138
+ return Complex.acosh(this);
139
+ }
140
+ tan() {
141
+ return Complex.tan(this);
142
+ }
143
+ atan() {
144
+ return Complex.atan(this);
145
+ }
146
+ tanh() {
147
+ return Complex.tanh(this);
148
+ }
149
+ atanh() {
150
+ return Complex.atanh(this);
151
+ }
152
+ cot() {
153
+ return Complex.cot(this);
154
+ }
155
+ acot() {
156
+ return Complex.acot(this);
157
+ }
158
+ coth() {
159
+ return Complex.coth(this);
160
+ }
161
+ acoth() {
162
+ return Complex.acoth(this);
163
+ }
164
+ sec() {
165
+ return Complex.sec(this);
166
+ }
167
+ asec() {
168
+ return Complex.asec(this);
169
+ }
170
+ sech() {
171
+ return Complex.sech(this);
172
+ }
173
+ asech() {
174
+ return Complex.asech(this);
175
+ }
176
+ csc() {
177
+ return Complex.csc(this);
178
+ }
179
+ acsc() {
180
+ return Complex.acsc(this);
181
+ }
182
+ csch() {
183
+ return Complex.csch(this);
184
+ }
185
+ acsch() {
186
+ return Complex.acsch(this);
187
+ }
188
+ equals(z) {
189
+ return Complex.equals(this, z, this.epsilon);
190
+ }
191
+ toPolar() {
192
+ return Complex.toPolar(this);
193
+ }
194
+ toVector() {
195
+ return Complex.toVector(this);
196
+ }
197
+ toString(dp = 3) {
198
+ return Complex.toString(this, dp);
199
+ }
200
+ static abs(z) {
201
+ return Math.sqrt(z.re ** 2 + z.im ** 2);
202
+ }
203
+ static arg(z) {
204
+ return Math.atan2(z.im, z.re);
205
+ }
206
+ static sign(z) {
207
+ const abs = z.abs();
208
+ return Complex.from({
209
+ re: z.re / abs,
210
+ im: z.im / abs,
211
+ });
212
+ }
213
+ static conj(z) {
214
+ return Complex.from(z.re, -z.im);
215
+ }
216
+ static neg(z) {
217
+ return Complex.from(-z.re, -z.im);
218
+ }
219
+ static inv(z) {
220
+ return Complex.reciprocal(z);
221
+ }
222
+ static add(z, v) {
223
+ if (typeof v === 'number') {
224
+ return Complex.from(z.re + v, z.im);
225
+ }
226
+ else {
227
+ return Complex.from(z.re + v.re, z.im + v.im);
228
+ }
229
+ }
230
+ static sub(z, v) {
231
+ if (typeof v === 'number') {
232
+ return Complex.from(z.re - v, z.im);
233
+ }
234
+ else {
235
+ return Complex.from(z.re - v.re, z.im - v.im);
236
+ }
237
+ }
238
+ static mul(z, v) {
239
+ if (!Complex.isFinite(z) ||
240
+ (typeof v === 'number' ? !Number.isFinite(v) : !Complex.isFinite(v))) {
241
+ return Complex.nan();
242
+ }
243
+ if (typeof v === 'number') {
244
+ return Complex.from(z.re * v, z.im * v);
245
+ }
246
+ const real = Complex.productSum(z.re, v.re, -z.im, v.im);
247
+ const imaginary = Complex.productSum(z.re, v.im, z.im, v.re);
248
+ return Complex.from(Complex.scalePowerOfTwo(...real), Complex.scalePowerOfTwo(...imaginary));
249
+ }
250
+ static div(z, v) {
251
+ if (!Complex.isFinite(z) ||
252
+ (typeof v === 'number' ? !Number.isFinite(v) : !Complex.isFinite(v))) {
253
+ return Complex.nan();
254
+ }
255
+ if (typeof v === 'number') {
256
+ return v === 0 ? Complex.nan() : Complex.from(z.re / v, z.im / v);
257
+ }
258
+ if (v.re === 0 && v.im === 0) {
259
+ return Complex.nan();
260
+ }
261
+ // Keep products as mantissa/exponent pairs, including subnormal inputs.
262
+ // Neither squaring the denominator nor cancellation requires an infinite intermediate.
263
+ const [denominator, exponent] = Complex.productSum(v.re, v.re, v.im, v.im);
264
+ const quotient = (a, b, c, d) => {
265
+ const [numerator, power] = Complex.productSum(a, b, c, d);
266
+ return Complex.scalePowerOfTwo(numerator / denominator, power - exponent);
267
+ };
268
+ return Complex.from(quotient(z.re, v.re, z.im, v.im), quotient(z.im, v.re, -z.re, v.im));
269
+ }
270
+ static exp(z) {
271
+ // e^(a + bi) = e^a * e^bi = e^a * (cos(b) + i sin(b))
272
+ const eRe = Math.exp(z.re);
273
+ return Complex.from({
274
+ re: eRe * Math.cos(z.im),
275
+ im: eRe * Math.sin(z.im),
276
+ });
277
+ }
278
+ static log(z) {
279
+ if (!Complex.isFinite(z)) {
280
+ return Complex.nan();
281
+ }
282
+ return Complex.from(Complex.logHypot(z.re, z.im), z.arg());
283
+ }
284
+ static log2(z) {
285
+ const value = Complex.log(z);
286
+ return Complex.from(value.re * Math.LOG2E, value.im * Math.LOG2E);
287
+ }
288
+ static log10(z) {
289
+ const value = Complex.log(z);
290
+ return Complex.from(value.re * Math.LOG10E, value.im * Math.LOG10E);
291
+ }
292
+ static pow(z, exponent) {
293
+ if (!Complex.isFinite(z) || !Number.isFinite(exponent)) {
294
+ return Complex.nan();
295
+ }
296
+ if (exponent === 0) {
297
+ return Complex.one();
298
+ }
299
+ if (exponent === 1) {
300
+ return Complex.from(z.re, z.im);
301
+ }
302
+ if (exponent === -1) {
303
+ return Complex.inv(z);
304
+ }
305
+ if (exponent === 0.5) {
306
+ return Complex.sqrt(z);
307
+ }
308
+ if (exponent === 2) {
309
+ return Complex.mul(z, z);
310
+ }
311
+ if (z.re === 0 && z.im === 0) {
312
+ return exponent > 0 ? Complex.zero() : Complex.nan();
313
+ }
314
+ const logRadius = Complex.logHypot(z.re, z.im) * exponent;
315
+ const angle = z.arg() * exponent;
316
+ const component = (factor) => factor === 0
317
+ ? factor
318
+ : Complex.copySign(Math.exp(logRadius + Math.log(Math.abs(factor))), factor);
319
+ return Complex.from(component(Math.cos(angle)), component(Math.sin(angle)));
320
+ }
321
+ static sqrt(z) {
322
+ if (!Complex.isFinite(z)) {
323
+ return Complex.nan();
324
+ }
325
+ const scale = Math.max(Math.abs(z.re), Math.abs(z.im));
326
+ if (scale === 0) {
327
+ return Complex.from(0, z.im);
328
+ }
329
+ const x = z.re / scale;
330
+ const y = z.im / scale;
331
+ const root = Math.sqrt(scale) * Math.sqrt((Math.hypot(x, y) + Math.abs(x)) / 2);
332
+ return z.re >= 0
333
+ ? Complex.from(root, z.im / (2 * root))
334
+ : Complex.from(Math.abs(z.im) / (2 * root), Complex.copySign(root, z.im));
335
+ }
336
+ static sin(z) {
337
+ // sin(a+bi) = sin(a)cosh(b) + icos(a)sinh(b)
338
+ // https://proofwiki.org/wiki/Sine_of_Complex_Number
339
+ return Complex.from(Math.sin(z.re) * Math.cosh(z.im), Math.cos(z.re) * Math.sinh(z.im));
340
+ }
341
+ static asin(z) {
342
+ // asin(z) = -i * ln(zi + sqrt(1 - z^2))
343
+ // ref. https://en.wikipedia.org/wiki/Inverse_trigonometric_functions#Logarithmic_forms
344
+ const C = Complex;
345
+ const i = C.i;
346
+ return i.neg().mul(C.log(z.mul(i).add(C.sqrt(C.one().sub(z.pow(2))))));
347
+ }
348
+ static sinh(z) {
349
+ if (!Complex.isFinite(z)) {
350
+ return Complex.nan();
351
+ }
352
+ return Complex.from(Complex.hyperbolicProduct(z.re, Math.cos(z.im), true), Complex.hyperbolicProduct(z.re, Math.sin(z.im), false));
353
+ }
354
+ static asinh(z) {
355
+ if (!Complex.isFinite(z)) {
356
+ return Complex.nan();
357
+ }
358
+ const x = Math.abs(z.re);
359
+ const y = Math.abs(z.im);
360
+ if (Math.max(x, y) < 1e-8) {
361
+ return Complex.from(z.re, z.im);
362
+ }
363
+ if (y < 1 && x < 1e-150) {
364
+ return Complex.from(z.re / (Math.sqrt(1 - y) * Math.sqrt(1 + y)), Math.asin(z.im));
365
+ }
366
+ if (Math.max(x, y) > 1e150) {
367
+ return Complex.from(Complex.copySign(Complex.logHypot(x, y) + Math.LN2, z.re), Math.atan2(z.im, x));
368
+ }
369
+ const { real, transverse } = Complex.inverseHyperbolicParts(y, x);
370
+ return Complex.from(Complex.copySign(real, z.re), Complex.copySign(Math.atan2(y, transverse), z.im));
371
+ }
372
+ static cos(z) {
373
+ // cos(a+bi) = cos(a)cosh(b) + isin(a)sinh(b)
374
+ // https://proofwiki.org/wiki/Cosine_of_Complex_Number
375
+ return Complex.from(Math.cos(z.re) * Math.cosh(z.im), -Math.sin(z.re) * Math.sinh(z.im));
376
+ }
377
+ static acos(z) {
378
+ // acos(z) = -i * ln(z + sqrt(z^2 - 1))
379
+ // = pi/2 + i * ln(zi + sqrt(1 - z^2))
380
+ // = pi/2 - asin(z)
381
+ // ref. https://en.wikipedia.org/wiki/Inverse_trigonometric_functions#Logarithmic_forms
382
+ return Complex.from(Math.PI / 2).sub(z.asin());
383
+ }
384
+ static cosh(z) {
385
+ if (!Complex.isFinite(z)) {
386
+ return Complex.nan();
387
+ }
388
+ return Complex.from(Complex.hyperbolicProduct(z.re, Math.cos(z.im), false), Complex.hyperbolicProduct(z.re, Math.sin(z.im), true));
389
+ }
390
+ static acosh(z) {
391
+ if (!Complex.isFinite(z)) {
392
+ return Complex.nan();
393
+ }
394
+ if (Math.abs(z.re) < 1 && Math.abs(z.im) < 1e-150) {
395
+ return Complex.from(Math.abs(z.im) / (Math.sqrt(1 - z.re) * Math.sqrt(1 + z.re)), Complex.copySign(Math.acos(z.re), z.im));
396
+ }
397
+ if (Math.max(Math.abs(z.re), Math.abs(z.im)) > 1e150) {
398
+ return Complex.from(Complex.logHypot(z.re, z.im) + Math.LN2, Math.atan2(z.im, z.re));
399
+ }
400
+ const { real, transverse } = Complex.inverseHyperbolicParts(Math.abs(z.re), Math.abs(z.im));
401
+ return Complex.from(real, Complex.copySign(Math.atan2(transverse, z.re), z.im));
402
+ }
403
+ static tan(z) {
404
+ return z.sin().div(z.cos());
405
+ }
406
+ static atan(z) {
407
+ // atan(z) = i / 2 * ln((i + z) / (i - z))
408
+ // = i / 2 * [ln(1 - iz) - ln(1 + iz)]
409
+ // ref. https://en.wikipedia.org/wiki/Inverse_trigonometric_functions#Logarithmic_forms
410
+ const C = Complex;
411
+ const i = C.i;
412
+ const z1 = C.log(C.one().sub(i.mul(z)));
413
+ const z2 = C.log(C.one().add(i.mul(z)));
414
+ return i.div(2).mul(z1.sub(z2));
415
+ }
416
+ static tanh(z) {
417
+ if (!Complex.isFinite(z)) {
418
+ return Complex.nan();
419
+ }
420
+ // Divide through by exp(2|x|); expm1 retains the real part near zero.
421
+ const q = Math.exp(-2 * Math.abs(z.re));
422
+ const difference = -Math.expm1(-2 * Math.abs(z.re));
423
+ const cos = Math.cos(z.im);
424
+ const sin = Math.sin(z.im);
425
+ const denominator = difference * difference + 4 * q * cos * cos;
426
+ return Complex.from(Complex.copySign((difference * (1 + q)) / denominator, z.re), (4 * q * sin * cos) / denominator);
427
+ }
428
+ static atanh(z) {
429
+ if (!Complex.isFinite(z)) {
430
+ return Complex.nan();
431
+ }
432
+ const x = Math.abs(z.re);
433
+ const y = Math.abs(z.im);
434
+ if (Math.max(x, y) > 1e150) {
435
+ return Complex.from(Complex.reciprocal(z).re, Complex.copySign(Math.PI / 2, z.im));
436
+ }
437
+ const distance = Math.hypot(1 - x, y);
438
+ const real = distance < 1e-150
439
+ ? (Complex.logHypot(1 + x, y) - Complex.logHypot(1 - x, y)) / 2
440
+ : Math.log1p((4 * (x / distance)) / distance) / 4;
441
+ const imag = Math.atan2(2 * z.im, (1 - x) * (1 + x) - y * y) / 2;
442
+ return Complex.from(Complex.copySign(real, z.re), imag);
443
+ }
444
+ static cot(z) {
445
+ return z.cos().div(z.sin());
446
+ }
447
+ static acot(z) {
448
+ // atan(z) = i / 2 * ln((i - z) / (i + z))
449
+ // = i / 2 * [ln(1 - i/z) - ln(1 + i/z)]
450
+ // ref. https://en.wikipedia.org/wiki/Inverse_trigonometric_functions#Logarithmic_forms
451
+ const C = Complex;
452
+ const i = C.i;
453
+ const z1 = C.log(C.one().sub(i.div(z)));
454
+ const z2 = C.log(C.one().add(i.div(z)));
455
+ return i.div(2).mul(z1.sub(z2));
456
+ }
457
+ static coth(z) {
458
+ if (!Complex.isFinite(z)) {
459
+ return Complex.nan();
460
+ }
461
+ return Complex.reciprocal(Complex.tanh(z));
462
+ }
463
+ static acoth(z) {
464
+ if (!Complex.isFinite(z)) {
465
+ return Complex.nan();
466
+ }
467
+ if (Math.max(Math.abs(z.re), Math.abs(z.im)) < 1e-150) {
468
+ return Complex.from(z.re, Complex.copySign(Math.PI / 2, -z.im));
469
+ }
470
+ return Complex.atanh(Complex.reciprocal(z));
471
+ }
472
+ static sec(z) {
473
+ return Complex.sech(Complex.from(-z.im, z.re));
474
+ }
475
+ static asec(z) {
476
+ // asec(z) = -i * ln(sqrt(1 / z^2 - 1) + 1 / z))
477
+ // ref. https://en.wikipedia.org/wiki/Inverse_trigonometric_functions#Logarithmic_forms
478
+ const C = Complex;
479
+ const i = C.i;
480
+ return i.neg().mul(C.log(C.sqrt(C.one().div(z.pow(2)).sub(1)).add(z.inv())));
481
+ }
482
+ static sech(z) {
483
+ return Complex.hyperbolicReciprocal(z, true);
484
+ }
485
+ static asech(z) {
486
+ if (!Complex.isFinite(z) || (z.re === 0 && z.im === 0)) {
487
+ return Complex.nan();
488
+ }
489
+ if (Math.max(Math.abs(z.re), Math.abs(z.im)) < 1e-150) {
490
+ return Complex.from(Math.LN2 - Complex.logHypot(z.re, z.im), -Math.atan2(z.im, z.re));
491
+ }
492
+ return Complex.acosh(Complex.reciprocal(z));
493
+ }
494
+ static csc(z) {
495
+ const value = Complex.csch(Complex.from(-z.im, z.re));
496
+ return Complex.from(-value.im, value.re);
497
+ }
498
+ static acsc(z) {
499
+ // acsc(z) = -i * ln(sqrt(1 - 1 / z^2) + i / z))
500
+ // ref. https://en.wikipedia.org/wiki/Inverse_trigonometric_functions#Logarithmic_forms
501
+ const C = Complex;
502
+ const i = C.i;
503
+ return i.neg().mul(C.log(C.sqrt(C.one().sub(C.one().div(z.pow(2)))).add(i.div(z))));
504
+ }
505
+ static csch(z) {
506
+ return Complex.hyperbolicReciprocal(z, false);
507
+ }
508
+ static acsch(z) {
509
+ if (!Complex.isFinite(z) || (z.re === 0 && z.im === 0)) {
510
+ return Complex.nan();
511
+ }
512
+ if (Math.max(Math.abs(z.re), Math.abs(z.im)) < 1e-150) {
513
+ return Complex.from(Complex.copySign(Math.LN2 - Complex.logHypot(z.re, z.im), z.re), Math.atan2(-z.im, Math.abs(z.re)));
514
+ }
515
+ return Complex.asinh(Complex.reciprocal(z));
516
+ }
517
+ static isFinite(z) {
518
+ return Number.isFinite(z.re) && Number.isFinite(z.im);
519
+ }
520
+ static nan() {
521
+ return Complex.from(NaN, NaN);
522
+ }
523
+ static copySign(magnitude, sign) {
524
+ return sign < 0 || Object.is(sign, -0) ? -Math.abs(magnitude) : Math.abs(magnitude);
525
+ }
526
+ static logHypot(x, y) {
527
+ const scale = Math.max(Math.abs(x), Math.abs(y));
528
+ return scale === 0 ? -Infinity : Math.log(scale) + Math.log(Math.hypot(x / scale, y / scale));
529
+ }
530
+ /** Sum two products without premature overflow/underflow. Result is mantissa × 2^exponent. */
531
+ static productSum(a, b, c, d) {
532
+ const product = (x, y) => {
533
+ if (x === 0 || y === 0) {
534
+ return [x * y, 0];
535
+ }
536
+ const ex = Math.min(1023, Math.floor(Math.log2(Math.abs(x))));
537
+ const ey = Math.min(1023, Math.floor(Math.log2(Math.abs(y))));
538
+ return [(x / 2 ** ex) * (y / 2 ** ey), ex + ey];
539
+ };
540
+ const [first, ef] = product(a, b);
541
+ const [second, es] = product(c, d);
542
+ if (first === 0) {
543
+ return second === 0 ? [first + second, 0] : [second, es];
544
+ }
545
+ if (second === 0) {
546
+ return [first, ef];
547
+ }
548
+ const exponent = Math.max(ef, es);
549
+ return [first * 2 ** (ef - exponent) + second * 2 ** (es - exponent), exponent];
550
+ }
551
+ static scalePowerOfTwo(value, exponent) {
552
+ if (value === 0) {
553
+ return value;
554
+ }
555
+ // Normalize after cancellation before splitting the final exponent.
556
+ const shift = Math.min(1023, Math.floor(Math.log2(Math.abs(value))));
557
+ value /= 2 ** shift;
558
+ exponent += shift;
559
+ if (exponent > 1023) {
560
+ return value * 2 ** (exponent - 1023) * 2 ** 1023;
561
+ }
562
+ if (exponent < -1022) {
563
+ return value * 2 ** (exponent + 1022) * 2 ** -1022;
564
+ }
565
+ return value * 2 ** exponent;
566
+ }
567
+ /** Cartesian reciprocal, preserving signed zeros on branch cuts. */
568
+ static reciprocal(z) {
569
+ const value = Complex.div(Complex.one(), z);
570
+ if (Number.isNaN(value.re)) {
571
+ return value;
572
+ }
573
+ return Complex.from(z.re === 0 ? Complex.copySign(0, z.re) : value.re, z.im === 0 ? Complex.copySign(0, -z.im) : value.im);
574
+ }
575
+ static hyperbolicProduct(x, factor, odd) {
576
+ if (Math.abs(x) < 20) {
577
+ return factor * (odd ? Math.sinh(x) : Math.cosh(x));
578
+ }
579
+ const sign = odd ? factor * Math.sign(x) : factor;
580
+ if (factor === 0) {
581
+ return sign;
582
+ }
583
+ // Combine the factor before exponentiation to avoid a spurious Infinity * 0.
584
+ return Complex.copySign(Math.exp(Math.abs(x) - Math.LN2 + Math.log(Math.abs(factor))), sign);
585
+ }
586
+ static hyperbolicReciprocal(z, even) {
587
+ if (!Complex.isFinite(z)) {
588
+ return Complex.nan();
589
+ }
590
+ const x = Math.abs(z.re);
591
+ const q = Math.exp(-2 * x);
592
+ const difference = -Math.expm1(-2 * x);
593
+ const cos = Math.cos(z.im);
594
+ const sin = Math.sin(z.im);
595
+ const denominator = even
596
+ ? Complex.from(cos * (1 + q), sin * Complex.copySign(difference, z.re))
597
+ : Complex.from(cos * Complex.copySign(difference, z.re), sin * (1 + q));
598
+ return Complex.reciprocal(denominator).mul(Math.exp(Math.LN2 - x));
599
+ }
600
+ /**
601
+ * Elliptic coordinates for principal inverse functions (x,y >= 0).
602
+ * With a = (|z+1| + |z-1|)/2, return acosh(a) and sqrt(a²-x²).
603
+ * Rationalized hypot differences retain tiny components near the branch cuts.
604
+ * Principal branches: https://dlmf.nist.gov/4.37
605
+ */
606
+ static inverseHyperbolicParts(x, y) {
607
+ const plus = Math.hypot(x + 1, y);
608
+ const minus = Math.hypot(x - 1, y);
609
+ const a = plus / 2 + minus / 2;
610
+ const first = y === 0 ? 0 : y / Math.sqrt(plus + x + 1);
611
+ const second = y === 0 ? 0 : y / Math.sqrt(minus + Math.abs(x - 1));
612
+ const correction = Math.hypot(first, second) / Math.SQRT2;
613
+ const rootAMinus1 = x <= 1 ? correction : Math.hypot(Math.sqrt(x - 1), correction);
614
+ const rootAMinusX = x <= 1 ? Math.hypot(Math.sqrt(1 - x), correction) : correction;
615
+ return {
616
+ real: 2 * Math.asinh(rootAMinus1 / Math.SQRT2),
617
+ transverse: rootAMinusX * Math.sqrt(a + x),
618
+ };
619
+ }
620
+ static equals(z1, z2, epsilon = Number.EPSILON) {
621
+ return Math.abs(z1.re - z2.re) < epsilon && Math.abs(z1.im - z2.im) < epsilon;
622
+ }
623
+ static toPolar(z) {
624
+ return [z.abs(), z.arg()];
625
+ }
626
+ static toVector(z) {
627
+ return [z.re, z.im];
628
+ }
629
+ // TODO: format
630
+ static toString(z, dp = 3) {
631
+ const re = z.re.toFixed(dp);
632
+ const im = Math.abs(z.im).toFixed(dp);
633
+ const imsign = z.im < 0 ? '-' : '+';
634
+ return `${re} ${imsign} ${im}i`;
635
+ }
636
+ }
@@ -0,0 +1,14 @@
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;
@@ -0,0 +1,26 @@
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
+ }