A library of commonly used JavaScript tools for Subnero, providing utilities for underwater acoustic modem configuration and digital signal processing.
- Modem Model Parser - Parse and generate model codes for Subnero Gen4 and Gen4X underwater acoustic modems
- DSP Functions - Compute power spectral density (PSD) and spectrograms for audio signal analysis
npm installParse and manipulate Subnero underwater acoustic modem model codes (Gen4, Gen4X, and UnetCube).
import { ModemModel } from './src/modem-model.js';
// Parse a Gen4 modem model code
const modem = new ModemModel("WNC-S60HSS4");
console.log(modem.spectrum); // "HF"
console.log(modem.frequency); // "60000"
console.log(modem.edition); // "Silver"
console.log(modem.configuration); // "Standalone"
console.log(modem.generation); // "4"
console.log(modem.bulkheadConnector); // "DBH13F"
console.log(modem.hullMaterial); // "aluminum"
console.log(modem.depthRating); // 300
// Parse a Gen4X modem model code
const modemX = new ModemModel("WNC-M25MSS4X");
console.log(modemX.generation); // "4X"
console.log(modemX.channels); // 1
console.log(modemX.storage); // 256- Parse model codes into structured data (edition, configuration, hardware specs)
- Generate model codes from configuration objects
- Support for Gen4, Gen4X, and UnetCube modem generations
- Decode customization codes (hull rating, storage, transducers, etc.)
- Handle project codes and prototype variants
- Validate model code format
- HF Band: S60H (60 kHz), S40H (40 kHz)
- MF Band: M25M (24 kHz)
- LF Band: L12L (12 kHz), L5L (5 kHz)
- UnetCube: X (multi-band)
Constructor
new ModemModel(modelString)Static Methods
ModemModel.getGeneration(model)- Get generation from model string ("4", "4X", or "5")
Instance Properties
productLine- Product line (e.g., "WNC")range- Frequency range (e.g., "S60H", "M25M")spectrum- Frequency band (e.g., "HF", "MF", "LF")frequency- Operating frequency in Hzedition- Edition ("Silver", "Gold", "Platinum", "Research")configuration- Configuration type ("Standalone", "Embedded", "Open")generation- Generation ("4", "4X", "5")bulkheadConnector- Bulkhead connector typetransducerType- Transducer modelhullMaterial- Hull material ("aluminum", "steel", "titanium")depthRating- Depth rating in metersstorage- Storage capacity in GBchannels- Number of receiving channels (Gen4X)additionalChannels- Additional channels (Gen4)coprocessor- Coprocessor typeprojectCode- Project code if anyprototype- Boolean indicating prototype status
Instance Methods
toString()- Generate model code string from configuration
Parse model with customization
const modem = new ModemModel("WNC-S60HSS4-00010100");
console.log(modem.bulkheadConnector); // Custom connector
console.log(modem.storage); // Custom storageParse model with project code
const modem = new ModemModel("WNC-M25MSS4X-PABC123");
console.log(modem.projectCode); // "ABC123"Generate model code
const modem = new ModemModel("WNC-S60HSS4");
modem.storage = 256;
modem.depthRating = 2000;
console.log(modem.toString()); // Updated model code with customizationFor complete API documentation and customization options, see the inline JSDoc comments in src/modem-model.js.
Digital signal processing functions for computing power spectral density and spectrograms of real-valued audio signals, optimized for web-based visualization.
These APIs accept plain JavaScript arrays and numeric typed arrays such as Float32Array and Float64Array.
import { welch, spectrogram } from './src/dsp.js';
// Generate a test signal
const fs = 1000; // 1 kHz sampling rate
const signal = Float32Array.from({ length: 2000 }, (_, i) =>
Math.sin(2 * Math.PI * 100 * i / fs)
);
// Compute power spectral density
const psd = welch(signal, { fs, nperseg: 512 });
console.log(psd.frequencies); // Frequency bins
console.log(psd.psd); // Power values
// Compute spectrogram
const spec = spectrogram(signal, { fs, nperseg: 256, mode: 'magnitude' });
console.log(spec.frequencies); // Frequency bins
console.log(spec.times); // Time bins
console.log(spec.spectrogram); // 2D array [freq][time]Estimates power spectral density using Welch's method with overlapping segments.
Parameters:
signal(number[] | TypedArray): Input signal (real-valued)options(Object):fs(number, default: 1.0): Sampling frequency in Hzwindow(string | number[] | TypedArray, default: 'hann'): Window type or custom arraynperseg(number, default: 256): Segment length (must be power of 2)noverlap(number, default: nperseg/2): Overlap between segmentsnfft(number, default: nperseg): FFT length (power of 2, >= nperseg)detrend(string | boolean, default: 'constant'): Detrend typescaling(string, default: 'density'): 'density' or 'spectrum'
Returns: {frequencies: number[], psd: number[]}
Computes time-frequency representation using short-time Fourier transform (STFT).
Parameters:
- Same as
welch(), plus:noverlap(default: nperseg/8 for spectrograms)mode(string, default: 'psd'): Output mode ('psd' or 'magnitude')
Returns: {frequencies: number[], times: number[], spectrogram: number[][]}
The spectrogram is a 2D array where spectrogram[f][t] gives the value at frequency index f and time index t.
Detect peak frequency
const { frequencies, psd } = welch(signal, { fs: 1000, nperseg: 1024 });
const peakIdx = psd.indexOf(Math.max(...psd));
console.log(`Peak at ${frequencies[peakIdx].toFixed(2)} Hz`);Custom Hamming window
const nperseg = 512;
const window = new Array(nperseg).fill(0).map((_, n) =>
0.54 - 0.46 * Math.cos(2 * Math.PI * n / (nperseg - 1))
);
const result = welch(signal, { fs: 1000, window, nperseg });Typed-array inputs are processed directly. When the source signal is a typed array, segment extraction uses typed-array views instead of first converting the full signal into a plain array.
Time-frequency chirp analysis
// Generate chirp: frequency increases over time
const signal = new Array(2000).fill(0).map((_, i) => {
const t = i / 1000;
return Math.sin(2 * Math.PI * (50 + 200 * t) * t);
});
const { frequencies, times, spectrogram: spec } = spectrogram(signal, {
fs: 1000,
nperseg: 256,
mode: 'magnitude'
});
// spec[f][t] shows energy distribution over time and frequency- Power-of-2 requirement:
npersegandnfftmust be powers of 2 (2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, etc.) due to FFT.js requirements - Overlap recommendations:
- Welch: 50% overlap (nperseg/2) optimal for Hann window
- Spectrogram: 12.5% overlap (nperseg/8) for statistical independence
- Scaling: 'density' returns V²/Hz, 'spectrum' returns V²
- One-sided spectrum: Always returned for real-valued inputs (DC to Nyquist)
For complete documentation, see docs/DSP.md.
Run all tests:
deno testRun specific module tests:
deno test src/modem-model_test.js
deno test src/dsp_test.jsRun the DSP demo:
deno run examples/dsp_demo.js- Modem Model: See inline JSDoc in src/modem-model.js
- DSP Functions: See docs/DSP.md
- fft.js - Fast Fourier Transform implementation
MIT
Chinmay Pendharkar (chinmay@subnero.com)