├── .gitignore ├── LICENSE.txt ├── README.md ├── package.json ├── tests └── fft-windowing-tests.js └── windowing.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | fft-windowing.pdf -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining a copy 2 | of this software and associated documentation files (the "Software"), to deal 3 | in the Software without restriction, including without limitation the rights 4 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 5 | copies of the Software, and to permit persons to whom the Software is 6 | furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in 9 | all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 17 | THE SOFTWARE. 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **nodejs-fft-windowing** is a [node.js](http://nodejs.org/) module that applies a [windowing function](http://en.wikipedia.org/wiki/Window_function) to an array of data, making it ready to be [FFT](http://en.wikipedia.org/wiki/Fast_Fourier_transform)'d. 2 | 3 | [This article](http://www.ni.com/white-paper/4844/en) by [National Instruments](http://uk.ni.com/) gives a good introduction to why windowing functions are useful. 4 | 5 | ## Installation ## 6 | 7 | If you have [npm](https://npmjs.org/) installed, just run: 8 | 9 | ``` 10 | npm install fft-windowing 11 | ``` 12 | 13 | ## Usage ## 14 | 15 | The [Hann (Hanning) window](http://en.wikipedia.org/wiki/Window_function#Hann_.28Hanning.29_window) is a good general-purpose window. You would use it like so: 16 | 17 | ```javascript 18 | var windowing = require('fft-windowing'); 19 | 20 | var raw = [2, 2, 0, -2, -2, 0, 2, 2]; 21 | 22 | var windowed = windowing.hann(raw); 23 | 24 | ``` 25 | 26 | The resulting `windowed` variable is then ready to be fed through a Fast Fourier Transform. A good [node.js](http://nodejs.org/) module to use would be [this](https://npmjs.org/package/fft) one. 27 | 28 | The following windows are available: 29 | 30 | - [hann](http://en.wikipedia.org/wiki/Window_function#Hann_.28Hanning.29_window) 31 | - [hamming](http://en.wikipedia.org/wiki/Window_function#Hamming_window) 32 | - [cosine](http://en.wikipedia.org/wiki/Window_function#Cosine_window) 33 | - [lanczos](http://en.wikipedia.org/wiki/Window_function#Lanczos_window) 34 | - [gaussian](http://en.wikipedia.org/wiki/Window_function#Gaussian_windows) 35 | - [tukey](http://en.wikipedia.org/wiki/Window_function#Tukey_window) 36 | - [blackman](http://en.wikipedia.org/wiki/Window_function#Blackman_windows) 37 | - [exact_blackman](http://en.wikipedia.org/wiki/Window_function#Blackman_windows) 38 | - [kaiser](http://en.wikipedia.org/wiki/Window_function#Kaiser_windows) 39 | - [nuttall](http://en.wikipedia.org/wiki/Window_function#Nuttall_window.2C_continuous_first_derivative) 40 | - [blackman_harris](http://en.wikipedia.org/wiki/Window_function#Blackman.E2.80.93Harris_window) 41 | - [blackman_nuttall](http://en.wikipedia.org/wiki/Window_function#Blackman.E2.80.93Nuttall_window) 42 | - [flat_top](http://en.wikipedia.org/wiki/Window_function#Flat_top_window) 43 | 44 | The following windows can also accept an extra parameter, `alpha`: 45 | 46 | - [gaussian](http://en.wikipedia.org/wiki/Window_function#Gaussian_windows) defaults to 0.4 47 | - [tukey](http://en.wikipedia.org/wiki/Window_function#Tukey_window) defaults to 0.5 48 | - [blackman](http://en.wikipedia.org/wiki/Window_function#Blackman_windows) defaults to 0.16 49 | - [kaiser](http://en.wikipedia.org/wiki/Window_function#Kaiser_windows) defaults 0.3 50 | 51 | You would use it like this: 52 | 53 | ```javascript 54 | var windowing = require('fft-windowing'); 55 | 56 | var raw = [2, 2, 0, -2, -2, 0, 2, 2]; 57 | 58 | var windowed = windowing.kaiser(raw, 0.5); 59 | 60 | ``` 61 | 62 | ## Tests ## 63 | 64 | Run `node tests/fft-windowing-tests.js`. This should generate a file called `fft-windowing.pdf` in the root directory which shows what happens if you apply each windowing function to a uniform array. 65 | 66 | ## LICENSE ## 67 | 68 | MIT 69 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fft-windowing", 3 | "version": "0.1.4", 4 | "description": "Applies a windowing function to an array of data, making it ready to be FFT'd.", 5 | "main": "windowing.js", 6 | "author": "Richard Eoin ", 7 | "devDependencies": { 8 | "plotter": "0.3.x", 9 | "underscore": "1.4.x" 10 | }, 11 | "scripts": { 12 | "test": "node tests/fft-windowing-tests.js" 13 | }, 14 | "keywords": [ 15 | "fft", 16 | "fourier", 17 | "windowing", 18 | "hann", 19 | "hamming", 20 | "cosine", 21 | "lanczos", 22 | "gaussian", 23 | "tukey", 24 | "blackman", 25 | "exact_blackman", 26 | "kaiser", 27 | "nuttall", 28 | "blackman_harris", 29 | "blackman_nuttall", 30 | "flat_top" 31 | ], 32 | "repository": { 33 | "type": "git", 34 | "url": "https://github.com/richardeoin/nodejs-fft-windowing" 35 | }, 36 | "license": "MIT", 37 | "engine": "node >= 0.9.4" 38 | } 39 | -------------------------------------------------------------------------------- /tests/fft-windowing-tests.js: -------------------------------------------------------------------------------- 1 | var windowing = require('../windowing.js'); 2 | var plot = require('plotter').plot; 3 | var _ = require('underscore'); 4 | 5 | var data = {}; 6 | 7 | console.log("Applying windowing functions to a uniform array.."); 8 | 9 | /* Create a uniform array of '1's */ 10 | var blank = new Array(); 11 | for (r in _.range(100)) { 12 | blank.push(1); 13 | } 14 | 15 | /* Foreach windowing function */ 16 | for (window in windowing) { 17 | var name = window.replace(/\_/g, ' '); 18 | /* Apply the windowing function to a deep copy of the uniform array */ 19 | data[name] = windowing[window](blank.slice(0)); 20 | } 21 | 22 | console.log("Plotting result to fft-windowing.pdf.."); 23 | 24 | /* Plot the result */ 25 | plot({ 26 | data: data, 27 | filename: 'fft-windowing.pdf', 28 | title : 'windows', 29 | }); 30 | 31 | 32 | -------------------------------------------------------------------------------- /windowing.js: -------------------------------------------------------------------------------- 1 | /* Richard Meadows 2013 */ 2 | 3 | /** 4 | * Extend Math 5 | */ 6 | Math.sinc = function(n) { return Math.sin(Math.PI*n)/(Math.PI*n); } 7 | Math.bessi0 = function(x) { /* Evaluate modified Bessel function In(x) and n=0. */ 8 | var ax = Math.abs(x); 9 | 10 | if (ax < 3.75) { 11 | y = x / 3.75; y = y * y; 12 | return 1.0 + y*(3.5156229+y*(3.0899424+y*(1.2067492+y*(0.2659732+y*(0.360768e-1+y*0.45813e-2))))); 13 | } else { 14 | y = 3.75 / ax; 15 | return (Math.exp(ax) / Math.sqrt(ax)) * 16 | (0.39894228+y*(0.1328592e-1+y*(0.225319e-2+y*(-0.157565e-2+y*(0.916281e-2+y* 17 | (-0.2057706e-1+y*(0.2635537e-1+y*(-0.1647633e-1+y*0.392377e-2)))))))); 18 | } 19 | } 20 | 21 | /** 22 | * Windowing functions. 23 | */ 24 | var windows = { 25 | hann: function (n, points) { return 0.5 - 0.5*Math.cos(2*Math.PI*n/(points-1)); }, 26 | hamming: function (n, points) { return 0.54 - 0.46*Math.cos(2*Math.PI*n/(points-1)); }, 27 | cosine: function (n, points) { return Math.sin(Math.PI*n/(points-1)); }, 28 | lanczos: function (n, points) { return Math.sinc((2*n/(points-1))-1); }, 29 | gaussian: function (n, points, alpha) { 30 | if (!alpha) { alpha = 0.4; } 31 | return Math.pow(Math.E, -0.5*Math.pow((n-(points-1)/2)/(alpha*(points-1)/2), 2)); 32 | }, 33 | tukey: function (n, points, alpha) { 34 | if (!alpha) { alpha = 0.5; } 35 | 36 | if (n < 0.5*alpha*(points-1)) { 37 | return 0.5*(1+(Math.cos(Math.PI*((2*n/(alpha*(points-1)))-1)))); 38 | } else if (n < (1-(0.5*alpha))*(points-1)) { 39 | return 1; 40 | } else { 41 | return 0.5*(1+(Math.cos(Math.PI*((2*n/(alpha*(points-1)))+1-(2/alpha))))); 42 | } 43 | }, 44 | blackman: function (n, points, alpha) { 45 | if (!alpha) { alpha = 0.16; } 46 | return 0.42 - 0.5*Math.cos(2*Math.PI*n/(points-1)) + 0.08*Math.cos(4*Math.PI*n/(points-1)); 47 | }, 48 | exact_blackman: function (n, points) { 49 | return 0.4243801 - 0.4973406*Math.cos(2*Math.PI*n/(points-1)) + 0.0782793*Math.cos(4*Math.PI*n/(points-1)); 50 | }, 51 | kaiser: function (n, points, alpha) { 52 | if (!alpha) { alpha = 3; } 53 | return Math.bessi0(Math.PI*alpha*Math.sqrt(1-Math.pow((2*n/(points-1))-1, 2))) / Math.bessi0(Math.PI*alpha); 54 | }, 55 | nuttall: function (n, points) { 56 | return 0.355768 - 0.487396*Math.cos(2*Math.PI*n/(points-1)) 57 | + 0.144232*Math.cos(4*Math.PI*n/(points-1)) 58 | - 0.012604*Math.cos(6*Math.PI*n/(points-1)); 59 | }, 60 | blackman_harris:function (n, points) { 61 | return 0.35875 - 0.48829*Math.cos(2*Math.PI*n/(points-1)) 62 | + 0.14128*Math.cos(4*Math.PI*n/(points-1)) 63 | - 0.01168*Math.cos(6*Math.PI*n/(points-1)); 64 | }, 65 | blackman_nuttall:function (n, points) { 66 | return 0.3635819 - 0.3635819*Math.cos(2*Math.PI*n/(points-1)) 67 | + 0.1365995*Math.cos(4*Math.PI*n/(points-1)) 68 | - 0.0106411*Math.cos(6*Math.PI*n/(points-1)); 69 | }, 70 | flat_top: function (n, points) { 71 | return 1 - 1.93*Math.cos(2*Math.PI*n/(points-1)) 72 | + 1.29*Math.cos(4*Math.PI*n/(points-1)) 73 | - 0.388*Math.cos(6*Math.PI*n/(points-1)) 74 | + 0.032*Math.cos(8*Math.PI*n/(points-1)); 75 | }, 76 | } 77 | 78 | /** 79 | * Applies a Windowing Function to an array. 80 | */ 81 | function window(data_array, windowing_function, alpha) { 82 | var datapoints = data_array.length; 83 | 84 | /* For each item in the array */ 85 | for (var n=0; n