added complex and phasor classes

This commit is contained in:
Ahmet Inan 2024-04-14 21:56:05 +02:00
parent abfdf69128
commit 16406fd710
3 changed files with 109 additions and 2 deletions

View file

@ -0,0 +1,70 @@
/*
Complex math
Copyright 2024 Ahmet Inan <xdsopl@gmail.com>
*/
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;
}
}

View file

@ -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() {

View file

@ -0,0 +1,21 @@
/*
Numerically controlled oscillator
Copyright 2024 Ahmet Inan <xdsopl@gmail.com>
*/
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());
}
}