aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhil Burk <philburk@mobileer.com>2022-12-13 14:07:23 -0800
committerGitHub <noreply@github.com>2022-12-13 14:07:23 -0800
commit2737bcd28cf1e998bab594af58658ee77605b4cd (patch)
tree04909e48533729e5fa88bd6c11519346be299eab
parent03db05df380486643bcf02eab9b3f1350b8069ad (diff)
downloadoboe-2737bcd28cf1e998bab594af58658ee77605b4cd.tar.gz
OboeTester: fix phase error calculation (#1674)
Tune the Data Paths test. Fixes #1672
-rw-r--r--apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDataPathsActivity.java74
1 files changed, 56 insertions, 18 deletions
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDataPathsActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDataPathsActivity.java
index 443e9096..b0aea932 100644
--- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDataPathsActivity.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDataPathsActivity.java
@@ -26,6 +26,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
+import android.util.Log;
import android.widget.CheckBox;
import com.mobileer.audio_device.AudioDeviceInfoConverter;
@@ -66,11 +67,7 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity {
private final static int TYPICAL_SAMPLE_RATE = 48000;
private final static double FRAMES_PER_CYCLE = TYPICAL_SAMPLE_RATE / MAX_SINE_FREQUENCY;
private final static double PHASE_PER_BIN = 2.0 * Math.PI / FRAMES_PER_CYCLE;
- private final static double MAX_ALLOWED_JITTER = 0.5 * PHASE_PER_BIN;
- // Start by failing then let good results drive us into a pass value.
- private final static double INITIAL_JITTER = 2.0 * MAX_ALLOWED_JITTER;
- // A coefficient of 0.0 is no filtering. 0.9999 is extreme low pass.
- private final static double JITTER_FILTER_COEFFICIENT = 0.8;
+ private final static double MAX_ALLOWED_JITTER = 2.0 * PHASE_PER_BIN;
private final static String MAGNITUDE_FORMAT = "%7.5f";
final int TYPE_BUILTIN_SPEAKER_SAFE = 0x18; // API 30
@@ -79,7 +76,8 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity {
private double mMaxMagnitude;
private int mPhaseCount;
private double mPhase;
- private double mPhaseJitter;
+ private double mPhaseErrorSum;
+ private double mPhaseErrorCount;
AudioManager mAudioManager;
private CheckBox mCheckBoxInputPresets;
@@ -112,6 +110,19 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity {
}
}
+ public static double calculatePhaseError(double p1, double p2) {
+ double diff = Math.abs(p1 - p2);
+ // Wrap around the circle.
+ while (diff > (2 * Math.PI)) {
+ diff -= (2 * Math.PI);
+ }
+ // A phase error close to 2*PI is actually a small phase error.
+ if (diff > Math.PI) {
+ diff = (2 * Math.PI) - diff;
+ }
+ return diff;
+ }
+
// Periodically query for magnitude and phase from the native detector.
protected class DataPathSniffer extends NativeSniffer {
@@ -125,7 +136,8 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity {
mMaxMagnitude = -1.0;
mPhaseCount = 0;
mPhase = 0.0;
- mPhaseJitter = INITIAL_JITTER;
+ mPhaseErrorSum = 0.0;
+ mPhaseErrorCount = 0;
super.startSniffer();
}
@@ -133,14 +145,21 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity {
public void run() {
mMagnitude = getMagnitude();
mMaxMagnitude = getMaxMagnitude();
+ Log.d(TAG, String.format("magnitude = %7.4f, maxMagnitude = %7.4f",
+ mMagnitude, mMaxMagnitude));
// Only look at the phase if we have a signal.
if (mMagnitude >= MIN_REQUIRED_MAGNITUDE) {
double phase = getPhase();
- if (mPhaseCount > 3) {
- double diff = Math.abs(phase - mPhase);
+ // Wait for the analyzer to get a lock on the signal.
+ // Arbitrary number of phase measurements before we start measuring jitter.
+ final int kMinPhaseMeasurementsRequired = 4;
+ if (mPhaseCount >= kMinPhaseMeasurementsRequired) {
+ double phaseError = calculatePhaseError(phase, mPhase);
// low pass filter
- mPhaseJitter = (mPhaseJitter * JITTER_FILTER_COEFFICIENT)
- + ((diff * (1.0 - JITTER_FILTER_COEFFICIENT)));
+ mPhaseErrorSum += phaseError;
+ mPhaseErrorCount++;
+ Log.d(TAG, String.format("phase = %7.4f, diff = %7.4f, jitter = %7.4f",
+ phase, phaseError, getAveragePhaseError()));
}
mPhase = phase;
mPhaseCount++;
@@ -154,7 +173,7 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity {
"magnitude = " + getMagnitudeText(mMagnitude)
+ ", max = " + getMagnitudeText(mMaxMagnitude)
+ "\nphase = " + getMagnitudeText(mPhase)
- + ", jitter = " + getMagnitudeText(mPhaseJitter)
+ + ", jitter = " + getJitterText()
+ ", #" + mPhaseCount
+ "\n");
return message.toString();
@@ -163,7 +182,7 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity {
@Override
public String getShortReport() {
return "maxMag = " + getMagnitudeText(mMaxMagnitude)
- + ", jitter = " + getMagnitudeText(mPhaseJitter);
+ + ", jitter = " + getJitterText();
}
@Override
@@ -175,6 +194,10 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity {
}
}
+ private String getJitterText() {
+ return isPhaseJitterValid() ? getMagnitudeText(getAveragePhaseError()) : "?";
+ }
+
@Override
NativeSniffer createNativeSniffer() {
return new TestDataPathsActivity.DataPathSniffer(this);
@@ -256,7 +279,9 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity {
@Override
protected boolean isFinishedEarly() {
- return (mMaxMagnitude > MIN_REQUIRED_MAGNITUDE) && (mPhaseJitter < MAX_ALLOWED_JITTER);
+ return (mMaxMagnitude > MIN_REQUIRED_MAGNITUDE)
+ && (getAveragePhaseError() < MAX_ALLOWED_JITTER)
+ && isPhaseJitterValid();
}
// @return reasons for failure of empty string
@@ -267,16 +292,29 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity {
StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration;
StreamConfiguration actualInConfig = mAudioInputTester.actualConfiguration;
StreamConfiguration actualOutConfig = mAudioOutTester.actualConfiguration;
- boolean passed = true;
if (mMaxMagnitude <= MIN_REQUIRED_MAGNITUDE) {
why += ", mag";
}
- if (mPhaseJitter > MAX_ALLOWED_JITTER) {
- why += ", jitter";
+ if (!isPhaseJitterValid()) {
+ why += ", jitterUnknown";
+ } else if (getAveragePhaseError() > MAX_ALLOWED_JITTER) {
+ why += ", jitterHigh";
}
return why;
}
+ private double getAveragePhaseError() {
+ // If we have no measurements then return maximum possible phase jitter
+ // to avoid dividing by zero.
+ return (mPhaseErrorCount > 0) ? (mPhaseErrorSum / mPhaseErrorCount) : Math.PI;
+ }
+
+ private boolean isPhaseJitterValid() {
+ // Arbitrary number of measurements to be considered valid.
+ final int kMinPhaseErrorCount = 5;
+ return mPhaseErrorCount >= kMinPhaseErrorCount;
+ }
+
String getOneLineSummary() {
StreamConfiguration actualInConfig = mAudioInputTester.actualConfiguration;
StreamConfiguration actualOutConfig = mAudioOutTester.actualConfiguration;
@@ -321,7 +359,7 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity {
TestResult testResult = testConfigurations();
if (testResult != null) {
testResult.addComment("mag = " + TestDataPathsActivity.getMagnitudeText(mMagnitude)
- + ", jitter = " + TestDataPathsActivity.getMagnitudeText(mPhaseJitter));
+ + ", jitter = " + getJitterText());
}
return testResult;
}