Updates complex decimation filters to use either scalar or vector optimal implementation. (#1148)

Updates HackRF native byte buffers with automatic DC removal.
Creates new half-band channel source to replace the cic-based channel source in the heterodyne channelizer.  Resolves issue in RTL native buffer processing.  Creates a CACHED thread pool and reduces the number of threads for the SCHEDULED thread pool to 2.  Changes each of the channel source implementations to use a dedicated thread (Dispatcher class) instead of the scheduled thread pool, to reduce the amount of buffered/retained samples objects in memory. Lots of other small changes and tweaks.
Removes last of Reusable buffer code.  Updates DFTProcessor to use a single thread scheduled executor.  Updates Polyphase channelizer to use threads instead of an executor.  Removes a number of unused classes.
Commenting out window calibration.  Scalar is faster in both implementations.
Adds vector and scalar implementations for windows.  Repackages window and window type classes.
WIP adds vector implementations for Airspy non-interleaved buffer iterator and calibration plugins for both interleaved and non-interleaved buffer iterators.
WIP adds vector implementations for Airspy interleaved buffer iterator.
Work on developing scalar and vector implementations of airspy sample conversion and airspy native buffer processing.
Introduces new INativeBuffer framework where tuner raw samples are retained in their native (compressed) format until when they're needed and they are converted on-demand into smaller complex sample buffers to aid garbage collection.
Removes all usage of ReusableComplexBuffers and ReusableChannelREsultsBuffers.  Updates polyphase channelizer to be more efficient in output channel processing.
Updates ViterbiDecoder to change Map usage to array for memory efficiency.
Updates channel processors to used scalar implementation for gain and mixer, until the polyphase channel results can be fixed to be a multiple of the SIMD lane width.
Resolves final changes for the conversion from interleaved sample arrays to complexsamples buffers for distributing baseband samples to channels and processing chains.
Updates tuner channel sources and all decoders to receive new complex samples buffers, removing the previous reusable complex buffers as the default baseband samples buffer object.
Still to resolve is the ComplexMixer implementations.  Needs validation and a calibration implementation with an update to the complex mixer factory.
Updates the DMR decoder to use optimal (scalar vs vector) implementations of filter and AGC controls.
Updates the AM demodulator for separated I&Q float sample processing.
Code review and testing changes.
updates build script for runtime configuration.
Integrates calibration manager with main sdrtrunk application.  Updates NBFMDecoder to use new optimized FIR and Decimation filter options.
Updates real half-band decimation filters to select the optimal (scalar vs vector) implementation.
Adds calibration manager plugins.
Adds calibration manager and plugins to determine the optimal (scalar vs vector) implementation type to use for various classes of dsp components.
Adds vector squelching FM demodulator and cleans up the IIR filter and power squelch to use all floats.
Adds vector implementation of FM demodulator.  This introduces a new interface that accepts i/q samples as two separate float arrays, versus an interleaved array, which enables more efficient processing.  This new complex sample interface will be used across the codebase eventually.
Adds ComplexOscillator and a SIMD version VectorComplexOscillator.  Deprecates the LowPhaseNoiseOscillator because the ComplexOscillator is about 35% faster.  The vectorized version is about 43% faster when SIMD lane width is 8x.
Adds new vector complex filters and new real oscillators.  Note: the RealOscillator using straight Java math sin() function is 3x slower than the existing legacy implementation.  Will replace this with a complex oscillator that only uses the real part.
Updates ComplexFIRFilter to be 50% more efficient.
Adds 23 tap filter implementations.  Will not add 63-tap implementations because they are slower than the default vector implementation.
Adds 15-tap customized vector half band filters.
Adds initial custom complex vector half-band decimation filters for 11-tap and 15-tap decimation filters..
Adds vector complex half band filter implementations.  Note: performance of the generic 64-bit 2-lane filter is horrible and is not included.
Optimizes complex half-band filter to be 27% more efficient.
Implements vectorized real half-band filter implementations.
Implements a new FIR filter class that processes sample buffers instead of single sample at a time.
Refactored all of the calibratons to be time-duration based.  Testing on windows i7 gen 3 CPU showed that it took 1000x longer for one of the calibrations to run, versus my AMD 5800x.
Changed gradle jvm args so that the windows plaf export is always applied.
Updates gradle build script to ensure incubator module is included and to cleanup javafx library management for building runtime images.
Testing tweaks and changes.
Adds logging limiter to dispatcher for buffer overflows
Adds User Preferences editor for performing Vector/SIMD calibrations and new startup dialog prompting the user to perform calibrations.
Updates calibration manager and all calibration implementations to add warm-up and test phases and to reduce the overall time it takes to calibrate a system.

Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
Denny Sheirer
2022-03-04 08:45:05 -05:00
committed by GitHub
parent 5e9c239ea3
commit 0eec2e7ab8
403 changed files with 22916 additions and 15088 deletions

View File

@@ -0,0 +1,194 @@
/*
* *****************************************************************************
* 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;
import io.github.dsheirer.sample.complex.ComplexSamples;
import jdk.incubator.vector.FloatVector;
import jdk.incubator.vector.VectorMask;
import jdk.incubator.vector.VectorSpecies;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Utilities for working with Project Panama SIMD vectors in JDK 17+.
*/
public class VectorUtilities
{
private static final Logger mLog = LoggerFactory.getLogger(VectorUtilities.class);
private static boolean mSpeciesMismatchLogged = false;
/**
* Checks the species to determine if it is compatible with the preferred species for the runtime CPU
* and logs a warning if the species' lane width is wider than the preferred species ... which would be
* hugely inefficient.
*
* @param species to test
*/
public static void checkSpecies(VectorSpecies<Float> species)
{
if(FloatVector.SPECIES_PREFERRED.length() < species.length())
{
if(!mSpeciesMismatchLogged)
{
mLog.warn("CPU supports maximum SIMD instructions of " + FloatVector.SPECIES_PREFERRED);
mSpeciesMismatchLogged = true;
}
}
}
/**
* Checks the I/Q sample array length to be an integer multiple of the SIMD lane width.
* @param i samples
* @param q samples
* @param species used for SIMD operations
*/
public static void checkComplexArrayLength(float[] i, float[] q, VectorSpecies<Float> species)
{
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() + "]");
}
}
/**
* Checks the I/Q sample array length to be an integer multiple of the SIMD lane width.
* @param samples buffer
* @param species used for SIMD operations
*/
public static void checkComplexArrayLength(ComplexSamples samples, VectorSpecies<Float> species)
{
checkComplexArrayLength(samples.i(), samples.q(), species);
}
/**
* Creates a vector mask for deinterleaving I samples from an interleaved complex sample vector.
* @param species of SIMD
* @return vector mask
*/
public static VectorMask<Float> getIVectorMask(VectorSpecies<Float> species)
{
switch(species.length())
{
case 2:
return VectorMask.fromArray(species, new boolean[]{true,false}, 0);
case 4:
return VectorMask.fromArray(species, new boolean[]{true,false,true,false}, 0);
case 8:
return VectorMask.fromArray(species, new boolean[]{true,false,true,false,true,false,true,false}, 0);
case 16:
return VectorMask.fromArray(species, new boolean[]{true,false,true,false,true,false,true,false,true,
false,true,false,true,false,true,false}, 0);
default:
throw new IllegalArgumentException("Unrecognized vector species: " + species);
}
}
/**
* Creates a vector mask for deinterleaving Q samples from an interleaved complex sample vector.
* @param species of SIMD
* @return vector mask
*/
public static VectorMask<Float> getQVectorMask(VectorSpecies<Float> species)
{
switch(species.length())
{
case 2:
return VectorMask.fromArray(species, new boolean[]{false,true}, 0);
case 4:
return VectorMask.fromArray(species, new boolean[]{false,true,false,true}, 0);
case 8:
return VectorMask.fromArray(species, new boolean[]{false,true,false,true,false,true,false,true}, 0);
case 16:
return VectorMask.fromArray(species, new boolean[]{false,true,false,true,false,true,false,true,false,true,
false,true,false,true,false,true}, 0);
default:
throw new IllegalArgumentException("Unrecognized vector species: " + species);
}
}
/**
* Creates an index map for routing inphase samples into a complex sample array
* @param species to determine lane width
* @return index map
*/
public static int[] getIIndexMap(VectorSpecies<Float> species)
{
switch(species.length())
{
case 2:
return new int[]{0,2};
case 4:
return new int[]{0,2,4,6};
case 8:
return new int[]{0,2,4,6,8,10,12,14};
case 16:
return new int[]{0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30};
default:
throw new IllegalArgumentException("Unrecognized vector species: " + species);
}
}
/**
* Creates an index map for routing quadrature samples into a complex sample array
* @param species to determine lane width
* @return index map
*/
public static int[] getQIndexMap(VectorSpecies<Float> species)
{
switch(species.length())
{
case 2:
return new int[]{1,3};
case 4:
return new int[]{1,3,5,7};
case 8:
return new int[]{1,3,5,7,9,11,13,15};
case 16:
return new int[]{1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31};
default:
throw new IllegalArgumentException("Unrecognized vector species: " + species);
}
}
/**
* Interleaves the samples from the I and Q vectors into a complex sample array
* @param iVector samples
* @param qVector samples
* @return interleaved sample array
*/
public static float[] interleave(FloatVector iVector, FloatVector qVector)
{
float[] interleaved = new float[iVector.length() * 2];
float[] i = new float[iVector.length()];
float[] q = new float[qVector.length()];
iVector.intoArray(i, 0);
qVector.intoArray(q, 0);
for(int x = 0; x < i.length; x++)
{
interleaved[2 * x] = i[x];
interleaved[2 * x + 1] = q[x];
}
return interleaved;
}
}

View File

@@ -0,0 +1,143 @@
/*
* *****************************************************************************
* 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;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DecimalFormat;
import java.util.Random;
import java.util.prefs.Preferences;
/**
* Abstract calibration plugin base class
*/
public abstract class Calibration
{
protected static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.0");
public static final Logger mLog = LoggerFactory.getLogger(Calibration.class);
private Preferences mPreferences = Preferences.userNodeForPackage(Calibration.class);
private CalibrationType mType;
private Implementation mImplementation;
/**
* Constructs an instance
* @param type
*/
public Calibration(CalibrationType type)
{
mType = type;
}
public Logger getLogger()
{
return mLog;
}
/**
* Type of calibration plugin
*/
public CalibrationType getType()
{
return mType;
}
/**
* Indicates if this plugin is calibrated.
*/
public boolean isCalibrated()
{
return getImplementation() != Implementation.UNCALIBRATED;
}
/**
* Resets calibration status to uncalibrated for the plugin
*/
public void reset()
{
setImplementation(Implementation.UNCALIBRATED);
}
/**
* Optimal implementation for this plugin
* @return implementation or uncalibrated if this plugin has not yet been calibrated
*/
public Implementation getImplementation()
{
if(mImplementation == null)
{
String implementation = mPreferences.get(getType().getPreferenceKey(), Implementation.UNCALIBRATED.name());
mImplementation = Implementation.valueOf(implementation);
}
return mImplementation;
}
/**
* Sets the optimal implementation as determined via calibration.
* @param implementation to set
*/
protected void setImplementation(Implementation implementation)
{
mImplementation = implementation;
mPreferences.put(getType().getPreferenceKey(), implementation.name());
}
/**
* Executes calibration for the plugin
*/
public abstract void calibrate() throws CalibrationException;
/**
* Generates an array of floating point samples in the range -1.0 - 1.0
* @param size of array
* @return generated samples
*/
protected float[] getFloatSamples(int size)
{
Random random = new Random();
float[] samples = new float[size];
for(int x = 0; x < samples.length; x++)
{
samples[x] = random.nextFloat() * 2.0f - 1.0f;
}
return samples;
}
/**
* Generates an array of floating point samples in the range -1.0 - 1.0
* @param size of array
* @return generated samples
*/
protected short[] getShortSamples(int size)
{
Random random = new Random();
short[] samples = new short[size];
for(int x = 0; x < samples.length; x++)
{
samples[x] = (short)((random.nextFloat() * 2.0f - 1.0f) * Short.MAX_VALUE);
}
return samples;
}
}

View File

@@ -0,0 +1,17 @@
package io.github.dsheirer.vector.calibrate;
/**
* Error encountered while calibrating
*/
public class CalibrationException extends Exception
{
/**
* Constructs a new instance
* @param description of the error
* @param error nested
*/
public CalibrationException(String description, Exception error)
{
super(description, error);
}
}

View File

@@ -0,0 +1,294 @@
/*
* *****************************************************************************
* 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;
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;
import io.github.dsheirer.vector.calibrate.filter.RealHalfBand15TapFilterCalibration;
import io.github.dsheirer.vector.calibrate.filter.RealHalfBand23TapFilterCalibration;
import io.github.dsheirer.vector.calibrate.filter.RealHalfBand63TapFilterCalibration;
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.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;
/**
* Determines the optimal (scalar vs vector) class to use for the current CPU architecture.
*/
public class CalibrationManager
{
private static final Logger mLog = LoggerFactory.getLogger(CalibrationManager.class);
private Map<CalibrationType, Calibration> mCalibrationMap = new HashMap<>();
private static CalibrationManager sInstance;
private static VectorCalibrationPreference sVectorCalibrationPreference;
/**
* Uses the singleton pattern to construct a single instance.
*/
private CalibrationManager()
{
}
/**
* Access a singleton instance of this class, initializing the instance with the
* specified User Preferences instance, if it hasn't already been intitialized.
*
* Note: invoke this method first with a preferences instance to ensure it is the one that is used.
*/
public static CalibrationManager getInstance(UserPreferences userPreferences)
{
if(sVectorCalibrationPreference == null)
{
sVectorCalibrationPreference = userPreferences.getVectorCalibrationPreference();
}
return getInstance();
}
/**
* Access a singleton instance of this class.
*/
public static CalibrationManager getInstance()
{
if(sInstance == null)
{
if(sVectorCalibrationPreference == null)
{
sVectorCalibrationPreference = new UserPreferences().getVectorCalibrationPreference();
}
sInstance = new CalibrationManager();
sInstance.add(new AirspySampleConverterCalibration());
sInstance.add(new AirspyUnpackedCalibration());
sInstance.add(new AirspyUnpackedInterleavedCalibration());
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 RealDcRemovalCalibration());
sInstance.add(new RealHalfBand11TapFilterCalibration());
sInstance.add(new RealHalfBand15TapFilterCalibration());
sInstance.add(new RealHalfBand23TapFilterCalibration());
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
}
return sInstance;
}
/**
* Adds the calibration to the map of calibrations for this manager.
* @param calibration to add
*/
private void add(Calibration calibration)
{
if(mCalibrationMap.containsKey(calibration.getType()))
{
throw new IllegalStateException("Calibration Type [" + calibration.getType() +
"] is already registered for [" + mCalibrationMap.get(calibration.getType()).getClass());
}
mCalibrationMap.put(calibration.getType(), calibration);
}
/**
* List of calibration types available
*/
public List<CalibrationType> getCalibrationTypes()
{
return List.copyOf(mCalibrationMap.keySet());
}
/**
* Access a calibration by type
* @param type of calibration
* @return calibration instance, or null.
*/
public Calibration getCalibration(CalibrationType type)
{
return mCalibrationMap.get(type);
}
/**
* Identifies the optimal operation for the calibration type.
* @param type of calibration
* @return operation
*/
public Implementation getImplementation(CalibrationType type)
{
if(sVectorCalibrationPreference.isVectorEnabled())
{
Calibration calibration = getCalibration(type);
if(calibration != null)
{
return calibration.getImplementation();
}
return Implementation.UNCALIBRATED;
}
return Implementation.SCALAR;
}
/**
* Indicates if all calibrations are calibrated.
* @return true if all calibrations are calibrated or if there are no calibrations registered.
*/
public boolean isCalibrated()
{
for(Calibration calibration: mCalibrationMap.values())
{
if(!calibration.isCalibrated())
{
return false;
}
}
return true;
}
/**
* Resets all calibrations to an uncalibrated state.
*/
public void reset()
{
for(Calibration calibration: mCalibrationMap.values())
{
calibration.reset();
}
}
/**
* Resets a specific calibration type.
*/
public void reset(CalibrationType type)
{
Calibration calibration = mCalibrationMap.get(type);
if(calibration != null)
{
calibration.reset();
}
}
/**
* Calibrates any calibrations that are not currently calibrated
* @throws CalibrationException if any errors are encountered by any of the calibrations.
*/
public void calibrate() throws CalibrationException
{
List<Calibration> uncalibrated = getUncalibrated();
if(uncalibrated.isEmpty())
{
mLog.info("No additional calibrations are required at this time.");
}
else
{
mLog.info("Calibrating software for optimal performance on this computer.");
mLog.info("*** Please be patient, this may take a few minutes ***");
int calibrationCounter = 0;
for(Calibration calibration: uncalibrated)
{
if(!calibration.isCalibrated())
{
mLog.info("Calibrating [" + ++calibrationCounter + " of " + uncalibrated.size() +
"] Type: " + calibration.getType());
calibration.calibrate();
}
}
mLog.info("Calibration Complete!");
}
}
/**
* List of calibrations that need to be performed.
*/
public List<Calibration> getUncalibrated()
{
List<Calibration> uncalibrated = new ArrayList<>();
for(Calibration calibration: mCalibrationMap.values())
{
if(!calibration.isCalibrated())
{
uncalibrated.add(calibration);
}
}
//Sort by calibration type
Collections.sort(uncalibrated, Comparator.comparing(Calibration::getType));
return uncalibrated;
}
public static void main(String[] args)
{
CalibrationManager manager = getInstance();
// manager.reset();
manager.reset(CalibrationType.WINDOW);
if(!manager.isCalibrated())
{
try
{
manager.calibrate();
}
catch(Exception e)
{
e.printStackTrace();
}
}
System.out.println("Complete");
}
}

View File

@@ -0,0 +1,92 @@
/*
* *****************************************************************************
* 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;
/**
* Calibrations used by the system
*
* Version numbers in each calibration can be incremented any time the calibration changes
* so that the calibration will automatically run.
*/
public enum CalibrationType
{
//There's an oddity with these two vector implementations where it takes ~30x longer when it runs
//after any other calibrations ... so we always sort to top to run this one first
OSCILLATOR_COMPLEX("Complex Oscillator", 1),
GAIN_COMPLEX("Complex Gain", 1),
AIRSPY_SAMPLE_CONVERTER("Airspy Sample Converter", 1),
AIRSPY_UNPACKED_INTERLEAVED_ITERATOR("Airspy Unpacked Interleaved Iterator", 1),
AIRSPY_UNPACKED_ITERATOR("Airspy Unpacked Iterator", 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),
FILTER_HALF_BAND_REAL_15_TAP("Real Half-Band Decimation Filter - 15 Tap", 1),
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),
GAIN_CONTROL_COMPLEX("Complex Gain Control", 1),
HILBERT_TRANSFORM("Hilbert Transform", 1),
MIXER_COMPLEX("Complex Mixer", 1),
OSCILLATOR_REAL("Real Oscillator", 1),
SQUELCHING_FM_DEMODULATOR("Squelching FM Demodulator", 1),
WINDOW("Window", 1);
private String mDescription;
private int mVersion;
/**
* Constructs an instance
* @param description
* @param version of the calibration.
*/
CalibrationType(String description, int version)
{
mDescription = description;
mVersion = version;
}
/**
* Formulates a unique value for the entry for use as a key value.
*/
public String getPreferenceKey()
{
return name() + " - V" + getVersion();
}
public String getDescription()
{
return mDescription;
}
/**
* Version of the calibration
*/
public int getVersion()
{
return mVersion;
}
@Override public String toString()
{
return getDescription();
}
}

View File

@@ -0,0 +1,15 @@
package io.github.dsheirer.vector.calibrate;
/**
* Identifies the optimal implementation (Scalar vs Vector) identified through calibration testing
*/
public enum Implementation
{
SCALAR,
VECTOR_SIMD_PREFERRED,
VECTOR_SIMD_64,
VECTOR_SIMD_128,
VECTOR_SIMD_256,
VECTOR_SIMD_512,
UNCALIBRATED;
}

View File

@@ -0,0 +1,138 @@
/*
* *****************************************************************************
* 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.airspy;
import io.github.dsheirer.buffer.airspy.ScalarUnpackedSampleConverter;
import io.github.dsheirer.buffer.airspy.VectorUnpackedSampleConverter;
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;
import java.nio.ByteBuffer;
public class AirspySampleConverterCalibration extends Calibration
{
private static final int BUFFER_SIZE = 262144;
private static final int ITERATION_DURATION_MS = 1000;
private static final int WARM_UP_ITERATIONS = 5;
private static final int TEST_ITERATIONS = 5;
/**
* Constructs an instance
*/
public AirspySampleConverterCalibration()
{
super(CalibrationType.AIRSPY_SAMPLE_CONVERTER);
}
@Override
public void calibrate() throws CalibrationException
{
Mean scalarMean = new Mean();
Mean vectorMean = new Mean();
byte[] samples = new byte[BUFFER_SIZE];
ByteBuffer buffer = ByteBuffer.wrap(samples);
for(int scalarTest = 0; scalarTest < WARM_UP_ITERATIONS; scalarTest++)
{
long score = testScalar(buffer);
scalarMean.increment(score);
}
mLog.info("AIRSPY CONVERTER WARMUP - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
for(int vectorTest = 0; vectorTest < WARM_UP_ITERATIONS; vectorTest++)
{
long score = testVector(buffer);
vectorMean.increment(score);
}
mLog.info("AIRSPY CONVERTER WARMUP - VECTOR: " + DECIMAL_FORMAT.format(vectorMean.getResult()));
scalarMean.clear();
vectorMean.clear();
for(int scalarTest = 0; scalarTest < TEST_ITERATIONS; scalarTest++)
{
long score = testScalar(buffer);
scalarMean.increment(score);
}
mLog.info("AIRSPY CONVERTER - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
for(int vectorTest = 0; vectorTest < TEST_ITERATIONS; vectorTest++)
{
long score = testVector(buffer);
vectorMean.increment(score);
}
mLog.info("AIRSPY CONVERTER - VECTOR: " + DECIMAL_FORMAT.format(vectorMean.getResult()));
if(scalarMean.getResult() > vectorMean.getResult())
{
setImplementation(Implementation.SCALAR);
}
else
{
setImplementation(Implementation.VECTOR_SIMD_PREFERRED);
}
mLog.info("AIRSPY CONVERTER - SETTING OPTIMAL IMPLEMENTATION TO: " + getImplementation());
}
private long testScalar(ByteBuffer buffer)
{
long start = System.currentTimeMillis();
ScalarUnpackedSampleConverter scalor = new ScalarUnpackedSampleConverter();
long count = 0;
long accumulator = 0;
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
short[] converted = scalor.convert(buffer);
accumulator += converted[2];
count++;
}
return count + (accumulator * 0);
}
private long testVector(ByteBuffer buffer)
{
VectorUnpackedSampleConverter vector = new VectorUnpackedSampleConverter();
long start = System.currentTimeMillis();
long accumulator = 0;
long count = 0;
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
short[] converted = vector.convert(buffer);
accumulator += converted[2];
count++;
}
return count + (accumulator * 0);
}
}

View File

@@ -0,0 +1,309 @@
/*
* *****************************************************************************
* 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.airspy;
import io.github.dsheirer.buffer.airspy.AirspyBufferIterator;
import io.github.dsheirer.buffer.airspy.AirspyBufferIteratorScalar;
import io.github.dsheirer.buffer.airspy.AirspyBufferIteratorVector128Bits;
import io.github.dsheirer.buffer.airspy.AirspyBufferIteratorVector256Bits;
import io.github.dsheirer.buffer.airspy.AirspyBufferIteratorVector512Bits;
import io.github.dsheirer.buffer.airspy.AirspyBufferIteratorVector64Bits;
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 org.apache.commons.math3.stat.descriptive.moment.Mean;
/**
* Calculates optimal implementation (SCALAR vs VECTOR) for non-interleaved airspy native buffers.
*/
public class AirspyUnpackedCalibration extends Calibration
{
private static final int BUFFER_SIZE = 131072;
private static final int ITERATION_DURATION_MS = 1000;
private static final int WARMUP_ITERATIONS = 5;
private static final int TEST_ITERATIONS = 5;
/**
* Constructs an instance
*/
public AirspyUnpackedCalibration()
{
super(CalibrationType.AIRSPY_UNPACKED_ITERATOR);
}
@Override
public void calibrate() throws CalibrationException
{
short[] samples = getShortSamples(BUFFER_SIZE);
short[] residualI = getShortSamples(AirspyBufferIterator.I_OVERLAP);
short[] residualQ = getShortSamples(AirspyBufferIterator.Q_OVERLAP);
//Warm-Up Phase ....
Mean scalarMean = new Mean();
for(int warmup = 0; warmup < WARMUP_ITERATIONS; warmup++)
{
long score = testScalar(samples, residualI, residualQ);
scalarMean.increment(score);
}
mLog.info("AIRSPY UNPACKED WARMUP - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
switch(FloatVector.SPECIES_PREFERRED.length())
{
//Deliberate fall-through of each case statement so that we can test the largest
//SIMD lane width supported by hardware down to the smallest SIMD lane width.
case 16:
{
Mean vector512Mean = new Mean();
for(int warmup = 0; warmup < WARMUP_ITERATIONS; warmup++)
{
long score = testVector512(samples, residualI, residualQ);
vector512Mean.increment(score);
}
mLog.info("AIRSPY UNPACKED WARMUP - VECTOR 512: " + DECIMAL_FORMAT.format(vector512Mean.getResult()));
}
case 8:
{
Mean vector256Mean = new Mean();
for(int warmup = 0; warmup < WARMUP_ITERATIONS; warmup++)
{
long score = testVector256(samples, residualI, residualQ);
vector256Mean.increment(score);
}
mLog.info("AIRSPY UNPACKED WARMUP - VECTOR 256: " + DECIMAL_FORMAT.format(vector256Mean.getResult()));
}
case 4:
{
Mean vector128Mean = new Mean();
for(int warmup = 0; warmup < WARMUP_ITERATIONS; warmup++)
{
long score = testVector128(samples, residualI, residualQ);
vector128Mean.increment(score);
}
mLog.info("AIRSPY UNPACKED WARMUP - VECTOR 128: " + DECIMAL_FORMAT.format(vector128Mean.getResult()));
}
case 2:
{
Mean vector64Mean = new Mean();
for(int warmup = 0; warmup < WARMUP_ITERATIONS; warmup++)
{
long score = testVector64(samples, residualI, residualQ);
vector64Mean.increment(score);
}
mLog.info("AIRSPY UNPACKED WARMUP - VECTOR 64: " + DECIMAL_FORMAT.format(vector64Mean.getResult()));
}
}
//Test Phase ....
scalarMean.clear();
for(int test = 0; test < TEST_ITERATIONS; test++)
{
long score = testScalar(samples, residualI, residualQ);
scalarMean.increment(score);
}
double bestScore = scalarMean.getResult();
setImplementation(Implementation.SCALAR);
mLog.info("AIRSPY UNPACKED - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
switch(FloatVector.SPECIES_PREFERRED.length())
{
//Deliberate fall-through of each case statement so that we can test the largest
//SIMD lane width supported by hardware down to the smallest SIMD lane width.
case 16:
{
Mean vector512Mean = new Mean();
for(int test = 0; test < TEST_ITERATIONS; test++)
{
long score = testVector512(samples, residualI, residualQ);
vector512Mean.increment(score);
}
mLog.info("AIRSPY UNPACKED - VECTOR 512: " + DECIMAL_FORMAT.format(vector512Mean.getResult()));
if(vector512Mean.getResult() > bestScore)
{
bestScore = vector512Mean.getResult();
setImplementation(Implementation.VECTOR_SIMD_512);
}
}
case 8:
{
Mean vector256Mean = new Mean();
for(int test = 0; test < TEST_ITERATIONS; test++)
{
long score = testVector256(samples, residualI, residualQ);
vector256Mean.increment(score);
}
mLog.info("AIRSPY UNPACKED - VECTOR 256: " + DECIMAL_FORMAT.format(vector256Mean.getResult()));
if(vector256Mean.getResult() > bestScore)
{
bestScore = vector256Mean.getResult();
setImplementation(Implementation.VECTOR_SIMD_256);
}
}
case 4:
{
Mean vector128Mean = new Mean();
for(int test = 0; test < TEST_ITERATIONS; test++)
{
long score = testVector128(samples, residualI, residualQ);
vector128Mean.increment(score);
}
mLog.info("AIRSPY UNPACKED - VECTOR 128: " + DECIMAL_FORMAT.format(vector128Mean.getResult()));
if(vector128Mean.getResult() > bestScore)
{
bestScore = vector128Mean.getResult();
setImplementation(Implementation.VECTOR_SIMD_128);
}
}
case 2:
{
Mean vector64Mean = new Mean();
for(int test = 0; test < TEST_ITERATIONS; test++)
{
long score = testVector64(samples, residualI, residualQ);
vector64Mean.increment(score);
}
mLog.info("AIRSPY UNPACKED - VECTOR 64: " + DECIMAL_FORMAT.format(vector64Mean.getResult()));
if(vector64Mean.getResult() > bestScore)
{
setImplementation(Implementation.VECTOR_SIMD_64);
}
}
}
mLog.info("AIRSPY UNPACKED - SET OPTIMAL IMPLEMENTATION TO: " + getImplementation());
}
private long testScalar(short[] samples, short[] residualI, short[] residualQ)
{
long start = System.currentTimeMillis();
long accumulator = 0;
long count = 0;
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
AirspyBufferIteratorScalar iterator = new AirspyBufferIteratorScalar(samples, residualI,
residualQ, 0.0f, System.currentTimeMillis());
while(iterator.hasNext())
{
accumulator += iterator.next().i()[2];
count++;
}
}
return count + (accumulator * 0);
}
private long testVector64(short[] samples, short[] residualI, short[] residualQ)
{
long start = System.currentTimeMillis();
long accumulator = 0;
long count = 0;
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
AirspyBufferIteratorVector64Bits iterator = new AirspyBufferIteratorVector64Bits(samples, residualI,
residualQ, 0.0f, System.currentTimeMillis());
while(iterator.hasNext())
{
accumulator += iterator.next().i()[2];
count++;
}
}
return count + (accumulator * 0);
}
private long testVector128(short[] samples, short[] residualI, short[] residualQ)
{
long start = System.currentTimeMillis();
long accumulator = 0;
long count = 0;
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
AirspyBufferIteratorVector128Bits iterator = new AirspyBufferIteratorVector128Bits(samples, residualI,
residualQ, 0.0f, System.currentTimeMillis());
while(iterator.hasNext())
{
accumulator += iterator.next().i()[2];
count++;
}
}
return count + (accumulator * 0);
}
private long testVector256(short[] samples, short[] residualI, short[] residualQ)
{
long start = System.currentTimeMillis();
long accumulator = 0;
long count = 0;
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
AirspyBufferIteratorVector256Bits iterator =
new AirspyBufferIteratorVector256Bits(samples, residualI, residualQ, 0.0f, System.currentTimeMillis());
while(iterator.hasNext())
{
accumulator += iterator.next().i()[2];
count++;
}
}
return count + (accumulator * 0);
}
private long testVector512(short[] samples, short[] residualI, short[] residualQ)
{
long start = System.currentTimeMillis();
long accumulator = 0;
long count = 0;
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
AirspyBufferIteratorVector512Bits iterator =
new AirspyBufferIteratorVector512Bits(samples, residualI, residualQ, 0.0f, System.currentTimeMillis());
while(iterator.hasNext())
{
accumulator += iterator.next().i()[2];
count++;
}
}
return count + (accumulator * 0);
}
}

View File

@@ -0,0 +1,321 @@
/*
* *****************************************************************************
* 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.airspy;
import io.github.dsheirer.buffer.airspy.AirspyBufferIterator;
import io.github.dsheirer.buffer.airspy.AirspyInterleavedBufferIteratorScalar;
import io.github.dsheirer.buffer.airspy.AirspyInterleavedBufferIteratorVector128Bits;
import io.github.dsheirer.buffer.airspy.AirspyInterleavedBufferIteratorVector256Bits;
import io.github.dsheirer.buffer.airspy.AirspyInterleavedBufferIteratorVector512Bits;
import io.github.dsheirer.buffer.airspy.AirspyInterleavedBufferIteratorVector64Bits;
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 org.apache.commons.math3.stat.descriptive.moment.Mean;
/**
* Calculates optimal implementation (SCALAR vs VECTOR) for interleaved airspy native buffers.
*/
public class AirspyUnpackedInterleavedCalibration extends Calibration
{
private static final int BUFFER_SIZE = 131072;
private static final int ITERATION_DURATION_MS = 1000;
private static final int WARMUP_ITERATIONS = 5;
private static final int TEST_ITERATIONS = 5;
/**
* Constructs an instance
*/
public AirspyUnpackedInterleavedCalibration()
{
super(CalibrationType.AIRSPY_UNPACKED_INTERLEAVED_ITERATOR);
}
@Override
public void calibrate() throws CalibrationException
{
short[] samples = getShortSamples(BUFFER_SIZE);
short[] residualI = getShortSamples(AirspyBufferIterator.I_OVERLAP);
short[] residualQ = getShortSamples(AirspyBufferIterator.Q_OVERLAP);
//Warm-Up Phase ....
Mean scalarMean = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = calibrateScalar(samples, residualI, residualQ);
scalarMean.increment(score);
}
mLog.info("AIRSPY UNPACKED INTERLEAVED WARMUP - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
switch(FloatVector.SPECIES_PREFERRED.length())
{
//Deliberate fall-through of each case statement so that we can test the largest
//SIMD lane width supported by hardware down to the smallest SIMD lane width.
case 16:
{
Mean vectorMean = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = calibrateVector512(samples, residualI, residualQ);
vectorMean.increment(score);
}
mLog.info("AIRSPY UNPACKED INTERLEAVED WARMUP - VECTOR 512: " + DECIMAL_FORMAT.format(vectorMean.getResult()));
}
case 8:
{
Mean vectorMean = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = calibrateVector256(samples, residualI, residualQ);
vectorMean.increment(score);
}
mLog.info("AIRSPY UNPACKED INTERLEAVED WARMUP - VECTOR 256: " + DECIMAL_FORMAT.format(vectorMean.getResult()));
}
case 4:
{
Mean vectorMean = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = calibrateVector128(samples, residualI, residualQ);
vectorMean.increment(score);
}
mLog.info("AIRSPY UNPACKED INTERLEAVED WARMUP - VECTOR 128: " + DECIMAL_FORMAT.format(vectorMean.getResult()));
}
case 2:
{
Mean vectorMean = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = calibrateVector64(samples, residualI, residualQ);
vectorMean.increment(score);
}
mLog.info("AIRSPY UNPACKED INTERLEAVED WARMUP - VECTOR 64: " + DECIMAL_FORMAT.format(vectorMean.getResult()));
}
//Test Phase ....
scalarMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = calibrateScalar(samples, residualI, residualQ);
scalarMean.increment(score);
}
double bestScore = scalarMean.getResult();
setImplementation(Implementation.SCALAR);
mLog.info("AIRSPY UNPACKED INTERLEAVED - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
switch(FloatVector.SPECIES_PREFERRED.length())
{
//Deliberate fall-through of each case statement so that we can test the largest
//SIMD lane width supported by hardware down to the smallest SIMD lane width.
case 16:
{
Mean vectorMean = new Mean();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = calibrateVector512(samples, residualI, residualQ);
vectorMean.increment(score);
}
if(vectorMean.getResult() > bestScore)
{
bestScore = vectorMean.getResult();
setImplementation(Implementation.VECTOR_SIMD_512);
}
mLog.info("AIRSPY UNPACKED INTERLEAVED - VECTOR 512: " + DECIMAL_FORMAT.format(vectorMean.getResult()));
}
case 8:
{
Mean vectorMean = new Mean();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = calibrateVector256(samples, residualI, residualQ);
vectorMean.increment(score);
}
if(vectorMean.getResult() > bestScore)
{
bestScore = vectorMean.getResult();
setImplementation(Implementation.VECTOR_SIMD_256);
}
mLog.info("AIRSPY UNPACKED INTERLEAVED - VECTOR 256: " + DECIMAL_FORMAT.format(vectorMean.getResult()));
}
case 4:
{
Mean vectorMean = new Mean();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = calibrateVector128(samples, residualI, residualQ);
vectorMean.increment(score);
}
if(vectorMean.getResult() > bestScore)
{
bestScore = vectorMean.getResult();
setImplementation(Implementation.VECTOR_SIMD_128);
}
mLog.info("AIRSPY UNPACKED INTERLEAVED - VECTOR 128: " + DECIMAL_FORMAT.format(vectorMean.getResult()));
}
case 2:
{
Mean vectorMean = new Mean();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = calibrateVector64(samples, residualI, residualQ);
vectorMean.increment(score);
}
if(vectorMean.getResult() > bestScore)
{
setImplementation(Implementation.VECTOR_SIMD_64);
}
mLog.info("AIRSPY UNPACKED INTERLEAVED - VECTOR 64: " + DECIMAL_FORMAT.format(vectorMean.getResult()));
}
}
}
mLog.info("AIRSPY UNPACKED INTERLEAVED - SET OPTIMAL IMPLEMENTATION TO: " + getImplementation());
}
private long calibrateScalar(short[] samples, short[] residualI, short[] residualQ)
{
long start = System.currentTimeMillis();
long accumulator = 0;
long count = 0;
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
AirspyInterleavedBufferIteratorScalar iterator = new AirspyInterleavedBufferIteratorScalar(samples, residualI,
residualQ, 0.0f, System.currentTimeMillis());
while(iterator.hasNext())
{
accumulator += iterator.next().samples()[2];
count++;
}
}
return count + (accumulator * 0);
}
private long calibrateVector64(short[] samples, short[] residualI, short[] residualQ)
{
long start = System.currentTimeMillis();
long accumulator = 0;
long count = 0;
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
AirspyInterleavedBufferIteratorVector64Bits iterator = new AirspyInterleavedBufferIteratorVector64Bits(samples, residualI,
residualQ, 0.0f, System.currentTimeMillis());
while(iterator.hasNext())
{
accumulator += iterator.next().samples()[2];
count++;
}
}
return count + (accumulator * 0);
}
private long calibrateVector128(short[] samples, short[] residualI, short[] residualQ)
{
long start = System.currentTimeMillis();
long accumulator = 0;
long count = 0;
for(int x = 0; x < ITERATION_DURATION_MS; x++)
{
AirspyInterleavedBufferIteratorVector128Bits iterator = new AirspyInterleavedBufferIteratorVector128Bits(samples, residualI,
residualQ, 0.0f, System.currentTimeMillis());
while(iterator.hasNext())
{
accumulator += iterator.next().samples()[2];
count++;
}
}
return count + (accumulator * 0);
}
private long calibrateVector256(short[] samples, short[] residualI, short[] residualQ)
{
long start = System.currentTimeMillis();
long accumulator = 0;
long count = 0;
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
AirspyInterleavedBufferIteratorVector256Bits iterator =
new AirspyInterleavedBufferIteratorVector256Bits(samples, residualI, residualQ, 0.0f, System.currentTimeMillis());
while(iterator.hasNext())
{
accumulator += iterator.next().samples()[2];
count++;
}
}
return count + (accumulator * 0);
}
private long calibrateVector512(short[] samples, short[] residualI, short[] residualQ)
{
long start = System.currentTimeMillis();
long accumulator = 0;
long count = 0;
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
AirspyInterleavedBufferIteratorVector512Bits iterator =
new AirspyInterleavedBufferIteratorVector512Bits(samples, residualI, residualQ, 0.0f, System.currentTimeMillis());
while(iterator.hasNext())
{
accumulator += iterator.next().samples()[2];
count++;
}
}
return count + (accumulator * 0);
}
}

View File

@@ -0,0 +1,142 @@
/*
* *****************************************************************************
* 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.ScalarFMDemodulator;
import io.github.dsheirer.dsp.fm.VectorFMDemodulator;
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 FmDemodulatorCalibration 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 IFmDemodulator mScalarDemodulator = new ScalarFMDemodulator();
private IFmDemodulator mVectorDemodulator = new VectorFMDemodulator();
/**
* Constructs an instance
*/
public FmDemodulatorCalibration()
{
super(CalibrationType.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("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("FM DEMODULATOR WARMUP - VECTOR: " + DECIMAL_FORMAT.format(vectorMean.getResult()));
//Start tests
scalarMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testScalar(i, q);
scalarMean.increment(score);
}
mLog.info("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("FM DEMODULATOR - VECTOR: " + DECIMAL_FORMAT.format(vectorMean.getResult()));
if(scalarMean.getResult() > vectorMean.getResult())
{
setImplementation(Implementation.SCALAR);
}
else
{
setImplementation(Implementation.VECTOR_SIMD_PREFERRED);
}
mLog.info("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 = mScalarDemodulator.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 = mVectorDemodulator.demodulate(i, q);
accumulator += demodulated[1];
count++;
}
return count + (long)(accumulator * 0);
}
}

View File

@@ -0,0 +1,148 @@
/*
* *****************************************************************************
* 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);
}
}

View File

@@ -0,0 +1,378 @@
/*
* *****************************************************************************
* 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.filter;
import io.github.dsheirer.dsp.filter.FilterFactory;
import io.github.dsheirer.dsp.filter.design.FilterDesignException;
import io.github.dsheirer.dsp.filter.fir.real.IRealFilter;
import io.github.dsheirer.dsp.filter.fir.real.RealFIRFilter;
import io.github.dsheirer.dsp.filter.fir.real.VectorRealFIRFilter128Bit;
import io.github.dsheirer.dsp.filter.fir.real.VectorRealFIRFilter256Bit;
import io.github.dsheirer.dsp.filter.fir.real.VectorRealFIRFilter512Bit;
import io.github.dsheirer.dsp.filter.fir.real.VectorRealFIRFilter64Bit;
import io.github.dsheirer.dsp.filter.fir.real.VectorRealFIRFilterDefaultBit;
import io.github.dsheirer.dsp.window.WindowType;
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 FirFilterCalibration extends Calibration
{
private static final VectorSpecies<Float> VECTOR_SPECIES = FloatVector.SPECIES_PREFERRED;
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 IRealFilter mScalar;
private IRealFilter mVectorPreferred;
private IRealFilter mVector512;
private IRealFilter mVector256;
private IRealFilter mVector128;
private IRealFilter mVector64;
/**
* Constructs an instance
*/
public FirFilterCalibration()
{
super(CalibrationType.FILTER_FIR);
float[] coefficients;
try
{
coefficients = FilterFactory.getSinc(0.25, 31, WindowType.BLACKMAN);
mScalar = new RealFIRFilter(coefficients);
mVectorPreferred = new VectorRealFIRFilterDefaultBit(coefficients);
mVector64 = new VectorRealFIRFilter64Bit(coefficients);
mVector128 = new VectorRealFIRFilter128Bit(coefficients);
mVector256 = new VectorRealFIRFilter256Bit(coefficients);
mVector512 = new VectorRealFIRFilter512Bit(coefficients);
}
catch(FilterDesignException fde)
{
mLog.error("Error creating sinc filter for real FIR filter calibration");
}
}
/**
* Performs calibration to determine optimal (Scalar vs Vector) operation type.
* @throws CalibrationException
*/
@Override public void calibrate() throws CalibrationException
{
if(mScalar == null)
{
return;
}
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("FIR FILTER WARMUP - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
Mean vectorPreferredMean = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVectorPreferred(samples);
vectorPreferredMean.increment(score);
}
mLog.info("FIR FILTER WARMUP - VECTOR PREFERRED: " + DECIMAL_FORMAT.format(vectorPreferredMean.getResult()));
Mean vector512Mean = new Mean();
if(VECTOR_SPECIES.length() >= 16)
{
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector512(samples);
vector512Mean.increment(score);
}
mLog.info("FIR FILTER WARMUP - VECTOR 512: " + DECIMAL_FORMAT.format(vector512Mean.getResult()));
}
Mean vector256Mean = new Mean();
if(VECTOR_SPECIES.length() >= 8)
{
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector256(samples);
vector256Mean.increment(score);
}
mLog.info("FIR FILTER 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);
vector128Mean.increment(score);
}
mLog.info("FIR FILTER 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);
vector64Mean.increment(score);
}
mLog.info("FIR FILTER WARMUP - VECTOR 64: " + DECIMAL_FORMAT.format(vector64Mean.getResult()));
}
//Test starts ...
scalarMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testScalar(samples);
scalarMean.increment(score);
}
mLog.info("FIR FILTER - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
double bestScore = scalarMean.getResult();
setImplementation(Implementation.SCALAR);
vectorPreferredMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVectorPreferred(samples);
vectorPreferredMean.increment(score);
}
mLog.info("FIR FILTER - VECTOR PREFERRED: " + DECIMAL_FORMAT.format(vectorPreferredMean.getResult()));
if(vectorPreferredMean.getResult() > bestScore)
{
bestScore = vectorPreferredMean.getResult();
setImplementation(Implementation.VECTOR_SIMD_PREFERRED);
}
if(VECTOR_SPECIES.length() >= 16)
{
vector512Mean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector512(samples);
vector512Mean.increment(score);
}
mLog.info("FIR FILTER - VECTOR 512: " + DECIMAL_FORMAT.format(vector512Mean.getResult()));
if(vector512Mean.getResult() > bestScore)
{
bestScore = vector512Mean.getResult();
setImplementation(Implementation.VECTOR_SIMD_512);
}
}
if(VECTOR_SPECIES.length() >= 8)
{
vector256Mean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector256(samples);
vector256Mean.increment(score);
}
mLog.info("FIR FILTER - 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);
vector128Mean.increment(score);
}
mLog.info("FIR FILTER - 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);
vector64Mean.increment(score);
}
mLog.info("FIR FILTER - VECTOR 64: " + DECIMAL_FORMAT.format(vector64Mean.getResult()));
if(vector64Mean.getResult() > bestScore)
{
setImplementation(Implementation.VECTOR_SIMD_64);
}
}
mLog.info("FIR FILTER - SET OPTIMAL IMPLEMENTATION TO: " + getImplementation());
}
private long testScalar(float[] samples)
{
double accumulator = 0.0f;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mScalar.filter(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector64(float[] samples)
{
double accumulator = 0.0f;
long start = System.currentTimeMillis();
long count = 0;
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector64.filter(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector128(float[] samples)
{
double accumulator = 0.0f;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector128.filter(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector256(float[] samples)
{
double accumulator = 0.0f;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector256.filter(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector512(float[] samples)
{
double accumulator = 0.0f;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector512.filter(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVectorPreferred(float[] samples)
{
double accumulator = 0.0f;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVectorPreferred.filter(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
}

View File

@@ -0,0 +1,144 @@
/*
* *****************************************************************************
* 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.filter;
import io.github.dsheirer.dsp.filter.dc.IDcRemovalFilter;
import io.github.dsheirer.dsp.filter.dc.ScalarDcRemovalFilter;
import io.github.dsheirer.dsp.filter.dc.VectorDcRemovalFilter;
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;
/**
* Determines optimal DC removal implementation
*/
public class RealDcRemovalCalibration extends Calibration
{
private static final float GAIN = 0.15f;
private static final int BUFFER_SIZE = 8192;
private static final int ITERATION_DURATION_MS = 1000;
private static final int TEST_ITERATIONS = 5;
private static final int WARMUP_ITERATIONS = 5;
private IDcRemovalFilter mScalar = new ScalarDcRemovalFilter(GAIN);
private IDcRemovalFilter mVector = new VectorDcRemovalFilter(GAIN);
/**
* Constructs an instance
*/
public RealDcRemovalCalibration()
{
super(CalibrationType.DC_REMOVAL_REAL);
}
@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("REAL DC REMOVAL WARMUP - SCALAR:" + DECIMAL_FORMAT.format(scalarMean.getResult()));
Mean vectorMean = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector(samples);
vectorMean.increment(score);
}
mLog.info("REAL DC REMOVAL WARMUP - VECTOR:" + DECIMAL_FORMAT.format(vectorMean.getResult()));
scalarMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testScalar(samples);
scalarMean.increment(score);
}
mLog.info("REAL DC REMOVAL - SCALAR:" + DECIMAL_FORMAT.format(scalarMean.getResult()));
vectorMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector(samples);
vectorMean.increment(score);
}
mLog.info("REAL DC REMOVAL - VECTOR:" + DECIMAL_FORMAT.format(vectorMean.getResult()));
if(scalarMean.getResult() > vectorMean.getResult())
{
setImplementation(Implementation.SCALAR);
}
else
{
setImplementation(Implementation.VECTOR_SIMD_PREFERRED);
}
mLog.info("REAL DC REMOVAL - SET OPTIMAL IMPLEMENTATION TO: " + getImplementation());
}
private long testScalar(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mScalar.filter(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector.filter(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
}

View File

@@ -0,0 +1,316 @@
/*
* *****************************************************************************
* 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.filter;
import io.github.dsheirer.dsp.filter.FilterFactory;
import io.github.dsheirer.dsp.filter.decimate.IRealDecimationFilter;
import io.github.dsheirer.dsp.filter.halfband.RealHalfBandDecimationFilter;
import io.github.dsheirer.dsp.filter.halfband.VectorRealHalfBandDecimationFilter11Tap128Bit;
import io.github.dsheirer.dsp.filter.halfband.VectorRealHalfBandDecimationFilter11Tap256Bit;
import io.github.dsheirer.dsp.filter.halfband.VectorRealHalfBandDecimationFilter11Tap512Bit;
import io.github.dsheirer.dsp.filter.halfband.VectorRealHalfBandDecimationFilter11Tap64Bit;
import io.github.dsheirer.dsp.window.WindowType;
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;
/**
* Base calibration plugin for real half-band filters
*/
public class RealHalfBand11TapFilterCalibration extends Calibration
{
private static final VectorSpecies<Float> VECTOR_SPECIES = FloatVector.SPECIES_PREFERRED;
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 IRealDecimationFilter mScalar;
private IRealDecimationFilter mVector512;
private IRealDecimationFilter mVector256;
private IRealDecimationFilter mVector128;
private IRealDecimationFilter mVector64;
/**
* Constructs an instance
*/
public RealHalfBand11TapFilterCalibration()
{
super(CalibrationType.FILTER_HALF_BAND_REAL_11_TAP);
float[] coefficients = FilterFactory.getHalfBand(11, WindowType.BLACKMAN);
mScalar = new RealHalfBandDecimationFilter(coefficients);
mVector512 = new VectorRealHalfBandDecimationFilter11Tap512Bit(coefficients);
mVector256 = new VectorRealHalfBandDecimationFilter11Tap256Bit(coefficients);
mVector128 = new VectorRealHalfBandDecimationFilter11Tap128Bit(coefficients);
mVector64 = new VectorRealHalfBandDecimationFilter11Tap64Bit(coefficients);
}
/**
* Performs calibration to determine optimal (Scalar vs Vector) operation type.
* @throws CalibrationException
*/
@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("REAL HALF-BAND 11-TAP DECIMATE WARMUP - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
Mean vector512Mean = new Mean();
if(VECTOR_SPECIES.length() >= 16)
{
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector512(samples);
vector512Mean.increment(score);
}
mLog.info("REAL HALF-BAND 11-TAP DECIMATE WARMUP - VECTOR 512: " + DECIMAL_FORMAT.format(vector512Mean.getResult()));
}
Mean vector256Mean = new Mean();
if(VECTOR_SPECIES.length() >= 8)
{
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector256(samples);
vector256Mean.increment(score);
}
mLog.info("REAL HALF-BAND 11-TAP DECIMATE 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);
vector128Mean.increment(score);
}
mLog.info("REAL HALF-BAND 11-TAP DECIMATE 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);
vector64Mean.increment(score);
}
mLog.info("REAL HALF-BAND 11-TAP DECIMATE WARMUP - VECTOR 64: " + DECIMAL_FORMAT.format(vector64Mean.getResult()));
}
//Test starts ...
scalarMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testScalar(samples);
scalarMean.increment(score);
}
mLog.info("REAL HALF-BAND 11-TAP DECIMATE - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
double bestScore = scalarMean.getResult();
setImplementation(Implementation.SCALAR);
if(VECTOR_SPECIES.length() >= 16)
{
vector512Mean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector512(samples);
vector512Mean.increment(score);
}
mLog.info("REAL HALF-BAND 11-TAP DECIMATE - VECTOR 512: " + DECIMAL_FORMAT.format(vector512Mean.getResult()));
if(vector512Mean.getResult() > bestScore)
{
bestScore = vector512Mean.getResult();
setImplementation(Implementation.VECTOR_SIMD_512);
}
}
if(VECTOR_SPECIES.length() >= 8)
{
vector256Mean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector256(samples);
vector256Mean.increment(score);
}
mLog.info("REAL HALF-BAND 11-TAP DECIMATE - 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);
vector128Mean.increment(score);
}
mLog.info("REAL HALF-BAND 11-TAP DECIMATE - 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);
vector64Mean.increment(score);
}
mLog.info("REAL HALF-BAND 11-TAP DECIMATE - VECTOR 64: " + DECIMAL_FORMAT.format(vector64Mean.getResult()));
if(vector64Mean.getResult() > bestScore)
{
setImplementation(Implementation.VECTOR_SIMD_64);
}
}
mLog.info("REAL HALF-BAND 11-TAP DECIMATE - SET OPTIMAL IMPLEMENTATION TO: " + getImplementation());
}
private long testScalar(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mScalar.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector512(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector512.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector256(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector256.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector128(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector128.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector64(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector64.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
}

View File

@@ -0,0 +1,315 @@
/*
* *****************************************************************************
* 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.filter;
import io.github.dsheirer.dsp.filter.FilterFactory;
import io.github.dsheirer.dsp.filter.decimate.IRealDecimationFilter;
import io.github.dsheirer.dsp.filter.halfband.RealHalfBandDecimationFilter;
import io.github.dsheirer.dsp.filter.halfband.VectorRealHalfBandDecimationFilter15Tap128Bit;
import io.github.dsheirer.dsp.filter.halfband.VectorRealHalfBandDecimationFilter15Tap256Bit;
import io.github.dsheirer.dsp.filter.halfband.VectorRealHalfBandDecimationFilter15Tap512Bit;
import io.github.dsheirer.dsp.filter.halfband.VectorRealHalfBandDecimationFilter15Tap64Bit;
import io.github.dsheirer.dsp.window.WindowType;
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;
/**
* Base calibration plugin for real half-band filters
*/
public class RealHalfBand15TapFilterCalibration extends Calibration
{
private static final VectorSpecies<Float> VECTOR_SPECIES = FloatVector.SPECIES_PREFERRED;
private static final int BUFFER_SIZE = 2048;
private static final int ITERATION_DURATION_MS = 1_000;
private static final int WARMUP_ITERATIONS = 5;
private static final int TEST_ITERATIONS = 5;
private IRealDecimationFilter mScalar;
private IRealDecimationFilter mVector512;
private IRealDecimationFilter mVector256;
private IRealDecimationFilter mVector128;
private IRealDecimationFilter mVector64;
/**
* Constructs an instance
*/
public RealHalfBand15TapFilterCalibration()
{
super(CalibrationType.FILTER_HALF_BAND_REAL_15_TAP);
float[] coefficients = FilterFactory.getHalfBand(15, WindowType.BLACKMAN);
mScalar = new RealHalfBandDecimationFilter(coefficients);
mVector512 = new VectorRealHalfBandDecimationFilter15Tap512Bit(coefficients);
mVector256 = new VectorRealHalfBandDecimationFilter15Tap256Bit(coefficients);
mVector128 = new VectorRealHalfBandDecimationFilter15Tap128Bit(coefficients);
mVector64 = new VectorRealHalfBandDecimationFilter15Tap64Bit(coefficients);
}
/**
* Performs calibration to determine optimal (Scalar vs Vector) operation type.
* @throws CalibrationException
*/
@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("REAL HALF-BAND 15-TAP DECIMATE WARMUP - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
Mean vector512Mean = new Mean();
if(VECTOR_SPECIES.length() >= 16)
{
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector512(samples);
vector512Mean.increment(score);
}
mLog.info("REAL HALF-BAND 15-TAP DECIMATE WARMUP - VECTOR 512: " + DECIMAL_FORMAT.format(vector512Mean.getResult()));
}
Mean vector256Mean = new Mean();
if(VECTOR_SPECIES.length() >= 8)
{
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector256(samples);
vector256Mean.increment(score);
}
mLog.info("REAL HALF-BAND 15-TAP DECIMATE 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);
vector128Mean.increment(score);
}
mLog.info("REAL HALF-BAND 15-TAP DECIMATE 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);
vector64Mean.increment(score);
}
mLog.info("REAL HALF-BAND 15-TAP DECIMATE WARMUP - VECTOR 64: " + DECIMAL_FORMAT.format(vector64Mean.getResult()));
}
//Test starts ...
scalarMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testScalar(samples);
scalarMean.increment(score);
}
mLog.info("REAL HALF-BAND 15-TAP DECIMATE - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
double bestScore = scalarMean.getResult();
setImplementation(Implementation.SCALAR);
if(VECTOR_SPECIES.length() >= 16)
{
vector512Mean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector512(samples);
vector512Mean.increment(score);
}
mLog.info("REAL HALF-BAND 15-TAP DECIMATE - VECTOR 512: " + DECIMAL_FORMAT.format(vector512Mean.getResult()));
if(vector512Mean.getResult() > bestScore)
{
bestScore = vector512Mean.getResult();
setImplementation(Implementation.VECTOR_SIMD_512);
}
}
if(VECTOR_SPECIES.length() >= 8)
{
vector256Mean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector256(samples);
vector256Mean.increment(score);
}
mLog.info("REAL HALF-BAND 15-TAP DECIMATE - 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);
vector128Mean.increment(score);
}
mLog.info("REAL HALF-BAND 15-TAP DECIMATE - 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);
vector64Mean.increment(score);
}
mLog.info("REAL HALF-BAND 15-TAP DECIMATE - VECTOR 64: " + DECIMAL_FORMAT.format(vector64Mean.getResult()));
if(vector64Mean.getResult() > bestScore)
{
setImplementation(Implementation.VECTOR_SIMD_64);
}
}
mLog.info("REAL HALF-BAND 15-TAP DECIMATE - SET OPTIMAL IMPLEMENTATION TO: " + getImplementation());
}
private long testScalar(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mScalar.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector512(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector512.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector256(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector256.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector128(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector128.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector64(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector64.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
}

View File

@@ -0,0 +1,315 @@
/*
* *****************************************************************************
* 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.filter;
import io.github.dsheirer.dsp.filter.FilterFactory;
import io.github.dsheirer.dsp.filter.decimate.IRealDecimationFilter;
import io.github.dsheirer.dsp.filter.halfband.RealHalfBandDecimationFilter;
import io.github.dsheirer.dsp.filter.halfband.VectorRealHalfBandDecimationFilter23Tap128Bit;
import io.github.dsheirer.dsp.filter.halfband.VectorRealHalfBandDecimationFilter23Tap256Bit;
import io.github.dsheirer.dsp.filter.halfband.VectorRealHalfBandDecimationFilter23Tap512Bit;
import io.github.dsheirer.dsp.filter.halfband.VectorRealHalfBandDecimationFilter23Tap64Bit;
import io.github.dsheirer.dsp.window.WindowType;
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;
/**
* Base calibration plugin for real half-band filters
*/
public class RealHalfBand23TapFilterCalibration extends Calibration
{
private static final VectorSpecies<Float> VECTOR_SPECIES = FloatVector.SPECIES_PREFERRED;
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 IRealDecimationFilter mScalar;
private IRealDecimationFilter mVector512;
private IRealDecimationFilter mVector256;
private IRealDecimationFilter mVector128;
private IRealDecimationFilter mVector64;
/**
* Constructs an instance
*/
public RealHalfBand23TapFilterCalibration()
{
super(CalibrationType.FILTER_HALF_BAND_REAL_23_TAP);
float[] coefficients = FilterFactory.getHalfBand(23, WindowType.BLACKMAN);
mScalar = new RealHalfBandDecimationFilter(coefficients);
mVector512 = new VectorRealHalfBandDecimationFilter23Tap512Bit(coefficients);
mVector256 = new VectorRealHalfBandDecimationFilter23Tap256Bit(coefficients);
mVector128 = new VectorRealHalfBandDecimationFilter23Tap128Bit(coefficients);
mVector64 = new VectorRealHalfBandDecimationFilter23Tap64Bit(coefficients);
}
/**
* Performs calibration to determine optimal (Scalar vs Vector) operation type.
* @throws CalibrationException
*/
@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("REAL HALF-BAND 23-TAP DECIMATE WARMUP - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
Mean vector512Mean = new Mean();
if(VECTOR_SPECIES.length() >= 16)
{
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector512(samples);
vector512Mean.increment(score);
}
mLog.info("REAL HALF-BAND 23-TAP DECIMATE WARMUP - VECTOR 512: " + DECIMAL_FORMAT.format(vector512Mean.getResult()));
}
Mean vector256Mean = new Mean();
if(VECTOR_SPECIES.length() >= 8)
{
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector256(samples);
vector256Mean.increment(score);
}
mLog.info("REAL HALF-BAND 23-TAP DECIMATE 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);
vector128Mean.increment(score);
}
mLog.info("REAL HALF-BAND 23-TAP DECIMATE 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);
vector64Mean.increment(score);
}
mLog.info("REAL HALF-BAND 23-TAP DECIMATE WARMUP - VECTOR 64: " + DECIMAL_FORMAT.format(vector64Mean.getResult()));
}
//Test starts ...
scalarMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testScalar(samples);
scalarMean.increment(score);
}
mLog.info("REAL HALF-BAND 23-TAP DECIMATE - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
double bestScore = scalarMean.getResult();
setImplementation(Implementation.SCALAR);
if(VECTOR_SPECIES.length() >= 16)
{
vector512Mean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector512(samples);
vector512Mean.increment(score);
}
mLog.info("REAL HALF-BAND 23-TAP DECIMATE - VECTOR 512: " + DECIMAL_FORMAT.format(vector512Mean.getResult()));
if(vector512Mean.getResult() > bestScore)
{
bestScore = vector512Mean.getResult();
setImplementation(Implementation.VECTOR_SIMD_512);
}
}
if(VECTOR_SPECIES.length() >= 8)
{
vector256Mean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector256(samples);
vector256Mean.increment(score);
}
mLog.info("REAL HALF-BAND 23-TAP DECIMATE - 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);
vector128Mean.increment(score);
}
mLog.info("REAL HALF-BAND 23-TAP DECIMATE - 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);
vector64Mean.increment(score);
}
mLog.info("REAL HALF-BAND 23-TAP DECIMATE - VECTOR 64: " + DECIMAL_FORMAT.format(vector64Mean.getResult()));
if(vector64Mean.getResult() > bestScore)
{
setImplementation(Implementation.VECTOR_SIMD_64);
}
}
mLog.info("REAL HALF-BAND 23-TAP DECIMATE - SET OPTIMAL IMPLEMENTATION TO: " + getImplementation());
}
private long testScalar(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mScalar.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector512(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector512.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector256(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector256.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector128(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector128.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector64(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector64.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
}

View File

@@ -0,0 +1,315 @@
/*
* *****************************************************************************
* 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.filter;
import io.github.dsheirer.dsp.filter.FilterFactory;
import io.github.dsheirer.dsp.filter.decimate.IRealDecimationFilter;
import io.github.dsheirer.dsp.filter.halfband.RealHalfBandDecimationFilter;
import io.github.dsheirer.dsp.filter.halfband.VectorRealHalfBandDecimationFilter63Tap128Bit;
import io.github.dsheirer.dsp.filter.halfband.VectorRealHalfBandDecimationFilter63Tap256Bit;
import io.github.dsheirer.dsp.filter.halfband.VectorRealHalfBandDecimationFilter63Tap512Bit;
import io.github.dsheirer.dsp.filter.halfband.VectorRealHalfBandDecimationFilter63Tap64Bit;
import io.github.dsheirer.dsp.window.WindowType;
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;
/**
* Base calibration plugin for real half-band filters
*/
public class RealHalfBand63TapFilterCalibration extends Calibration
{
private static final VectorSpecies<Float> VECTOR_SPECIES = FloatVector.SPECIES_PREFERRED;
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 IRealDecimationFilter mScalar;
private IRealDecimationFilter mVector512;
private IRealDecimationFilter mVector256;
private IRealDecimationFilter mVector128;
private IRealDecimationFilter mVector64;
/**
* Constructs an instance
*/
public RealHalfBand63TapFilterCalibration()
{
super(CalibrationType.FILTER_HALF_BAND_REAL_63_TAP);
float[] coefficients = FilterFactory.getHalfBand(63, WindowType.BLACKMAN);
mScalar = new RealHalfBandDecimationFilter(coefficients);
mVector512 = new VectorRealHalfBandDecimationFilter63Tap512Bit(coefficients);
mVector256 = new VectorRealHalfBandDecimationFilter63Tap256Bit(coefficients);
mVector128 = new VectorRealHalfBandDecimationFilter63Tap128Bit(coefficients);
mVector64 = new VectorRealHalfBandDecimationFilter63Tap64Bit(coefficients);
}
/**
* Performs calibration to determine optimal (Scalar vs Vector) operation type.
* @throws CalibrationException
*/
@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("REAL HALF-BAND 63-TAP DECIMATE WARMUP - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
Mean vector512Mean = new Mean();
if(VECTOR_SPECIES.length() >= 16)
{
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector512(samples);
vector512Mean.increment(score);
}
mLog.info("REAL HALF-BAND 63-TAP DECIMATE WARMUP - VECTOR 512: " + DECIMAL_FORMAT.format(vector512Mean.getResult()));
}
Mean vector256Mean = new Mean();
if(VECTOR_SPECIES.length() >= 8)
{
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector256(samples);
vector256Mean.increment(score);
}
mLog.info("REAL HALF-BAND 63-TAP DECIMATE 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);
vector128Mean.increment(score);
}
mLog.info("REAL HALF-BAND 63-TAP DECIMATE 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);
vector64Mean.increment(score);
}
mLog.info("REAL HALF-BAND 63-TAP DECIMATE WARMUP - VECTOR 64: " + DECIMAL_FORMAT.format(vector64Mean.getResult()));
}
//Test starts ...
scalarMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testScalar(samples);
scalarMean.increment(score);
}
mLog.info("REAL HALF-BAND 63-TAP DECIMATE - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
double bestScore = scalarMean.getResult();
setImplementation(Implementation.SCALAR);
if(VECTOR_SPECIES.length() >= 16)
{
vector512Mean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector512(samples);
vector512Mean.increment(score);
}
mLog.info("REAL HALF-BAND 63-TAP DECIMATE - VECTOR 512: " + DECIMAL_FORMAT.format(vector512Mean.getResult()));
if(vector512Mean.getResult() > bestScore)
{
bestScore = vector512Mean.getResult();
setImplementation(Implementation.VECTOR_SIMD_512);
}
}
if(VECTOR_SPECIES.length() >= 8)
{
vector256Mean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector256(samples);
vector256Mean.increment(score);
}
mLog.info("REAL HALF-BAND 63-TAP DECIMATE - 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);
vector128Mean.increment(score);
}
mLog.info("REAL HALF-BAND 63-TAP DECIMATE - 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);
vector64Mean.increment(score);
}
mLog.info("REAL HALF-BAND 63-TAP DECIMATE - VECTOR 64: " + DECIMAL_FORMAT.format(vector64Mean.getResult()));
if(vector64Mean.getResult() > bestScore)
{
setImplementation(Implementation.VECTOR_SIMD_64);
}
}
mLog.info("REAL HALF-BAND 63-TAP DECIMATE - SET OPTIMAL IMPLEMENTATION TO: " + getImplementation());
}
private long testScalar(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mScalar.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector512(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector512.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector256(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector256.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector128(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector128.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector64(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector64.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
}

View File

@@ -0,0 +1,361 @@
/*
* *****************************************************************************
* 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.filter;
import io.github.dsheirer.dsp.filter.FilterFactory;
import io.github.dsheirer.dsp.filter.decimate.IRealDecimationFilter;
import io.github.dsheirer.dsp.filter.halfband.RealHalfBandDecimationFilter;
import io.github.dsheirer.dsp.filter.halfband.VectorRealHalfBandDecimationFilter128Bit;
import io.github.dsheirer.dsp.filter.halfband.VectorRealHalfBandDecimationFilter256Bit;
import io.github.dsheirer.dsp.filter.halfband.VectorRealHalfBandDecimationFilter512Bit;
import io.github.dsheirer.dsp.filter.halfband.VectorRealHalfBandDecimationFilter64Bit;
import io.github.dsheirer.dsp.filter.halfband.VectorRealHalfBandDecimationFilterDefaultBit;
import io.github.dsheirer.dsp.window.WindowType;
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;
/**
* Base calibration plugin for real half-band filters
*/
public class RealHalfBandDefaultFilterCalibration extends Calibration
{
private static final VectorSpecies<Float> VECTOR_SPECIES = FloatVector.SPECIES_PREFERRED;
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 IRealDecimationFilter mScalar;
private IRealDecimationFilter mVectorPreferred;
private IRealDecimationFilter mVector512;
private IRealDecimationFilter mVector256;
private IRealDecimationFilter mVector128;
private IRealDecimationFilter mVector64;
/**
* Constructs an instance
*/
public RealHalfBandDefaultFilterCalibration()
{
super(CalibrationType.FILTER_HALF_BAND_REAL_DEFAULT);
float[] coefficients = FilterFactory.getHalfBand(63, WindowType.BLACKMAN);
mScalar = new RealHalfBandDecimationFilter(coefficients);
mVectorPreferred = new VectorRealHalfBandDecimationFilterDefaultBit(coefficients);
mVector512 = new VectorRealHalfBandDecimationFilter512Bit(coefficients);
mVector256 = new VectorRealHalfBandDecimationFilter256Bit(coefficients);
mVector128 = new VectorRealHalfBandDecimationFilter128Bit(coefficients);
mVector64 = new VectorRealHalfBandDecimationFilter64Bit(coefficients);
}
/**
* Performs calibration to determine optimal (Scalar vs Vector) operation type.
* @throws CalibrationException
*/
@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("REAL HALF-BAND DEFAULT DECIMATE WARMUP - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
Mean vectorPreferredMean = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVectorPreferred(samples);
vectorPreferredMean.increment(score);
}
mLog.info("REAL HALF-BAND DEFAULT DECIMATE WARMUP - VECTOR PREFERRED: " + DECIMAL_FORMAT.format(vectorPreferredMean.getResult()));
Mean vector512Mean = new Mean();
if(VECTOR_SPECIES.length() >= 16)
{
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector512(samples);
vector512Mean.increment(score);
}
mLog.info("REAL HALF-BAND DEFAULT DECIMATE WARMUP - VECTOR 512: " + DECIMAL_FORMAT.format(vector512Mean.getResult()));
}
Mean vector256Mean = new Mean();
if(VECTOR_SPECIES.length() >= 8)
{
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector256(samples);
vector256Mean.increment(score);
}
mLog.info("REAL HALF-BAND DEFAULT DECIMATE 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);
vector128Mean.increment(score);
}
mLog.info("REAL HALF-BAND DEFAULT DECIMATE 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);
vector64Mean.increment(score);
}
mLog.info("REAL HALF-BAND DEFAULT DECIMATE WARMUP - VECTOR 64: " + DECIMAL_FORMAT.format(vector64Mean.getResult()));
}
//Test starts ...
scalarMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testScalar(samples);
scalarMean.increment(score);
}
mLog.info("REAL HALF-BAND DEFAULT DECIMATE - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
double bestScore = scalarMean.getResult();
setImplementation(Implementation.SCALAR);
vectorPreferredMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVectorPreferred(samples);
vectorPreferredMean.increment(score);
}
mLog.info("REAL HALF-BAND DEFAULT DECIMATE - VECTOR PREFERRED: " + DECIMAL_FORMAT.format(vectorPreferredMean.getResult()));
if(vectorPreferredMean.getResult() > bestScore)
{
bestScore = vectorPreferredMean.getResult();
setImplementation(Implementation.VECTOR_SIMD_PREFERRED);
}
if(VECTOR_SPECIES.length() >= 16)
{
vector512Mean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector512(samples);
vector512Mean.increment(score);
}
mLog.info("REAL HALF-BAND DEFAULT DECIMATE - VECTOR 512: " + DECIMAL_FORMAT.format(vector512Mean.getResult()));
if(vector512Mean.getResult() > bestScore)
{
bestScore = vector512Mean.getResult();
setImplementation(Implementation.VECTOR_SIMD_512);
}
}
if(VECTOR_SPECIES.length() >= 8)
{
vector256Mean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector256(samples);
vector256Mean.increment(score);
}
mLog.info("REAL HALF-BAND DEFAULT DECIMATE - 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);
vector128Mean.increment(score);
}
mLog.info("REAL HALF-BAND DEFAULT DECIMATE - 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);
vector64Mean.increment(score);
}
mLog.info("REAL HALF-BAND DEFAULT DECIMATE - VECTOR 64: " + DECIMAL_FORMAT.format(vector64Mean.getResult()));
if(vector64Mean.getResult() > bestScore)
{
setImplementation(Implementation.VECTOR_SIMD_64);
}
}
mLog.info("REAL HALF-BAND DEFAULT DECIMATE - SET OPTIMAL IMPLEMENTATION TO: " + getImplementation());
}
private long testScalar(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mScalar.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVectorPreferred(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVectorPreferred.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector512(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector512.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector256(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector256.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector128(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector128.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector64(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] filtered = mVector64.decimateReal(samples);
accumulator += filtered[0];
count++;
}
return count + (long)(accumulator * 0);
}
}

View File

@@ -0,0 +1,150 @@
/*
* *****************************************************************************
* 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.gain;
import io.github.dsheirer.dsp.gain.complex.ComplexGain;
import io.github.dsheirer.dsp.gain.complex.ScalarComplexGain;
import io.github.dsheirer.dsp.gain.complex.VectorComplexGain;
import io.github.dsheirer.sample.complex.ComplexSamples;
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;
/**
* Determines the optimal scalar vs vector implementation of complex gain.
*/
public class ComplexGainCalibration 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 static final float GAIN = 0.99f;
/**
* Constructs an instance
*/
public ComplexGainCalibration()
{
super(CalibrationType.GAIN_COMPLEX);
}
@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("COMPLEX GAIN WARMUP - SCALAR:" + DECIMAL_FORMAT.format(scalarMean.getResult()));
i = getFloatSamples(BUFFER_SIZE);
q = getFloatSamples(BUFFER_SIZE);
Mean vectorMean = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector(i, q);
vectorMean.increment(score);
}
mLog.info("COMPLEX GAIN WARMUP - VECTOR:" + DECIMAL_FORMAT.format(vectorMean.getResult()));
i = getFloatSamples(BUFFER_SIZE);
q = getFloatSamples(BUFFER_SIZE);
scalarMean.clear();;
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testScalar(i, q);
scalarMean.increment(score);
}
mLog.info("COMPLEX GAIN - SCALAR:" + DECIMAL_FORMAT.format(scalarMean.getResult()));
i = getFloatSamples(BUFFER_SIZE);
q = getFloatSamples(BUFFER_SIZE);
vectorMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector(i, q);
vectorMean.increment(score);
}
mLog.info("COMPLEX GAIN - VECTOR:" + DECIMAL_FORMAT.format(vectorMean.getResult()));
if(scalarMean.getResult() > vectorMean.getResult())
{
setImplementation(Implementation.SCALAR);
}
else
{
setImplementation(Implementation.VECTOR_SIMD_PREFERRED);
}
mLog.info("COMPLEX GAIN - SET IMPLEMENTATION TO:" + getImplementation());
}
private long testScalar(float[] i, float[] q)
{
float accumulator = 0.0f;
long count = 0;
ComplexGain scalar = new ScalarComplexGain(GAIN);
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
ComplexSamples amplified = scalar.apply(i, q);
accumulator += amplified.i()[2];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector(float[] i, float[] q)
{
float accumulator = 0.0f;
long count = 0;
ComplexGain scalar = new VectorComplexGain(GAIN);
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
ComplexSamples amplified = scalar.apply(i, q);
accumulator += amplified.i()[2];
count++;
}
return count + (long)(accumulator * 0);
}
}

View File

@@ -0,0 +1,143 @@
/*
* *****************************************************************************
* 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.gain;
import io.github.dsheirer.dsp.gain.complex.ComplexGainControl;
import io.github.dsheirer.dsp.gain.complex.IComplexGainControl;
import io.github.dsheirer.dsp.gain.complex.VectorComplexGainControl;
import io.github.dsheirer.sample.complex.ComplexSamples;
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;
/**
* Determines the optimal scalar vs vector implementation of complex gain control.
*/
public class ComplexGainControlCalibration 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 IComplexGainControl mScalarGainControl = new ComplexGainControl();
private IComplexGainControl mVectorGainControl = new VectorComplexGainControl();
/**
* Constructs an instance
*/
public ComplexGainControlCalibration()
{
super(CalibrationType.GAIN_CONTROL_COMPLEX);
}
@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("COMPLEX GAIN CONTROL 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("COMPLEX GAIN CONTROL WARMUP - VECTOR:" + DECIMAL_FORMAT.format(vectorMean.getResult()));
scalarMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testScalar(i, q);
scalarMean.increment(score);
}
mLog.info("COMPLEX GAIN CONTROL - 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("COMPLEX GAIN CONTROL - VECTOR:" + DECIMAL_FORMAT.format(vectorMean.getResult()));
if(scalarMean.getResult() > vectorMean.getResult())
{
setImplementation(Implementation.SCALAR);
}
else
{
setImplementation(Implementation.VECTOR_SIMD_PREFERRED);
}
mLog.info("COMPLEX GAIN CONTROL - SET IMPLEMENTATION TO:" + getImplementation());
}
private long testScalar(float[] i, float[] q)
{
float accumulator = 0.0f;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
ComplexSamples amplified = mScalarGainControl.process(i, q);
accumulator += amplified.i()[2];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector(float[] i, float[] q)
{
float accumulator = 0.0f;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
ComplexSamples amplified = mVectorGainControl.process(i, q);
accumulator += amplified.i()[2];
count++;
}
return count + (long)(accumulator * 0);
}
}

View File

@@ -0,0 +1,350 @@
/*
* *****************************************************************************
* 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.hilbert;
import io.github.dsheirer.dsp.filter.hilbert.HilbertTransform;
import io.github.dsheirer.dsp.filter.hilbert.ScalarHilbertTransform;
import io.github.dsheirer.dsp.filter.hilbert.VectorHilbertTransform128Bits;
import io.github.dsheirer.dsp.filter.hilbert.VectorHilbertTransform256Bits;
import io.github.dsheirer.dsp.filter.hilbert.VectorHilbertTransform512Bits;
import io.github.dsheirer.dsp.filter.hilbert.VectorHilbertTransform64Bits;
import io.github.dsheirer.dsp.filter.hilbert.VectorHilbertTransformDefaultBits;
import io.github.dsheirer.sample.complex.ComplexSamples;
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;
public class HilbertCalibration extends Calibration
{
private static final VectorSpecies<Float> VECTOR_SPECIES = FloatVector.SPECIES_PREFERRED;
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 HilbertTransform mScalar = new ScalarHilbertTransform();
private HilbertTransform mVectorPreferred = new VectorHilbertTransformDefaultBits();
private HilbertTransform mVector512 = new VectorHilbertTransform512Bits();
private HilbertTransform mVector256 = new VectorHilbertTransform256Bits();
private HilbertTransform mVector128 = new VectorHilbertTransform128Bits();
private HilbertTransform mVector64 = new VectorHilbertTransform64Bits();
/**
* Constructs an instance
*/
public HilbertCalibration()
{
super(CalibrationType.HILBERT_TRANSFORM);
}
/**
* Performs calibration to determine optimal (Scalar vs Vector) operation type.
* @throws CalibrationException
*/
@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("HILBERT WARMUP - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
Mean vectorPreferredMean = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVectorPreferred(samples);
vectorPreferredMean.increment(score);
}
mLog.info("HILBERT WARMUP - VECTOR PREFERRED: " + DECIMAL_FORMAT.format(vectorPreferredMean.getResult()));
Mean vector512Mean = new Mean();
if(VECTOR_SPECIES.length() >= 16)
{
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector512(samples);
vector512Mean.increment(score);
}
mLog.info("HILBERT WARMUP - VECTOR 512: " + DECIMAL_FORMAT.format(vector512Mean.getResult()));
}
Mean vector256Mean = new Mean();
if(VECTOR_SPECIES.length() >= 8)
{
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector256(samples);
vector256Mean.increment(score);
}
mLog.info("HILBERT 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);
vector128Mean.increment(score);
}
mLog.info("HILBERT 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);
vector64Mean.increment(score);
}
mLog.info("HILBERT WARMUP - VECTOR 64: " + DECIMAL_FORMAT.format(vector64Mean.getResult()));
}
//Test starts ...
scalarMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testScalar(samples);
scalarMean.increment(score);
}
mLog.info("HILBERT - SCALAR: " + DECIMAL_FORMAT.format(scalarMean.getResult()));
double bestScore = scalarMean.getResult();
setImplementation(Implementation.SCALAR);
vectorPreferredMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVectorPreferred(samples);
vectorPreferredMean.increment(score);
}
mLog.info("HILBERT - VECTOR PREFERRED: " + DECIMAL_FORMAT.format(vectorPreferredMean.getResult()));
if(vectorPreferredMean.getResult() > bestScore)
{
bestScore = vectorPreferredMean.getResult();
setImplementation(Implementation.VECTOR_SIMD_PREFERRED);
}
if(VECTOR_SPECIES.length() >= 16)
{
vector512Mean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector512(samples);
vector512Mean.increment(score);
}
mLog.info("HILBERT - VECTOR 512: " + DECIMAL_FORMAT.format(vector512Mean.getResult()));
if(vector512Mean.getResult() > bestScore)
{
bestScore = vector512Mean.getResult();
setImplementation(Implementation.VECTOR_SIMD_512);
}
}
if(VECTOR_SPECIES.length() >= 8)
{
vector256Mean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector256(samples);
vector256Mean.increment(score);
}
mLog.info("HILBERT - 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);
vector128Mean.increment(score);
}
mLog.info("HILBERT - 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);
vector64Mean.increment(score);
}
mLog.info("HILBERT - VECTOR 64: " + DECIMAL_FORMAT.format(vector64Mean.getResult()));
if(vector64Mean.getResult() > bestScore)
{
setImplementation(Implementation.VECTOR_SIMD_64);
}
}
mLog.info("HILBERT - SET OPTIMAL IMPLEMENTATION TO: " + getImplementation());
}
private long testScalar(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
ComplexSamples complex = mScalar.filter(samples);
accumulator += complex.i()[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVectorPreferred(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
ComplexSamples complex = mVectorPreferred.filter(samples);
accumulator += complex.i()[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector512(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
ComplexSamples complex = mVector512.filter(samples);
accumulator += complex.i()[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector256(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
ComplexSamples complex = mVector256.filter(samples);
accumulator += complex.i()[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector128(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
ComplexSamples complex = mVector128.filter(samples);
accumulator += complex.i()[0];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector64(float[] samples)
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
ComplexSamples complex = mVector64.filter(samples);
accumulator += complex.i()[0];
count++;
}
return count + (long)(accumulator * 0);
}
}

View File

@@ -0,0 +1,141 @@
/*
* *****************************************************************************
* 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.mixer;
import io.github.dsheirer.dsp.mixer.ScalarComplexMixer;
import io.github.dsheirer.dsp.mixer.VectorComplexMixer;
import io.github.dsheirer.sample.complex.ComplexSamples;
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 the complex mixer implementations to determine the optimal instance.
*/
public class ComplexMixerCalibration extends Calibration
{
private static final double FREQUENCY = 2.0;
private static final double SAMPLE_RATE = 10.0;
private static final int SAMPLE_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 ScalarComplexMixer mScalarComplexMixer = new ScalarComplexMixer(FREQUENCY, SAMPLE_RATE);
private VectorComplexMixer mVectorComplexMixer = new VectorComplexMixer(FREQUENCY, SAMPLE_RATE);
/**
* Constructs an instance
*/
public ComplexMixerCalibration()
{
super(CalibrationType.MIXER_COMPLEX);
}
@Override public void calibrate() throws CalibrationException
{
float[] i = getFloatSamples(SAMPLE_SIZE);
float[] q = getFloatSamples(SAMPLE_SIZE);
Mean scalarMean = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testScalar(i, q);
scalarMean.increment(score);
}
mLog.info("COMPLEX MIXER 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("COMPLEX MIXER WARMUP - VECTOR:" + DECIMAL_FORMAT.format(vectorMean.getResult()));
scalarMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testScalar(i, q);
scalarMean.increment(score);
}
mLog.info("COMPLEX MIXER - SCALAR:" + DECIMAL_FORMAT.format(scalarMean.getResult()));
vectorMean.clear();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector(i, q);
vectorMean.increment(score);
}
mLog.info("COMPLEX MIXER - VECTOR:" + DECIMAL_FORMAT.format(vectorMean.getResult()));
if(scalarMean.getResult() > vectorMean.getResult())
{
setImplementation(Implementation.SCALAR);
}
else
{
setImplementation(Implementation.VECTOR_SIMD_PREFERRED);
}
mLog.info("COMPLEX MIXER - IMPLEMENTATION SET TO:" + getImplementation());
}
private long testScalar(float[] i, float[] q)
{
long start = System.currentTimeMillis();
double accumulator = 0.0;
long count = 0;
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
ComplexSamples mixed = mScalarComplexMixer.mix(i, q);
accumulator += mixed.i()[2];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector(float[] i, float[] q)
{
long start = System.currentTimeMillis();
double accumulator = 0.0;
long count = 0;
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
ComplexSamples mixed = mVectorComplexMixer.mix(i, q);
accumulator += mixed.i()[2];
count++;
}
return count + (long)(accumulator * 0);
}
}

View File

@@ -0,0 +1,154 @@
/*
* *****************************************************************************
* 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.oscillator;
import io.github.dsheirer.dsp.oscillator.IComplexOscillator;
import io.github.dsheirer.dsp.oscillator.ScalarComplexOscillator;
import io.github.dsheirer.dsp.oscillator.VectorComplexOscillator;
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;
/**
* Calibration plugin for complex oscillators
*/
public class ComplexOscillatorCalibration extends Calibration
{
private static final double FREQUENCY = 5.0d;
private static final double SAMPLE_RATE = 100.0d;
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 IComplexOscillator mScalarOscillator = new ScalarComplexOscillator(FREQUENCY, SAMPLE_RATE);
private IComplexOscillator mVectorOscillator = new VectorComplexOscillator(FREQUENCY, SAMPLE_RATE);
/**
* Constructs an instance
*/
public ComplexOscillatorCalibration()
{
super(CalibrationType.OSCILLATOR_COMPLEX);
}
/**
* Performs calibration to determine optimal (Scalar vs Vector) operation type.
* @throws CalibrationException
*/
@Override public void calibrate() throws CalibrationException
{
Mean scalarMean = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testScalar();
scalarMean.increment(score);
}
mLog.info("COMPLEX OSCILLATOR WARMUP - SCALAR:" + DECIMAL_FORMAT.format(scalarMean.getResult()));
Mean vectorMean = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector();
vectorMean.increment(score);
}
mLog.info("COMPLEX OSCILLATOR WARMUP - VECTOR:" + DECIMAL_FORMAT.format(vectorMean.getResult()));
scalarMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testScalar();
scalarMean.increment(score);
}
mLog.info("COMPLEX OSCILLATOR - SCALAR:" + DECIMAL_FORMAT.format(scalarMean.getResult()));
vectorMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector();
vectorMean.increment(score);
}
mLog.info("COMPLEX OSCILLATOR - VECTOR:" + DECIMAL_FORMAT.format(vectorMean.getResult()));
if(scalarMean.getResult() > vectorMean.getResult())
{
setImplementation(Implementation.SCALAR);
}
else
{
setImplementation(Implementation.VECTOR_SIMD_PREFERRED);
}
mLog.info("COMPLEX OSCILLATOR - SETTING OPTIMAL OPERATION TO:" + getImplementation());
}
/**
* Calculates the time duration needed to generate the sample buffers of the specified size and iteration count
* @return time duration in milliseconds
*/
private long testScalar()
{
float accumulator = 0.0f;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] generated = mScalarOscillator.generate(BUFFER_SIZE);
accumulator += generated[0];
count++;
}
return count + (long)(accumulator * 0);
}
/**
* Calculates the time duration to process the sample buffer with the filter coefficients.
* @return time duration in milliseconds
*/
private long testVector()
{
float accumulator = 0.0f;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] generated = mVectorOscillator.generate(BUFFER_SIZE);
accumulator += generated[0];
count++;
}
return count + (long)(accumulator * 0);
}
}

View File

@@ -0,0 +1,146 @@
/*
* *****************************************************************************
* 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.oscillator;
import io.github.dsheirer.dsp.oscillator.IRealOscillator;
import io.github.dsheirer.dsp.oscillator.ScalarRealOscillator;
import io.github.dsheirer.dsp.oscillator.VectorRealOscillator;
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;
/**
* Calibration plugin for real oscillators
*/
public class RealOscillatorCalibration extends Calibration
{
private static final double FREQUENCY = 5.0d;
private static final double SAMPLE_RATE = 100.0d;
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 IRealOscillator mScalar = new ScalarRealOscillator(FREQUENCY, SAMPLE_RATE);
private IRealOscillator mVector = new VectorRealOscillator(FREQUENCY, SAMPLE_RATE);
/**
* Constructs an instance
*/
public RealOscillatorCalibration()
{
super(CalibrationType.OSCILLATOR_REAL);
}
/**
* Performs calibration to determine optimal (Scalar vs Vector) operation type.
* @throws CalibrationException
*/
@Override public void calibrate() throws CalibrationException
{
Mean scalarMean = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testScalar();
scalarMean.increment(score);
}
mLog.info("REAL OSCILLATOR WARMUP - SCALAR:" + DECIMAL_FORMAT.format(scalarMean.getResult()));
Mean vectorMean = new Mean();
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
long score = testVector();
vectorMean.increment(score);
}
mLog.info("REAL OSCILLATOR WARMUP - VECTOR:" + DECIMAL_FORMAT.format(vectorMean.getResult()));
//Test begins
scalarMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testScalar();
scalarMean.increment(score);
}
mLog.info("REAL OSCILLATOR - SCALAR:" + DECIMAL_FORMAT.format(scalarMean.getResult()));
vectorMean.clear();
for(int x = 0; x < TEST_ITERATIONS; x++)
{
long score = testVector();
vectorMean.increment(score);
}
mLog.info("REAL OSCILLATOR - VECTOR:" + DECIMAL_FORMAT.format(vectorMean.getResult()));
if(scalarMean.getResult() > vectorMean.getResult())
{
setImplementation(Implementation.SCALAR);
}
else
{
setImplementation(Implementation.VECTOR_SIMD_PREFERRED);
}
mLog.info("REAL OSCILLATOR - SET OPTIMAL IMPLEMENTATION TO:" + getImplementation());
}
private long testScalar()
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] generated = mScalar.generate(BUFFER_SIZE);
accumulator += generated[1];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector()
{
double accumulator = 0.0;
long count = 0;
long start = System.currentTimeMillis();
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
float[] generated = mVector.generate(BUFFER_SIZE);
accumulator += generated[1];
count++;
}
return count + (long)(accumulator * 0);
}
}

View File

@@ -0,0 +1,144 @@
/*
* *****************************************************************************
* 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.window;
import io.github.dsheirer.dsp.window.ScalarWindow;
import io.github.dsheirer.dsp.window.VectorWindow;
import io.github.dsheirer.dsp.window.Window;
import io.github.dsheirer.dsp.window.WindowFactory;
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;
/**
* Calculates the optimal (scalar vs vector) implementation for windowing samples.
*/
public class WindowCalibration extends Calibration
{
private static final int WINDOW_SIZE = 8192;
private static final int ITERATION_DURATION_MS = 1000;
private static final int WARMUP_ITERATIONS = 5;
private static final int TEST_ITERATIONS = 5;
private Window mScalarWindow;
private Window mVectorWindow;
/**
* Constructs an instance
*/
public WindowCalibration()
{
super(CalibrationType.WINDOW);
float[] window = WindowFactory.getBlackman(WINDOW_SIZE);
mScalarWindow = new ScalarWindow(window);
mVectorWindow = new VectorWindow(window);
}
@Override public void calibrate() throws CalibrationException
{
Mean scalarMean = new Mean();
float[] samples = getFloatSamples(WINDOW_SIZE);
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
scalarMean.increment(testScalar(samples));
}
mLog.info("WINDOW WARMUP - SCALAR: " + scalarMean.getResult());
Mean vectorMean = new Mean();
samples = getFloatSamples(WINDOW_SIZE);
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
vectorMean.increment(testVector(samples));
}
mLog.info("WINDOW WARMUP - VECTOR: " + vectorMean.getResult());
//Test starts ...
scalarMean.clear();
samples = getFloatSamples(WINDOW_SIZE);
for(int x = 0; x < TEST_ITERATIONS; x++)
{
scalarMean.increment(testScalar(samples));
}
mLog.info("WINDOW - SCALAR: " + scalarMean.getResult());
vectorMean.clear();
samples = getFloatSamples(WINDOW_SIZE);
for(int x = 0; x < WARMUP_ITERATIONS; x++)
{
vectorMean.increment(testVector(samples));
}
mLog.info("WINDOW - VECTOR: " + vectorMean.getResult());
if(scalarMean.getResult() > vectorMean.getResult())
{
setImplementation(Implementation.SCALAR);
}
else
{
setImplementation(Implementation.VECTOR_SIMD_PREFERRED);
}
mLog.info("WINDOW - OPTIMAL IMPLEMENTATION SET TO: " + getImplementation());
}
private long testScalar(float[] samples)
{
long start = System.currentTimeMillis();
double accumulator = 0.0d;
long count = 0;
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
mScalarWindow.apply(samples);
accumulator += samples[3];
count++;
}
return count + (long)(accumulator * 0);
}
private long testVector(float[] samples)
{
long start = System.currentTimeMillis();
double accumulator = 0.0d;
long count = 0;
while((System.currentTimeMillis() - start) < ITERATION_DURATION_MS)
{
mVectorWindow.apply(samples);
accumulator += samples[3];
count++;
}
return count + (long)(accumulator * 0);
}
}