dsp-collection 0.2.5 → 0.2.6
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 +5 -2
- package/filter/SpecFilt.d.ts +10 -10
- package/filter/SpecFilt.js +98 -99
- package/math/Complex.d.ts +42 -42
- package/math/Complex.js +130 -130
- package/math/ComplexArray.d.ts +36 -36
- package/math/ComplexArray.js +170 -171
- package/math/MathUtils.d.ts +9 -7
- package/math/MathUtils.js +116 -82
- package/math/MutableComplex.d.ts +22 -22
- package/math/MutableComplex.js +64 -65
- package/math/NumApprox.d.ts +3 -3
- package/math/NumApprox.js +67 -68
- package/math/PolyReal.d.ts +13 -13
- package/math/PolyReal.js +226 -227
- package/package.json +11 -3
- package/signal/AdaptiveStft.d.ts +12 -12
- package/signal/AdaptiveStft.js +57 -58
- package/signal/Autocorrelation.d.ts +5 -5
- package/signal/Autocorrelation.js +53 -54
- package/signal/Dft.d.ts +9 -9
- package/signal/Dft.js +87 -88
- package/signal/EnvelopeDetection.d.ts +1 -1
- package/signal/EnvelopeDetection.js +9 -10
- package/signal/Fft.d.ts +9 -9
- package/signal/Fft.js +275 -276
- package/signal/Goertzel.d.ts +5 -5
- package/signal/Goertzel.js +48 -49
- package/signal/InstFreq.d.ts +8 -8
- package/signal/InstFreq.js +26 -27
- package/signal/PitchDetectionHarm.d.ts +26 -26
- package/signal/PitchDetectionHarm.js +68 -69
- package/signal/Resampling.d.ts +7 -7
- package/signal/Resampling.js +218 -219
- package/signal/WindowFunctions.d.ts +40 -40
- package/signal/WindowFunctions.js +194 -195
- package/utils/ArrayUtils.d.ts +9 -9
- package/utils/ArrayUtils.js +68 -69
- package/utils/DspUtils.d.ts +4 -2
- package/utils/DspUtils.js +12 -7
- package/utils/MiscUtils.d.ts +6 -6
- package/utils/MiscUtils.js +20 -21
- package/filter/SpecFilt.js.map +0 -1
- package/math/Complex.js.map +0 -1
- package/math/ComplexArray.js.map +0 -1
- package/math/MathUtils.js.map +0 -1
- package/math/MutableComplex.js.map +0 -1
- package/math/NumApprox.js.map +0 -1
- package/math/PolyReal.js.map +0 -1
- package/signal/AdaptiveStft.js.map +0 -1
- package/signal/Autocorrelation.js.map +0 -1
- package/signal/Dft.js.map +0 -1
- package/signal/EnvelopeDetection.js.map +0 -1
- package/signal/Fft.js.map +0 -1
- package/signal/Goertzel.js.map +0 -1
- package/signal/InstFreq.js.map +0 -1
- package/signal/PitchDetectionHarm.js.map +0 -1
- package/signal/Resampling.js.map +0 -1
- package/signal/WindowFunctions.js.map +0 -1
- package/utils/ArrayUtils.js.map +0 -1
- package/utils/DspUtils.js.map +0 -1
- package/utils/MiscUtils.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
# The
|
|
1
|
+
# The JavaScript DSP Collection
|
|
2
2
|
|
|
3
3
|
A collection of JavaScript modules for digital signal processing (written in TypeScript).
|
|
4
4
|
|
|
5
5
|
(This package is currently in development)
|
|
6
6
|
|
|
7
|
+
NPM package: [dsp-collection](https://www.npmjs.com/package/dsp-collection)
|
|
8
|
+
|
|
7
9
|
## Online test applications
|
|
8
10
|
|
|
9
11
|
* [Window functions test](https://www.source-code.biz/dsp/js/simpleTests/testWindowFunctions.html)
|
|
@@ -18,7 +20,8 @@ A collection of JavaScript modules for digital signal processing (written in Typ
|
|
|
18
20
|
|
|
19
21
|
## Associated JavaScript packages
|
|
20
22
|
|
|
21
|
-
* [commons-math-interpolation
|
|
23
|
+
* [commons-math-interpolation](https://github.com/chdh/commons-math-interpolation) - Interpolation and regression algorithms
|
|
22
24
|
* [Function curve editor widget](https://www.source-code.biz/snippets/typescript/functionCurveEditor)
|
|
23
25
|
* [Function curve viewer widget](https://www.source-code.biz/snippets/typescript/functionCurveViewer)
|
|
24
26
|
* [WAV file encoder](https://github.com/chdh/wav-file-encoder)
|
|
27
|
+
* [WAV file decoder](https://github.com/chdh/wav-file-decoder)
|
package/filter/SpecFilt.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export declare const enum FilterType {
|
|
2
|
-
lowPass = "LP",
|
|
3
|
-
highPass = "HP",
|
|
4
|
-
bandPass = "BP",
|
|
5
|
-
bandStop = "BS"
|
|
6
|
-
}
|
|
7
|
-
export
|
|
8
|
-
export declare function getFilterCurveFunction(filterType: FilterType, filterFreq1: number, filterFreq2: number, smoothingWidth: number): FilterCurveFunction;
|
|
9
|
-
export declare function applyFilterCurveFunction(inAmplitudes: ArrayLike<number>, scalingFactor: number, filterCurveFunction: FilterCurveFunction): Float64Array
|
|
10
|
-
export declare function filterSignal(inSamples: ArrayLike<number>, sampleRate: number, filterType: FilterType, filterFreq1: number, filterFreq2: number, smoothingWidth: number): Float64Array;
|
|
1
|
+
export declare const enum FilterType {
|
|
2
|
+
lowPass = "LP",
|
|
3
|
+
highPass = "HP",
|
|
4
|
+
bandPass = "BP",
|
|
5
|
+
bandStop = "BS"
|
|
6
|
+
}
|
|
7
|
+
export type FilterCurveFunction = (frequency: number) => number;
|
|
8
|
+
export declare function getFilterCurveFunction(filterType: FilterType, filterFreq1: number, filterFreq2: number, smoothingWidth: number): FilterCurveFunction;
|
|
9
|
+
export declare function applyFilterCurveFunction(inAmplitudes: ArrayLike<number>, scalingFactor: number, filterCurveFunction: FilterCurveFunction): Float64Array<ArrayBuffer>;
|
|
10
|
+
export declare function filterSignal(inSamples: ArrayLike<number>, sampleRate: number, filterType: FilterType, filterFreq1: number, filterFreq2: number, smoothingWidth: number): Float64Array;
|
package/filter/SpecFilt.js
CHANGED
|
@@ -1,99 +1,98 @@
|
|
|
1
|
-
import ComplexArray from "../math/ComplexArray.js";
|
|
2
|
-
import * as Fft from "../signal/Fft.js";
|
|
3
|
-
function smoothingFunction(x) {
|
|
4
|
-
return (Math.sin(x * Math.PI / 2) + 1) / 2;
|
|
5
|
-
}
|
|
6
|
-
export function getFilterCurveFunction(filterType, filterFreq1, filterFreq2, smoothingWidth) {
|
|
7
|
-
switch (filterType) {
|
|
8
|
-
case "LP": {
|
|
9
|
-
return (freq) => {
|
|
10
|
-
if (freq < filterFreq1 - smoothingWidth) {
|
|
11
|
-
return 1;
|
|
12
|
-
}
|
|
13
|
-
else if (freq < filterFreq1 + smoothingWidth) {
|
|
14
|
-
return smoothingFunction((filterFreq1 - freq) / smoothingWidth);
|
|
15
|
-
}
|
|
16
|
-
else {
|
|
17
|
-
return 0;
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
case "HP": {
|
|
22
|
-
return (freq) => {
|
|
23
|
-
if (freq < filterFreq1 - smoothingWidth) {
|
|
24
|
-
return 0;
|
|
25
|
-
}
|
|
26
|
-
else if (freq < filterFreq1 + smoothingWidth) {
|
|
27
|
-
return smoothingFunction((freq - filterFreq1) / smoothingWidth);
|
|
28
|
-
}
|
|
29
|
-
else {
|
|
30
|
-
return 1;
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
case "BP": {
|
|
35
|
-
return (freq) => {
|
|
36
|
-
if (freq < filterFreq1 - smoothingWidth) {
|
|
37
|
-
return 0;
|
|
38
|
-
}
|
|
39
|
-
else if (freq < filterFreq1 + smoothingWidth) {
|
|
40
|
-
return smoothingFunction((freq - filterFreq1) / smoothingWidth);
|
|
41
|
-
}
|
|
42
|
-
else if (freq < filterFreq2 - smoothingWidth) {
|
|
43
|
-
return 1;
|
|
44
|
-
}
|
|
45
|
-
else if (freq < filterFreq2 + smoothingWidth) {
|
|
46
|
-
return smoothingFunction((filterFreq2 - freq) / smoothingWidth);
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
return 0;
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
case "BS": {
|
|
54
|
-
return (freq) => {
|
|
55
|
-
if (freq < filterFreq1 - smoothingWidth) {
|
|
56
|
-
return 1;
|
|
57
|
-
}
|
|
58
|
-
else if (freq < filterFreq1 + smoothingWidth) {
|
|
59
|
-
return smoothingFunction((filterFreq1 - freq) / smoothingWidth);
|
|
60
|
-
}
|
|
61
|
-
else if (freq < filterFreq2 - smoothingWidth) {
|
|
62
|
-
return 0;
|
|
63
|
-
}
|
|
64
|
-
else if (freq < filterFreq2 + smoothingWidth) {
|
|
65
|
-
return smoothingFunction((freq - filterFreq2) / smoothingWidth);
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
return 1;
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
default: {
|
|
73
|
-
throw new Error("Unsupported filter type.");
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
export function applyFilterCurveFunction(inAmplitudes, scalingFactor, filterCurveFunction) {
|
|
78
|
-
const n = inAmplitudes.length;
|
|
79
|
-
const outAmplitudes = new Float64Array(n);
|
|
80
|
-
for (let p = 0; p < n; p++) {
|
|
81
|
-
const frequency = p / scalingFactor;
|
|
82
|
-
const filterFactor = filterCurveFunction(frequency);
|
|
83
|
-
outAmplitudes[p] = filterFactor * inAmplitudes[p];
|
|
84
|
-
}
|
|
85
|
-
return outAmplitudes;
|
|
86
|
-
}
|
|
87
|
-
export function filterSignal(inSamples, sampleRate, filterType, filterFreq1, filterFreq2, smoothingWidth) {
|
|
88
|
-
const n = inSamples.length;
|
|
89
|
-
const inSpectrum = Fft.fftRealSpectrum(inSamples);
|
|
90
|
-
const inAmplitudes = inSpectrum.getAbsArray();
|
|
91
|
-
const inPhases = inSpectrum.getArgArray();
|
|
92
|
-
const filterCurveFunction = getFilterCurveFunction(filterType, filterFreq1, filterFreq2, smoothingWidth);
|
|
93
|
-
const outAmplitudes = applyFilterCurveFunction(inAmplitudes, n / sampleRate, filterCurveFunction);
|
|
94
|
-
const outPhases = inPhases;
|
|
95
|
-
const outSpectrum = ComplexArray.fromPolar(outAmplitudes, outPhases);
|
|
96
|
-
const outSignal = Fft.iFftRealHalf(outSpectrum, n);
|
|
97
|
-
return outSignal;
|
|
98
|
-
}
|
|
99
|
-
//# sourceMappingURL=SpecFilt.js.map
|
|
1
|
+
import ComplexArray from "../math/ComplexArray.js";
|
|
2
|
+
import * as Fft from "../signal/Fft.js";
|
|
3
|
+
function smoothingFunction(x) {
|
|
4
|
+
return (Math.sin(x * Math.PI / 2) + 1) / 2;
|
|
5
|
+
}
|
|
6
|
+
export function getFilterCurveFunction(filterType, filterFreq1, filterFreq2, smoothingWidth) {
|
|
7
|
+
switch (filterType) {
|
|
8
|
+
case "LP": {
|
|
9
|
+
return (freq) => {
|
|
10
|
+
if (freq < filterFreq1 - smoothingWidth) {
|
|
11
|
+
return 1;
|
|
12
|
+
}
|
|
13
|
+
else if (freq < filterFreq1 + smoothingWidth) {
|
|
14
|
+
return smoothingFunction((filterFreq1 - freq) / smoothingWidth);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
return 0;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
case "HP": {
|
|
22
|
+
return (freq) => {
|
|
23
|
+
if (freq < filterFreq1 - smoothingWidth) {
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
else if (freq < filterFreq1 + smoothingWidth) {
|
|
27
|
+
return smoothingFunction((freq - filterFreq1) / smoothingWidth);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
return 1;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
case "BP": {
|
|
35
|
+
return (freq) => {
|
|
36
|
+
if (freq < filterFreq1 - smoothingWidth) {
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
else if (freq < filterFreq1 + smoothingWidth) {
|
|
40
|
+
return smoothingFunction((freq - filterFreq1) / smoothingWidth);
|
|
41
|
+
}
|
|
42
|
+
else if (freq < filterFreq2 - smoothingWidth) {
|
|
43
|
+
return 1;
|
|
44
|
+
}
|
|
45
|
+
else if (freq < filterFreq2 + smoothingWidth) {
|
|
46
|
+
return smoothingFunction((filterFreq2 - freq) / smoothingWidth);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
return 0;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
case "BS": {
|
|
54
|
+
return (freq) => {
|
|
55
|
+
if (freq < filterFreq1 - smoothingWidth) {
|
|
56
|
+
return 1;
|
|
57
|
+
}
|
|
58
|
+
else if (freq < filterFreq1 + smoothingWidth) {
|
|
59
|
+
return smoothingFunction((filterFreq1 - freq) / smoothingWidth);
|
|
60
|
+
}
|
|
61
|
+
else if (freq < filterFreq2 - smoothingWidth) {
|
|
62
|
+
return 0;
|
|
63
|
+
}
|
|
64
|
+
else if (freq < filterFreq2 + smoothingWidth) {
|
|
65
|
+
return smoothingFunction((freq - filterFreq2) / smoothingWidth);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
return 1;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
default: {
|
|
73
|
+
throw new Error("Unsupported filter type.");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export function applyFilterCurveFunction(inAmplitudes, scalingFactor, filterCurveFunction) {
|
|
78
|
+
const n = inAmplitudes.length;
|
|
79
|
+
const outAmplitudes = new Float64Array(n);
|
|
80
|
+
for (let p = 0; p < n; p++) {
|
|
81
|
+
const frequency = p / scalingFactor;
|
|
82
|
+
const filterFactor = filterCurveFunction(frequency);
|
|
83
|
+
outAmplitudes[p] = filterFactor * inAmplitudes[p];
|
|
84
|
+
}
|
|
85
|
+
return outAmplitudes;
|
|
86
|
+
}
|
|
87
|
+
export function filterSignal(inSamples, sampleRate, filterType, filterFreq1, filterFreq2, smoothingWidth) {
|
|
88
|
+
const n = inSamples.length;
|
|
89
|
+
const inSpectrum = Fft.fftRealSpectrum(inSamples);
|
|
90
|
+
const inAmplitudes = inSpectrum.getAbsArray();
|
|
91
|
+
const inPhases = inSpectrum.getArgArray();
|
|
92
|
+
const filterCurveFunction = getFilterCurveFunction(filterType, filterFreq1, filterFreq2, smoothingWidth);
|
|
93
|
+
const outAmplitudes = applyFilterCurveFunction(inAmplitudes, n / sampleRate, filterCurveFunction);
|
|
94
|
+
const outPhases = inPhases;
|
|
95
|
+
const outSpectrum = ComplexArray.fromPolar(outAmplitudes, outPhases);
|
|
96
|
+
const outSignal = Fft.iFftRealHalf(outSpectrum, n);
|
|
97
|
+
return outSignal;
|
|
98
|
+
}
|
package/math/Complex.d.ts
CHANGED
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
export default class Complex {
|
|
2
|
-
static readonly I: Complex;
|
|
3
|
-
static readonly ZERO: Complex;
|
|
4
|
-
static readonly ONE: Complex;
|
|
5
|
-
static readonly TWO: Complex;
|
|
6
|
-
static readonly NaN: Complex;
|
|
7
|
-
static readonly INFINITY: Complex;
|
|
8
|
-
readonly re: number;
|
|
9
|
-
readonly im: number;
|
|
10
|
-
constructor(re: number, im?: number);
|
|
11
|
-
toString(): string;
|
|
12
|
-
toNumber(eps: number): number;
|
|
13
|
-
isNaN(): boolean;
|
|
14
|
-
isInfinite(): boolean;
|
|
15
|
-
isFinite(): boolean;
|
|
16
|
-
equals(x: Complex): boolean;
|
|
17
|
-
fuzzyEquals(x: Complex, eps: number): boolean;
|
|
18
|
-
static expj(arg: number): Complex;
|
|
19
|
-
static fromPolar(abs: number, arg: number): Complex;
|
|
20
|
-
abs(): number;
|
|
21
|
-
arg(): number;
|
|
22
|
-
conj(): Complex;
|
|
23
|
-
neg(): Complex;
|
|
24
|
-
reciprocal(): Complex;
|
|
25
|
-
exp(): Complex;
|
|
26
|
-
log(): Complex;
|
|
27
|
-
sqr(): Complex;
|
|
28
|
-
sqrt(): Complex;
|
|
29
|
-
addReal(x: number): Complex;
|
|
30
|
-
add(x: Complex): Complex;
|
|
31
|
-
subReal(x: number): Complex;
|
|
32
|
-
static subFromReal(x: number, y: Complex): Complex;
|
|
33
|
-
sub(x: Complex): Complex;
|
|
34
|
-
mulReal(x: number): Complex;
|
|
35
|
-
mul(x: Complex): Complex;
|
|
36
|
-
divReal(x: number): Complex;
|
|
37
|
-
div(x: Complex): Complex;
|
|
38
|
-
static divFromReal(x: number, y: Complex): Complex;
|
|
39
|
-
powInt(x: number): Complex;
|
|
40
|
-
powReal(x: number): Complex;
|
|
41
|
-
pow(x: Complex): Complex;
|
|
42
|
-
}
|
|
1
|
+
export default class Complex {
|
|
2
|
+
static readonly I: Complex;
|
|
3
|
+
static readonly ZERO: Complex;
|
|
4
|
+
static readonly ONE: Complex;
|
|
5
|
+
static readonly TWO: Complex;
|
|
6
|
+
static readonly NaN: Complex;
|
|
7
|
+
static readonly INFINITY: Complex;
|
|
8
|
+
readonly re: number;
|
|
9
|
+
readonly im: number;
|
|
10
|
+
constructor(re: number, im?: number);
|
|
11
|
+
toString(): string;
|
|
12
|
+
toNumber(eps: number): number;
|
|
13
|
+
isNaN(): boolean;
|
|
14
|
+
isInfinite(): boolean;
|
|
15
|
+
isFinite(): boolean;
|
|
16
|
+
equals(x: Complex): boolean;
|
|
17
|
+
fuzzyEquals(x: Complex, eps: number): boolean;
|
|
18
|
+
static expj(arg: number): Complex;
|
|
19
|
+
static fromPolar(abs: number, arg: number): Complex;
|
|
20
|
+
abs(): number;
|
|
21
|
+
arg(): number;
|
|
22
|
+
conj(): Complex;
|
|
23
|
+
neg(): Complex;
|
|
24
|
+
reciprocal(): Complex;
|
|
25
|
+
exp(): Complex;
|
|
26
|
+
log(): Complex;
|
|
27
|
+
sqr(): Complex;
|
|
28
|
+
sqrt(): Complex;
|
|
29
|
+
addReal(x: number): Complex;
|
|
30
|
+
add(x: Complex): Complex;
|
|
31
|
+
subReal(x: number): Complex;
|
|
32
|
+
static subFromReal(x: number, y: Complex): Complex;
|
|
33
|
+
sub(x: Complex): Complex;
|
|
34
|
+
mulReal(x: number): Complex;
|
|
35
|
+
mul(x: Complex): Complex;
|
|
36
|
+
divReal(x: number): Complex;
|
|
37
|
+
div(x: Complex): Complex;
|
|
38
|
+
static divFromReal(x: number, y: Complex): Complex;
|
|
39
|
+
powInt(x: number): Complex;
|
|
40
|
+
powReal(x: number): Complex;
|
|
41
|
+
pow(x: Complex): Complex;
|
|
42
|
+
}
|
package/math/Complex.js
CHANGED
|
@@ -1,130 +1,130 @@
|
|
|
1
|
-
import * as MathUtils from "./MathUtils.js";
|
|
2
|
-
|
|
3
|
-
constructor(re, im = 0) {
|
|
4
|
-
this.re = re;
|
|
5
|
-
this.im = im;
|
|
6
|
-
}
|
|
7
|
-
toString() {
|
|
8
|
-
return "(" + this.re + ", " + this.im + ")";
|
|
9
|
-
}
|
|
10
|
-
toNumber(eps) {
|
|
11
|
-
const absIm = Math.abs(this.im);
|
|
12
|
-
if (!(absIm <= eps || absIm <= Math.abs(this.re) * eps)) {
|
|
13
|
-
throw new Error("The imaginary part of the complex number is not neglectable small for the conversion to a real number. re=" + this.re + " im=" + this.im + " eps=" + eps + ".");
|
|
14
|
-
}
|
|
15
|
-
return this.re;
|
|
16
|
-
}
|
|
17
|
-
isNaN() {
|
|
18
|
-
return isNaN(this.re) || isNaN(this.im);
|
|
19
|
-
}
|
|
20
|
-
isInfinite() {
|
|
21
|
-
return this.re == Infinity || this.re == -Infinity || this.im == Infinity || this.im == -Infinity;
|
|
22
|
-
}
|
|
23
|
-
isFinite() {
|
|
24
|
-
return isFinite(this.re) && isFinite(this.im);
|
|
25
|
-
}
|
|
26
|
-
equals(x) {
|
|
27
|
-
return x && this.re == x.re && this.im == x.im;
|
|
28
|
-
}
|
|
29
|
-
fuzzyEquals(x, eps) {
|
|
30
|
-
return MathUtils.fuzzyEquals(this.re, x.re, eps) && MathUtils.fuzzyEquals(this.im, x.im, eps);
|
|
31
|
-
}
|
|
32
|
-
static expj(arg) {
|
|
33
|
-
return new Complex(Math.cos(arg), Math.sin(arg));
|
|
34
|
-
}
|
|
35
|
-
static fromPolar(abs, arg) {
|
|
36
|
-
return new Complex(abs * Math.cos(arg), abs * Math.sin(arg));
|
|
37
|
-
}
|
|
38
|
-
abs() {
|
|
39
|
-
return Math.hypot(this.re, this.im);
|
|
40
|
-
}
|
|
41
|
-
arg() {
|
|
42
|
-
return Math.atan2(this.im, this.re);
|
|
43
|
-
}
|
|
44
|
-
conj() {
|
|
45
|
-
return new Complex(this.re, -this.im);
|
|
46
|
-
}
|
|
47
|
-
neg() {
|
|
48
|
-
return new Complex(-this.re, -this.im);
|
|
49
|
-
}
|
|
50
|
-
reciprocal() {
|
|
51
|
-
if (this.isNaN()) {
|
|
52
|
-
return Complex.NaN;
|
|
53
|
-
}
|
|
54
|
-
if (this.isInfinite()) {
|
|
55
|
-
return Complex.ZERO;
|
|
56
|
-
}
|
|
57
|
-
const scale = this.re * this.re + this.im * this.im;
|
|
58
|
-
if (scale == 0) {
|
|
59
|
-
return Complex.INFINITY;
|
|
60
|
-
}
|
|
61
|
-
return new Complex(this.re / scale, -this.im / scale);
|
|
62
|
-
}
|
|
63
|
-
exp() {
|
|
64
|
-
return Complex.fromPolar(Math.exp(this.re), this.im);
|
|
65
|
-
}
|
|
66
|
-
log() {
|
|
67
|
-
return new Complex(Math.log(this.abs()), this.arg());
|
|
68
|
-
}
|
|
69
|
-
sqr() {
|
|
70
|
-
return new Complex(this.re * this.re - this.im * this.im, 2 * this.re * this.im);
|
|
71
|
-
}
|
|
72
|
-
sqrt() {
|
|
73
|
-
if (this.re == 0 && this.im == 0) {
|
|
74
|
-
return Complex.ZERO;
|
|
75
|
-
}
|
|
76
|
-
const m = this.abs();
|
|
77
|
-
return new Complex(Math.sqrt((m + this.re) / 2), Math.sign(this.im) * Math.sqrt((m - this.re) / 2));
|
|
78
|
-
}
|
|
79
|
-
addReal(x) {
|
|
80
|
-
return new Complex(this.re + x, this.im);
|
|
81
|
-
}
|
|
82
|
-
add(x) {
|
|
83
|
-
return new Complex(this.re + x.re, this.im + x.im);
|
|
84
|
-
}
|
|
85
|
-
subReal(x) {
|
|
86
|
-
return new Complex(this.re - x, this.im);
|
|
87
|
-
}
|
|
88
|
-
static subFromReal(x, y) {
|
|
89
|
-
return new Complex(x - y.re, -y.im);
|
|
90
|
-
}
|
|
91
|
-
sub(x) {
|
|
92
|
-
return new Complex(this.re - x.re, this.im - x.im);
|
|
93
|
-
}
|
|
94
|
-
mulReal(x) {
|
|
95
|
-
return new Complex(this.re * x, this.im * x);
|
|
96
|
-
}
|
|
97
|
-
mul(x) {
|
|
98
|
-
return new Complex(this.re * x.re - this.im * x.im, this.re * x.im + this.im * x.re);
|
|
99
|
-
}
|
|
100
|
-
divReal(x) {
|
|
101
|
-
return new Complex(this.re / x, this.im / x);
|
|
102
|
-
}
|
|
103
|
-
div(x) {
|
|
104
|
-
const m = x.re * x.re + x.im * x.im;
|
|
105
|
-
return new Complex((this.re * x.re + this.im * x.im) / m, (this.im * x.re - this.re * x.im) / m);
|
|
106
|
-
}
|
|
107
|
-
static divFromReal(x, y) {
|
|
108
|
-
const m = y.re * y.re + y.im * y.im;
|
|
109
|
-
return new Complex(x * y.re / m, -x * y.im / m);
|
|
110
|
-
}
|
|
111
|
-
powInt(x) {
|
|
112
|
-
if (!Number.isInteger(x)) {
|
|
113
|
-
throw new Error("powInt() used with non-integer exponent.");
|
|
114
|
-
}
|
|
115
|
-
return Complex.fromPolar(Math.pow(this.abs(), x), this.arg() * x);
|
|
116
|
-
}
|
|
117
|
-
powReal(x) {
|
|
118
|
-
return this.log().mulReal(x).exp();
|
|
119
|
-
}
|
|
120
|
-
pow(x) {
|
|
121
|
-
return this.log().mul(x).exp();
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
Complex.I = new Complex(0, 1);
|
|
125
|
-
Complex.ZERO = new Complex(0);
|
|
126
|
-
Complex.ONE = new Complex(1);
|
|
127
|
-
Complex.TWO = new Complex(2);
|
|
128
|
-
Complex.NaN = new Complex(NaN, NaN);
|
|
129
|
-
Complex.INFINITY = new Complex(Infinity, Infinity);
|
|
130
|
-
|
|
1
|
+
import * as MathUtils from "./MathUtils.js";
|
|
2
|
+
class Complex {
|
|
3
|
+
constructor(re, im = 0) {
|
|
4
|
+
this.re = re;
|
|
5
|
+
this.im = im;
|
|
6
|
+
}
|
|
7
|
+
toString() {
|
|
8
|
+
return "(" + this.re + ", " + this.im + ")";
|
|
9
|
+
}
|
|
10
|
+
toNumber(eps) {
|
|
11
|
+
const absIm = Math.abs(this.im);
|
|
12
|
+
if (!(absIm <= eps || absIm <= Math.abs(this.re) * eps)) {
|
|
13
|
+
throw new Error("The imaginary part of the complex number is not neglectable small for the conversion to a real number. re=" + this.re + " im=" + this.im + " eps=" + eps + ".");
|
|
14
|
+
}
|
|
15
|
+
return this.re;
|
|
16
|
+
}
|
|
17
|
+
isNaN() {
|
|
18
|
+
return isNaN(this.re) || isNaN(this.im);
|
|
19
|
+
}
|
|
20
|
+
isInfinite() {
|
|
21
|
+
return this.re == Infinity || this.re == -Infinity || this.im == Infinity || this.im == -Infinity;
|
|
22
|
+
}
|
|
23
|
+
isFinite() {
|
|
24
|
+
return isFinite(this.re) && isFinite(this.im);
|
|
25
|
+
}
|
|
26
|
+
equals(x) {
|
|
27
|
+
return x && this.re == x.re && this.im == x.im;
|
|
28
|
+
}
|
|
29
|
+
fuzzyEquals(x, eps) {
|
|
30
|
+
return MathUtils.fuzzyEquals(this.re, x.re, eps) && MathUtils.fuzzyEquals(this.im, x.im, eps);
|
|
31
|
+
}
|
|
32
|
+
static expj(arg) {
|
|
33
|
+
return new Complex(Math.cos(arg), Math.sin(arg));
|
|
34
|
+
}
|
|
35
|
+
static fromPolar(abs, arg) {
|
|
36
|
+
return new Complex(abs * Math.cos(arg), abs * Math.sin(arg));
|
|
37
|
+
}
|
|
38
|
+
abs() {
|
|
39
|
+
return Math.hypot(this.re, this.im);
|
|
40
|
+
}
|
|
41
|
+
arg() {
|
|
42
|
+
return Math.atan2(this.im, this.re);
|
|
43
|
+
}
|
|
44
|
+
conj() {
|
|
45
|
+
return new Complex(this.re, -this.im);
|
|
46
|
+
}
|
|
47
|
+
neg() {
|
|
48
|
+
return new Complex(-this.re, -this.im);
|
|
49
|
+
}
|
|
50
|
+
reciprocal() {
|
|
51
|
+
if (this.isNaN()) {
|
|
52
|
+
return Complex.NaN;
|
|
53
|
+
}
|
|
54
|
+
if (this.isInfinite()) {
|
|
55
|
+
return Complex.ZERO;
|
|
56
|
+
}
|
|
57
|
+
const scale = this.re * this.re + this.im * this.im;
|
|
58
|
+
if (scale == 0) {
|
|
59
|
+
return Complex.INFINITY;
|
|
60
|
+
}
|
|
61
|
+
return new Complex(this.re / scale, -this.im / scale);
|
|
62
|
+
}
|
|
63
|
+
exp() {
|
|
64
|
+
return Complex.fromPolar(Math.exp(this.re), this.im);
|
|
65
|
+
}
|
|
66
|
+
log() {
|
|
67
|
+
return new Complex(Math.log(this.abs()), this.arg());
|
|
68
|
+
}
|
|
69
|
+
sqr() {
|
|
70
|
+
return new Complex(this.re * this.re - this.im * this.im, 2 * this.re * this.im);
|
|
71
|
+
}
|
|
72
|
+
sqrt() {
|
|
73
|
+
if (this.re == 0 && this.im == 0) {
|
|
74
|
+
return Complex.ZERO;
|
|
75
|
+
}
|
|
76
|
+
const m = this.abs();
|
|
77
|
+
return new Complex(Math.sqrt((m + this.re) / 2), Math.sign(this.im) * Math.sqrt((m - this.re) / 2));
|
|
78
|
+
}
|
|
79
|
+
addReal(x) {
|
|
80
|
+
return new Complex(this.re + x, this.im);
|
|
81
|
+
}
|
|
82
|
+
add(x) {
|
|
83
|
+
return new Complex(this.re + x.re, this.im + x.im);
|
|
84
|
+
}
|
|
85
|
+
subReal(x) {
|
|
86
|
+
return new Complex(this.re - x, this.im);
|
|
87
|
+
}
|
|
88
|
+
static subFromReal(x, y) {
|
|
89
|
+
return new Complex(x - y.re, -y.im);
|
|
90
|
+
}
|
|
91
|
+
sub(x) {
|
|
92
|
+
return new Complex(this.re - x.re, this.im - x.im);
|
|
93
|
+
}
|
|
94
|
+
mulReal(x) {
|
|
95
|
+
return new Complex(this.re * x, this.im * x);
|
|
96
|
+
}
|
|
97
|
+
mul(x) {
|
|
98
|
+
return new Complex(this.re * x.re - this.im * x.im, this.re * x.im + this.im * x.re);
|
|
99
|
+
}
|
|
100
|
+
divReal(x) {
|
|
101
|
+
return new Complex(this.re / x, this.im / x);
|
|
102
|
+
}
|
|
103
|
+
div(x) {
|
|
104
|
+
const m = x.re * x.re + x.im * x.im;
|
|
105
|
+
return new Complex((this.re * x.re + this.im * x.im) / m, (this.im * x.re - this.re * x.im) / m);
|
|
106
|
+
}
|
|
107
|
+
static divFromReal(x, y) {
|
|
108
|
+
const m = y.re * y.re + y.im * y.im;
|
|
109
|
+
return new Complex(x * y.re / m, -x * y.im / m);
|
|
110
|
+
}
|
|
111
|
+
powInt(x) {
|
|
112
|
+
if (!Number.isInteger(x)) {
|
|
113
|
+
throw new Error("powInt() used with non-integer exponent.");
|
|
114
|
+
}
|
|
115
|
+
return Complex.fromPolar(Math.pow(this.abs(), x), this.arg() * x);
|
|
116
|
+
}
|
|
117
|
+
powReal(x) {
|
|
118
|
+
return this.log().mulReal(x).exp();
|
|
119
|
+
}
|
|
120
|
+
pow(x) {
|
|
121
|
+
return this.log().mul(x).exp();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
Complex.I = new Complex(0, 1);
|
|
125
|
+
Complex.ZERO = new Complex(0);
|
|
126
|
+
Complex.ONE = new Complex(1);
|
|
127
|
+
Complex.TWO = new Complex(2);
|
|
128
|
+
Complex.NaN = new Complex(NaN, NaN);
|
|
129
|
+
Complex.INFINITY = new Complex(Infinity, Infinity);
|
|
130
|
+
export default Complex;
|
package/math/ComplexArray.d.ts
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
import Complex from "./Complex.
|
|
2
|
-
import MutableComplex from "./MutableComplex.
|
|
3
|
-
export default class ComplexArray {
|
|
4
|
-
re: Float64Array;
|
|
5
|
-
im: Float64Array;
|
|
6
|
-
length: number;
|
|
7
|
-
constructor(x?: number | Complex[] | ArrayLike<number>);
|
|
8
|
-
private constructByLength;
|
|
9
|
-
private constructByArrayOfComplex;
|
|
10
|
-
private constructByArrayOfNumber;
|
|
11
|
-
static fromPolar(absArray: ArrayLike<number>, argArray: ArrayLike<number>): ComplexArray;
|
|
12
|
-
slice(begin?: number, end?: number): ComplexArray;
|
|
13
|
-
subarray(begin: number, end: number): ComplexArray;
|
|
14
|
-
set(i: number, c: Complex): void;
|
|
15
|
-
setReIm(i: number, re: number, im: number): void;
|
|
16
|
-
setPolar(i: number, abs: number, arg: number): void;
|
|
17
|
-
static copy1(a1: ComplexArray, i1: number, a2: ComplexArray, i2: number): void;
|
|
18
|
-
get(i: number): MutableComplex;
|
|
19
|
-
getAbs(i: number): number;
|
|
20
|
-
getArg(i: number): number;
|
|
21
|
-
toString(): string;
|
|
22
|
-
getAbsArray(): Float64Array;
|
|
23
|
-
getArgArray(): Float64Array;
|
|
24
|
-
addRealTo(i: number, x: number): void;
|
|
25
|
-
addTo(i: number, x: Complex): void;
|
|
26
|
-
subRealFrom(i: number, x: number): void;
|
|
27
|
-
subFrom(i: number, x: Complex): void;
|
|
28
|
-
mulByReal(i: number, x: number): void;
|
|
29
|
-
mulBy(i: number, x: Complex): void;
|
|
30
|
-
divByReal(i: number, x: number): void;
|
|
31
|
-
divBy(i: number, x: Complex): void;
|
|
32
|
-
mulByArray(a2: ComplexArray): void;
|
|
33
|
-
mulAllByReal(x: number): void;
|
|
34
|
-
setMul(i: number, re1: number, im1: number, re2: number, im2: number): void;
|
|
35
|
-
setDiv(i: number, re1: number, im1: number, re2: number, im2: number): void;
|
|
36
|
-
}
|
|
1
|
+
import Complex from "./Complex.ts";
|
|
2
|
+
import MutableComplex from "./MutableComplex.ts";
|
|
3
|
+
export default class ComplexArray {
|
|
4
|
+
re: Float64Array;
|
|
5
|
+
im: Float64Array;
|
|
6
|
+
length: number;
|
|
7
|
+
constructor(x?: number | Complex[] | ArrayLike<number>);
|
|
8
|
+
private constructByLength;
|
|
9
|
+
private constructByArrayOfComplex;
|
|
10
|
+
private constructByArrayOfNumber;
|
|
11
|
+
static fromPolar(absArray: ArrayLike<number>, argArray: ArrayLike<number>): ComplexArray;
|
|
12
|
+
slice(begin?: number, end?: number): ComplexArray;
|
|
13
|
+
subarray(begin: number, end: number): ComplexArray;
|
|
14
|
+
set(i: number, c: Complex): void;
|
|
15
|
+
setReIm(i: number, re: number, im: number): void;
|
|
16
|
+
setPolar(i: number, abs: number, arg: number): void;
|
|
17
|
+
static copy1(a1: ComplexArray, i1: number, a2: ComplexArray, i2: number): void;
|
|
18
|
+
get(i: number): MutableComplex;
|
|
19
|
+
getAbs(i: number): number;
|
|
20
|
+
getArg(i: number): number;
|
|
21
|
+
toString(): string;
|
|
22
|
+
getAbsArray(): Float64Array;
|
|
23
|
+
getArgArray(): Float64Array;
|
|
24
|
+
addRealTo(i: number, x: number): void;
|
|
25
|
+
addTo(i: number, x: Complex): void;
|
|
26
|
+
subRealFrom(i: number, x: number): void;
|
|
27
|
+
subFrom(i: number, x: Complex): void;
|
|
28
|
+
mulByReal(i: number, x: number): void;
|
|
29
|
+
mulBy(i: number, x: Complex): void;
|
|
30
|
+
divByReal(i: number, x: number): void;
|
|
31
|
+
divBy(i: number, x: Complex): void;
|
|
32
|
+
mulByArray(a2: ComplexArray): void;
|
|
33
|
+
mulAllByReal(x: number): void;
|
|
34
|
+
setMul(i: number, re1: number, im1: number, re2: number, im2: number): void;
|
|
35
|
+
setDiv(i: number, re1: number, im1: number, re2: number, im2: number): void;
|
|
36
|
+
}
|