Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Signal processing (in Java)

I have a sensor that I am reading from, currently the code is in Java, but I dont think the issue is language specific, more approach related.

The sensor produces a signal with high and low pulses, roughly like a heartbeat. However, the "high" pulse is not always the same level, nor is the "low". What I am interested in is the relative difference. However, this alone is not enough, as within a single "session" the high and low values may also change (think a curved mid point)

Ive included an image of the 4 "types" of signals I would like to be able to handle. Top left is the "ideal" I'm fairly sure I can already handle that, the other three sadly are more common and less easy to handle.

My current approach has been to look for the average of the data, and see how many times that point is crossed, which will tell me how many high and low pulses there were.

I'd like to know if there is a simple way of detecting the high and low pulse, without using the averaging method.

enter image description here

like image 325
Zack Newsham Avatar asked Dec 19 '22 13:12

Zack Newsham


1 Answers

When you stated you wanted to extract the frequency of the wave the first thing I thought of was a fourier transform; this converts the signal from the time domain to the frequency domain. Given the following sample wave:

enter image description here

This is a sine way to which I have added noise and a trend. The underlying sine wave has a frequency of 1.5Hz

You get this fourier transform

enter image description here

Here you can see a large response at 0hz, this is the linear trend and we can ignore it in this case. After that you can see one peak in the response at 1.5Hz, the frequency of our input signal. In other words; once you have the fourier transform your result is the data point with the largest value (after you remove the very low frequency results)

Java Code

Apachi commons has a fast fourier transform class which I used to create this transformation. It takes as an input the sampled data for your wave and outputs a complex number, the modulus of the complex number (the square root of the real part squared plus the imaginary part squared) is equal to the energy at that frequency. Each entry i in the outputted array referes to the frequency at i*samplingFrequency/noOfSamples.

However the java code below largly deals with these issues for you. The only issue with the fast fourier transform is that the number of input entries must be a power of 2.

import org.apache.commons.math3.complex.Complex;
import org.apache.commons.math3.transform.DftNormalization;
import org.apache.commons.math3.transform.FastFourierTransformer;
import org.apache.commons.math3.transform.TransformType;

public class FourierTest {

    public static void main(String[] args) {
      
        double samplingFrequency=10; //hz, You will know this from your data and need to set it here
        
        

        double[] frequencyDomain = new double[input.length];

        FastFourierTransformer transformer = new FastFourierTransformer(DftNormalization.STANDARD);
        try {           
            Complex[] complex = transformer.transform(input, TransformType.FORWARD);
            
            for (int i = 0; i < complex.length; i++) {               
                double real = (complex[i].getReal());
                double imaginary = (complex[i].getImaginary());

                frequencyDomain[i] = Math.sqrt((real * real) + (imaginary * imaginary));
            }

        } catch (IllegalArgumentException e) {
            System.out.println(e);
        }

        //only to frequencyDomain.length/2 since second half is mirror image or first half
        for(int i=0;i<frequencyDomain.length/2;i++){
            double frequency=samplingFrequency*i/frequencyDomain.length;
            System.out.println("Frequency: " + frequency + "\t\tEnergyComponent: " + frequencyDomain[i]);
        }
    }
    
    static double[]  input = new double[]{
            0.017077407 , //sample at 0 seconds
            1.611895528 , //sample at 0.1 seconds
            2.063967663 , //sample at 0.2 seconds
            1.598492541 , //etc
            0.184678933 ,
            0.02654732  ,
            0.165869218 ,
            1.026139745 ,
            1.914179294 ,
            2.523684208 ,
            1.71795312  ,
            0.932131202 ,
            1.097366772 ,
            1.107912105 ,
            2.843777623 ,
            2.503608192 ,
            2.540595787 ,
            2.048111122 ,
            1.515498608 ,
            1.828077941 ,
            2.400006658 ,
            3.562953532 ,
            3.34333491  ,
            2.620231348 ,
            2.769874641 ,
            2.423059324 ,
            2.11147835  ,
            3.473525478 ,
            4.504105599 ,
            4.325642774 ,
            3.963498242 ,
            2.842688545 ,
            2.573038184 ,
            3.434226007 ,
            4.924115479 ,
            4.876122332 ,
            4.553580015 ,
            3.92554604  ,
            3.804585546 ,
            3.476610932 ,
            4.535171252 ,
            5.398007229 ,
            5.729933758 ,
            5.573444511 ,
            4.487695977 ,
            4.133046459 ,
            4.796637209 ,
            5.091399617 ,
            6.420441446 ,
            6.473462022 ,
            5.663322311 ,
            4.866446009 ,
            4.840966187 ,
            5.329697081 ,
            6.746910181 ,
            6.580067494 ,
            7.140083322 ,
            6.243532245 ,
            4.960520462 ,
            5.100901901 ,
            6.794495306 ,
            6.959324497 ,
            7.194674358 ,
            7.035874424 

        };
}
like image 84
Richard Tingle Avatar answered Jan 06 '23 09:01

Richard Tingle