package org.spin.gaitlib.cadence; import android.location.Location; import android.util.Log; import org.spin.gaitlib.GaitAnalysis; import org.spin.gaitlib.core.ILoggable; import org.spin.gaitlib.filter.FilterNotSetException; import org.spin.gaitlib.filter.IFilter; import org.spin.gaitlib.filter.IFilterable; import org.spin.gaitlib.sensor.SignalListener; import org.spin.gaitlib.util.Logger; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.TimeUnit; /** * Abstract class for cadence estimation. * * @author Mike */ public abstract class CadenceDetector implements IFilterable, ILoggable { private static final String TAG = "CadenceDetector"; private final ArrayBlockingQueue<CadenceState> filterBuffer; private final int filterBufferSize = 3; private SignalListener signalListener; private CadenceState currentCadenceState; private IFilter filter; private final Logger cadenceResultLogger = new Logger(null, ".ccsv", "TimeSinceStart(ms), cadence, speed, cadence confidence"); public CadenceDetector() { currentCadenceState = new CadenceState(1, 0, 0, 0, 0); filterBuffer = new ArrayBlockingQueue<CadenceState>(filterBufferSize); } /** * Update the current cadence state. */ public void updateCadenceState() { CadenceState cadenceState = estimateCadence(signalListener); setCurrentCadenceState(cadenceState); } /** * Perform calculation and return the current CadenceState. */ protected abstract CadenceState estimateCadence(SignalListener signalListener); protected void updateLocation(Location loc) { float speed = loc.getSpeed(); float cadence = currentCadenceState.getCadence(); float cadenceConfidence = currentCadenceState.getCadenceConfidence(); long nanoTime = System.nanoTime(); long timeSinceStart = signalListener.getTimeSinceStart(nanoTime, TimeUnit.NANOSECONDS); setCurrentCadenceState(new CadenceState(cadence, speed, cadenceConfidence, nanoTime, timeSinceStart)); } public void setSignalListener(SignalListener signalListener) { this.signalListener = signalListener; } public void setFilter(IFilter filter) { this.filter = filter; } public IFilter getFilter() { return filter; } /** * See {@link GaitAnalysis#getCadence(boolean)}. */ public float getCadence(boolean filtered) throws FilterNotSetException { if (!filtered) { return currentCadenceState.getCadence(); } else { if (filter == null) { throw new FilterNotSetException(); } float[] bufferedValues = new float[filterBufferSize]; int i = 0; for (CadenceState c : filterBuffer) { bufferedValues[i++] = c.getCadence(); } return filter.getFilteredValue(bufferedValues); } } /** * See {@link GaitAnalysis#getStrideLength(boolean)}. */ public float getStrideLength(boolean filtered) throws FilterNotSetException { return getSpeed() / getCadence(filtered); } /** * See {@link GaitAnalysis#getSpeed()}. */ public float getSpeed() { return currentCadenceState.getSpeed(); } /** * See {@link GaitAnalysis#getCadenceConfidence()}. */ public float getCadenceConfidence() { return currentCadenceState.getCadenceConfidence(); } public CadenceState getCurrentCadenceState() { return currentCadenceState; } private void setCurrentCadenceState(CadenceState currentCadenceState) { this.currentCadenceState = currentCadenceState; if (filterBuffer.remainingCapacity() == 0) { filterBuffer.poll(); } try { filterBuffer.put(currentCadenceState); } catch (InterruptedException e) { Log.v(TAG, e.toString()); } cadenceResultLogger.printRow(currentCadenceState.getStringArray()); } public void setLoggingEnabled(boolean enabled) { cadenceResultLogger.setEnabled(enabled); } public boolean isLogging() { return cadenceResultLogger.isEnabled(); } }