mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 16:47:31 -05:00
#35 Updates AM & NBFM decoders to use Adaptive Squelch, a power squelch that includes an adaptive noise floor monitor. Implements vectorized magnitude operations for AM & FM decoders. Adds talkgroup assignment and squelch controls to AM channel configuration editor. Implements new AM gain control that attempts to normalize audio gain quickly at beginning of call/transmission and maintains that gain across lifecycle of the call and resets the gain for the next call. (#1540)
Notes on usage: - When using either AM or FM squelch control use either the Heterodyne channelizer or if using the Polyphase channelizer, avoid using trunk tracking decoders like DMR or P25 or set the squelch threshold high enough to avoid changes in noise floor from polyphase channelizer where it can vary between using the one channel or the two-channel combined channel sources. Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
@@ -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
|
||||
@@ -63,8 +63,22 @@ public class VectorUtilities
|
||||
{
|
||||
if(i.length % species.length() != 0)
|
||||
{
|
||||
throw new IllegalArgumentException("I/Q buffer lengths [" + i.length + "] must be a power of 2 multiple of SIMD lane width [" +
|
||||
species.length() + "]");
|
||||
throw new IllegalArgumentException("I/Q buffer lengths [" + i.length + "] must be a power of 2 multiple of " +
|
||||
"SIMD lane width [" + species.length() + "]");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the I/Q sample array length to be an integer multiple of the SIMD lane width.
|
||||
* @param array samples
|
||||
* @param species used for SIMD operations
|
||||
*/
|
||||
public static void checkArrayLength(float[] array, VectorSpecies<Float> species)
|
||||
{
|
||||
if(array.length % species.length() != 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Buffer array length [" + array.length + "] must be a power of 2 multiple " +
|
||||
"of SIMD lane width [" + species.length() + "]");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,13 +19,13 @@
|
||||
|
||||
package io.github.dsheirer.vector.calibrate;
|
||||
|
||||
import io.github.dsheirer.dsp.am.AmDemodulatorCalibration;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
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.FmDemodulatorCalibration;
|
||||
import io.github.dsheirer.vector.calibrate.demodulator.SquelchingFmDemodulatorCalibration;
|
||||
import io.github.dsheirer.vector.calibrate.filter.FirFilterCalibration;
|
||||
import io.github.dsheirer.vector.calibrate.filter.RealDcRemovalCalibration;
|
||||
import io.github.dsheirer.vector.calibrate.filter.RealHalfBand11TapFilterCalibration;
|
||||
@@ -35,19 +35,19 @@ 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.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.window.WindowCalibration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Determines the optimal (scalar vs vector) class to use for the current CPU architecture.
|
||||
@@ -99,12 +99,14 @@ public class CalibrationManager
|
||||
sInstance.add(new AirspySampleConverterCalibration());
|
||||
sInstance.add(new AirspyUnpackedCalibration());
|
||||
sInstance.add(new AirspyUnpackedInterleavedCalibration());
|
||||
sInstance.add(new AmDemodulatorCalibration());
|
||||
sInstance.add(new ComplexGainCalibration());
|
||||
sInstance.add(new ComplexGainControlCalibration());
|
||||
sInstance.add(new ComplexOscillatorCalibration());
|
||||
sInstance.add(new ComplexMixerCalibration());
|
||||
sInstance.add(new FirFilterCalibration());
|
||||
sInstance.add(new FmDemodulatorCalibration());
|
||||
sInstance.add(new MagnitudeCalibration());
|
||||
sInstance.add(new RealDcRemovalCalibration());
|
||||
sInstance.add(new RealHalfBand11TapFilterCalibration());
|
||||
sInstance.add(new RealHalfBand15TapFilterCalibration());
|
||||
@@ -112,7 +114,6 @@ public class CalibrationManager
|
||||
sInstance.add(new RealHalfBand63TapFilterCalibration());
|
||||
sInstance.add(new RealHalfBandDefaultFilterCalibration());
|
||||
sInstance.add(new RealOscillatorCalibration());
|
||||
sInstance.add(new SquelchingFmDemodulatorCalibration());
|
||||
|
||||
// sInstance.add(new HilbertCalibration()); //Not currently used
|
||||
sInstance.add(new WindowCalibration()); //Not currently used
|
||||
|
||||
@@ -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
|
||||
@@ -35,6 +35,7 @@ public enum CalibrationType
|
||||
AIRSPY_SAMPLE_CONVERTER("Airspy Sample Converter", 1),
|
||||
AIRSPY_UNPACKED_INTERLEAVED_ITERATOR("Airspy Unpacked Interleaved Iterator", 1),
|
||||
AIRSPY_UNPACKED_ITERATOR("Airspy Unpacked Iterator", 1),
|
||||
AM_DEMODULATOR("AM Demodulator", 1),
|
||||
DC_REMOVAL_REAL("Real DC Removal Filter", 1),
|
||||
FILTER_FIR("FIR Filter", 1),
|
||||
FILTER_HALF_BAND_REAL_11_TAP("Real Half-Band Decimation Filter - 11 Tap", 1),
|
||||
@@ -42,9 +43,10 @@ public enum CalibrationType
|
||||
FILTER_HALF_BAND_REAL_23_TAP("Real Half-Band Decimation Filter - 23 Tap", 1),
|
||||
FILTER_HALF_BAND_REAL_63_TAP("Real Half-Band Decimation Filter - 63 Tap", 1),
|
||||
FILTER_HALF_BAND_REAL_DEFAULT("Real Half-Band Decimation Filter - Default", 1),
|
||||
FM_DEMODULATOR("FM Demodulator", 1),
|
||||
FM_DEMODULATOR("FM Demodulator", 2),
|
||||
GAIN_CONTROL_COMPLEX("Complex Gain Control", 1),
|
||||
HILBERT_TRANSFORM("Hilbert Transform", 1),
|
||||
MAGNITUDE("Magnitude", 1),
|
||||
MIXER_COMPLEX("Complex Mixer", 1),
|
||||
OSCILLATOR_REAL("Real Oscillator", 1),
|
||||
SQUELCHING_FM_DEMODULATOR("Squelching FM Demodulator", 1),
|
||||
|
||||
@@ -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,9 +19,12 @@
|
||||
|
||||
package io.github.dsheirer.vector.calibrate.demodulator;
|
||||
|
||||
import io.github.dsheirer.dsp.fm.IFmDemodulator;
|
||||
import io.github.dsheirer.dsp.fm.IDemodulator;
|
||||
import io.github.dsheirer.dsp.fm.ScalarFMDemodulator;
|
||||
import io.github.dsheirer.dsp.fm.VectorFMDemodulator;
|
||||
import io.github.dsheirer.dsp.fm.VectorFMDemodulator128;
|
||||
import io.github.dsheirer.dsp.fm.VectorFMDemodulator256;
|
||||
import io.github.dsheirer.dsp.fm.VectorFMDemodulator512;
|
||||
import io.github.dsheirer.dsp.fm.VectorFMDemodulator64;
|
||||
import io.github.dsheirer.vector.calibrate.Calibration;
|
||||
import io.github.dsheirer.vector.calibrate.CalibrationException;
|
||||
import io.github.dsheirer.vector.calibrate.CalibrationType;
|
||||
@@ -37,9 +40,11 @@ public class FmDemodulatorCalibration extends Calibration
|
||||
private static final int ITERATION_DURATION_MS = 1000;
|
||||
private static final int WARMUP_ITERATIONS = 5;
|
||||
private static final int TEST_ITERATIONS = 5;
|
||||
private IFmDemodulator mScalarDemodulator = new ScalarFMDemodulator();
|
||||
private IFmDemodulator mVectorDemodulator = new VectorFMDemodulator();
|
||||
|
||||
private IDemodulator mScalarDemodulator = new ScalarFMDemodulator();
|
||||
private IDemodulator mVectorDemodulator64 = new VectorFMDemodulator64();
|
||||
private IDemodulator mVectorDemodulator128 = new VectorFMDemodulator128();
|
||||
private IDemodulator mVectorDemodulator256 = new VectorFMDemodulator256();
|
||||
private IDemodulator mVectorDemodulator512 = new VectorFMDemodulator512();
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
@@ -64,15 +69,45 @@ public class FmDemodulatorCalibration extends Calibration
|
||||
|
||||
mLog.info("FM DEMODULATOR WARMUP - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
|
||||
|
||||
Mean vectorMean = new Mean();
|
||||
Mean vectorMean64 = new Mean();
|
||||
|
||||
for(int x = 0; x < WARMUP_ITERATIONS; x++)
|
||||
{
|
||||
long score = testVector(i, q);
|
||||
vectorMean.increment(score);
|
||||
long score = testVector64(i, q);
|
||||
vectorMean64.increment(score);
|
||||
}
|
||||
|
||||
mLog.info("FM DEMODULATOR WARMUP - VECTOR: " + DECIMAL_FORMAT.format(vectorMean.getResult()));
|
||||
mLog.info("FM 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("FM 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("FM 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("FM DEMODULATOR WARMUP - VECTOR 512: " + DECIMAL_FORMAT.format(vectorMean512.getResult()));
|
||||
|
||||
//Start tests
|
||||
scalarMean.clear();
|
||||
@@ -85,25 +120,74 @@ public class FmDemodulatorCalibration extends Calibration
|
||||
|
||||
mLog.info("FM DEMODULATOR - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
|
||||
|
||||
vectorMean.clear();
|
||||
vectorMean64.clear();
|
||||
|
||||
for(int x = 0; x < TEST_ITERATIONS; x++)
|
||||
{
|
||||
long score = testVector(i, q);
|
||||
vectorMean.increment(score);
|
||||
long score = testVector64(i, q);
|
||||
vectorMean64.increment(score);
|
||||
}
|
||||
|
||||
mLog.info("FM DEMODULATOR - VECTOR: " + DECIMAL_FORMAT.format(vectorMean.getResult()));
|
||||
mLog.info("FM DEMODULATOR - VECTOR 64: " + DECIMAL_FORMAT.format(vectorMean64.getResult()));
|
||||
|
||||
if(scalarMean.getResult() > vectorMean.getResult())
|
||||
vectorMean128.clear();
|
||||
|
||||
for(int x = 0; x < TEST_ITERATIONS; x++)
|
||||
{
|
||||
setImplementation(Implementation.SCALAR);
|
||||
long score = testVector128(i, q);
|
||||
vectorMean128.increment(score);
|
||||
}
|
||||
else
|
||||
|
||||
mLog.info("FM DEMODULATOR - VECTOR 128: " + DECIMAL_FORMAT.format(vectorMean128.getResult()));
|
||||
|
||||
vectorMean256.clear();
|
||||
|
||||
for(int x = 0; x < TEST_ITERATIONS; x++)
|
||||
{
|
||||
setImplementation(Implementation.VECTOR_SIMD_PREFERRED);
|
||||
long score = testVector256(i, q);
|
||||
vectorMean256.increment(score);
|
||||
}
|
||||
|
||||
mLog.info("FM 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("FM 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("FM DEMODULATOR - SET OPTIMAL IMPLEMENTATION TO:" + getImplementation());
|
||||
}
|
||||
|
||||
@@ -124,7 +208,7 @@ public class FmDemodulatorCalibration extends Calibration
|
||||
return count + (long)(accumulator * 0);
|
||||
}
|
||||
|
||||
private long testVector(float[] i, float[] q)
|
||||
private long testVector64(float[] i, float[] q)
|
||||
{
|
||||
double accumulator = 0.0;
|
||||
long count = 0;
|
||||
@@ -132,11 +216,73 @@ public class FmDemodulatorCalibration extends Calibration
|
||||
|
||||
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
|
||||
{
|
||||
float[] demodulated = mVectorDemodulator.demodulate(i, q);
|
||||
float[] demodulated = mVectorDemodulator64.demodulate(i, q);
|
||||
accumulator += demodulated[1];
|
||||
count++;
|
||||
}
|
||||
|
||||
return count + (long)(accumulator * 0);
|
||||
}
|
||||
|
||||
private long testVector128(float[] i, float[] q)
|
||||
{
|
||||
double accumulator = 0.0;
|
||||
long count = 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)
|
||||
{
|
||||
double accumulator = 0.0;
|
||||
long count = 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)
|
||||
{
|
||||
double accumulator = 0.0;
|
||||
long count = 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)
|
||||
{
|
||||
FmDemodulatorCalibration calibration = new FmDemodulatorCalibration();
|
||||
|
||||
try
|
||||
{
|
||||
calibration.calibrate();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
mLog.error("Error during calibration", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 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.fm.IFmDemodulator;
|
||||
import io.github.dsheirer.dsp.fm.ScalarSquelchingFMDemodulator;
|
||||
import io.github.dsheirer.dsp.fm.VectorSquelchingFMDemodulator;
|
||||
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 squelching FM demodulator options
|
||||
*/
|
||||
public class SquelchingFmDemodulatorCalibration extends Calibration
|
||||
{
|
||||
private static final float POWER_SQUELCH_ALPHA_DECAY = 0.0004f;
|
||||
private static final float POWER_SQUELCH_THRESHOLD_DB = -78.0f;
|
||||
private static final int POWER_SQUELCH_RAMP = 4;
|
||||
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 IFmDemodulator mScalar = new ScalarSquelchingFMDemodulator(POWER_SQUELCH_ALPHA_DECAY,
|
||||
POWER_SQUELCH_THRESHOLD_DB, POWER_SQUELCH_RAMP);
|
||||
private IFmDemodulator mVector = new VectorSquelchingFMDemodulator(POWER_SQUELCH_ALPHA_DECAY,
|
||||
POWER_SQUELCH_THRESHOLD_DB, POWER_SQUELCH_RAMP);
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
*/
|
||||
public SquelchingFmDemodulatorCalibration()
|
||||
{
|
||||
super(CalibrationType.SQUELCHING_FM_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("SQUELCHING FM DEMODULATOR WARMUP - SCALAR:" + DECIMAL_FORMAT.format(scalarMean.getResult()));
|
||||
|
||||
Mean vectorMean = new Mean();
|
||||
|
||||
for(int x = 0; x < WARMUP_ITERATIONS; x++)
|
||||
{
|
||||
long score = testVector(i, q);
|
||||
vectorMean.increment(score);
|
||||
}
|
||||
|
||||
mLog.info("SQUELCHING FM DEMODULATOR WARMUP - VECTOR:" + DECIMAL_FORMAT.format(vectorMean.getResult()));
|
||||
|
||||
//Test begins ...
|
||||
scalarMean.clear();
|
||||
|
||||
for(int x = 0; x < TEST_ITERATIONS; x++)
|
||||
{
|
||||
long score = testScalar(i, q);
|
||||
scalarMean.increment(score);
|
||||
}
|
||||
|
||||
mLog.info("SQUELCHING FM DEMODULATOR - SCALAR:" + DECIMAL_FORMAT.format(scalarMean.getResult()));
|
||||
|
||||
vectorMean.clear();
|
||||
|
||||
for(int x = 0; x < TEST_ITERATIONS; x++)
|
||||
{
|
||||
long score = testVector(i, q);
|
||||
vectorMean.increment(score);
|
||||
}
|
||||
|
||||
mLog.info("SQUELCHING FM DEMODULATOR - VECTOR:" + DECIMAL_FORMAT.format(vectorMean.getResult()));
|
||||
|
||||
if(scalarMean.getResult() > vectorMean.getResult())
|
||||
{
|
||||
setImplementation(Implementation.SCALAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
setImplementation(Implementation.VECTOR_SIMD_PREFERRED);
|
||||
}
|
||||
|
||||
mLog.info("SQUELCHING FM DEMODULATOR - SET OPTIMAL IMPLEMENTATION TO:" + getImplementation());
|
||||
}
|
||||
|
||||
private long testScalar(float[] i, float[] q)
|
||||
{
|
||||
double accumulator = 0.0;
|
||||
long count = 0;
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
|
||||
{
|
||||
float[] demodulated = mScalar.demodulate(i, q);
|
||||
accumulator += demodulated[1];
|
||||
count++;
|
||||
}
|
||||
|
||||
return count + (long)(accumulator * 0);
|
||||
}
|
||||
|
||||
private long testVector(float[] i, float[] q)
|
||||
{
|
||||
double accumulator = 0.0;
|
||||
long count = 0;
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
|
||||
{
|
||||
float[] demodulated = mVector.demodulate(i, q);
|
||||
accumulator += demodulated[1];
|
||||
count++;
|
||||
}
|
||||
|
||||
return count + (long)(accumulator * 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* 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
|
||||
* 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.magnitude;
|
||||
|
||||
import io.github.dsheirer.dsp.magnitude.IMagnitudeCalculator;
|
||||
import io.github.dsheirer.dsp.magnitude.ScalarMagnitudeCalculator;
|
||||
import io.github.dsheirer.dsp.magnitude.VectorMagnitudeCalculator128;
|
||||
import io.github.dsheirer.dsp.magnitude.VectorMagnitudeCalculator256;
|
||||
import io.github.dsheirer.dsp.magnitude.VectorMagnitudeCalculator512;
|
||||
import io.github.dsheirer.dsp.magnitude.VectorMagnitudeCalculator64;
|
||||
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 FM demodulator options
|
||||
*/
|
||||
public class MagnitudeCalibration 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 IMagnitudeCalculator mScalarMagnitude = new ScalarMagnitudeCalculator();
|
||||
private final IMagnitudeCalculator mVectorMagnitude64 = new VectorMagnitudeCalculator64();
|
||||
private final IMagnitudeCalculator mVectorMagnitude128 = new VectorMagnitudeCalculator128();
|
||||
private final IMagnitudeCalculator mVectorMagnitude256 = new VectorMagnitudeCalculator256();
|
||||
private final IMagnitudeCalculator mVectorMagnitude512 = new VectorMagnitudeCalculator512();
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
*/
|
||||
public MagnitudeCalibration()
|
||||
{
|
||||
super(CalibrationType.MAGNITUDE);
|
||||
}
|
||||
|
||||
@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("MAGNITUDE 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("MAGNITUDE 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("MAGNITUDE 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("MAGNITUDE 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("MAGNITUDE 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("MAGNITUDE - 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("MAGNITUDE - 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("MAGNITUDE - 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("MAGNITUDE - 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("MAGNITUDE - 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("MAGNITUDE - SET OPTIMAL IMPLEMENTATION TO:" + getImplementation());
|
||||
}
|
||||
|
||||
private long testScalar(float[] i, float[] q)
|
||||
{
|
||||
double accumulator = 0.0;
|
||||
long count = 0;
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
|
||||
{
|
||||
float[] demodulated = mScalarMagnitude.calculate(i, q);
|
||||
accumulator += demodulated[1];
|
||||
count++;
|
||||
}
|
||||
|
||||
return count + (long)(accumulator * 0);
|
||||
}
|
||||
|
||||
private long testVector64(float[] i, float[] q)
|
||||
{
|
||||
double accumulator = 0.0;
|
||||
long count = 0;
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
|
||||
{
|
||||
float[] demodulated = mVectorMagnitude64.calculate(i, q);
|
||||
accumulator += demodulated[1];
|
||||
count++;
|
||||
}
|
||||
|
||||
return count + (long)(accumulator * 0);
|
||||
}
|
||||
|
||||
private long testVector128(float[] i, float[] q)
|
||||
{
|
||||
double accumulator = 0.0;
|
||||
long count = 0;
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
|
||||
{
|
||||
float[] demodulated = mVectorMagnitude128.calculate(i, q);
|
||||
accumulator += demodulated[1];
|
||||
count++;
|
||||
}
|
||||
|
||||
return count + (long)(accumulator * 0);
|
||||
}
|
||||
|
||||
private long testVector256(float[] i, float[] q)
|
||||
{
|
||||
double accumulator = 0.0;
|
||||
long count = 0;
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
|
||||
{
|
||||
float[] demodulated = mVectorMagnitude256.calculate(i, q);
|
||||
accumulator += demodulated[1];
|
||||
count++;
|
||||
}
|
||||
|
||||
return count + (long)(accumulator * 0);
|
||||
}
|
||||
|
||||
private long testVector512(float[] i, float[] q)
|
||||
{
|
||||
double accumulator = 0.0;
|
||||
long count = 0;
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
|
||||
{
|
||||
float[] demodulated = mVectorMagnitude512.calculate(i, q);
|
||||
accumulator += demodulated[1];
|
||||
count++;
|
||||
}
|
||||
|
||||
return count + (long)(accumulator * 0);
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
MagnitudeCalibration calibration = new MagnitudeCalibration();
|
||||
|
||||
try
|
||||
{
|
||||
calibration.calibrate();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
mLog.error("Error during calibration", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user