/***************************************************************************** * Limpet - the Lightweight InforMation ProcEssing Toolkit * http://limpet.info * * (C) 2015-2016, Deep Blue C Technologies Ltd * * This library is free software; you can redistribute it and/or * modify it under the terms of the Eclipse Public License v1.0 * (http://www.eclipse.org/legal/epl-v10.html) * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ package info.limpet.data.impl.helpers; import info.limpet.IBaseQuantityCollection; import info.limpet.QuantityRange; import java.util.ArrayList; import java.util.Iterator; import javax.measure.Measurable; import javax.measure.Measure; import javax.measure.quantity.Quantity; import javax.measure.unit.Dimension; import javax.measure.unit.Unit; public class QuantityHelper<T extends Quantity> implements IBaseQuantityCollection<T> { private ArrayList<Measurable<T>> _values; private Measurable<T> _min = null; private Measurable<T> _max = null; private Measurable<T> _mean; private Measurable<T> _variance; private Measurable<T> _sd; private Unit<T> _myUnits; private QuantityRange<T> _range; public QuantityHelper(ArrayList<Measurable<T>> values, Unit<T> units) { _values = values; _myUnits = units; } public void add(Number value) { Measurable<T> newVal = Measure.valueOf(value.doubleValue(), getUnits()); _values.add(newVal); } public void add(Measurable<T> quantity) { _values.add(quantity); if (_min == null) { // ok, store the first value _min = quantity; _max = quantity; } else { double doubleVal = quantity.doubleValue(getUnits()); _min = _min.doubleValue(getUnits()) < doubleVal ? _min : quantity; _max = _max.doubleValue(getUnits()) > doubleVal ? _max : quantity; } clearRunningTotal(); } private void clearRunningTotal() { _mean = null; _sd = null; } @Override public Measurable<T> min() { return _min; } @Override public Measurable<T> max() { return _max; } @Override public Measurable<T> mean() { if (_mean == null) { calcStats(); } return _mean; } @Override public Measurable<T> sd() { if (_sd == null) { calcStats(); } return _sd; } @Override public Measurable<T> variance() { if (_variance == null) { calcStats(); } return _variance; } private void calcStats() { if (_values.size() > 0) { Iterator<Measurable<T>> iter = _values.iterator(); double runningSum = 0; while (iter.hasNext()) { Measurable<T> quantity = (Measurable<T>) iter.next(); runningSum += quantity.doubleValue(getUnits()); } final double mean = runningSum / _values.size(); _mean = Measure.valueOf(mean, _myUnits); iter = _values.iterator(); runningSum = 0; while (iter.hasNext()) { Measurable<T> quantity = iter.next(); double a = quantity.doubleValue(_myUnits); runningSum += (mean - a) * (mean - a); } final double variance = runningSum / _values.size(); _variance = Measure.valueOf(variance, _myUnits); final double sd = Math.sqrt(variance); _sd = Measure.valueOf(sd, _myUnits); } } @Override public Dimension getDimension() { return _myUnits.getDimension(); } @Override public Unit<T> getUnits() { return _myUnits; } public void replace(Number newValue) { if (_values.size() != 1) { throw new RuntimeException("We only call this on singletons"); } // create a new value Measurable<T> newVal = Measure.valueOf(newValue.doubleValue(), getUnits()); // drop the existing value _values.clear(); // and insert the new value _values.add(newVal); } public void setRange(QuantityRange<T> range) { _range = range; } public QuantityRange<T> getRange() { return _range; } public double getValue() { if (_values.size() != 1) { throw new RuntimeException("We only call this on singletons"); } return _values.iterator().next().doubleValue(getUnits()); } }