Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions apps/OboeTester/app/src/main/cpp/analyzer/BaseSineAnalyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ class BaseSineAnalyzer : public LoopbackProcessor {
switch (mSignalType) {
case Chirp: {
if (mFrameCounter < getSampleRate() * kChirpDurationSeconds) {
float sinOut = sinf(mOutputPhase);
double sinOut = sin(mOutputPhase);
// Simple linear chirp from kChirpStartFrequency to mChirpEndFrequencyActual
// in kChirpDurationSeconds seconds.
double freq = kChirpStartFrequency
Expand All @@ -157,7 +157,7 @@ class BaseSineAnalyzer : public LoopbackProcessor {
}
case Sine:
default: {
float sinOut = sinf(mOutputPhase);
double sinOut = sin(mOutputPhase);
incrementOutputPhase();
output = (sinOut * mOutputAmplitude)
+ (mWhiteNoise.nextRandomDouble() * getNoiseAmplitude());
Expand Down Expand Up @@ -214,8 +214,8 @@ class BaseSineAnalyzer : public LoopbackProcessor {
*/
bool transformSample(float sample) {
// Compare incoming signal with the reference input sine wave.
mSinAccumulator += static_cast<double>(sample) * sinf(mInputPhase);
mCosAccumulator += static_cast<double>(sample) * cosf(mInputPhase);
mSinAccumulator += static_cast<double>(sample) * sin(mInputPhase);
mCosAccumulator += static_cast<double>(sample) * cos(mInputPhase);
incrementInputPhase();

mFramesAccumulated++;
Expand All @@ -224,7 +224,8 @@ class BaseSineAnalyzer : public LoopbackProcessor {
const double coefficient = 0.1;
double magnitude = calculateMagnitudePhase(&mPhaseOffset);

ALOGD("%s(), phaseOffset = %f\n", __func__, mPhaseOffset);
ALOGD("%s(), magnitude = %f, phaseOffset = %f\n", __func__,
magnitude, mPhaseOffset);
if (mPhaseOffset != kPhaseInvalid) {
// One pole averaging filter for magnitude.
setMagnitude((mMagnitude * (1.0 - coefficient)) + (magnitude * coefficient));
Expand Down
26 changes: 24 additions & 2 deletions apps/OboeTester/app/src/main/cpp/analyzer/DataPathAnalyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,12 +169,20 @@ BaseSineAnalyzer::result_code DataPathAnalyzer::processInputFrame(const float *f

if (transformSample(sample)) {
// Analyze magnitude and phase on every period.
if (mPhaseOffset != kPhaseInvalid) {
double diff = fabs(calculatePhaseError(mPhaseOffset, mPreviousPhaseOffset));
if (mPhaseOffset != kPhaseInvalid &&
mMagnitude >= kMinSmoothedMagnitude) {
double diff = fabs(
calculatePhaseError(mPhaseOffset, mPreviousPhaseOffset));
if (diff < mPhaseTolerance) {
mMaxMagnitude = std::max(mMagnitude, mMaxMagnitude);
}
constexpr int kMinPhaseCount = 4;
if (mPhaseCount >= kMinPhaseCount) {
mPhaseErrorSum += diff;
mPhaseErrorCount++;
}
mPreviousPhaseOffset = mPhaseOffset;
mPhaseCount++;
}
}
break;
Expand Down Expand Up @@ -207,6 +215,9 @@ std::string DataPathAnalyzer::analyze() {

void DataPathAnalyzer::reset() {
BaseSineAnalyzer::reset();
mPhaseErrorSum = 0.0;
mPhaseErrorCount = 0;
mPhaseCount = 0;
mPreviousPhaseOffset = 999.0; // Arbitrary high offset to prevent early lock.
mMaxMagnitude = 0.0;
}
Expand All @@ -227,3 +238,14 @@ int DataPathAnalyzer::getAnalysisResult() {
return mAnalysisResult;
}

double DataPathAnalyzer::getAveragePhaseError() {
return mPhaseErrorCount > 0 ? mPhaseErrorSum / mPhaseErrorCount : M_PI;
}

int DataPathAnalyzer::getPhaseCount() { return mPhaseCount; }

bool DataPathAnalyzer::isPhaseJitterValid() {
// Arbitrary number of measurements to be considered valid.
constexpr int kMinPhaseErrorCount = 5;
return mPhaseErrorCount >= kMinPhaseErrorCount;
}
8 changes: 8 additions & 0 deletions apps/OboeTester/app/src/main/cpp/analyzer/DataPathAnalyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,25 @@ class DataPathAnalyzer : public BaseSineAnalyzer {
void reset() override;

double getMaxMagnitude();
double getAveragePhaseError();
int getPhaseCount();
bool isPhaseJitterValid();

std::string getFrequencyResponse();
std::string getDistortionReport();
int getAnalysisResult();

private:
static constexpr double kMinSmoothedMagnitude = 0.001;

double calculatePhaseError(double p1, double p2);

double mPreviousPhaseOffset = 0.0;
double mPhaseTolerance = 2 * M_PI / 48;
double mMaxMagnitude = 0.0;
int mPhaseCount = 0;
double mPhaseErrorSum = 0.0;
int mPhaseErrorCount = 0;

// For multi-tone analysis
std::vector<float> mFftBuffer;
Expand Down
18 changes: 18 additions & 0 deletions apps/OboeTester/app/src/main/cpp/jni-bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1007,6 +1007,24 @@ Java_com_mobileer_oboetester_TestDataPathsActivity_getPhaseDataPaths(JNIEnv *env
return engine.mActivityDataPath.getDataPathAnalyzer()->getPhaseOffset();
}

JNIEXPORT double JNICALL
Java_com_mobileer_oboetester_TestDataPathsActivity_getAveragePhaseError(
JNIEnv* env, jobject instance) {
return engine.mActivityDataPath.getDataPathAnalyzer()->getAveragePhaseError();
}

JNIEXPORT bool JNICALL
Java_com_mobileer_oboetester_TestDataPathsActivity_isPhaseJitterValid(
JNIEnv* env, jobject instance) {
return engine.mActivityDataPath.getDataPathAnalyzer()->isPhaseJitterValid();
}

JNIEXPORT int JNICALL
Java_com_mobileer_oboetester_TestDataPathsActivity_getPhaseCount(JNIEnv *env,
jobject instance) {
return engine.mActivityDataPath.getDataPathAnalyzer()->getPhaseCount();
}

JNIEXPORT void JNICALL
Java_com_mobileer_oboetester_TestDataPathsActivity_setSignalType(JNIEnv *env,
jobject instance,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -344,13 +344,13 @@ protected TestResult testCurrentConfigurations() throws InterruptedException {
long now = System.currentTimeMillis();
long startedAt = now;
long endTime = System.currentTimeMillis() + (mDurationSeconds * 1000);
boolean finishedEarly = false;
while (now < endTime && !finishedEarly) {
while (now < endTime) {
Comment thread
q23175401 marked this conversation as resolved.
Thread.sleep(100); // Let test run.
now = System.currentTimeMillis();
finishedEarly = isFinishedEarly();
if (finishedEarly) {
double runningTimeSeconds = (now - startedAt) / 1000.0;
if (isFinishedEarly(runningTimeSeconds)) {
log("Finished early after " + (now - startedAt) + " msec.");
break;
}
}
}
Expand Down Expand Up @@ -585,7 +585,7 @@ protected AudioDeviceInfo findCompatibleInputDevice(int outputDeviceType) {
return null;
}

protected boolean isFinishedEarly() {
protected boolean isFinishedEarly(double runningTimeSeconds) {
return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity {
public static final boolean VALUE_DEFAULT_USE_OUTPUT_DEVICES = true;

public static final int DURATION_SECONDS = 4;
public static final int EARLY_STOP_DURATION_SECONDS = 1;
private final static double MIN_REQUIRED_MAGNITUDE = 0.001;
private final static double MAX_ALLOWED_JITTER = 0.1; // Matches CTS Verifier
// This must match the value of kPhaseInvalid in BaseSineAnalyzer.h
Expand Down Expand Up @@ -135,8 +136,6 @@ public class TestDataPathsActivity extends BaseAutoGlitchActivity {
private double mMaxMagnitude;
private int mPhaseCount;
private double mPhase;
private double mPhaseErrorSum;
private double mPhaseErrorCount;

private boolean mSkipRemainingTests;

Expand Down Expand Up @@ -256,35 +255,17 @@ public void startSniffer() {
mMaxMagnitude = -1.0;
mPhaseCount = 0;
mPhase = 0.0;
mPhaseErrorSum = 0.0;
mPhaseErrorCount = 0;
super.startSniffer();
}

private void gatherData() {
mMagnitude = getMagnitude();
mMaxMagnitude = getMaxMagnitude();
Log.d(TAG, String.format(Locale.getDefault(), "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 = getPhaseDataPaths();
if (phase != PHASE_INVALID) {
// 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 = Math.abs(calculatePhaseError(phase, mPhase));
// collect average error
mPhaseErrorSum += phaseError;
mPhaseErrorCount++;
Log.d(TAG, String.format(Locale.getDefault(), "phase = %7.4f, mPhase = %7.4f, phaseError = %7.4f, jitter = %7.4f",
phase, mPhase, phaseError, getAveragePhaseError()));
}
mPhase = phase;
}
mPhaseCount++;
}
mPhase = getPhaseDataPaths();
mPhaseCount = getPhaseCount();
Log.d(TAG, String.format(Locale.getDefault(),
"magnitude = %7.4f, maxMagnitude = %7.4f, phase = %7.4f, phaseCount = %d, jitter = %7.4f",
mMagnitude, mMaxMagnitude, mPhase, mPhaseCount, getAveragePhaseError()));
}

public String getCurrentStatusReport() {
Expand Down Expand Up @@ -366,6 +347,9 @@ public String getShortReport() {
native double getMaxMagnitude();

native double getPhaseDataPaths();
native int getPhaseCount();
native double getAveragePhaseError();
native boolean isPhaseJitterValid();

native void setSignalType(int type);
native String getFrequencyResponse();
Expand Down Expand Up @@ -457,10 +441,13 @@ protected String whyShouldTestBeSkipped() {
}

@Override
protected boolean isFinishedEarly() {
return (mMaxMagnitude > MIN_REQUIRED_MAGNITUDE)
&& (getAveragePhaseError() < MAX_ALLOWED_JITTER)
&& isPhaseJitterValid();
protected boolean isFinishedEarly(double runningTimeSeconds) {
Comment thread
q23175401 marked this conversation as resolved.
if (mSignalType == 0) { // Sine
boolean passed = mMagnitude > MIN_REQUIRED_MAGNITUDE && getAveragePhaseError() < MAX_ALLOWED_JITTER
&& isPhaseJitterValid();
return passed && (runningTimeSeconds >= EARLY_STOP_DURATION_SECONDS);
}
return false;
}

// @return reasons for failure of empty string
Expand Down Expand Up @@ -491,18 +478,6 @@ public String didTestFail() {
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;
Expand Down
Loading