Skip to content

Repository files navigation

dspkit

npm version npm downloads CI License: MIT

Zero-dependency digital signal processing: FFT/IFFT, spectrum analysis, FIR filter design, window functions, and signal utilities — TypeScript-first npm equivalent of Python's scipy.signal, Go's gonum/dsp, Java's JTransforms.

import { fft, magnitudeSpectrum, dominantFrequency, generateSine, lowpassFilter, applyFilter } from "@billdaddy/dspkit";

// Generate a 440 Hz sine wave at 44100 Hz sample rate
const signal = generateSine(440, 1.0, 44100, 4096);

// Compute FFT and find dominant frequency
const spectrum = fft(signal);
const { magnitude, frequencies } = magnitudeSpectrum(spectrum, 44100);
const freq = dominantFrequency(magnitude, frequencies); // ≈ 440

// Design a 1 kHz lowpass FIR filter and apply it
const cutoff = 1000 / 44100; // normalized (0–0.5)
const h = lowpassFilter(cutoff, 128);
const filtered = applyFilter(signal, h);

Why dspkit?

Every major scientific computing ecosystem ships DSP primitives in its standard or near-standard library:

  • Pythonscipy.signal (FFT, IIR/FIR design, spectrogram)
  • Gogonum.org/v1/gonum/dsp (FFT, windowing)
  • JavaJTransforms, Apache Commons Math
  • C#Math.NET Numerics (FFT, filter design)
  • JuliaDSP.jl (comprehensive)

The only npm package attempting this space — dsp.js — was self-declared unmaintained as of 2014, has no TypeScript support, and receives ~38k downloads per week only because no alternative exists. dspkit is its modern, zero-dep, TypeScript-native replacement.

Install

npm install @billdaddy/dspkit

Usage

FFT / IFFT

import { fft, ifft, fftConvolve, nextPow2 } from "@billdaddy/dspkit";

// Real-valued signal → complex spectrum (auto zero-pads to next power of 2)
const spectrum = fft([1, 2, 3, 4, 5, 6, 7, 8]);
spectrum.re; // real parts
spectrum.im; // imaginary parts
spectrum.length; // 8 (already a power of 2)

// Non-power-of-2 inputs are zero-padded automatically
fft([1, 2, 3]).length; // 4

// Inverse FFT → recover original signal
const back = ifft(spectrum);
back.re; // ≈ [1, 2, 3, 4, 5, 6, 7, 8]

// FFT-based convolution: O(N log N) vs direct O(N*M)
const result = fftConvolve([1, 2, 3], [4, 5, 6]); // → Float64Array([4, 13, 28, 27, 18])

Spectrum analysis

import { fft, magnitude, powerSpectrum, phase, magnitudeSpectrum, dominantFrequency, rms, peak, crestFactor } from "@billdaddy/dspkit";

const c = fft(signal);

magnitude(c);      // |X[k]|  — amplitude at each bin
powerSpectrum(c);  // |X[k]|² — power at each bin
phase(c);          // atan2(im, re) — phase at each bin

// One-sided magnitude spectrum with physical frequency labels
const { magnitude: mag, frequencies } = magnitudeSpectrum(c, 44100);
// mag[k] is amplitude at frequencies[k] Hz
dominantFrequency(mag, frequencies); // frequency with highest amplitude

// Time-domain statistics
rms(signal);          // root-mean-square energy
peak(signal);         // maximum absolute value
crestFactor(signal);  // peak / rms

Window functions

Reduce spectral leakage when your signal doesn't contain an integer number of cycles.

import { hannWindow, hammingWindow, blackmanWindow, bartlettWindow,
         nuttallWindow, blackmanHarrisWindow, flatTopWindow, rectangularWindow,
         applyWindow, coherentGain, getWindow } from "@billdaddy/dspkit";

const N = 1024;
const w = hannWindow(N);     // → Float64Array of length N
applyWindow(signal, w);      // element-wise multiply signal × window
coherentGain(w);             // mean of window (≈ 0.5 for Hann)

// Get window by name
getWindow("blackman", N);    // one of: rectangular|hann|hamming|blackman|bartlett|nuttall|blackman-harris|flat-top
Window Sidelobe level Main lobe width Use case
Rectangular -13 dB Narrowest Never leak matters
Hann -31 dB Moderate General purpose
Hamming -41 dB Moderate General purpose
Blackman -57 dB Wide Low sidelobes
Nuttall -93 dB Wide Very low sidelobes
Blackman-Harris -92 dB Wide Very low sidelobes
Flat-Top -44 dB Widest Amplitude accuracy

FIR filter design (windowed-sinc)

All cutoff frequencies are normalized: cutoff = f_Hz / f_sample. Valid range: (0, 0.5) where 0.5 = Nyquist.

import { lowpassFilter, highpassFilter, bandpassFilter, bandstopFilter, applyFilter } from "@billdaddy/dspkit";

const sampleRate = 44100;

// Lowpass: pass < 2 kHz, attenuate > 2 kHz
const lp = lowpassFilter(2000 / sampleRate, 128);  // order 128 → 129 coefficients

// Highpass: pass > 5 kHz, attenuate < 5 kHz
const hp = highpassFilter(5000 / sampleRate, 128);

// Bandpass: pass 300–3400 Hz (telephone band)
const bp = bandpassFilter(300 / sampleRate, 3400 / sampleRate, 128);

// Bandstop (notch): suppress 50 Hz power-line hum
const bs = bandstopFilter(45 / sampleRate, 55 / sampleRate, 128);

// Apply any FIR filter to a signal (causal, same output length as input)
const filtered = applyFilter(signal, lp);
// Note: group delay = order/2 samples (filter is linear-phase)

Direct convolution

import { convolve } from "@billdaddy/dspkit";

convolve([1, 2, 3], [4, 5, 6]);
// → Float64Array([4, 13, 28, 27, 18])  (length = 3 + 3 - 1 = 5)

Signal generation

import { generateSine, generateCosine, generateSquare, generateNoise, linspace } from "@billdaddy/dspkit";

const sr = 44100, n = 4096;

generateSine(440, 1.0, sr, n);       // A4 at full amplitude
generateCosine(440, 0.5, sr, n);     // half-amplitude cosine
generateSquare(100, 1.0, sr, n, 10); // square wave (10 harmonics)
generateNoise(0.1, n);               // white noise at 10% amplitude

linspace(0, 1, 11); // [0, 0.1, 0.2, ..., 1.0]

Signal utilities

import { zeroPad, mean, removeDC, normalize, toDb, fromDb } from "@billdaddy/dspkit";

zeroPad(signal, 512);    // extend with zeros to length 512
mean(signal);            // arithmetic mean
removeDC(signal);        // subtract mean (remove DC offset)
normalize(signal);       // scale so peak absolute value = 1
toDb(0.5);               // ≈ -6 dB
fromDb(-6);              // ≈ 0.5

API summary

FFT

Function Description
fft(signal) Forward FFT of real signal → ComplexArray
ifft(complex) Inverse FFT → ComplexArray
fftConvolve(a, b) FFT-based linear convolution
nextPow2(n) Smallest power of 2 ≥ n

Spectrum

Function Description
magnitude(c) |X[k]| for each bin
powerSpectrum(c) |X[k]|² for each bin
phase(c) atan2(im, re) for each bin
magnitudeSpectrum(c, sr?) One-sided spectrum with frequency labels
dominantFrequency(mag, freqs) Frequency at spectral peak
rms(signal) Root-mean-square
peak(signal) Maximum absolute value
crestFactor(signal) peak / rms

Windows

Function Description
hannWindow(n) Hann window
hammingWindow(n) Hamming window
blackmanWindow(n) Blackman window
bartlettWindow(n) Bartlett (triangular) window
nuttallWindow(n) Nuttall window
blackmanHarrisWindow(n) Blackman-Harris window
flatTopWindow(n) Flat-top window
rectangularWindow(n) No windowing (boxcar)
applyWindow(signal, w) Element-wise multiply
coherentGain(w) Mean of window coefficients
getWindow(name, n) Get window by name

Filters (FIR)

Function Description
lowpassFilter(cutoff, order, window?) Lowpass FIR coefficients
highpassFilter(cutoff, order, window?) Highpass FIR coefficients
bandpassFilter(lo, hi, order, window?) Bandpass FIR coefficients
bandstopFilter(lo, hi, order, window?) Bandstop (notch) FIR coefficients
applyFilter(signal, coeffs) Apply FIR filter (causal)
convolve(a, b) Direct linear convolution

Signal utilities

Function Description
generateSine(f, amp, sr, n, phase?) Sine wave
generateCosine(f, amp, sr, n, phase?) Cosine wave
generateSquare(f, amp, sr, n, harmonics?) Square wave
generateNoise(amp, n) White noise
zeroPad(signal, length) Zero-pad to length
linspace(start, end, n) Evenly-spaced values
mean(signal) Arithmetic mean
removeDC(signal) Subtract mean
normalize(signal) Scale peak to 1
toDb(linear) Amplitude → dB
fromDb(db) dB → amplitude

Performance

Operation Complexity
fft(n) O(n log n)
ifft(n) O(n log n)
fftConvolve(a, b) O(N log N), N = nextPow2(a+b-1)
convolve(a, b) O(a.length × b.length) — fine for FIR taps
applyFilter(signal, h) O(signal.length × h.length)
Window functions O(n)

Contributors ✨

License

MIT © trananhtung

About

Zero-dep DSP: FFT/IFFT, spectrum analysis, FIR filter design, 8 window functions, signal generators. TypeScript-first replacement for abandoned dsp.js.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages