/** * Utility to facilitate fitting data plotted in JFreeChart Provide data in JFReeChart format * (XYSeries), and retrieve univariate function parameters that best fit (using least squares) the * data. All data points will be weighted equally. * * <p>TODO: investigate whether weighting (possibly automatic weighting) can improve accuracy * * @param data xy series in JFReeChart format * @param type one of the Fitter.FunctionType predefined functions * @param guess initial guess for the fit. The number and meaning of these parameters depends on * the FunctionType. Implemented: Gaussian: 0: Normalization, 1: Mean 2: Sigma * @return array with parameters, whose meaning depends on the FunctionType. Use the function * getXYSeries to retrieve the XYDataset predicted by this fit */ public static double[] fit(XYSeries data, FunctionType type, double[] guess) { if (type == FunctionType.NoFit) { return null; } // create the commons math data object from the JFreeChart data object final WeightedObservedPoints obs = new WeightedObservedPoints(); for (int i = 0; i < data.getItemCount(); i++) { obs.add(1.0, data.getX(i).doubleValue(), data.getY(i).doubleValue()); } double[] result = null; switch (type) { case Pol1: final PolynomialCurveFitter fitter1 = PolynomialCurveFitter.create(1); result = fitter1.fit(obs.toList()); break; case Pol2: final PolynomialCurveFitter fitter2 = PolynomialCurveFitter.create(2); result = fitter2.fit(obs.toList()); break; case Pol3: final PolynomialCurveFitter fitter3 = PolynomialCurveFitter.create(3); result = fitter3.fit(obs.toList()); break; case Gaussian: final GaussianWithOffsetCurveFitter gf = GaussianWithOffsetCurveFitter.create(); if (guess != null) { gf.withStartPoint(guess); } result = gf.fit(obs.toList()); } return result; }
/** * Approximate an already fitted model to polynomial only terms. * * <p>This method is mainly used in order to combine the large amplitude long periods with the * secular part as a new approximate polynomial model over some time range. This should be used * rather than simply extracting the polynomial coefficients from {@link #getFittedParameters()} * when some periodic terms amplitudes are large (for example Sun resonance effects on local solar * time in sun synchronous orbits). In theses cases, the pure polynomial secular part in the * coefficients may be far from the mean model. * * @param combinedDegree desired degree for the combined polynomial * @param combinedReference desired reference date for the combined polynomial * @param meanDegree degree of polynomial secular part to consider * @param meanHarmonics number of harmonics terms to consider * @param start start date of the approximation time range * @param end end date of the approximation time range * @param step sampling step * @return coefficients of the approximate polynomial (in increasing degree order), using the user * provided reference date */ public double[] approximateAsPolynomialOnly( final int combinedDegree, final AbsoluteDate combinedReference, final int meanDegree, final int meanHarmonics, final AbsoluteDate start, final AbsoluteDate end, final double step) { final List<WeightedObservedPoint> points = new ArrayList<WeightedObservedPoint>(); for (AbsoluteDate date = start; date.compareTo(end) < 0; date = date.shiftedBy(step)) { points.add( new WeightedObservedPoint( 1.0, date.durationFrom(combinedReference), meanValue(date, meanDegree, meanHarmonics))); } return PolynomialCurveFitter.create(combinedDegree).fit(points); }
public static void main(String[] args) { ////////////////////////// // The values in following 4 lines should be user input int startPos = 200; int endPos = 1000; int totalNumPixel = 1044; double threshhold = 0.0001; ///////////////////////// int numPixel = endPos - startPos; double wavelength[] = new double[totalNumPixel]; double photonCount[] = new double[totalNumPixel]; double SpecNoBk[] = new double[numPixel]; double ThisSpectrum[] = new double[numPixel]; double ThisXaxis[] = new double[numPixel]; double Po[] = new double[numPixel]; double Re[] = new double[numPixel]; double P[] = new double[6]; double Re2[] = new double[numPixel - 1]; double mySUM[] = new double[numPixel]; int ind[]; double DEV; double prevDEV; Connection connection = null; Statement stmt = null; String pattern = "##.##"; try { Scanner in = new Scanner(new FileReader(args[0])); int i = 0; while (in.hasNextDouble()) { wavelength[i] = in.nextDouble(); photonCount[i] = in.nextDouble(); ++i; } } catch (FileNotFoundException e) { e.printStackTrace(); } ThisSpectrum = Arrays.copyOfRange(photonCount, startPos, endPos); ThisXaxis = Arrays.copyOfRange(wavelength, startPos, endPos); final WeightedObservedPoints obs = new WeightedObservedPoints(); for (int i = 0; i < numPixel; i++) { obs.add(ThisXaxis[i], ThisSpectrum[i]); } final PolynomialCurveFitter fitter = PolynomialCurveFitter.create(5); P = fitter.fit(obs.toList()); Polyval pVal = new Polyval(P, ThisXaxis, numPixel); Po = pVal.evl(); for (int i = 0; i < numPixel; i++) { Re[i] = ThisSpectrum[i] - Po[i]; } for (int i = 0; i < numPixel - 1; i++) { Re2[i] = Re[i + 1] - Re[i]; } DEV = Math.sqrt(StatUtils.populationVariance(Re2, 0, Re2.length)); for (int i = 0; i < numPixel; i++) { mySUM[i] = Po[i] + DEV; } int jj = 0; // jj is the length of points to be removed for (int i = 0; i < numPixel; i++) { if (ThisSpectrum[i] > mySUM[i]) { jj++; ; } } ind = new int[jj]; int jjj = 0; for (int i = 0; i < numPixel; i++) { if (ThisSpectrum[i] > mySUM[i]) { ind[jjj] = i; jjj++; } } int indKeepLength = numPixel - ind.length; int indKeep[] = new int[indKeepLength]; int k = 0; for (int i = 0; i < numPixel; i++) { if (!ArrayUtils.contains(ind, i)) { indKeep[k] = i; k++; } } double ThisSpectrumKeep[] = new double[indKeepLength]; double ThisXaxisKeep[] = new double[indKeepLength]; double PoKeep[] = new double[indKeepLength]; double ReKeep[] = new double[indKeepLength]; double Re2Keep[] = new double[indKeepLength - 1]; double mySUMKeep[] = new double[indKeepLength]; for (int i = 0; i < indKeepLength; i++) { ThisSpectrumKeep[i] = ThisSpectrum[indKeep[i]]; ThisXaxisKeep[i] = ThisXaxis[indKeep[i]]; } prevDEV = DEV; // at the point, ThisSpectrum and ThisXaxis should have reduced size final WeightedObservedPoints obs1 = new WeightedObservedPoints(); for (int i = 0; i < indKeepLength; i++) { obs1.add(ThisXaxisKeep[i], ThisSpectrumKeep[i]); } while (true) { final PolynomialCurveFitter fitter1 = PolynomialCurveFitter.create(5); P = fitter1.fit(obs1.toList()); Polyval pVal1 = new Polyval(P, ThisXaxisKeep, indKeepLength); PoKeep = pVal1.evl(); for (int i = 0; i < indKeepLength; i++) { ReKeep[i] = ThisSpectrumKeep[i] - PoKeep[i]; } for (int i = 0; i < indKeepLength - 1; i++) { Re2Keep[i] = ReKeep[i + 1] - ReKeep[i]; } DEV = Math.sqrt(StatUtils.populationVariance(Re2Keep, 0, Re2Keep.length)); for (int i = 0; i < indKeepLength; i++) { mySUMKeep[i] = PoKeep[i] + DEV; } for (int i = 0; i < indKeepLength; i++) { if (ThisSpectrumKeep[i] > mySUMKeep[i]) ThisSpectrumKeep[i] = mySUMKeep[i]; } if ((Math.abs(DEV - prevDEV) / DEV) < threshhold) break; prevDEV = DEV; obs1.clear(); for (int i = 0; i < indKeepLength; i++) { obs1.add(ThisXaxisKeep[i], ThisSpectrumKeep[i]); } } Polyval pVal2 = new Polyval(P, ThisXaxis, numPixel); double FLbk[] = pVal2.evl(); for (int i = 0; i < ThisXaxis.length; i++) { SpecNoBk[i] = ThisSpectrum[i] - FLbk[i]; } // the write-to-file part is only for testing purpose, ThisXaxis and SpecNoBk are two outputs try { FileWriter fr = new FileWriter(args[1]); BufferedWriter br = new BufferedWriter(fr); PrintWriter out = new PrintWriter(br); DecimalFormat df = new DecimalFormat(pattern); for (int j = 0; j < ThisXaxis.length; j++) { if (Double.toString(wavelength[j]) != null) out.write(ThisXaxis[j] + "\t" + SpecNoBk[j]); out.write("\r\n"); } out.close(); } catch (IOException e) { System.out.println(e); } }