展示 HN:JSciPy – 受 SciPy 启发,为 Java 和 Android 设计的信号处理库
Show HN: JSciPy – SciPy-inspired signal processing library for Java and Android

原始链接: https://github.com/hissain/jscipy

## jSciPy:一个Java SciPy实现 jSciPy是一个全面的Java库,旨在复制Python的SciPy的功能,用于在JVM和Android上进行科学计算和信号处理。它通过提供机器学习流水线中基本算法的高性能实现,填补了Java生态系统中的一个空白。 该库包括用于**信号处理**(滤波、窗口函数、卷积)、**变换**(FFT、希尔伯特变换、DCT)、**数学与分析**(ODE求解器、插值、多项式拟合)等的模块。主要功能包括高级滤波选项(巴特沃斯、切比雪夫等)、二维信号处理以及与SciPy兼容的API。 jSciPy通过其更广泛的功能集和与SciPy行为的一致性,在严格测试下实现了出色的精度(RMSE为10^-16或更低),从而使其与其他Java库(如Commons Math和JDSP)区分开来。 该库通过JitPack提供,并欢迎贡献,特别是在性能基准测试、功能扩展和文档方面。 还有一个演示Android应用程序可供参考。

Hacker News 新闻 | 过去 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 展示 HN: JSciPy – 受 SciPy 启发的 Java 和 Android 信号处理库 (github.com/hissain) 8 分,来自 hissain 1 天前 | 隐藏 | 过去 | 收藏 | 1 条评论 JSciPy 是一个开源的 Java 信号处理和科学计算库,灵感来自 SciPy。它专注于 FFT、滤波器、PSD、STFT、DCT 和 Android 兼容性,旨在填补 JVM 和 Android 上 DSP 密集型工作负载的空白。 kernal 1 天前 [–] 非常棒。感谢您的贡献。回复 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索:
相关文章

原文

jSciPy is a comprehensive Java Scientific Computing and Signal Processing Library designed for Machine Learning on the JVM and Android. Inspired by Python's SciPy, it provides high-performance implementations of essential algorithms.

It currently includes modules for:

  • Signal Processing: Butterworth, Chebyshev, Elliptic, Bessel, and FIR (firwin) filters, Window Functions, 2D Convolution, Savitzky-Golay smoothing, Peak detection, Detrending, Median Filter.
  • Transformations: FFT (Fast Fourier Transform), Hilbert Transform, Welch PSD, Spectrogram, Periodogram, Convolution, DCT/IDCT.
  • Math & Analysis: RK4 ODE Solver, Interpolation (Linear, Cubic Spline), Resampling, Polynomial fitting.

In modern machine learning workflows, most signal processing tasks rely on Python's SciPy utilities. However, there is no Java library that replicates SciPy's behavior with comparable completeness and consistency. This creates a significant gap for teams building ML or signal processing pipelines on the JVM. jSciPy aims to fill this gap, and the demand for such a library is higher than ever.

The table below compares jSciPy’s signal processing and scientific computing features with several other popular Java libraries, highlighting areas where jSciPy provides more comprehensive functionality.

Feature / Characteristic jSciPy Commons Math JDSP TarsosDSP IIRJ EJML
Primary Focus SciPy-style Signal + Scientific General Math/Stats Java DSP Toolbox Audio Processing IIR Filter Only Linear Algebra
Zero-Phase Filtering (filtfilt) ✅ Yes (SciPy-compatible) ❌ No ❌ No ❌ No ❌ No ❌ No
2D Signal Ops (conv2d, fft2) ✅ Yes ❌ No ❌ No ❌ No ❌ No ❌ No
SciPy-like API Consistency ✅ High (SciPy semantics) ❌ Low ⚠️ Partial Java DSP ❌ No ❌ No ❌ No
Filtering Capabilities ⭐⭐⭐⭐⭐ (IIR+FIR+advanced) ⭐ Basic ⭐⭐⭐ (IIR/FIR & adaptive) ⭐⭐ (audio filters) ⭐⭐ (IIR only) ❌ No
Transforms (FFT/DCT/Hilbert) ✅ FFT, DCT + Hilbert Limited / Basic FFT only ✅ FFT + Hilbert ✅ FFT spectrum tools (audio) ❌ No ❌ No
Interpolation (Linear/Cubic) ✅ Yes ✅ Yes ✅ Yes ❌ No ❌ No ❌ No
ODE Solvers (RK4) ✅ Yes ✅ Yes ❌ No ❌ No ❌ No ❌ No
Signal Analysis (Peak/PSD) ✅ Yes ❌ No ⚠️ Partial (peak detection) ⚠️ Partial (audio metrics) ❌ No ❌ No
Welch PSD ✅ Yes ❌ No ❌ No ❌ No ❌ No ❌ No
Spectrogram ✅ Yes ❌ No ✅ Yes ✅ Yes ❌ No ❌ No
Window Functions ✅ Yes ❌ No ✅ Yes ✅ Yes ❌ No ❌ No
Savitzky-Golay Filter ✅ Yes ❌ No ✅ Yes ❌ No ❌ No ❌ No
Median Filter (medfilt) ✅ Yes ❌ No ✅ Yes ❌ No ❌ No ❌ No
Detrending ✅ Yes ❌ No ✅ Yes ❌ No ❌ No ❌ No
Real-Optimized FFT (rfft/irfft) ✅ Yes ❌ No ✅ Yes ❌ No ❌ No ❌ No
STFT / ISTFT Support ✅ Yes (SciPy-like) ❌ No ✅ Yes (dedicated classes) ⚠️ Partial (internal use only) ❌ No ❌ No
1D Convolution with Modes (convolve) ✅ Yes (with modes) ❌ No ⚠️ Partial (convolve1d, limited modes) ⚠️ Partial (implied, no modes) ❌ No ❌ No
Resampling (resample) ✅ Yes ❌ No ✅ Yes ✅ Yes ❌ No ❌ No
Signal Padding Utilities (padSignal) ✅ Yes ❌ No ❌ No ❌ No ❌ No ❌ No
Configurable Peak Finding (find_peaks with prominence etc.) ✅ Yes ❌ No ✅ Yes ⚠️ Partial (spectral peaks only) ❌ No ❌ No
Cross-Correlation (correlate) ✅ Yes ❌ No ❌ No ❌ No ❌ No ❌ No
Polynomials (polyfit, polyval) ✅ Yes (via Commons Math) ✅ Yes ✅ Yes ❌ No ❌ No ❌ No
  • Advanced Filtering: Butterworth, Chebyshev, Elliptic, Bessel, FIR Design (firwin). Supports zero-phase (filtfilt), causal (lfilter), and Second-Order Sections (sosfilt) modes.
  • 2D Processing: convolve2d (Full/Same/Valid), fft2, ifft2.
  • Transforms: standard 1D fft / ifft, real-optimized rfft / irfft, dct / idct (Discrete Cosine Transform), stft / istft, hilbert transform.
  • Smoothing & Analysis: Savitzky-Golay, medfilt (Median Filter), find_peaks, Welch's PSD, spectrogram, detrend, resample.
  • Correlation: correlate (Cross-Correlation with FULL/SAME/VALID modes).
  • Polynomials: polyfit, polyval, polyder.
  • Window Functions: Hamming, Hanning, Blackman, Kaiser, Bartlett, Flat-top, Parzen, Bohman, Triangle.
  • Numerical Methods: Interpolation (Linear, Cubic Spline), RK4 ODE Solver.

jSciPy is rigorously tested against Python's SciPy using a "Golden Master" approach. Below is a summary of the precision (RMSE) achieved across various modules:

Module Test Case RMSE (Approx) Status
Filters Butterworth, Chebyshev, Elliptic, Bessel 1e-14 to 1e-16 ✅ Excellent
FFT 1D FFT, RFFT, IFFT 1e-15 to 1e-16 ✅ Excellent
Spectral Spectrogram, Welch, STFT/ISTFT, Periodogram 1e-16 to 1e-18 ✅ Excellent
SOS Filt Second-Order Sections Filter 1e-16 ✅ Excellent
2D Ops 2D FFT, 2D Convolution 1e-16 ✅ Excellent
Math Interpolation, Resample 1e-16 ✅ Excellent
DCT DCT Type-II, Ortho 1e-15 to 1e-16 ✅ Excellent
Poly Polyfit, Val, Der 1e-14 to 1e-15 ✅ Excellent
ODE RK4 Solver 5e-13 ✅ Excellent

You can access full documentation javadoc of the jscipy library HERE.

  • Java Development Kit (JDK) 8 or higher
  • Gradle (for building the project)

How to Include as a Dependency (JitPack)

JitPack is a novel package repository for JVM projects. It builds GitHub projects on demand and provides ready-to-use artifacts (jar, javadoc, sources).

To use this library in your Gradle project, add the JitPack repository and the dependency to your build.gradle file:

// In your root build.gradle (or settings.gradle for repository definition)
allprojects {
    repositories {
        mavenCentral()
        maven { url 'https://jitpack.io' }
    }
}

// In your app's build.gradle
dependencies {
    implementation 'com.github.hissain:jSciPy:3.1.3' // Replace 3.1.3 with the desired version or commit hash
}

A seperate demo android application is built on this library that might be helpful to understand how to consume this library. The application can be accessed here.

Butterworth Filter Comparison

Butterworth Comparison

Chebyshev Filter Comparison

Type I:

Chebyshev Type I Comparison

Type II:

Chebyshev Type II Comparison

Elliptic Filter Comparison

Elliptic Filter Comparison Bessel Filter Comparison RK4 Comparison FindPeaks Comparison Interpolation Comparison FFT Comparison

Welch's Method Comparison

Welch Comparison Spectrogram Comparison STFT Comparison Periodogram Comparison Resample Comparison

Savitzky-Golay Comparison

Smoothing:

Savitzky-Golay Smoothing

Differentiation:

Savitzky-Golay Differentiation Detrend Comparison MedFilt Comparison Convolve Comparison 2D Convolve Comparison

Cross-Correlation Comparison

Cross-Correlation Comparison DCT Comparison IDCT Comparison FIR Filter Verification

Polynomial Fit Comparison

Polynomial Fit Comparison 2D FFT Comparison

Hilbert Transform Comparison

Hilbert Transform Comparison SOS Filtering Comparison

Window Functions Comparison

Window Functions Comparison

All standard IIR filters (Butterworth, Chebyshev I/II, Elliptic, Bessel) are supported with consistent APIs.

import com.hissain.jscipy.Signal;

public class FilterExample {
    public static void main(String[] args) {
        double[] signal = {/*... input data ...*/};
        double fs = 100.0;
        double fc = 10.0;
        int order = 4;

        // 1. Butterworth: Zero-phase vs Causal
        double[] zeroPhase = Signal.filtfilt(signal, fs, fc, order);
        double[] causal = Signal.lfilter(signal, fs, fc, order);

        // 2. Chebyshev Type I (Ripple 1dB) & Type II (Stopband 20dB)
        double[] cheby1 = Signal.cheby1_filtfilt(signal, fs, fc, order, 1.0);
        double[] cheby2 = Signal.cheby2_filtfilt(signal, fs, fc, order, 20.0);

        // 3. Elliptic (Ripple 1dB, Stopband 40dB)
        double[] ellip = Signal.ellip_filtfilt(signal, fs, fc, order, 1.0, 40.0);
        
        // 4. Bessel (Linear Phase)
        double[] bessel = Signal.bessel_filtfilt(signal, fs, fc, order);

        // Filter Modes: High-pass, Band-pass, Band-stop
        // Available for all filter types (suffix: _highpass, _bandpass, _bandstop)
        double[] bandPass = Signal.filtfilt_bandpass(signal, fs, 8.0, 4.0, order); // Center=10, Width=4

        // 5. Second-Order Sections (SOS) Filtering
        // If you have SOS coefficients (e.g., from Python/SciPy)
        double[][] sos = { /* ... 6 coefficients per section ... */ };
        double[] sosFiltered = Signal.sosfilt(signal, sos);
    }
}

Correlation & Polynomials

Cross-correlation and polynomial fitting/evaluation.

import com.hissain.jscipy.Signal;
import com.hissain.jscipy.Math;
import com.hissain.jscipy.signal.ConvolutionMode;

public class MathSignalExample {
    public static void main(String[] args) {
        // 1. Cross-Correlation
        double[] x = {1, 2, 3};
        double[] target = {0, 1, 0.5};
        // equivalent to convolve(x, reverse(target), mode)
        double[] corr = Signal.correlate(x, target, ConvolutionMode.FULL);
        
        // 2. Discrete Cosine Transform (DCT Type-II)
        double[] dct = Signal.dct(x);             // Standard
        double[] dctOrtho = Signal.dct(x, true);  // Ortho-normalized
        
        // 3. Polynomials
        // Fit a 2nd degree polynomial to (x, y) points
        double[] xPoints = {0, 1, 2, 3};
        double[] yPoints = {1, 2, 5, 10}; // roughly x^2 + 1
        
        // Coefficients: [1.0, 0.0, 1.0] (for x^2 + 1)
        double[] coeffs = Math.polyfit(xPoints, yPoints, 2);
        
        // Evaluate polynomial at new points
        double[] val = Math.polyval(coeffs, new double[]{4, 5}); 
        
        // Compute derivative: [2.0, 0.0] (2x)
        double[] deriv = Math.polyder(coeffs);
    }
}

Spectral Analysis & Transforms

Includes 1D/2D FFT, DCT/IDCT, STFT/ISTFT, Welch's Method, Periodogram, spectrogram, and Hilbert Transform.

import com.hissain.jscipy.Signal;
import com.hissain.jscipy.signal.JComplex;
import com.hissain.jscipy.signal.fft.Welch;
import com.hissain.jscipy.signal.fft.Spectrogram;
import com.hissain.jscipy.signal.fft.Hilbert;

public class SpectralExample {
    public static void main(String[] args) {
        double[] signal = {/*... input data ...*/};
        double fs = 1000.0;

        // 1. FFT / IFFT
        JComplex[] fft = Signal.fft(signal);
        JComplex[] ifft = Signal.ifft(fft);
        
        // 2. Real-optimized FFT (RFFT)
        JComplex[] rfft = Signal.rfft(signal);
        
        // 3. Welch's Method (PSD)
        Welch.WelchResult psd = Signal.welch(signal, fs, 256);
        // Access: psd.f (frequencies), psd.Pxx (power spectrum)

        // 4. Spectrogram
        Spectrogram.SpectrogramResult spec = Signal.spectrogram(signal, fs);
        // Access: spec.frequencies, spec.times, spec.Sxx

        // 5. Hilbert Transform (Analytic Signal)
        Hilbert h = new Hilbert();
        JComplex[] analytic = h.hilbert(signal);

        // 6. Short-Time Fourier Transform (STFT)
        JComplex[][] stft = Signal.stft(signal); // Uses default nperseg=256, noverlap=128
        
        // 7. Inverse STFT
        double[] reconstructed = Signal.istft(stft);
    }
}

Smoothing & Signal Operations

Common operations for signal conditioning and feature extraction.

import com.hissain.jscipy.Signal;
import com.hissain.jscipy.signal.filter.SavitzkyGolay;
import com.hissain.jscipy.signal.filter.MedFilt;

public class OperationsExample {
    public static void main(String[] args) {
        double[] signal = {/*... data ...*/};

        // 1. Savitzky-Golay Smoothing
        SavitzkyGolay sg = new SavitzkyGolay();
        double[] smoothed = sg.savgol_filter(signal, 5, 2); // Window=5, PolyOrder=2
        double[] deriv = sg.savgol_filter(signal, 5, 2, 1, 1.0); // 1st Derivative

        // 2. Peak Detection
        // Min Height=0.5, Min Distance=10, Min Prominence=0.2
        int[] peaks = Signal.find_peaks(signal, 0.5, 10, 0.2);

        // 3. Median Filter
        double[] med = new MedFilt().medfilt(signal, 3); // Kernel=3

        // 4. Convolution (Mode: SAME, FULL, VALID)
        double[] window = {0.25, 0.5, 0.25};
        double[] conv = Signal.convolve(signal, window, ConvolutionMode.SAME);
        
        // 5. Detrending (Linear)
        double[] detrended = Signal.detrend(signal, DetrendType.LINEAR);
        
        // 6. Resampling (Up/Down sampling)
        // Note: Resampling is part of the Math module
        double[] resampled = com.hissain.jscipy.Math.resample(signal, NEW_LENGTH);
    }
}

General-purpose numerical utilities.

import com.hissain.jscipy.math.RK4Solver;
import com.hissain.jscipy.Math;

public class MathExample {
    public static void main(String[] args) {
        // 1. Interpolation (Linear & Cubic)
        double[] x = {0, 1, 2}, y = {0, 1, 4};
        double[] query = {0.5, 1.5};
        
        double[] lin = Math.interp1d_linear(x, y, query);
        double[] cub = Math.interp1d_cubic(x, y, query);

        // 2. RK4 ODE Solver (dy/dt = -y)
        RK4Solver solver = new RK4Solver();
        RK4Solver.Solution sol = solver.solve((t, y) -> -y, y0, t0, tf, step);
    }
}

Contributions are welcome! Please read our Contribution Guidelines for details on our workflow and coding standards. Feel free to submit issues or pull requests.

Areas for Contribution (Help Wanted)

We are actively looking for contributors to help with:

  1. Performance Benchmarking: Creating benchmarks for large datasets to compare Java's performance vs NumPy/SciPy.
  2. Feature Expansion: Implementing missing window functions or additional filter types.
  3. Edge Case Robustness: Improving handling of NaN, Infinity, and edge cases in signal processing algorithms.
  4. Documentation: Adding more usage examples and javadocs.

Want to join in community discord? click here

This project is licensed under the MIT License.

联系我们 contact @ memedata.com