// methods public Detector calibrateParameters(Detector d) { if (d.getHealthStatus() != 100) { // assign NaN if detector is bad vf = Double.NaN; w = Double.NaN; q_max = Double.NaN; } else { // organize into an array of DataPoint ArrayList<DataPoint> datavec = new ArrayList<DataPoint>(); int i; for (i = 0; i < d.getDensityData().size(); i++) datavec.add( new DataPoint( d.getDensityData().get(i), d.getFlowData().get(i), d.getSpeedData().get(i))); // maximum flow and its corresponding density DataPoint maxflw = new DataPoint(0, Double.NEGATIVE_INFINITY, 0); for (i = 0; i < d.getFlowData().size(); i++) if (datavec.get(i).flw > maxflw.flw) maxflw.setval(datavec.get(i)); q_max = maxflw.flw; // split data into congested and freeflow regimes ............... ArrayList<DataPoint> congestion = new ArrayList<DataPoint>(); // congestion states ArrayList<DataPoint> freeflow = new ArrayList<DataPoint>(); // freeflow states for (i = 0; i < d.getDensityData().size(); i++) if (datavec.get(i).dty >= maxflw.dty) congestion.add(datavec.get(i)); else freeflow.add(datavec.get(i)); // vf is the average freeflow speed vf = percentile("spd", freeflow, 0.5f); // compute critical density rho_crit = q_max / vf; // BINNING ArrayList<DataPoint> supercritical = new ArrayList<DataPoint>(); // data points above rho_crit for (i = 0; i < d.getDensityData().size(); i++) if (datavec.get(i).dty >= rho_crit) supercritical.add(datavec.get(i)); // sort supercritical w.r.t. density Collections.sort(supercritical); int numsupercritical = supercritical.size(); int Bin_width = 10; int step = Bin_width; ArrayList<DataPoint> BinData = new ArrayList<DataPoint>(); for (i = 0; i < numsupercritical; i += Bin_width) { if (i + Bin_width >= numsupercritical) step = numsupercritical - i; if (step != 0) { List<DataPoint> Bin = (List<DataPoint>) supercritical.subList(i, i + step); if (!Bin.isEmpty()) { double a = 2.5f * percentile("flw", Bin, 0.75f) - 1.5f * percentile("flw", Bin, 0.25f); double b = percentile("flw", Bin, 1f); BinData.add(new DataPoint(percentile("dty", Bin, 0.5f), Math.min(a, b), Float.NaN)); } } } // Do constrained LS ArrayList<Double> ai = new ArrayList<Double>(); ArrayList<Double> bi = new ArrayList<Double>(); for (i = 0; i < BinData.size(); i++) { bi.add(q_max - BinData.get(i).flw); ai.add(BinData.get(i).dty - rho_crit); } if (BinData.size() > 0) { float sumaibi = 0; float sumaiai = 0; for (i = 0; i < BinData.size(); i++) { sumaibi += ai.get(i) * bi.get(i); sumaiai += ai.get(i) * ai.get(i); } w = (double) (sumaibi / sumaiai); w = Math.max(w, w_min); w = Math.min(w, w_max); } else { w = Double.NaN; } } // store parameters in sensor d.setFdParams(new FDParameters()); // assigns nominal d.getFdParams().setFD(vf, w, q_max); // assigns calculated values, keeps nominals if NaN return d; }