#1633 DMR Decoder redesign. Uses new DQPSK vector/scalar demodulator implementations and soft sync detectors for more accurate detections and symbol timing and symbol period calculations. Includes two new calibrations with scalar and vector implementations for DQPSK demodulator and Interpolator. Enhances DMR error detection and correction algorithms, specifically the block product turbo code algorithms. (#2115)

Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
Denny Sheirer
2024-12-24 06:53:58 -05:00
committed by GitHub
parent 11abb87177
commit 9ffa02e2e5
188 changed files with 8066 additions and 3192 deletions

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,12 +19,11 @@
package io.github.dsheirer.vector.calibrate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DecimalFormat;
import java.util.Random;
import java.util.prefs.Preferences;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Abstract calibration plugin base class
@@ -123,6 +122,24 @@ public abstract class Calibration
return samples;
}
/**
* Generates an array of floating point samples in the range 0.0 - 1.0
* @param size of array
* @return generated samples
*/
protected float[] getPositiveFloatSamples(int size)
{
Random random = new Random();
float[] samples = new float[size];
for(int x = 0; x < samples.length; x++)
{
samples[x] = random.nextFloat();
}
return samples;
}
/**
* Generates an array of floating point samples in the range -1.0 - 1.0
* @param size of array

View File

@@ -25,6 +25,7 @@ import io.github.dsheirer.preference.calibration.VectorCalibrationPreference;
import io.github.dsheirer.vector.calibrate.airspy.AirspySampleConverterCalibration;
import io.github.dsheirer.vector.calibrate.airspy.AirspyUnpackedCalibration;
import io.github.dsheirer.vector.calibrate.airspy.AirspyUnpackedInterleavedCalibration;
import io.github.dsheirer.vector.calibrate.demodulator.DqpskDemodulatorCalibration;
import io.github.dsheirer.vector.calibrate.demodulator.FmDemodulatorCalibration;
import io.github.dsheirer.vector.calibrate.filter.FirFilterCalibration;
import io.github.dsheirer.vector.calibrate.filter.RealDcRemovalCalibration;
@@ -35,10 +36,12 @@ import io.github.dsheirer.vector.calibrate.filter.RealHalfBand63TapFilterCalibra
import io.github.dsheirer.vector.calibrate.filter.RealHalfBandDefaultFilterCalibration;
import io.github.dsheirer.vector.calibrate.gain.ComplexGainCalibration;
import io.github.dsheirer.vector.calibrate.gain.ComplexGainControlCalibration;
import io.github.dsheirer.vector.calibrate.interpolator.InterpolatorCalibration;
import io.github.dsheirer.vector.calibrate.magnitude.MagnitudeCalibration;
import io.github.dsheirer.vector.calibrate.mixer.ComplexMixerCalibration;
import io.github.dsheirer.vector.calibrate.oscillator.ComplexOscillatorCalibration;
import io.github.dsheirer.vector.calibrate.oscillator.RealOscillatorCalibration;
import io.github.dsheirer.vector.calibrate.sync.DMRSoftSyncCalibration;
import io.github.dsheirer.vector.calibrate.window.WindowCalibration;
import java.util.ArrayList;
import java.util.Collections;
@@ -104,8 +107,11 @@ public class CalibrationManager
sInstance.add(new ComplexGainControlCalibration());
sInstance.add(new ComplexOscillatorCalibration());
sInstance.add(new ComplexMixerCalibration());
sInstance.add(new DMRSoftSyncCalibration());
sInstance.add(new DqpskDemodulatorCalibration());
sInstance.add(new FirFilterCalibration());
sInstance.add(new FmDemodulatorCalibration());
sInstance.add(new InterpolatorCalibration());
sInstance.add(new MagnitudeCalibration());
sInstance.add(new RealDcRemovalCalibration());
sInstance.add(new RealHalfBand11TapFilterCalibration());
@@ -114,7 +120,6 @@ public class CalibrationManager
sInstance.add(new RealHalfBand63TapFilterCalibration());
sInstance.add(new RealHalfBandDefaultFilterCalibration());
sInstance.add(new RealOscillatorCalibration());
// sInstance.add(new HilbertCalibration()); //Not currently used
sInstance.add(new WindowCalibration()); //Not currently used
}
@@ -275,20 +280,8 @@ public class CalibrationManager
public static void main(String[] args)
{
CalibrationManager manager = getInstance();
StringBuilder sb = new StringBuilder();
sb.append("Current Calibration Settings:\n");
for(CalibrationType type: CalibrationType.values())
{
Calibration calibration = manager.getCalibration(type);
if(calibration != null)
{
sb.append("\t").append(type.name()).append("\t").append(manager.getCalibration(type).getImplementation()).append("\n");
}
}
System.out.println(sb);
manager.reset();
// manager.reset();
manager.reset(CalibrationType.DQPSK_DEMODULATOR);
if(!manager.isCalibrated())
{

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -37,6 +37,8 @@ public enum CalibrationType
AIRSPY_UNPACKED_ITERATOR("Airspy Unpacked Iterator", 1),
AM_DEMODULATOR("AM Demodulator", 1),
DC_REMOVAL_REAL("Real DC Removal Filter", 1),
DMR_SOFT_SYNC_DETECTOR("DMR Soft Sync Detector", 1),
DQPSK_DEMODULATOR("DQPSK Demodulator", 1),
FILTER_FIR("FIR Filter", 1),
FILTER_HALF_BAND_REAL_11_TAP("Real Half-Band Decimation Filter - 11 Tap", 1),
FILTER_HALF_BAND_REAL_15_TAP("Real Half-Band Decimation Filter - 15 Tap", 1),
@@ -46,6 +48,7 @@ public enum CalibrationType
FM_DEMODULATOR("FM Demodulator", 2),
GAIN_CONTROL_COMPLEX("Complex Gain Control", 1),
HILBERT_TRANSFORM("Hilbert Transform", 1),
INTERPOLATOR("Interpolator", 1),
MAGNITUDE("Magnitude", 1),
MIXER_COMPLEX("Complex Mixer", 1),
OSCILLATOR_REAL("Real Oscillator", 1),

View File

@@ -0,0 +1,287 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.vector.calibrate.demodulator;
import io.github.dsheirer.dsp.psk.dqpsk.DQPSKDemodulator;
import io.github.dsheirer.dsp.psk.dqpsk.DQPSKDemodulatorScalar;
import io.github.dsheirer.dsp.psk.dqpsk.DQPSKDemodulatorVector128;
import io.github.dsheirer.dsp.psk.dqpsk.DQPSKDemodulatorVector256;
import io.github.dsheirer.dsp.psk.dqpsk.DQPSKDemodulatorVector512;
import io.github.dsheirer.dsp.psk.dqpsk.DQPSKDemodulatorVector64;
import io.github.dsheirer.vector.calibrate.Calibration;
import io.github.dsheirer.vector.calibrate.CalibrationException;
import io.github.dsheirer.vector.calibrate.CalibrationType;
import io.github.dsheirer.vector.calibrate.Implementation;
import org.apache.commons.math3.stat.descriptive.moment.Mean;
/**
* Calibrates DQPSK demodulator options
*/
public class DqpskDemodulatorCalibration extends Calibration
{
private static final int BUFFER_SIZE = 2048;
private static final int ITERATION_DURATION_MS = 1000;
private static final int WARMUP_ITERATIONS = 5;
private static final int TEST_ITERATIONS = 5;
private DQPSKDemodulator mScalarDemodulator = new DQPSKDemodulatorScalar(50000.0, 4800);
private final DQPSKDemodulator mVectorDemodulator64 = new DQPSKDemodulatorVector64(50000.0, 4800);
private final DQPSKDemodulator mVectorDemodulator128 = new DQPSKDemodulatorVector128(50000.0, 4800);
private final DQPSKDemodulator mVectorDemodulator256 = new DQPSKDemodulatorVector256(50000.0, 4800);
private final DQPSKDemodulator mVectorDemodulator512 = new DQPSKDemodulatorVector512(50000.0, 4800);
/**
* Constructs an instance
*/
public DqpskDemodulatorCalibration()
{
super(CalibrationType.DQPSK_DEMODULATOR);
}
@Override public void calibrate() throws CalibrationException
{
float[] i = getFloatSamples(BUFFER_SIZE);
float[] q = getFloatSamples(BUFFER_SIZE);
Mean scalarMean = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testScalar(i, q);
scalarMean.increment(score);
}
mLog.info("DQPSK DEMODULATOR WARMUP - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
Mean vectorMean64 = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector64(i, q);
vectorMean64.increment(score);
}
mLog.info("DQPSK DEMODULATOR WARMUP - VECTOR 64: " + DECIMAL_FORMAT.format(vectorMean64.getResult()));
Mean vectorMean128 = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector128(i, q);
vectorMean128.increment(score);
}
mLog.info("DQPSK DEMODULATOR WARMUP - VECTOR 128: " + DECIMAL_FORMAT.format(vectorMean128.getResult()));
Mean vectorMean256 = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector256(i, q);
vectorMean256.increment(score);
}
mLog.info("DQPSK DEMODULATOR WARMUP - VECTOR 256: " + DECIMAL_FORMAT.format(vectorMean256.getResult()));
Mean vectorMean512 = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector512(i, q);
vectorMean512.increment(score);
}
mLog.info("DQPSK DEMODULATOR WARMUP - VECTOR 512: " + DECIMAL_FORMAT.format(vectorMean512.getResult()));
//Start tests
scalarMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testScalar(i, q);
scalarMean.increment(score);
}
mLog.info("DQPSK DEMODULATOR - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
vectorMean64.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector64(i, q);
vectorMean64.increment(score);
}
mLog.info("DQPSK DEMODULATOR - VECTOR 64: " + DECIMAL_FORMAT.format(vectorMean64.getResult()));
vectorMean128.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector128(i, q);
vectorMean128.increment(score);
}
mLog.info("DQPSK DEMODULATOR - VECTOR 128: " + DECIMAL_FORMAT.format(vectorMean128.getResult()));
vectorMean256.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector256(i, q);
vectorMean256.increment(score);
}
mLog.info("DQPSK DEMODULATOR - VECTOR 256: " + DECIMAL_FORMAT.format(vectorMean256.getResult()));
vectorMean512.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector512(i, q);
vectorMean512.increment(score);
}
mLog.info("DQPSK DEMODULATOR - VECTOR 512: " + DECIMAL_FORMAT.format(vectorMean512.getResult()));
Implementation best = Implementation.SCALAR;
double bestScore = scalarMean.getResult();
if(vectorMean64.getResult() > bestScore)
{
bestScore = vectorMean64.getResult();
best = Implementation.VECTOR_SIMD_64;
}
if(vectorMean128.getResult() > bestScore)
{
bestScore = vectorMean128.getResult();
best = Implementation.VECTOR_SIMD_128;
}
if(vectorMean256.getResult() > bestScore)
{
bestScore = vectorMean256.getResult();
best = Implementation.VECTOR_SIMD_256;
}
if(vectorMean512.getResult() > bestScore)
{
best = Implementation.VECTOR_SIMD_512;
}
setImplementation(best);
mLog.info("DQPSK DEMODULATOR - SET OPTIMAL IMPLEMENTATION TO:" + getImplementation());
}
private long testScalar(float[] i, float[] q)
{
long count = 0;
float accumulator = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] demodulated = mScalarDemodulator.demodulate(i, q);
accumulator += demodulated[1];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector64(float[] i, float[] q)
{
long count = 0;
float accumulator = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] demodulated = mVectorDemodulator64.demodulate(i, q);
accumulator += demodulated[1];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector128(float[] i, float[] q)
{
long count = 0;
float accumulator = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] demodulated = mVectorDemodulator128.demodulate(i, q);
accumulator += demodulated[1];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector256(float[] i, float[] q)
{
long count = 0;
float accumulator = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] demodulated = mVectorDemodulator256.demodulate(i, q);
accumulator += demodulated[1];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector512(float[] i, float[] q)
{
long count = 0;
float accumulator = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] demodulated = mVectorDemodulator512.demodulate(i, q);
accumulator += demodulated[1];
count++;
}
return count + (long)(accumulator * 0);
}
public static void main(String[] args)
{
DqpskDemodulatorCalibration calibration = new DqpskDemodulatorCalibration();
try
{
calibration.calibrate();
}
catch(Exception e)
{
mLog.error("Error during calibration", e);
}
}
}

View File

@@ -0,0 +1,268 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.vector.calibrate.interpolator;
import io.github.dsheirer.dsp.filter.interpolator.Interpolator;
import io.github.dsheirer.dsp.filter.interpolator.InterpolatorScalar;
import io.github.dsheirer.dsp.filter.interpolator.InterpolatorVector128;
import io.github.dsheirer.dsp.filter.interpolator.InterpolatorVector256;
import io.github.dsheirer.dsp.filter.interpolator.InterpolatorVector64;
import io.github.dsheirer.vector.calibrate.Calibration;
import io.github.dsheirer.vector.calibrate.CalibrationException;
import io.github.dsheirer.vector.calibrate.CalibrationType;
import io.github.dsheirer.vector.calibrate.Implementation;
import jdk.incubator.vector.FloatVector;
import jdk.incubator.vector.VectorSpecies;
import org.apache.commons.math3.stat.descriptive.moment.Mean;
/**
* Calibration plugin for FIR filters
*/
public class InterpolatorCalibration extends Calibration
{
private static final VectorSpecies<Float> VECTOR_SPECIES = FloatVector.SPECIES_PREFERRED;
private static final int BUFFER_SIZE = 8;
private static final int ITERATION_DURATION_MS = 1000;
private static final int WARMUP_ITERATIONS = 5;
private static final int TEST_ITERATIONS = 5;
private Interpolator mScalar = new InterpolatorScalar();
private Interpolator mVector256 = new InterpolatorVector256();
private Interpolator mVector128 = new InterpolatorVector128();
private Interpolator mVector64 = new InterpolatorVector64();
/**
* Constructs an instance
*/
public InterpolatorCalibration()
{
super(CalibrationType.INTERPOLATOR);
}
/**
* Performs calibration to determine optimal (Scalar vs Vector) operation type.
* @throws CalibrationException
*/
@Override public void calibrate() throws CalibrationException
{
float[] samples = getFloatSamples(BUFFER_SIZE);
float[] interpolationPoints = getPositiveFloatSamples(2048);
Mean scalarMean = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testScalar(samples, interpolationPoints);
scalarMean.increment(score);
}
mLog.info("INTERPOLATOR WARMUP - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
Mean vector256Mean = new Mean();
if(VECTOR_SPECIES.length() >= 8)
{
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector256(samples, interpolationPoints);
vector256Mean.increment(score);
}
mLog.info("INTERPOLATOR WARMUP - VECTOR 256: " + DECIMAL_FORMAT.format(vector256Mean.getResult()));
}
Mean vector128Mean = new Mean();
if(VECTOR_SPECIES.length() >= 4)
{
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector128(samples, interpolationPoints);
vector128Mean.increment(score);
}
mLog.info("INTERPOLATOR WARMUP - VECTOR 128: " + DECIMAL_FORMAT.format(vector128Mean.getResult()));
}
Mean vector64Mean = new Mean();
if(VECTOR_SPECIES.length() >= 2)
{
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector64(samples, interpolationPoints);
vector64Mean.increment(score);
}
mLog.info("INTERPOLATOR WARMUP - VECTOR 64: " + DECIMAL_FORMAT.format(vector64Mean.getResult()));
}
//Test starts ...
scalarMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testScalar(samples, interpolationPoints);
scalarMean.increment(score);
}
mLog.info("INTERPOLATOR - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
double bestScore = scalarMean.getResult();
setImplementation(Implementation.SCALAR);
if(VECTOR_SPECIES.length() >= 8)
{
vector256Mean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector256(samples, interpolationPoints);
vector256Mean.increment(score);
}
mLog.info("INTERPOLATOR - VECTOR 256: " + DECIMAL_FORMAT.format(vector256Mean.getResult()));
if(vector256Mean.getResult() > bestScore)
{
bestScore = vector256Mean.getResult();
setImplementation(Implementation.VECTOR_SIMD_256);
}
}
if(VECTOR_SPECIES.length() >= 4)
{
vector128Mean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector128(samples, interpolationPoints);
vector128Mean.increment(score);
}
mLog.info("INTERPOLATOR - VECTOR 128: " + DECIMAL_FORMAT.format(vector128Mean.getResult()));
if(vector128Mean.getResult() > bestScore)
{
bestScore = vector128Mean.getResult();
setImplementation(Implementation.VECTOR_SIMD_128);
}
}
if(VECTOR_SPECIES.length() >= 2)
{
vector64Mean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector64(samples, interpolationPoints);
vector64Mean.increment(score);
}
mLog.info("INTERPOLATOR - VECTOR 64: " + DECIMAL_FORMAT.format(vector64Mean.getResult()));
if(vector64Mean.getResult() > bestScore)
{
setImplementation(Implementation.VECTOR_SIMD_64);
}
}
mLog.info("INTERPOLATOR - SET OPTIMAL IMPLEMENTATION TO: " + getImplementation());
}
private long testScalar(float[] samples, float[] interpolationPoints)
{
double accumulator = 0.0f;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
for(int x = 0; x < interpolationPoints.length; x++)
{
accumulator += mScalar.filter(samples, 0, interpolationPoints[x]);
}
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector64(float[] samples, float[] interpolationPoints)
{
double accumulator = 0.0f;
long start = System.currentTimeMillis();
long count = 0;
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
for(int x = 0; x < interpolationPoints.length; x++)
{
accumulator += mVector64.filter(samples, 0, interpolationPoints[x]);
}
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector128(float[] samples, float[] interpolationPoints)
{
double accumulator = 0.0f;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
for(int x = 0; x < interpolationPoints.length; x++)
{
accumulator += mVector128.filter(samples, 0, interpolationPoints[x]);
}
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector256(float[] samples, float[] interpolationPoints)
{
double accumulator = 0.0f;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
for(int x = 0; x < interpolationPoints.length; x++)
{
accumulator += mVector256.filter(samples, 0, interpolationPoints[x]);
}
count++;
}
return count + (long)(accumulator * 0);
}
}

View File

@@ -0,0 +1,292 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.vector.calibrate.sync;
import io.github.dsheirer.module.decode.dmr.sync.DMRSoftSyncDetector;
import io.github.dsheirer.module.decode.dmr.sync.DMRSoftSyncDetectorScalar;
import io.github.dsheirer.module.decode.dmr.sync.DMRSoftSyncDetectorVector128;
import io.github.dsheirer.module.decode.dmr.sync.DMRSoftSyncDetectorVector256;
import io.github.dsheirer.module.decode.dmr.sync.DMRSoftSyncDetectorVector512;
import io.github.dsheirer.module.decode.dmr.sync.DMRSoftSyncDetectorVector64;
import io.github.dsheirer.vector.calibrate.Calibration;
import io.github.dsheirer.vector.calibrate.CalibrationException;
import io.github.dsheirer.vector.calibrate.CalibrationType;
import io.github.dsheirer.vector.calibrate.Implementation;
import org.apache.commons.math3.stat.descriptive.moment.Mean;
/**
* DMR Soft Sync Detector calibration
*/
public class DMRSoftSyncCalibration extends Calibration
{
private static final int BUFFER_SIZE = 2048;
private static final int ITERATION_DURATION_MS = 1000;
private static final int WARMUP_ITERATIONS = 5;
private static final int TEST_ITERATIONS = 5;
private final DMRSoftSyncDetector mScalarDetector = new DMRSoftSyncDetectorScalar();
private final DMRSoftSyncDetector mVectorDetector64 = new DMRSoftSyncDetectorVector64();
private final DMRSoftSyncDetector mVectorDetector128 = new DMRSoftSyncDetectorVector128();
private final DMRSoftSyncDetector mVectorDetector256 = new DMRSoftSyncDetectorVector256();
private final DMRSoftSyncDetector mVectorDetector512 = new DMRSoftSyncDetectorVector512();
/**
* Constructs an instance
*/
public DMRSoftSyncCalibration()
{
super(CalibrationType.DMR_SOFT_SYNC_DETECTOR);
}
@Override public void calibrate() throws CalibrationException
{
float[] samples = getFloatSamples(BUFFER_SIZE);
Mean scalarMean = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testScalar(samples);
scalarMean.increment(score);
}
mLog.info("DMR SOFT SYNC DETECTOR WARMUP - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
Mean vectorMean64 = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector64(samples);
vectorMean64.increment(score);
}
mLog.info("DMR SOFT SYNC DETECTOR WARMUP - VECTOR 64: " + DECIMAL_FORMAT.format(vectorMean64.getResult()));
Mean vectorMean128 = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector128(samples);
vectorMean128.increment(score);
}
mLog.info("DMR SOFT SYNC DETECTOR WARMUP - VECTOR 128: " + DECIMAL_FORMAT.format(vectorMean128.getResult()));
Mean vectorMean256 = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector256(samples);
vectorMean256.increment(score);
}
mLog.info("DMR SOFT SYNC DETECTOR WARMUP - VECTOR 256: " + DECIMAL_FORMAT.format(vectorMean256.getResult()));
Mean vectorMean512 = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector512(samples);
vectorMean512.increment(score);
}
mLog.info("DMR SOFT SYNC DETECTOR WARMUP - VECTOR 512: " + DECIMAL_FORMAT.format(vectorMean512.getResult()));
//Start tests
scalarMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testScalar(samples);
scalarMean.increment(score);
}
mLog.info("DMR SOFT SYNC DETECTOR - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
vectorMean64.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector64(samples);
vectorMean64.increment(score);
}
mLog.info("DMR SOFT SYNC DETECTOR - VECTOR 64: " + DECIMAL_FORMAT.format(vectorMean64.getResult()));
vectorMean128.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector128(samples);
vectorMean128.increment(score);
}
mLog.info("DMR SOFT SYNC DETECTOR - VECTOR 128: " + DECIMAL_FORMAT.format(vectorMean128.getResult()));
vectorMean256.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector256(samples);
vectorMean256.increment(score);
}
mLog.info("DMR SOFT SYNC DETECTOR - VECTOR 256: " + DECIMAL_FORMAT.format(vectorMean256.getResult()));
vectorMean512.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector512(samples);
vectorMean512.increment(score);
}
mLog.info("DMR SOFT SYNC DETECTOR - VECTOR 512: " + DECIMAL_FORMAT.format(vectorMean512.getResult()));
Implementation best = Implementation.SCALAR;
double bestScore = scalarMean.getResult();
if(vectorMean64.getResult() > bestScore)
{
bestScore = vectorMean64.getResult();
best = Implementation.VECTOR_SIMD_64;
}
if(vectorMean128.getResult() > bestScore)
{
bestScore = vectorMean128.getResult();
best = Implementation.VECTOR_SIMD_128;
}
if(vectorMean256.getResult() > bestScore)
{
bestScore = vectorMean256.getResult();
best = Implementation.VECTOR_SIMD_256;
}
if(vectorMean512.getResult() > bestScore)
{
best = Implementation.VECTOR_SIMD_512;
}
setImplementation(best);
mLog.info("DMR SOFT SYNC DETECTOR - SET OPTIMAL IMPLEMENTATION TO:" + getImplementation());
}
private long testScalar(float[] samples)
{
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
for(float sample : samples)
{
mScalarDetector.process(sample);
}
count++;
}
return count;
}
private long testVector64(float[] samples)
{
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
for(float sample : samples)
{
mVectorDetector64.process(sample);
}
count++;
}
return count;
}
private long testVector128(float[] samples)
{
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
for(float sample : samples)
{
mVectorDetector128.process(sample);
}
count++;
}
return count;
}
private long testVector256(float[] samples)
{
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
for(float sample : samples)
{
mVectorDetector256.process(sample);
}
count++;
}
return count;
}
private long testVector512(float[] samples)
{
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
for(float sample : samples)
{
mVectorDetector512.process(sample);
}
count++;
}
return count;
}
public static void main(String[] args)
{
DMRSoftSyncCalibration calibration = new DMRSoftSyncCalibration();
try
{
calibration.calibrate();
}
catch(Exception e)
{
mLog.error("Error during calibration", e);
}
}
}