├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── fft.js ├── lib └── fft-matrix.js ├── package.json └── test └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | npm-debug.log 15 | node_modules/* -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | npm-debug.log 15 | node_modules/* 16 | test/* -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "node" 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Mikola Lysenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ndarray-fft 2 | =========== 3 | 4 | [![Build Status](https://travis-ci.org/scijs/ndarray-fft.svg)](https://travis-ci.org/scijs/ndarray-fft) 5 | 6 | > A fast Fourier transform implementation for [ndarrays](https://github.com/mikolalysenko/ndarray). You can use this to do image processing operations on big, higher dimensional typed arrays in JavaScript. 7 | 8 | ## Example 9 | 10 | ```javascript 11 | var zeros = require("zeros") 12 | var ops = require("ndarray-ops") 13 | var fft = require("ndarray-fft") 14 | 15 | var x = ops.random(zeros([256, 256])) 16 | , y = ops.random(zeros([256, 256])) 17 | 18 | //Forward transform x/y 19 | fft(1, x, y) 20 | 21 | //Invert transform 22 | fft(-1, x, y) 23 | ``` 24 | 25 | ## Install 26 | Via npm: 27 | 28 | npm install ndarray-fft 29 | 30 | 31 | ### `require("ndarray-fft")(dir, x, y)` 32 | Executes a fast Fourier transform on the complex valued array x/y. 33 | 34 | * `dir` - Either +/- 1. Determines whether to use a forward or inverse FFT 35 | * `x` the real part of the signal, encoded as an ndarray 36 | * `y` the imaginary part of the signal, encoded as an ndarray 37 | 38 | `x` and `y` are transformed in place. 39 | 40 | **Note** This code is fastest when the components of the shapes arrays are all powers of two. For non-power of two shapes, Bluestein's fft is used which is somewhat slower. 41 | 42 | **Note2** The inverse FFT is scaled by 1/N, forward FFT is unnormalized. 43 | 44 | # Credits 45 | (c) 2013 Mikola Lysenko. MIT License. 46 | 47 | Radix 2 FFT based on code by Paul Bourke. 48 | -------------------------------------------------------------------------------- /fft.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var ops = require('ndarray-ops') 4 | var ndarray = require('ndarray') 5 | var pool = require('typedarray-pool') 6 | var fftm = require('./lib/fft-matrix.js') 7 | 8 | function ndfft(dir, x, y) { 9 | var shape = x.shape 10 | , d = shape.length 11 | , size = 1 12 | , stride = new Array(d) 13 | , pad = 0 14 | , i, j 15 | for(i=d-1; i>=0; --i) { 16 | stride[i] = size 17 | size *= shape[i] 18 | pad = Math.max(pad, fftm.scratchMemory(shape[i])) 19 | if(x.shape[i] !== y.shape[i]) { 20 | throw new Error('Shape mismatch, real and imaginary arrays must have same size') 21 | } 22 | } 23 | var buf_size = 4 * size + pad 24 | var buffer 25 | if( x.dtype === 'array' || 26 | x.dtype === 'float64' || 27 | x.dtype === 'custom' ) { 28 | buffer = pool.mallocDouble(buf_size) 29 | } else { 30 | buffer = pool.mallocFloat(buf_size) 31 | } 32 | var x1 = ndarray(buffer, shape.slice(0), stride, 0) 33 | , y1 = ndarray(buffer, shape.slice(0), stride.slice(0), size) 34 | , x2 = ndarray(buffer, shape.slice(0), stride.slice(0), 2*size) 35 | , y2 = ndarray(buffer, shape.slice(0), stride.slice(0), 3*size) 36 | , tmp, n, s1, s2 37 | , scratch_ptr = 4 * size 38 | 39 | //Copy into x1/y1 40 | ops.assign(x1, x) 41 | ops.assign(y1, y) 42 | 43 | for(i=d-1; i>=0; --i) { 44 | fftm(dir, size/shape[i], shape[i], buffer, x1.offset, y1.offset, scratch_ptr) 45 | if(i === 0) { 46 | break 47 | } 48 | 49 | //Compute new stride for x2/y2 50 | n = 1 51 | s1 = x2.stride 52 | s2 = y2.stride 53 | for(j=i-1; j=0; --j) { 58 | s2[j] = s1[j] = n 59 | n *= shape[j] 60 | } 61 | 62 | //Transpose 63 | ops.assign(x2, x1) 64 | ops.assign(y2, y1) 65 | 66 | //Swap buffers 67 | tmp = x1 68 | x1 = x2 69 | x2 = tmp 70 | tmp = y1 71 | y1 = y2 72 | y2 = tmp 73 | } 74 | 75 | //Copy result back into x 76 | ops.assign(x, x1) 77 | ops.assign(y, y1) 78 | 79 | pool.free(buffer) 80 | } 81 | 82 | module.exports = ndfft -------------------------------------------------------------------------------- /lib/fft-matrix.js: -------------------------------------------------------------------------------- 1 | var bits = require('bit-twiddle') 2 | 3 | function fft(dir, nrows, ncols, buffer, x_ptr, y_ptr, scratch_ptr) { 4 | dir |= 0 5 | nrows |= 0 6 | ncols |= 0 7 | x_ptr |= 0 8 | y_ptr |= 0 9 | if(bits.isPow2(ncols)) { 10 | fftRadix2(dir, nrows, ncols, buffer, x_ptr, y_ptr) 11 | } else { 12 | fftBluestein(dir, nrows, ncols, buffer, x_ptr, y_ptr, scratch_ptr) 13 | } 14 | } 15 | module.exports = fft 16 | 17 | function scratchMemory(n) { 18 | if(bits.isPow2(n)) { 19 | return 0 20 | } 21 | return 2 * n + 4 * bits.nextPow2(2*n + 1) 22 | } 23 | module.exports.scratchMemory = scratchMemory 24 | 25 | 26 | //Radix 2 FFT Adapted from Paul Bourke's C Implementation 27 | function fftRadix2(dir, nrows, ncols, buffer, x_ptr, y_ptr) { 28 | dir |= 0 29 | nrows |= 0 30 | ncols |= 0 31 | x_ptr |= 0 32 | y_ptr |= 0 33 | var nn,m,i,i1,j,k,i2,l,l1,l2 34 | var c1,c2,t,t1,t2,u1,u2,z,row,a,b,c,d,k1,k2,k3 35 | 36 | // Calculate the number of points 37 | nn = ncols 38 | m = bits.log2(nn) 39 | 40 | for(row=0; row> 1; 43 | j = 0; 44 | for(i=0;i>= 1 57 | } 58 | j += k 59 | } 60 | 61 | // Compute the FFT 62 | c1 = -1.0 63 | c2 = 0.0 64 | l2 = 1 65 | for(l=0;l