/** * @param sensorRevolveCount センサーから取得した合計回転数 * @param sensorUpdatedTime センサー時刻(1/1024秒単位で刻まれる) * @return 更新が行われたらtrue */ public boolean update(int sensorRevolveCount, int sensorUpdatedTime) { sensorRevolveCount &= BleSpeedCadenceUtil.SENSOR_16BIT_MASK; sensorUpdatedTime &= BleSpeedCadenceUtil.SENSOR_16BIT_MASK; if (mLastUpdatedRevolveCount < 0 || mStartRevolveCount < 0) { mStartRevolveCount = sensorRevolveCount; mLastUpdatedRevolveCount = sensorRevolveCount; mLastUpdatedSensorTime = sensorUpdatedTime; return false; } final double oldSensorRPM = getRpm(); // 古いRPM // 回転差分と時間差分を取得する final int offsetRevolve = BleSpeedCadenceUtil.get16bitOffset(mLastUpdatedRevolveCount, sensorRevolveCount); final int offsetTimeMs = (int) (BleSpeedCadenceUtil.sensorTimeToSeconds( BleSpeedCadenceUtil.get16bitOffset(mLastUpdatedSensorTime, sensorUpdatedTime)) * 1000.0); // 指定秒経過していなかったら時間単位の精度が低いため何もしない if (offsetTimeMs < mStatusCheckIntervalMs) { // AppLog.cadence("abort interval (%d ms < %d ms)", offsetTimeMs, // mStatusCheckIntervalMs); return false; } AppLog.bleData(String.format("Revolve(+%d) Time(+%d ms) ", offsetRevolve, offsetTimeMs)); // 計算する { // 1minuteが基本 final double mult = (1000.0 * 60.0) / (double) offsetTimeMs; // 指定時間に行われた回転数から、1分間の回転数を求める mRpm = (double) offsetRevolve * mult; if (mRpm > 600) { // 何らかのエラー // 600RPMを超えると、ロードバイクなら時速220kmを超えることになり、世界記録を超えてしまうためこれはエラーと判断出来る mRpm = oldSensorRPM; } } // 値を上書きする if (BleSpeedCadenceUtil.is16bitOverflow(mLastUpdatedRevolveCount, sensorRevolveCount)) { // 回転数がオーバーフローしたので、カウンタを回す ++mRevolvingOverflowCount; } mLastUpdatedRevolveCount = sensorRevolveCount; mLastUpdatedSensorTime = sensorUpdatedTime; mUpdatedTime = mClock.now(); return true; }
@Test public void 想定通りの回転値が取得できることを確認する() throws Exception { // ランダムで結果が多少上下するので、サンプリング数を上げる for (int i = 0; i < 128; ++i) { final long START_TIME = System.currentTimeMillis(); Clock clock = new Clock(START_TIME); SpeedCadenceSensorData data = new SpeedCadenceSensorData(clock, BleDevice.SENSOR_TIMEOUT_MS, (int) (1000.0 * 7.5)); float current = 0; // 経過時間(分) double sensorTime = 12345; // センサー時間 double revolveCount = 1234; // 合計回転数 int sumUpdated = 0; double sumRpm = 0; final double SAMPLE_RPM = 200.0; int oldRevolve = 0; boolean validData = false; while (current < 60.0) { final double OFFSET_MINUTE = (1.0 / 60.0 * (1.5 + Math.random())); // 2.5秒以内の適当なインターバル秒でデータが飛んできていることにする // final double SAMPLE_RPM = 190.0 + (Math.random() * 10.0); clock.offset((long) (OFFSET_MINUTE * 60.0 * 1000.0)); sensorTime += (OFFSET_MINUTE * 60.0 * 1024.0); revolveCount += (SAMPLE_RPM * OFFSET_MINUTE); current += OFFSET_MINUTE; // データを流してみる if (data.update( ((int) revolveCount) & BleSpeedCadenceUtil.SENSOR_16BIT_MASK, ((int) sensorTime) & BleSpeedCadenceUtil.SENSOR_16BIT_MASK)) { // 合計回転数が上がらなければならない assertNotEquals(data.getSumRevolveCount(), oldRevolve); assertThat( "SumRevolve :: " + data.getSumRevolveCount(), data.getSumRevolveCount() > oldRevolve, CoreMatchers.is(true)); oldRevolve = data.getSumRevolveCount(); assertTrue(data.valid()); assertNotEquals(data.getRpm(), 0.0); // 誤差があるので適当に上下1割は許容する assertThat( "RPM :: " + data.getRpm(), data.getRpm() > (SAMPLE_RPM * 0.9) && data.getRpm() < (SAMPLE_RPM * 1.1), CoreMatchers.is(true)); // 平均計算用 ++sumUpdated; sumRpm += data.getRpm(); validData = true; } assertEquals(data.valid(), validData); } // 平均値は誤差を小さく見積もるする final double AVG_RPM = (sumRpm / sumUpdated); assertThat( "AVG RPM :: " + AVG_RPM, AVG_RPM > (SAMPLE_RPM * 0.99) && AVG_RPM < (SAMPLE_RPM * 1.01), CoreMatchers.is(true)); } }
/** データが有効であればtrue */ public boolean valid() { return mClock.absDiff(mUpdatedTime) < mSensorTimeoutMs; }