mirror of
https://github.com/xdsopl/robot36.git
synced 2026-01-02 22:50:01 +01:00
do a bit of smoothing
This commit is contained in:
parent
1a0c2e5aaf
commit
0556940817
|
|
@ -55,23 +55,23 @@ public class Decoder {
|
|||
scanLineToleranceSamples = (int) Math.round(scanLineToleranceSeconds * sampleRate);
|
||||
rawMode = new RawDecoder();
|
||||
syncPulse5msModes = new ArrayList<>();
|
||||
syncPulse5msModes.add(RGBModes.Wraase_SC2_180(sampleRate));
|
||||
syncPulse5msModes.add(RGBModes.Martin("1", 0.146432, sampleRate));
|
||||
syncPulse5msModes.add(RGBModes.Martin("2", 0.073216, sampleRate));
|
||||
syncPulse5msModes.add(RGBModes.Wraase_SC2_180(sampleRate, scopeWidth));
|
||||
syncPulse5msModes.add(RGBModes.Martin("1", 0.146432, sampleRate, scopeWidth));
|
||||
syncPulse5msModes.add(RGBModes.Martin("2", 0.073216, sampleRate, scopeWidth));
|
||||
syncPulse9msModes = new ArrayList<>();
|
||||
syncPulse9msModes.add(new Robot_36_Color(sampleRate));
|
||||
syncPulse9msModes.add(new Robot_72_Color(sampleRate));
|
||||
syncPulse9msModes.add(RGBModes.Scottie("1", 0.138240, sampleRate));
|
||||
syncPulse9msModes.add(RGBModes.Scottie("2", 0.088064, sampleRate));
|
||||
syncPulse9msModes.add(RGBModes.Scottie("DX", 0.3456, sampleRate));
|
||||
syncPulse9msModes.add(new Robot_36_Color(sampleRate, scopeWidth));
|
||||
syncPulse9msModes.add(new Robot_72_Color(sampleRate, scopeWidth));
|
||||
syncPulse9msModes.add(RGBModes.Scottie("1", 0.138240, sampleRate, scopeWidth));
|
||||
syncPulse9msModes.add(RGBModes.Scottie("2", 0.088064, sampleRate, scopeWidth));
|
||||
syncPulse9msModes.add(RGBModes.Scottie("DX", 0.3456, sampleRate, scopeWidth));
|
||||
syncPulse20msModes = new ArrayList<>();
|
||||
syncPulse20msModes.add(new PaulDon("50", 0.09152, sampleRate));
|
||||
syncPulse20msModes.add(new PaulDon("90", 0.17024, sampleRate));
|
||||
syncPulse20msModes.add(new PaulDon("120", 0.1216, sampleRate));
|
||||
syncPulse20msModes.add(new PaulDon("160", 0.195584, sampleRate));
|
||||
syncPulse20msModes.add(new PaulDon("180", 0.18304, sampleRate));
|
||||
syncPulse20msModes.add(new PaulDon("240", 0.24448, sampleRate));
|
||||
syncPulse20msModes.add(new PaulDon("290", 0.2288, sampleRate));
|
||||
syncPulse20msModes.add(new PaulDon("50", 0.09152, sampleRate, scopeWidth));
|
||||
syncPulse20msModes.add(new PaulDon("90", 0.17024, sampleRate, scopeWidth));
|
||||
syncPulse20msModes.add(new PaulDon("120", 0.1216, sampleRate, scopeWidth));
|
||||
syncPulse20msModes.add(new PaulDon("160", 0.195584, sampleRate, scopeWidth));
|
||||
syncPulse20msModes.add(new PaulDon("180", 0.18304, sampleRate, scopeWidth));
|
||||
syncPulse20msModes.add(new PaulDon("240", 0.24448, sampleRate, scopeWidth));
|
||||
syncPulse20msModes.add(new PaulDon("290", 0.2288, sampleRate, scopeWidth));
|
||||
}
|
||||
|
||||
private void adjustSyncPulses(int[] pulses, int shift) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
Exponential Moving Average
|
||||
|
||||
Copyright 2024 Ahmet Inan <xdsopl@gmail.com>
|
||||
*/
|
||||
|
||||
package xdsopl.robot36;
|
||||
|
||||
public class ExponentialMovingAverage {
|
||||
private final float alpha;
|
||||
private float prev;
|
||||
ExponentialMovingAverage(float alpha) {
|
||||
this.alpha = alpha;
|
||||
}
|
||||
public float avg(float input) {
|
||||
return prev = prev * (1 - alpha) + alpha * input;
|
||||
}
|
||||
public void reset() {
|
||||
prev = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ Copyright 2024 Ahmet Inan <xdsopl@gmail.com>
|
|||
package xdsopl.robot36;
|
||||
|
||||
public class PaulDon implements Mode {
|
||||
private final ExponentialMovingAverage lowPassFilter;
|
||||
private final int scanLineSamples;
|
||||
private final int channelSamples;
|
||||
private final int beginSamples;
|
||||
|
|
@ -17,7 +18,7 @@ public class PaulDon implements Mode {
|
|||
private final int endSamples;
|
||||
private final String name;
|
||||
|
||||
PaulDon(String name, double channelSeconds, int sampleRate) {
|
||||
PaulDon(String name, double channelSeconds, int sampleRate, int bufferWidth) {
|
||||
this.name = "PD " + name;
|
||||
double syncPulseSeconds = 0.02;
|
||||
double syncPorchSeconds = 0.00208;
|
||||
|
|
@ -35,6 +36,7 @@ public class PaulDon implements Mode {
|
|||
yOddBeginSamples = (int) Math.round(yOddBeginSeconds * sampleRate);
|
||||
double yOddEndSeconds = yOddBeginSeconds + channelSeconds;
|
||||
endSamples = (int) Math.round(yOddEndSeconds * sampleRate);
|
||||
lowPassFilter = new ExponentialMovingAverage((float) (bufferWidth / (sampleRate * channelSeconds)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -51,6 +53,12 @@ public class PaulDon implements Mode {
|
|||
public int decodeScanLine(int[] evenBuffer, int[] oddBuffer, float[] scanLineBuffer, int prevPulseIndex, int scanLineSamples) {
|
||||
if (prevPulseIndex + beginSamples < 0 || prevPulseIndex + endSamples > scanLineBuffer.length)
|
||||
return 0;
|
||||
lowPassFilter.reset();
|
||||
for (int i = prevPulseIndex + beginSamples; i < prevPulseIndex + endSamples; ++i)
|
||||
scanLineBuffer[i] = lowPassFilter.avg(scanLineBuffer[i]);
|
||||
lowPassFilter.reset();
|
||||
for (int i = prevPulseIndex + endSamples - 1; i >= scanLineSamples + beginSamples; --i)
|
||||
scanLineBuffer[i] = lowPassFilter.avg(scanLineBuffer[i]);
|
||||
for (int i = 0; i < evenBuffer.length; ++i) {
|
||||
int position = (i * channelSamples) / evenBuffer.length + prevPulseIndex;
|
||||
int yEvenPos = position + yEvenBeginSamples;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ Copyright 2024 Ahmet Inan <xdsopl@gmail.com>
|
|||
package xdsopl.robot36;
|
||||
|
||||
public class RGBDecoder implements Mode {
|
||||
private final ExponentialMovingAverage lowPassFilter;
|
||||
private final int scanLineSamples;
|
||||
private final int beginSamples;
|
||||
private final int redBeginSamples;
|
||||
|
|
@ -18,7 +19,7 @@ public class RGBDecoder implements Mode {
|
|||
private final int endSamples;
|
||||
private final String name;
|
||||
|
||||
RGBDecoder(String name, double scanLineSeconds, double beginSeconds, double redBeginSeconds, double redEndSeconds, double greenBeginSeconds, double greenEndSeconds, double blueBeginSeconds, double blueEndSeconds, double endSeconds, int sampleRate) {
|
||||
RGBDecoder(String name, double scanLineSeconds, double beginSeconds, double redBeginSeconds, double redEndSeconds, double greenBeginSeconds, double greenEndSeconds, double blueBeginSeconds, double blueEndSeconds, double endSeconds, int sampleRate, int bufferWidth) {
|
||||
this.name = name;
|
||||
scanLineSamples = (int) Math.round(scanLineSeconds * sampleRate);
|
||||
beginSamples = (int) Math.round(beginSeconds * sampleRate);
|
||||
|
|
@ -29,6 +30,7 @@ public class RGBDecoder implements Mode {
|
|||
blueBeginSamples = (int) Math.round(blueBeginSeconds * sampleRate);
|
||||
blueSamples = (int) Math.round((blueEndSeconds - blueBeginSeconds) * sampleRate);
|
||||
endSamples = (int) Math.round(endSeconds * sampleRate);
|
||||
lowPassFilter = new ExponentialMovingAverage((float) (bufferWidth / (sampleRate * (greenEndSeconds - greenBeginSeconds))));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -45,6 +47,12 @@ public class RGBDecoder implements Mode {
|
|||
public int decodeScanLine(int[] evenBuffer, int[] oddBuffer, float[] scanLineBuffer, int prevPulseIndex, int scanLineSamples) {
|
||||
if (prevPulseIndex + beginSamples < 0 || prevPulseIndex + endSamples > scanLineBuffer.length)
|
||||
return 0;
|
||||
lowPassFilter.reset();
|
||||
for (int i = prevPulseIndex + beginSamples; i < prevPulseIndex + endSamples; ++i)
|
||||
scanLineBuffer[i] = lowPassFilter.avg(scanLineBuffer[i]);
|
||||
lowPassFilter.reset();
|
||||
for (int i = prevPulseIndex + endSamples - 1; i >= scanLineSamples + beginSamples; --i)
|
||||
scanLineBuffer[i] = lowPassFilter.avg(scanLineBuffer[i]);
|
||||
for (int i = 0; i < evenBuffer.length; ++i) {
|
||||
int redPos = redBeginSamples + (i * redSamples) / evenBuffer.length + prevPulseIndex;
|
||||
int greenPos = greenBeginSamples + (i * greenSamples) / evenBuffer.length + prevPulseIndex;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ package xdsopl.robot36;
|
|||
|
||||
public final class RGBModes {
|
||||
|
||||
public static RGBDecoder Martin(String name, double channelSeconds, int sampleRate) {
|
||||
public static RGBDecoder Martin(String name, double channelSeconds, int sampleRate, int bufferWidth) {
|
||||
double syncPulseSeconds = 0.004862;
|
||||
double separatorSeconds = 0.000572;
|
||||
double scanLineSeconds = syncPulseSeconds + separatorSeconds + 3 * (channelSeconds + separatorSeconds);
|
||||
|
|
@ -18,10 +18,10 @@ public final class RGBModes {
|
|||
double blueEndSeconds = blueBeginSeconds + channelSeconds;
|
||||
double redBeginSeconds = blueEndSeconds + separatorSeconds;
|
||||
double redEndSeconds = redBeginSeconds + channelSeconds;
|
||||
return new RGBDecoder("Martin " + name, scanLineSeconds, greenBeginSeconds, redBeginSeconds, redEndSeconds, greenBeginSeconds, greenEndSeconds, blueBeginSeconds, blueEndSeconds, redEndSeconds, sampleRate);
|
||||
return new RGBDecoder("Martin " + name, scanLineSeconds, greenBeginSeconds, redBeginSeconds, redEndSeconds, greenBeginSeconds, greenEndSeconds, blueBeginSeconds, blueEndSeconds, redEndSeconds, sampleRate, bufferWidth);
|
||||
}
|
||||
|
||||
public static RGBDecoder Scottie(String name, double channelSeconds, int sampleRate) {
|
||||
public static RGBDecoder Scottie(String name, double channelSeconds, int sampleRate, int bufferWidth) {
|
||||
double syncPulseSeconds = 0.009;
|
||||
double separatorSeconds = 0.0015;
|
||||
double scanLineSeconds = syncPulseSeconds + 3 * (channelSeconds + separatorSeconds);
|
||||
|
|
@ -31,10 +31,10 @@ public final class RGBModes {
|
|||
double greenBeginSeconds = greenEndSeconds - channelSeconds;
|
||||
double redBeginSeconds = syncPulseSeconds / 2 + separatorSeconds;
|
||||
double redEndSeconds = redBeginSeconds + channelSeconds;
|
||||
return new RGBDecoder("Scottie " + name, scanLineSeconds, greenBeginSeconds, redBeginSeconds, redEndSeconds, greenBeginSeconds, greenEndSeconds, blueBeginSeconds, blueEndSeconds, redEndSeconds, sampleRate);
|
||||
return new RGBDecoder("Scottie " + name, scanLineSeconds, greenBeginSeconds, redBeginSeconds, redEndSeconds, greenBeginSeconds, greenEndSeconds, blueBeginSeconds, blueEndSeconds, redEndSeconds, sampleRate, bufferWidth);
|
||||
}
|
||||
|
||||
public static RGBDecoder Wraase_SC2_180(int sampleRate) {
|
||||
public static RGBDecoder Wraase_SC2_180(int sampleRate, int bufferWidth) {
|
||||
double syncPulseSeconds = 0.0055225;
|
||||
double syncPorchSeconds = 0.0005;
|
||||
double channelSeconds = 0.235;
|
||||
|
|
@ -45,6 +45,6 @@ public final class RGBModes {
|
|||
double greenEndSeconds = greenBeginSeconds + channelSeconds;
|
||||
double blueBeginSeconds = greenEndSeconds;
|
||||
double blueEndSeconds = blueBeginSeconds + channelSeconds;
|
||||
return new RGBDecoder("Wraase SC2-180", scanLineSeconds, redBeginSeconds, redBeginSeconds, redEndSeconds, greenBeginSeconds, greenEndSeconds, blueBeginSeconds, blueEndSeconds, blueEndSeconds, sampleRate);
|
||||
return new RGBDecoder("Wraase SC2-180", scanLineSeconds, redBeginSeconds, redBeginSeconds, redEndSeconds, greenBeginSeconds, greenEndSeconds, blueBeginSeconds, blueEndSeconds, blueEndSeconds, sampleRate, bufferWidth);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ Copyright 2024 Ahmet Inan <xdsopl@gmail.com>
|
|||
package xdsopl.robot36;
|
||||
|
||||
public class Robot_36_Color implements Mode {
|
||||
private final ExponentialMovingAverage lowPassFilter;
|
||||
private final int scanLineSamples;
|
||||
private final int luminanceSamples;
|
||||
private final int separatorSamples;
|
||||
|
|
@ -17,7 +18,7 @@ public class Robot_36_Color implements Mode {
|
|||
private final int chrominanceBeginSamples;
|
||||
private final int endSamples;
|
||||
|
||||
Robot_36_Color(int sampleRate) {
|
||||
Robot_36_Color(int sampleRate, int bufferWidth) {
|
||||
double syncPulseSeconds = 0.009;
|
||||
double syncPorchSeconds = 0.003;
|
||||
double luminanceSeconds = 0.088;
|
||||
|
|
@ -39,6 +40,7 @@ public class Robot_36_Color implements Mode {
|
|||
chrominanceBeginSamples = (int) Math.round(chrominanceBeginSeconds * sampleRate);
|
||||
double chrominanceEndSeconds = chrominanceBeginSeconds + chrominanceSeconds;
|
||||
endSamples = (int) Math.round(chrominanceEndSeconds * sampleRate);
|
||||
lowPassFilter = new ExponentialMovingAverage((float) (bufferWidth / (sampleRate * luminanceSeconds)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -60,6 +62,12 @@ public class Robot_36_Color implements Mode {
|
|||
separator += scanLineBuffer[prevPulseIndex + separatorBeginSamples + i];
|
||||
separator /= separatorSamples;
|
||||
boolean even = separator < 0.5f;
|
||||
lowPassFilter.reset();
|
||||
for (int i = prevPulseIndex + beginSamples; i < prevPulseIndex + endSamples; ++i)
|
||||
scanLineBuffer[i] = lowPassFilter.avg(scanLineBuffer[i]);
|
||||
lowPassFilter.reset();
|
||||
for (int i = prevPulseIndex + endSamples - 1; i >= scanLineSamples + beginSamples; --i)
|
||||
scanLineBuffer[i] = lowPassFilter.avg(scanLineBuffer[i]);
|
||||
for (int i = 0; i < evenBuffer.length; ++i) {
|
||||
int luminancePos = luminanceBeginSamples + (i * luminanceSamples) / evenBuffer.length + prevPulseIndex;
|
||||
int chrominancePos = chrominanceBeginSamples + (i * chrominanceSamples) / evenBuffer.length + prevPulseIndex;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ Copyright 2024 Ahmet Inan <xdsopl@gmail.com>
|
|||
package xdsopl.robot36;
|
||||
|
||||
public class Robot_72_Color implements Mode {
|
||||
private final ExponentialMovingAverage lowPassFilter;
|
||||
private final int scanLineSamples;
|
||||
private final int luminanceSamples;
|
||||
private final int chrominanceSamples;
|
||||
|
|
@ -16,7 +17,7 @@ public class Robot_72_Color implements Mode {
|
|||
private final int uBeginSamples;
|
||||
private final int endSamples;
|
||||
|
||||
Robot_72_Color(int sampleRate) {
|
||||
Robot_72_Color(int sampleRate, int bufferWidth) {
|
||||
double syncPulseSeconds = 0.009;
|
||||
double syncPorchSeconds = 0.003;
|
||||
double luminanceSeconds = 0.138;
|
||||
|
|
@ -38,6 +39,7 @@ public class Robot_72_Color implements Mode {
|
|||
uBeginSamples = (int) Math.round(uBeginSeconds * sampleRate);
|
||||
double uEndSeconds = uBeginSeconds + chrominanceSeconds;
|
||||
endSamples = (int) Math.round(uEndSeconds * sampleRate);
|
||||
lowPassFilter = new ExponentialMovingAverage((float) (bufferWidth / (sampleRate * luminanceSeconds)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -54,6 +56,12 @@ public class Robot_72_Color implements Mode {
|
|||
public int decodeScanLine(int[] evenBuffer, int[] oddBuffer, float[] scanLineBuffer, int prevPulseIndex, int scanLineSamples) {
|
||||
if (prevPulseIndex + beginSamples < 0 || prevPulseIndex + endSamples > scanLineBuffer.length)
|
||||
return 0;
|
||||
lowPassFilter.reset();
|
||||
for (int i = prevPulseIndex + beginSamples; i < prevPulseIndex + endSamples; ++i)
|
||||
scanLineBuffer[i] = lowPassFilter.avg(scanLineBuffer[i]);
|
||||
lowPassFilter.reset();
|
||||
for (int i = prevPulseIndex + endSamples - 1; i >= scanLineSamples + beginSamples; --i)
|
||||
scanLineBuffer[i] = lowPassFilter.avg(scanLineBuffer[i]);
|
||||
for (int i = 0; i < evenBuffer.length; ++i) {
|
||||
int yPos = yBeginSamples + (i * luminanceSamples) / evenBuffer.length + prevPulseIndex;
|
||||
int uPos = uBeginSamples + (i * chrominanceSamples) / evenBuffer.length + prevPulseIndex;
|
||||
|
|
|
|||
Loading…
Reference in a new issue