/** * This conducts both nonlinear regression-derived Fb subtraction and baseline slope correction. * * @param profile */ private void conductBaselineCorrection() { // Start with correcting for the NR-derived Fb slope double[] rawFcReadings = profile.getRawFcReadings(); double[] processedFcDataset = new double[rawFcReadings.length]; // The new optimized Fc dataset // This assumes that nonlinear regression has been conducted AND it was successfully completed double nrFb = profile.getNrFb(); // The regression derived Fb double nrFbSlope = profile.getNrFbSlope(); // The regression-derived Fb slope for (int i = 0; i < processedFcDataset.length; i++) { processedFcDataset[i] = rawFcReadings[i] - nrFb - (nrFbSlope * (i + 1)); } profile.setFcReadings(processedFcDataset); }
/** * Generates an optimized working Fc dataset via nonlinear regression to derived Fb and Fb-slope * using the current LRE window. * * <p>Nonlinear regression is conducted using Emax, Fmax and Fo derived from the current LRE * window, from WHICH values for Fb and Fb-slope are determined. These are then used to calculate * a new working Fc dataset, followed by recalculation of the LRE parameters. This process * repeated 3 times from which an average Fb and Fb-slope are then determined and a final * optimized working Fc dataset generated. This is followed by a final recalculation of the LRE * parameters to determine final values for Emax, Fmax and Fo. THIS DOES THIS INCLUDE ANY * MODIFICATION TO THE LRE WINDOW. * * <p>Note also that the LRE parameters are updated and the modified Profile is saved, which * includes initialization of a new Cycle linked list, so any calling function must reset its * runner. * * @param prfSum the ProfileSummary encapsulating the Profile * @return true if nonlinear regression analysis was successful or false if it failed */ public boolean generateOptimizedFcDatasetUsingNonliearRegression(ProfileSummary prfSum) { this.prfSum = prfSum; profile = prfSum.getProfile(); // The profile must have a valid LRE window if (!profile.hasAnLreWindowBeenFound()) { return false; } // Need to trim the profile in order to avoid aberrancies within early cycles and within the // plateau phase // Exclude the first three cycles int firstCycle = 4; // Start at cycle 4 // Use the top of the LRE window as the last cycle included in the regression analysis******THIS // IS VERY IMPORTANT double[] fcArray = profile.getRawFcReadings(); int lastCycle = 0; if (prfSum.getLreWindowEndCycle() != null) { lastCycle = prfSum.getLreWindowEndCycle().getCycNum(); } else { return false; } int numberOfCycles = lastCycle - firstCycle + 1; // Construct the trimmed Fc dataset TreeMap<cycle number, Fc reading> TreeMap<Integer, Double> profileMap = new TreeMap<Integer, Double>(); for (int i = 0; i < numberOfCycles; i++) { profileMap.put(firstCycle + i, fcArray[firstCycle - 1 + i]); } // Run NR once to grossly stablize the LRE-derived parameters LreParameters lreDerivedParam = getLreParameters(); LreParameters optParam = nrService.conductNonlinearRegression(lreDerivedParam, profileMap); // Reinitialize the LRE-derived parameters // First Reset nonlinear regression-derived Fb and Fb-slope within the profile profile.setNrFb(optParam.getFb()); profile.setNrFbSlope(optParam.getFbSlope()); // Generate a new optimized Fc dataset based on NR-derived Fb and Fb-slope conductBaselineCorrection(); // Updating the ProfileSummary updates the LRE-derived parameters within the Profile with no // change to the LRE window // However, this assumes that the NR was successful prfSum.update(); // Reset the LRE-derived paramaters lreDerivedParam = getLreParameters(); // Run the regression analysis 10 times to determine the average and SD // This is necessary due to the poor performance of Peter Abeles’s EJML implementation int numberOfIterations = 3; ArrayList<Double> emaxArray = new ArrayList<Double>(); ArrayList<Double> fbArray = new ArrayList<Double>(); ArrayList<Double> foArray = new ArrayList<Double>(); ArrayList<Double> fmaxArray = new ArrayList<Double>(); ArrayList<Double> fbSlopeArray = new ArrayList<Double>(); double emaxSum = 0; double fbSum = 0; double foSum = 0; double fmaxSum = 0; double fbSlopeSum = 0; for (int i = 0; i < numberOfIterations; i++) { optParam = nrService.conductNonlinearRegression(lreDerivedParam, profileMap); emaxArray.add(optParam.getEmax()); emaxSum += optParam.getEmax(); fbArray.add(optParam.getFb()); fbSum += optParam.getFb(); foArray.add(optParam.getFo()); foSum += optParam.getFo(); fmaxArray.add(optParam.getFmax()); fmaxSum += optParam.getFmax(); fbSlopeArray.add(optParam.getFbSlope()); fbSlopeSum += optParam.getFbSlope(); // Reinitialize the LRE-derived parameters // First reset nonlinear regression-derived Fb and Fb-slope within the profile profile.setNrFb(optParam.getFb()); profile.setNrFbSlope(optParam.getFbSlope()); // Generate a new optimized Fc dataset conductBaselineCorrection(); // Update the LRE-derived parameters within the Profile prfSum.update(); // Retrieve the new LRE parameters lreDerivedParam = getLreParameters(); } // Set the average for each parameter into the Profile // This allows the final recalculation of the LRE parameters based on the average Fb and // Fb-slope profile.setNrEmax(emaxSum / numberOfIterations); profile.setNrFb(fbSum / numberOfIterations); profile.setNrFo(foSum / numberOfIterations); profile.setNrFmax(fmaxSum / numberOfIterations); profile.setNrFbSlope(fbSlopeSum / numberOfIterations); // Determine and set the parameter SD profile.setNrEmaxSD(MathFunctions.calcStDev(emaxArray)); profile.setNrFbSD(MathFunctions.calcStDev(fbArray)); profile.setNrFoSD(MathFunctions.calcStDev(foArray)); profile.setNrFmaxSD(MathFunctions.calcStDev(fmaxArray)); profile.setNrFbSlopeSD(MathFunctions.calcStDev(fbSlopeArray)); // Recaculate the optimized Fc dataset using the average NR-derived Fb and Fb-slope conductBaselineCorrection(); // Update the LRE parameters prfSum.update(); return testIfRegressionWasSuccessful(); }