numz 0.1.0 → 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 (75) hide show
  1. package/docs/.vscode/extensions.json +4 -0
  2. package/docs/.vscode/launch.json +11 -0
  3. package/docs/README.md +49 -0
  4. package/docs/astro.config.mjs +64 -0
  5. package/docs/package-lock.json +7592 -0
  6. package/docs/package.json +19 -0
  7. package/docs/public/favicon.svg +1 -0
  8. package/docs/src/assets/houston.webp +0 -0
  9. package/docs/src/content/docs/about.md +11 -0
  10. package/docs/src/content/docs/guides/example.md +11 -0
  11. package/docs/src/content/docs/index.mdx +40 -0
  12. package/docs/src/content/docs/philosophy.md +15 -0
  13. package/docs/src/content/docs/reference/complex/complex.mdx +66 -0
  14. package/docs/src/content/docs/reference/functions/arithmetic.md +14 -0
  15. package/docs/src/content/docs/reference/functions/mapfun.md +81 -0
  16. package/docs/src/content/docs/reference/functions/ufunc.md +41 -0
  17. package/docs/src/content/docs/reference/functions/utils.md +16 -0
  18. package/docs/src/content/docs/reference/matrix/matrix.mdx +97 -0
  19. package/docs/src/content/docs/reference/signal/functions/periodic/pulse-train.md +6 -0
  20. package/docs/src/content/docs/reference/signal/functions/periodic/pwm.md +6 -0
  21. package/docs/src/content/docs/reference/signal/functions/periodic/sawtooth-train.md +6 -0
  22. package/docs/src/content/docs/reference/signal/functions/periodic/sinusoid.md +6 -0
  23. package/docs/src/content/docs/reference/signal/functions/periodic/square.md +6 -0
  24. package/docs/src/content/docs/reference/signal/functions/periodic/triangle.md +6 -0
  25. package/docs/src/content/docs/reference/signal/functions/pulse/dirac.md +12 -0
  26. package/docs/src/content/docs/reference/signal/functions/pulse/noise.md +12 -0
  27. package/docs/src/content/docs/reference/signal/functions/pulse/rampe.md +12 -0
  28. package/docs/src/content/docs/reference/signal/functions/pulse/rect.md +12 -0
  29. package/docs/src/content/docs/reference/signal/functions/pulse/signum.md +12 -0
  30. package/docs/src/content/docs/reference/signal/functions/pulse/sinc.md +12 -0
  31. package/docs/src/content/docs/reference/signal/functions/pulse/trapezoid.md +12 -0
  32. package/docs/src/content/docs/reference/signal/functions/pulse/tri.md +12 -0
  33. package/docs/src/content/docs/reference/signal/functions/sequences/arange.md +21 -0
  34. package/docs/src/content/docs/reference/signal/functions/sequences/geomspace.md +21 -0
  35. package/docs/src/content/docs/reference/signal/functions/sequences/linspace.md +16 -0
  36. package/docs/src/content/docs/reference/signal/functions/sequences/logspace.md +20 -0
  37. package/docs/src/content/docs/reference/signal/functions/sequences/nums.md +17 -0
  38. package/docs/src/content/docs/reference/signal/functions/sequences/ones.md +19 -0
  39. package/docs/src/content/docs/reference/signal/functions/sequences/zeros.md +20 -0
  40. package/docs/src/content/docs/reference/stats/accum/accum-max.md +4 -0
  41. package/docs/src/content/docs/reference/stats/accum/accum-min.md +4 -0
  42. package/docs/src/content/docs/reference/stats/accum/accum-prod.md +4 -0
  43. package/docs/src/content/docs/reference/stats/accum/accum-sum.md +4 -0
  44. package/docs/src/content/docs/reference/stats/averages/contraharmonic-mean.md +4 -0
  45. package/docs/src/content/docs/reference/stats/averages/geo_mean.md +6 -0
  46. package/docs/src/content/docs/reference/stats/averages/harmonic_mean.md +4 -0
  47. package/docs/src/content/docs/reference/stats/averages/iq-mean.md +4 -0
  48. package/docs/src/content/docs/reference/stats/averages/mean.md +6 -0
  49. package/docs/src/content/docs/reference/stats/averages/midhinge.md +4 -0
  50. package/docs/src/content/docs/reference/stats/averages/midrange.md +4 -0
  51. package/docs/src/content/docs/reference/stats/averages/power_mean.md +4 -0
  52. package/docs/src/content/docs/reference/stats/averages/rms.md +12 -0
  53. package/docs/src/content/docs/reference/stats/averages/trimmed_mean.md +4 -0
  54. package/docs/src/content/docs/reference/stats/averages/weighted_mean.md +4 -0
  55. package/docs/src/content/docs/reference/stats/averages/winsorized_mean.md +4 -0
  56. package/docs/src/content.config.ts +7 -0
  57. package/docs/src/pages/a.astro +0 -0
  58. package/docs/src/styles/custom.css +21 -0
  59. package/docs/tsconfig.json +5 -0
  60. package/package.json +2 -2
  61. package/src/signal/conv/conv.js +43 -0
  62. package/src/signal/conv/conv2.js +71 -0
  63. package/src/signal/conv/index.js +2 -0
  64. package/src/signal/fft/fft.js +47 -0
  65. package/src/signal/fft/ifft.js +16 -0
  66. package/src/signal/fft/index.js +2 -52
  67. package/src/signal/fft/utils/index.js +1 -19
  68. package/src/signal/functions/index.js +1 -1
  69. package/src/signal/functions/sequence/index.js +13 -3
  70. package/src/signal/index.js +1 -1
  71. package/src/stats/average/index.js +2 -2
  72. package/test/index.js +39 -0
  73. package/test/index.py +14 -0
  74. package/src/signal/fft/fft1d/index.js +0 -18
  75. package/src/signal/fft/fftnd/index.js +0 -27
@@ -0,0 +1,17 @@
1
+ ---
2
+ title: nums
3
+ description: nums
4
+ sidebar :
5
+ order: 2
6
+ ---
7
+ ## Definition
8
+
9
+ ## Signature
10
+ ```ts
11
+ nums(num : number, n : number) : number[]
12
+ ```
13
+ ## Usage
14
+
15
+ ```ts
16
+ const z = nums(1.5, 10) // [1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5]
17
+ ```
@@ -0,0 +1,19 @@
1
+ ---
2
+ title: ones
3
+ description: ones
4
+ sidebar :
5
+ order: 1
6
+ ---
7
+ ## Definition
8
+
9
+ ## Signature
10
+
11
+ ```ts
12
+ ones(n : number) : number[]
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ```ts
18
+ const z = ones(10) // [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
19
+ ```
@@ -0,0 +1,20 @@
1
+ ---
2
+ title: zeros
3
+ description: zeros
4
+ sidebar:
5
+ order : 0
6
+ ---
7
+
8
+ ## Defintion
9
+
10
+ ## Signature
11
+
12
+ ```ts
13
+ zeros(n : number) : []number
14
+ ```
15
+
16
+ ## Usage
17
+
18
+ ```ts
19
+ const z = zeros(10) // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
20
+ ```
@@ -0,0 +1,4 @@
1
+ ---
2
+ title: accum_max
3
+ description: accum_max
4
+ ---
@@ -0,0 +1,4 @@
1
+ ---
2
+ title: accum_min
3
+ description: accum_min
4
+ ---
@@ -0,0 +1,4 @@
1
+ ---
2
+ title: accum_prod
3
+ description: accum_prod
4
+ ---
@@ -0,0 +1,4 @@
1
+ ---
2
+ title: accum_sum
3
+ description: accum_sum
4
+ ---
@@ -0,0 +1,4 @@
1
+ ---
2
+ title: ch_mean
3
+ description: contraharmonic mean
4
+ ---
@@ -0,0 +1,6 @@
1
+ ---
2
+ title: geo_mean
3
+ description: geo_mean
4
+ sidebar :
5
+ order: 1
6
+ ---
@@ -0,0 +1,4 @@
1
+ ---
2
+ title: har_mean
3
+ description: har_mean
4
+ ---
@@ -0,0 +1,4 @@
1
+ ---
2
+ title: iq_mean
3
+ description: iq_mean
4
+ ---
@@ -0,0 +1,6 @@
1
+ ---
2
+ title: mean
3
+ description: mean
4
+ sidebar :
5
+ order: 0
6
+ ---
@@ -0,0 +1,4 @@
1
+ ---
2
+ title: midhinge
3
+ description: midhinge
4
+ ---
@@ -0,0 +1,4 @@
1
+ ---
2
+ title: midrange
3
+ description: midrange
4
+ ---
@@ -0,0 +1,4 @@
1
+ ---
2
+ title: pow_mean
3
+ description: accum_prod
4
+ ---
@@ -0,0 +1,12 @@
1
+ ---
2
+ title: rms
3
+ description: rms
4
+ sidebar :
5
+ order: 2
6
+ ---
7
+
8
+
9
+ # 11
10
+
11
+
12
+ ## 22
@@ -0,0 +1,4 @@
1
+ ---
2
+ title: trim_mean
3
+ description: trim_mean
4
+ ---
@@ -0,0 +1,4 @@
1
+ ---
2
+ title: w_mean
3
+ description: weighted mean
4
+ ---
@@ -0,0 +1,4 @@
1
+ ---
2
+ title: win_mean
3
+ description: win_mean
4
+ ---
@@ -0,0 +1,7 @@
1
+ import { defineCollection } from 'astro:content';
2
+ import { docsLoader } from '@astrojs/starlight/loaders';
3
+ import { docsSchema } from '@astrojs/starlight/schema';
4
+
5
+ export const collections = {
6
+ docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
7
+ };
File without changes
@@ -0,0 +1,21 @@
1
+ :root {
2
+ --sl-content-width: 50rem;
3
+ --sl-text-5xl: 3.5rem;
4
+ }
5
+
6
+ h1{
7
+ color : darkblue;
8
+ /* text-decoration: 2px underline blueviolet;
9
+ text-decoration-skip-ink: auto; */
10
+ /* border-bottom: 1px red solid; */
11
+ }
12
+ p a{
13
+ color: blueviolet;
14
+ text-decoration: none;
15
+ &:hover{
16
+ text-decoration: underline;
17
+ }
18
+ }
19
+ /* strong{
20
+ color: blueviolet;
21
+ } */
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": "astro/tsconfigs/strict",
3
+ "include": [".astro/types.d.ts", "**/*"],
4
+ "exclude": ["dist"]
5
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "numz",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "scientific computing with zikojs",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -29,6 +29,6 @@
29
29
  "rollup": "^4.24.0"
30
30
  },
31
31
  "dependencies": {
32
- "ziko": "^0.54.4"
32
+ "ziko": "^0.57.0"
33
33
  }
34
34
  }
@@ -0,0 +1,43 @@
1
+ import { Complex } from 'ziko/math/complex';
2
+ import { add, mul} from 'ziko/math/functions'
3
+
4
+ // const nextPow2 = n => 1 << Math.ceil(Math.log2(n));
5
+
6
+
7
+ export function conv(signal, kernel, mode = 'full') {
8
+ const N = signal.length;
9
+ const M = kernel.length;
10
+ if(signal.some(n => n?.isComplex?.()) || kernel.some(n => n?.isComplex?.())){
11
+ signal = new Complex(signal, 0);
12
+ kernel = new Complex(kernel, 0);
13
+ }
14
+ let outLength;
15
+ let startIdx;
16
+ switch(mode){
17
+ case 'full' : {
18
+ outLength = N + M - 1;
19
+ startIdx = 0;
20
+ }; break;
21
+ case 'same' : {
22
+ outLength = N;
23
+ startIdx = Math.floor((M - 1) / 2);
24
+ }; break;
25
+ case 'valid' : {
26
+ outLength = Math.max(N - M + 1, 0);
27
+ startIdx = M - 1;
28
+ }; break;
29
+ default : throw new Error(`Invalid mode: ${mode}. Must be 'full', 'same', or 'valid'`);
30
+ }
31
+ const out = new Array(outLength);
32
+ for (let n = 0; n < outLength; n++) {
33
+ let sum = new Complex(0, 0);
34
+ const actualN = n + startIdx;
35
+ for (let k = 0; k < M; k++) {
36
+ const idx = actualN - k;
37
+ if (idx >= 0 && idx < N)
38
+ sum = add(mul(signal[idx], kernel[k]))
39
+ }
40
+ out[n] = sum;
41
+ }
42
+ return out;
43
+ }
@@ -0,0 +1,71 @@
1
+ import { Complex } from 'ziko/math/complex';
2
+ import { add, mul} from 'ziko/math/functions'
3
+ export function conv2(signal, kernel, mode = 'full', boundary = 'fill', fillValue = 0) {
4
+ const isMatix = signal?.isMatix?.() || kernel?.isMatix?.();
5
+ const signalRows = signal.length;
6
+ const signalCols = signal[0].length;
7
+ const kernelRows = kernel.length;
8
+ const kernelCols = kernel[0].length;
9
+
10
+ const flippedKernel = kernel.map(row => [...row].reverse()).reverse();
11
+
12
+ // Determine output size
13
+ let outRows, outCols;
14
+ switch(mode){
15
+ case 'full':{
16
+ outRows = signalRows + kernelRows - 1;
17
+ outCols = signalCols + kernelCols - 1;
18
+ }; break;
19
+ case 'same':{
20
+ outRows = signalRows;
21
+ outCols = signalCols;
22
+ }; break;
23
+ case 'valid':{
24
+ outRows = signalRows - kernelRows + 1;
25
+ outCols = signalCols - kernelCols + 1;
26
+ }; break;
27
+ default: throw new Error("mode must be 'full', 'same', or 'valid'");
28
+
29
+ }
30
+ // Initialize output
31
+ const output = Array.from({ length: outRows }, () => Array(outCols).fill(0));
32
+
33
+ // Helper to get signal value considering boundary
34
+ function getSignalValue(i, j) {
35
+ if (i < 0 || i >= signalRows || j < 0 || j >= signalCols) {
36
+ if (boundary === 'fill') return fillValue;
37
+ if (boundary === 'wrap') return signal[(i + signalRows) % signalRows][(j + signalCols) % signalCols];
38
+ if (boundary === 'symm') {
39
+ const ii = i < 0 ? -i - 1 : i >= signalRows ? 2*signalRows - i - 1 : i;
40
+ const jj = j < 0 ? -j - 1 : j >= signalCols ? 2*signalCols - j - 1 : j;
41
+ return signal[ii][jj];
42
+ }
43
+ return 0;
44
+ }
45
+ return signal[i][j];
46
+ }
47
+
48
+ // Convolution
49
+ for (let i = 0; i < outRows; i++) {
50
+ for (let j = 0; j < outCols; j++) {
51
+ let sum = 0;
52
+ for (let m = 0; m < kernelRows; m++) {
53
+ for (let n = 0; n < kernelCols; n++) {
54
+ const ii = i + m - Math.floor(kernelRows / 2);
55
+ const jj = j + n - Math.floor(kernelCols / 2);
56
+ sum += flippedKernel[m][n] * getSignalValue(ii, jj);
57
+ sum = add(
58
+ mul(
59
+ flippedKernel[m][n],
60
+ getSignalValue(ii, jj)
61
+ )
62
+ )
63
+ }
64
+ }
65
+ output[i][j] = sum;
66
+ }
67
+ }
68
+
69
+ return output;
70
+ }
71
+
@@ -0,0 +1,2 @@
1
+ export * from './conv.js'
2
+ export * from './conv2.js'
@@ -0,0 +1,47 @@
1
+ import { Complex } from 'ziko/math/complex'
2
+ import { isPow2 } from './utils/index.js';
3
+
4
+ export function dft(arr) {
5
+ const N = arr.length;
6
+ const out = new Array(N);
7
+
8
+ for (let k = 0; k < N; k++) {
9
+ let sum = new Complex(0, 0);
10
+ for (let n = 0; n < N; n++) {
11
+ const W = Complex.twiddle(k * n, N);
12
+ sum = sum.add(W.mul(arr[n]));
13
+ }
14
+ out[k] = sum;
15
+ }
16
+ return out;
17
+ }
18
+
19
+ export function fft(arr) {
20
+ const N = arr.length;
21
+
22
+ // fallback for non power-of-two
23
+ if (!isPow2(N)) {
24
+ return dft(arr);
25
+ }
26
+
27
+ if (N === 1) return [arr[0]];
28
+
29
+ const even = new Array(N / 2);
30
+ const odd = new Array(N / 2);
31
+
32
+ for (let i = 0; i < N / 2; i++) {
33
+ even[i] = arr[2*i];
34
+ odd[i] = arr[2*i+1];
35
+ }
36
+
37
+ const Fe = fft(even);
38
+ const Fo = fft(odd);
39
+
40
+ const out = new Array(N);
41
+ for (let k = 0; k < N / 2; k++) {
42
+ const t = Complex.twiddle(k, N).mul(Fo[k]);
43
+ out[k] = Fe[k].add(t);
44
+ out[k+N/2] = Fe[k].sub(t);
45
+ }
46
+ return out;
47
+ }
@@ -0,0 +1,16 @@
1
+ import { Complex } from 'ziko/math/complex';
2
+ import { fft, dft } from './fft.js';
3
+ import { isPow2 } from './utils/index.js';
4
+
5
+ export function ifft(arr) {
6
+ const N = arr.length;
7
+
8
+ // Step 1: conjugate input
9
+ const conjugated = arr.map(n => new Complex(n, 0).conj)
10
+
11
+ // Step 2: compute FFT (or DFT if not power-of-2)
12
+ const y = isPow2(N) ? fft(conjugated) : dft(conjugated);
13
+
14
+ // Step 3: conjugate output and normalize
15
+ return y.map(c => new Complex(c.a / N, -c.b / N));
16
+ }
@@ -1,52 +1,2 @@
1
- import { Complex } from 'ziko/math/complex'
2
- import {add, sub} from 'ziko/math/functions/arithmetic'
3
- export function fft1d(arr) {
4
- const N = arr.length;
5
- if (N === 1) return [arr[0]];
6
-
7
- const even = fft1d(arr.filter((_, i) => i % 2 === 0));
8
- const odd = fft1d(arr.filter((_, i) => i % 2 === 1));
9
-
10
-
11
-
12
- const out = new Array(N);
13
- for (let k = 0; k < N/2; k++) {
14
- const t = Complex.Twidlle(N, k).mul(odd[k]);
15
- out[k] = add(even[k], t)
16
- out[k + N/2] = sub(even[k], t)
17
- }
18
- return out;
19
- }
20
-
21
- export function fftnd(data) {
22
- if (data instanceof Matrix) data = data.toComplex();
23
-
24
- if (Array.isArray(data) && !Array.isArray(data[0])) {
25
- return fft1d(data);
26
- }
27
-
28
- if (data instanceof Matrix) {
29
- const rows = data.rows;
30
- const cols = data.cols;
31
-
32
- // FFT along rows
33
- let rowFFT = new Matrix(rows, cols, []);
34
- for (let i = 0; i < rows; i++) {
35
- rowFFT.arr[i] = fft1d(data.arr[i]);
36
- }
37
-
38
- let colFFT = new Matrix(cols, rows, []);
39
- const rowFFT_T = rowFFT.T;
40
- for (let i = 0; i < cols; i++) {
41
- colFFT.arr[i] = fft1d(rowFFT_T.arr[i]);
42
- }
43
-
44
- return colFFT.T;
45
- }
46
-
47
- if (Array.isArray(data)) {
48
- return data.map(fftnd);
49
- }
50
-
51
- throw new Error("Invalid data type for FFT");
52
- }
1
+ export * from './fft.js';
2
+ export * from './ifft.js'
@@ -1,19 +1 @@
1
- // export const C = (x) => x?.isComplex?.() ? x : new Complex(x, 0);
2
- // export function twiddle(N, k) {
3
- // const angle = -2 * Math.PI * k / N;
4
- // return new Complex(Math.cos(angle), Math.sin(angle));
5
- // }
6
-
7
- // function normalizeComplexND(data) {
8
- // if (data instanceof Matrix) {
9
- // return new Matrix(
10
- // data.rows,
11
- // data.cols,
12
- // data.arr.flat(1).map(C)
13
- // );
14
- // } else if (Array.isArray(data)) {
15
- // return data.map(normalizeComplexND);
16
- // } else {
17
- // return C(data);
18
- // }
19
- // }
1
+ export const isPow2 = n => (n & (n - 1)) === 0;
@@ -1,3 +1,3 @@
1
1
  export * from './pulse/index.js'
2
2
  export * from './sequence/index.js'
3
- export * from './periodic'
3
+ export * from './periodic/index.js'
@@ -1,8 +1,18 @@
1
1
  import { mapfun, nthr, pow } from "ziko/math/functions";
2
+ import { Matrix } from 'ziko/math/matrix'
2
3
 
3
- export const zeros = n => new Array(n).fill(0);
4
- export const ones = n => new Array(n).fill(1);
5
- export const nums = (n, num) => new Array(n).fill(num);
4
+ export const zeros = (n, m, d) => {
5
+ if(m) return Matrix.zeros(n, m);
6
+ return new Array(n).fill(0)
7
+ }
8
+ export const ones = (n, m) => {
9
+ if(m) return Matrix.ones(n, m);
10
+ return new Array(n).fill(1)
11
+ };
12
+ export const nums = (num, n, m, d) => {
13
+ if(m) return Matrix.nums(n, m);
14
+ return new Array(n).fill(num)
15
+ };
6
16
 
7
17
 
8
18
  export const arange = (a, b, step, include = false) => {
@@ -1,2 +1,2 @@
1
1
  export * from './functions/index.js'
2
- // export * from './fft/index.js'
2
+ export * from './fft/index.js'
@@ -55,8 +55,8 @@ export const midhinge = (...x) =>{
55
55
  return (q1 + q3) / 2;
56
56
  }
57
57
 
58
-
59
- export const interquartile_mean = (...x) =>{
58
+ // interquartile_mean
59
+ export const iq_mean = (...x) =>{
60
60
  let a = x.sort((a,b)=>a-b);
61
61
  let q1 = a[Math.floor((a.length - 1) * 0.25)];
62
62
  let q3 = a[Math.floor((a.length - 1) * 0.75)];
package/test/index.js ADDED
@@ -0,0 +1,39 @@
1
+ import { fft, ifft } from "../src/signal/fft/index.js";
2
+ import { conv, conv2 } from '../src/signal/conv/index.js'
3
+ import { Complex } from "ziko/math/complex";
4
+ // import { cos } from 'ziko/math/functions'
5
+
6
+ // const x = Array.from({ length: 100 }, (_, j)=> j/10)
7
+ // const y = cos(x)
8
+
9
+ // const ff = fft(x)
10
+ // // const ff = fft([1,2,3])
11
+ // // console.log(ff)
12
+
13
+ // // console.log(ifft(ff))
14
+ const signal = [1, 2, 3, 4, 5];
15
+ let kernel = [1, 0.5];
16
+ // kernel = [1, new Complex(0, 0.5)];
17
+ const result = conv(signal, kernel);
18
+ console.log(
19
+ result
20
+ )
21
+
22
+ // console.log(ff)
23
+ // console.log(ifft(ff).map(n=>+ n.a.toFixed(7)))
24
+ // console.log(x)
25
+
26
+
27
+ // Example usage:
28
+ const image = [
29
+ [1, 2, 3],
30
+ [4, 5, 6],
31
+ [7, 8, 9]
32
+ ];
33
+
34
+ const filter = [
35
+ [1, 0],
36
+ [0, 1]
37
+ ];
38
+
39
+ console.log(conv2(image, filter, 'full', 'fill'));
package/test/index.py ADDED
@@ -0,0 +1,14 @@
1
+ from scipy import signal
2
+ image = [
3
+ [1, 2, 3],
4
+ [4, 5, 6],
5
+ [7, 8, 9]
6
+ ]
7
+
8
+ kernel = [
9
+ [1, 0],
10
+ [0, 1]
11
+ ]
12
+ print(
13
+ signal.convolve2d(image, kernel, 'full')
14
+ )
@@ -1,18 +0,0 @@
1
- import { twiddle } from "../utils/index.js";
2
- export function fft1d(arr) {
3
- const N = arr.length;
4
- if (N === 1) return [arr[0]];
5
-
6
- // Split even/odd
7
- const even = fft1d(arr.filter((_, i) => i % 2 === 0));
8
- const odd = fft1d(arr.filter((_, i) => i % 2 === 1));
9
-
10
- const out = new Array(N);
11
- for (let k = 0; k < N/2; k++) {
12
- const w = twiddle(N, k);
13
- const t = w.mul(odd[k]);
14
- out[k] = even[k].add(t);
15
- out[k + N/2] = even[k].sub(t);
16
- }
17
- return out;
18
- }
@@ -1,27 +0,0 @@
1
- import { normalizeComplexND } from '../utils/index.js'
2
- import { fft1d } from '../fft1d/index.js';
3
- function fftND(arr) {
4
- arr = normalizeComplexND(arr);
5
-
6
- // Base case: 1-D
7
- if (!Array.isArray(arr[0]))
8
- return fft1d(arr);
9
-
10
- const transformed = arr.map(sub => fftND(sub));
11
-
12
- const rows = transformed.length;
13
- const cols = transformed[0].length;
14
-
15
- const colsData = Array.from({ length: cols }, (_, c) =>
16
- Array.from({ length: rows }, (_, r) => transformed[r][c])
17
- );
18
-
19
- const colsTransformed = colsData.map(col => fft1d(col));
20
-
21
- // Transpose back
22
- const out = Array.from({ length: rows }, (_, r) =>
23
- Array.from({ length: cols }, (_, c) => colsTransformed[c][r])
24
- );
25
-
26
- return out;
27
- }