From 16406fd7103236661951f4a704ee8c8a5cd123b5 Mon Sep 17 00:00:00 2001 From: Ahmet Inan Date: Sun, 14 Apr 2024 21:56:05 +0200 Subject: [PATCH] added complex and phasor classes --- app/src/main/java/xdsopl/robot36/Complex.java | 70 +++++++++++++++++++ .../java/xdsopl/robot36/MainActivity.java | 20 +++++- app/src/main/java/xdsopl/robot36/Phasor.java | 21 ++++++ 3 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/xdsopl/robot36/Complex.java create mode 100644 app/src/main/java/xdsopl/robot36/Phasor.java diff --git a/app/src/main/java/xdsopl/robot36/Complex.java b/app/src/main/java/xdsopl/robot36/Complex.java new file mode 100644 index 0000000..db9bb71 --- /dev/null +++ b/app/src/main/java/xdsopl/robot36/Complex.java @@ -0,0 +1,70 @@ +/* +Complex math + +Copyright 2024 Ahmet Inan +*/ + +package xdsopl.robot36; + +public class Complex { + public float real, imag; + Complex() { + real = 0; + imag = 0; + } + Complex(float real, float imag) { + this.real = real; + this.imag = imag; + } + float norm() { + return real * real + imag * imag; + } + float abs() { + return (float) Math.sqrt(norm()); + } + float arg() { + return (float) Math.atan2(imag, real); + } + Complex polar(float a, float b) { + real = a * (float) Math.cos(b); + imag = a * (float) Math.sin(b); + return this; + } + Complex conj() { + imag = -imag; + return this; + } + Complex add(Complex other) { + real += other.real; + imag += other.imag; + return this; + } + Complex sub(Complex other) { + real -= other.real; + imag -= other.imag; + return this; + } + Complex mul(float value) { + real *= value; + imag *= value; + return this; + } + Complex mul(Complex other) { + float tmp = real * other.real - imag * other.imag; + imag = real * other.imag + imag * other.real; + real = tmp; + return this; + } + Complex div(float value) { + real /= value; + imag /= value; + return this; + } + Complex div(Complex other) { + float den = other.norm(); + float tmp = (real * other.real + imag * other.imag) / den; + imag = (imag * other.real - real * other.imag) / den; + real = tmp; + return this; + } +} diff --git a/app/src/main/java/xdsopl/robot36/MainActivity.java b/app/src/main/java/xdsopl/robot36/MainActivity.java index f8b88dc..4e320f9 100644 --- a/app/src/main/java/xdsopl/robot36/MainActivity.java +++ b/app/src/main/java/xdsopl/robot36/MainActivity.java @@ -38,6 +38,9 @@ public class MainActivity extends AppCompatActivity { private AudioRecord audioRecord; private TextView status; private SimpleMovingAverage powerAvg; + private SimpleMovingAverage realSyncAvg, imagSyncAvg; + private Phasor osc_1200; + private Complex sad; private int tint; private int curLine; @@ -59,7 +62,13 @@ public class MainActivity extends AppCompatActivity { private void processSamples() { for (float v : recordBuffer) { - int x = Math.min((int) (scopeWidth * powerAvg.avg(v * v)), scopeWidth); + sad.real = v; + sad.imag = 0; + sad.mul(osc_1200.rotate()); + sad.real = realSyncAvg.avg(sad.real); + sad.imag = imagSyncAvg.avg(sad.imag); + float level = sad.norm() / powerAvg.avg(v * v); + int x = Math.min((int) (scopeWidth * level), scopeWidth); for (int i = 0; i < x; ++i) scopePixels[scopeWidth * curLine + i] = tint; for (int i = x; i < scopeWidth; ++i) @@ -74,7 +83,14 @@ public class MainActivity extends AppCompatActivity { private void initTools(int sampleRate) { double powerWindowSeconds = 0.5; - powerAvg = new SimpleMovingAverage((int) Math.round(powerWindowSeconds * sampleRate)); + int powerWindowSamples = (int) Math.round(powerWindowSeconds * sampleRate); + powerAvg = new SimpleMovingAverage(powerWindowSamples); + double syncPulseSeconds = 0.01; + int syncPulseSamples = (int) Math.round(syncPulseSeconds * sampleRate); + realSyncAvg = new SimpleMovingAverage(syncPulseSamples); + imagSyncAvg = new SimpleMovingAverage(syncPulseSamples); + osc_1200 = new Phasor(-1200, sampleRate); + sad = new Complex(); } private void initAudioRecord() { diff --git a/app/src/main/java/xdsopl/robot36/Phasor.java b/app/src/main/java/xdsopl/robot36/Phasor.java new file mode 100644 index 0000000..958a85b --- /dev/null +++ b/app/src/main/java/xdsopl/robot36/Phasor.java @@ -0,0 +1,21 @@ +/* +Numerically controlled oscillator + +Copyright 2024 Ahmet Inan +*/ + +package xdsopl.robot36; + +public class Phasor { + private final Complex value; + private final Complex delta; + Phasor(float freq, float rate) { + value = new Complex(1, 0); + double omega = 2 * Math.PI * freq / rate; + delta = new Complex((float) Math.cos(omega), (float) Math.sin(omega)); + } + Complex rotate() { + value.mul(delta); + return value.div(value.abs()); + } +}