Search code examples
javaleast-squarestrigonometry

How do I fit a sine curve to my data in Java?


I've spend a few days trying to get this exact same code running in java: How do I fit a sine curve to my data with pylab and numpy?

Based on this answer: Sine Wave Curve Fitting in Java, I've started putting together this code:

public double sine_fit(double[] current_sample){
        double[] half_cycle = Arrays.copyOfRange(current_sample, 175, 225);
        double amp = 3*ArrayUtils.std(half_cycle)/Math.sqrt(2);
        double freq = 0;
        double phase = 0;
        double[] guess = new double[]{amp, freq, phase};
        HarmonicCurveFitter curveFit = new HarmonicCurveFitter(new LevenbergMarquardtOptimizer());
        //curveFit.withStartPoint(guess);
        for (int i=0; i < half_cycle.length; i++) {
            curveFit.addObservedPoint(i, half_cycle[i]);
        }
        double[] vals = curveFit.fit();
        System.out.println(vals);
    }

It doesn't compile, and it's not quite what I want (i.e., exactlty what's in the first link)

I'd really appreciate some help. Not being able to do in Java what I can do with only a few lines in Python is driving me nuts.

P.S.: Long time Python coder, newbee Java programmer.

Update

Based on @17slim's answer:

    double[] half_cycle = Arrays.copyOfRange(current_sample, 175, 225);
    double amp = 3*ArrayUtils.std(half_cycle)/Math.sqrt(2);
    double freq = 0;
    double phase = 0;
    double[] guess = new double[]{amp, freq, phase};
    HarmonicCurveFitter curveFit = HarmonicCurveFitter.create();
    curveFit.withStartPoint(guess);
    List<WeightedObservedPoint> points = new ArrayList<WeightedObservedPoint>();
    for (int i=0; i < half_cycle.length; i++) {
        points.add(new WeightedObservedPoint(1.0, i, half_cycle[i]));
    }
    double[] vals = curveFit.fit(points);
    for (double val: vals){
        System.out.println(val);
    }

Solution

  • HarmonicCurveFitter does not extend CurveFitter; it extends AbstractCurveFitter, which does not have method addObservedPoint. GaussianFitter, HarmonicFitter, and PolynomialFitter are the known extenders of CurveFitter, which has the required method. Use HarmonicFitter.

    See: CurveFitter and HarmonicCurveFitter

    EDIT: Since HarmonicFitter is deprecated, you are correct to use HarmonicCurveFitter. Since it doesn't have the method you need, use fit(Collection<WeightedObservedPoint> points) instead of addObservedPoint.

    Instead do:

    HarmonicCurveFitter curveFit = new HarmonicCurveFitter.create();
    List<WeightedObservedPoint> points = new ArrayList<WeightedObservedPoint>();
    for (int i=0; i < half_cycle.length; i++) {
        points.add(new WeightedObservedPoint(1.0, i, half_cycle[i]));
    }
    double[] vals = curveFit.fit(points);
    

    From the documentation:

    The default implementation uses a Levenberg-Marquardt optimizer.

    Make sure to import org.apache.commons.math3.fitting.WeightedObservedPoint, org.apache.commons.math3.fittingHarmonicCurveFitter, java.util.List and java.util.ArrayList.

    Also, printing vals does not print each value like in Python, it prints a pointer to the array. Use for (double val: vals) and display each value individually.