psambit9791 / jdsp

A Java Library for Digital Signal Processing
https://jdsp.dev
MIT License
240 stars 45 forks source link

UtilMethods.diff throws java.lang.NegativeArraySizeException: -1 #79

Open mrkrizic opened 3 months ago

mrkrizic commented 3 months ago

When using detectPeaks on a Signal where all values are 0.0, a NegativeArraySizeException is thrown.

Steps to reproduce:

Create the signal as an array with only 0.0 values (I guess any same value would work) Initialize a FindPeak object and pass the signal through the constructor. On the FindPeak object, call the detectPeaks() method.

In Kotlin, a minimal example looks like this: FindPeak(doubleArrayOf(0.0, 0.0, 0.0)).detectPeaks()

The FindPeak method detect() will try to instantiate a new Peak instance. It fails to do so upon calling findPeakDistance() in the Peak constructor code. The reason is it expects an array containing elements. Since there are no peaks in the signal, the array has length 0 and calling UtilMethods.diff(peaks) will result in the following exception:

java.lang.NegativeArraySizeException: -1
    at com.github.psambit9791.jdsp.misc.UtilMethods.diff(UtilMethods.java:568)
    at com.github.psambit9791.jdsp.signal.peaks.Peak.findPeakDistance(Peak.java:262)
    at com.github.psambit9791.jdsp.signal.peaks.Peak.<init>(Peak.java:78)
    at com.github.psambit9791.jdsp.signal.peaks.FindPeak.detect(FindPeak.java:174)
    at com.github.psambit9791.jdsp.signal.peaks.FindPeak.detectPeaks(FindPeak.java:125)
    ...

For now, I will try to find a workaround, but I hope this can be fixed in the future to avoid crashes when working with live data.

Cheers

mrkrizic commented 3 months ago

If somebody is facing the same problem, you can use the following workaround:

I created an extension function tryDetectPeaks, where I try to call detectPeaks(), if it fails, simply catch the exception and return an empty array.

Kotlin code:

private fun FindPeak.tryDetectPeaks(): IntArray {
        return try {
            this.detectPeaks().peaks
        } catch (e: NegativeArraySizeException) {
            intArrayOf()
        }
    } 

Then simply call this method instead like this: FindPeak(doubleArrayOf(0.0, 0.0, 0.0)).tryDetectPeaks()

In Java extension methods are not supported, but here the principle is the same, but instead of calling the method directly on the FindPeak instance, it has to be passed as a method parameter.