mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 16:47:31 -05:00
#1633 DMR Decoder redesign. Uses new DQPSK vector/scalar demodulator implementations and soft sync detectors for more accurate detections and symbol timing and symbol period calculations. Includes two new calibrations with scalar and vector implementations for DQPSK demodulator and Interpolator. Enhances DMR error detection and correction algorithms, specifically the block product turbo code algorithms. (#2115)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 Dennis Sheirer
|
||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -56,15 +56,14 @@ import io.github.dsheirer.dsp.window.WindowType;
|
||||
import io.github.dsheirer.vector.calibrate.CalibrationManager;
|
||||
import io.github.dsheirer.vector.calibrate.CalibrationType;
|
||||
import io.github.dsheirer.vector.calibrate.Implementation;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import org.apache.commons.math3.util.FastMath;
|
||||
import org.jtransforms.fft.FloatFFT_1D;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* Utility methods for designing various types of filters.
|
||||
*/
|
||||
@@ -627,11 +626,13 @@ public class FilterFactory
|
||||
* @param samplesPerSymbol - number of samples per symbol
|
||||
* @param symbolCount - number of symbol intervals for the filter. This directly impacts the filter size
|
||||
* @param alpha - roll-off factor.
|
||||
* @param gain of the filter
|
||||
* @return - filter coefficients
|
||||
*/
|
||||
public static float[] getRootRaisedCosine(double samplesPerSymbol, int symbolCount, float alpha)
|
||||
{
|
||||
int taps = (int)(samplesPerSymbol * symbolCount);
|
||||
samplesPerSymbol /= 2;
|
||||
int taps = (int)Math.round(samplesPerSymbol * symbolCount);
|
||||
|
||||
float scale = 0;
|
||||
|
||||
@@ -639,47 +640,47 @@ public class FilterFactory
|
||||
|
||||
for(int x = 0; x < taps; x++)
|
||||
{
|
||||
float index = (float)x - ((float)taps / 2.0f);
|
||||
double index = x - (taps / 2.0f);
|
||||
|
||||
float x1 = (float)FastMath.PI * index / (float)samplesPerSymbol;
|
||||
float x2 = 4.0f * alpha * index / (float)samplesPerSymbol;
|
||||
float x3 = x2 * x2 - 1.0f;
|
||||
double x1 = FastMath.PI * index / samplesPerSymbol;
|
||||
double x2 = 4.0 * alpha * index / samplesPerSymbol;
|
||||
double x3 = x2 * x2 - 1.0;
|
||||
|
||||
float numerator, denominator;
|
||||
double numerator, denominator;
|
||||
|
||||
if(FastMath.abs(x3) >= 0.000001)
|
||||
{
|
||||
if(x != taps / 2)
|
||||
{
|
||||
numerator = (float)FastMath.cos((1.0 + alpha) * x1) +
|
||||
(float)FastMath.sin((1.0f - alpha) * x1) / (4.0f * alpha * index / (float)samplesPerSymbol);
|
||||
numerator = FastMath.cos((1.0 + alpha) * x1) +
|
||||
FastMath.sin((1.0 - alpha) * x1) / (4.0 * alpha * index / samplesPerSymbol);
|
||||
}
|
||||
else
|
||||
{
|
||||
numerator = (float)FastMath.cos((1.0f + alpha) * x1) + (1.0f - alpha) * (float)FastMath.PI / (4.0f * alpha);
|
||||
numerator = FastMath.cos((1.0 + alpha) * x1) + (1.0 - alpha) * FastMath.PI / (4.0 * alpha);
|
||||
}
|
||||
|
||||
denominator = x3 * (float)FastMath.PI;
|
||||
denominator = x3 * FastMath.PI;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(alpha == 1.0f)
|
||||
if(alpha == 1.0)
|
||||
{
|
||||
coefficients[x] = -1.0f;
|
||||
continue;
|
||||
}
|
||||
|
||||
x3 = (1.0f - alpha) * x1;
|
||||
x2 = (1.0f + alpha) * x1;
|
||||
x3 = (1.0 - alpha) * x1;
|
||||
x2 = (1.0 + alpha) * x1;
|
||||
|
||||
numerator = (float)(FastMath.sin(x2) * (1.0f + alpha) * FastMath.PI - FastMath.cos(x3) * ((1.0 - alpha) * FastMath.PI *
|
||||
(double)samplesPerSymbol) / (4.0 * alpha * index) + FastMath.sin(x3) * (double)samplesPerSymbol *
|
||||
(double)samplesPerSymbol / (4.0 * alpha * index * index));
|
||||
numerator = (FastMath.sin(x2) * (1.0 + alpha) * FastMath.PI - FastMath.cos(x3) * ((1.0 - alpha) * FastMath.PI *
|
||||
samplesPerSymbol) / (4.0 * alpha * index) + FastMath.sin(x3) * samplesPerSymbol *
|
||||
samplesPerSymbol / (4.0 * alpha * index * index));
|
||||
|
||||
denominator = (float)(-32.0 * FastMath.PI * alpha * alpha * index / (double)samplesPerSymbol);
|
||||
denominator = -32.0 * FastMath.PI * alpha * alpha * index / samplesPerSymbol;
|
||||
}
|
||||
|
||||
coefficients[x] = 4.0f * alpha * numerator / denominator;
|
||||
coefficients[x] = (float)(4.0 * alpha * numerator / denominator);
|
||||
|
||||
scale += coefficients[x];
|
||||
}
|
||||
@@ -1210,13 +1211,20 @@ public class FilterFactory
|
||||
{
|
||||
DecimalFormat df = new DecimalFormat("0.000000");
|
||||
|
||||
int length = 15;
|
||||
int length = 49;
|
||||
|
||||
float [] taps = FilterFactory.getHalfBand(length, WindowType.HAMMING);
|
||||
|
||||
for(int x = 0; x < length; x++)
|
||||
try
|
||||
{
|
||||
mLog.debug("Tap: " + x + " Value: " + df.format(taps[x]));
|
||||
float [] taps = FilterFactory.getSinc(0.5, length, WindowType.NONE);
|
||||
|
||||
for(int x = 0; x < length; x++)
|
||||
{
|
||||
mLog.debug("Tap: " + x + " Value: " + df.format(taps[x]));
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
mLog.debug("Done!");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 Dennis Sheirer
|
||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -20,7 +20,6 @@
|
||||
package io.github.dsheirer.dsp.filter.design;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.hilbert.HilbertTransform;
|
||||
import io.github.dsheirer.dsp.window.WindowType;
|
||||
import javafx.application.Application;
|
||||
import javafx.scene.Scene;
|
||||
@@ -62,9 +61,10 @@ public class FilterViewer extends Application
|
||||
int filterLength = 47;
|
||||
WindowType windowType = WindowType.HAMMING;
|
||||
|
||||
float[] taps = FilterFactory.getHalfBand(filterLength, windowType);
|
||||
// float[] taps = FilterFactory.getHalfBand(filterLength, windowType);
|
||||
float[] taps = FilterFactory.getRootRaisedCosine(50000.0 / 4800.0, 20, 0.2f);
|
||||
|
||||
taps = HilbertTransform.HALF_BAND_FILTER_47_TAP;
|
||||
// taps = HilbertTransform.HALF_BAND_FILTER_47_TAP;
|
||||
|
||||
if(taps == null)
|
||||
{
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.interpolator;
|
||||
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2015 Dennis Sheirer
|
||||
*
|
||||
* Copyright (C) 2002,2012 Free Software Foundation, Inc.
|
||||
* Ported to java from gnuradio - interpolator_taps.h
|
||||
*
|
||||
* 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/>
|
||||
******************************************************************************/
|
||||
public abstract class Interpolator
|
||||
{
|
||||
public static final int NTAPS = 8;
|
||||
@@ -158,4 +157,19 @@ public abstract class Interpolator
|
||||
{ -1.98993e-04f, 1.24642e-03f, -5.41054e-03f, 9.98534e-01f, 7.89295e-03f, -2.76968e-03f, 8.53777e-04f, -1.54700e-04f }, // 127/128
|
||||
{ 0.00000e+00f, 0.00000e+00f, 0.00000e+00f, 1.00000e+00f, 0.00000e+00f, 0.00000e+00f, 0.00000e+00f, 0.00000e+00f }, // 128/128
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculates an interpolated value from eight samples that start at the offset into the sample array. The
|
||||
* interpolated sample will fall within the middle of the eight sample array, between indexes offset+3 and
|
||||
* offset+4. The mu argument is translated into an index position between 0 and 128, where a mu of 0.0 will be
|
||||
* converted to index zero and will be equal to the sample at index offset+3 and a mu of 1.0 will be equal to
|
||||
* the sample at offset+4. All mu values between 0.0 and 1.0 will be converted to a 1 - 127 index and will
|
||||
* produce an approximated value from among 127 interpolated sample points between indexes offset+3 and offset+4.
|
||||
*
|
||||
* @param samples - sample array of length at least offset + 7
|
||||
* @param offset into the sample array for the start of the 8-value sequence
|
||||
* @param mu - interpolated sample position between 0.0 and 1.0
|
||||
* @return - interpolated sample value
|
||||
*/
|
||||
public abstract float filter(float[] samples, int offset, float mu);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.interpolator;
|
||||
|
||||
import io.github.dsheirer.vector.calibrate.CalibrationManager;
|
||||
import io.github.dsheirer.vector.calibrate.CalibrationType;
|
||||
import io.github.dsheirer.vector.calibrate.Implementation;
|
||||
|
||||
/**
|
||||
* Factory for creating an optimal scalar or vector (SIMD) interpolator implementation
|
||||
*/
|
||||
public class InterpolatorFactory
|
||||
{
|
||||
/**
|
||||
* Selects and instantiates the best interpolator version, scalar or vector, based on previous calibration.
|
||||
* @return interpolator
|
||||
*/
|
||||
public static Interpolator getInterpolator()
|
||||
{
|
||||
Implementation implementation = CalibrationManager.getInstance().getImplementation(CalibrationType.INTERPOLATOR);
|
||||
return getInterpolator(implementation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates the specified interpolator implementation.
|
||||
* @param implementation to construct.
|
||||
* @return interpolator.
|
||||
*/
|
||||
public static Interpolator getInterpolator(Implementation implementation)
|
||||
{
|
||||
return switch(implementation)
|
||||
{
|
||||
case VECTOR_SIMD_64 -> new InterpolatorVector64();
|
||||
case VECTOR_SIMD_128 -> new InterpolatorVector128();
|
||||
case VECTOR_SIMD_256, VECTOR_SIMD_512 -> new InterpolatorVector256(); //Vector 512 not supported
|
||||
case SCALAR, UNCALIBRATED -> new InterpolatorScalar();
|
||||
default -> throw new IllegalArgumentException("Unknown implementation type: " + implementation);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,35 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.interpolator;
|
||||
|
||||
import io.github.dsheirer.sample.complex.Complex;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Arrays;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.math3.util.FastMath;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class RealInterpolator extends Interpolator
|
||||
public class InterpolatorScalar extends Interpolator
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(RealInterpolator.class);
|
||||
private final static Logger mLog = LoggerFactory.getLogger(InterpolatorScalar.class);
|
||||
|
||||
private float mGain;
|
||||
|
||||
@@ -21,11 +39,16 @@ public class RealInterpolator extends Interpolator
|
||||
*
|
||||
* @param gain to apply to the interpolated sample
|
||||
*/
|
||||
public RealInterpolator(float gain)
|
||||
public InterpolatorScalar(float gain)
|
||||
{
|
||||
mGain = gain;
|
||||
}
|
||||
|
||||
public InterpolatorScalar()
|
||||
{
|
||||
this(1.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates an interpolated value from eight samples that start at the offset into the sample array. The
|
||||
* interpolated sample will fall within the middle of the eight sample array, between indexes offset+3 and
|
||||
@@ -68,7 +91,7 @@ public class RealInterpolator extends Interpolator
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
RealInterpolator interpolator = new RealInterpolator(1.0f);
|
||||
InterpolatorScalar interpolator = new InterpolatorScalar(1.0f);
|
||||
DecimalFormat decimalFormat = new DecimalFormat("0.0000");
|
||||
|
||||
double TWO_PI = FastMath.PI * 2.0;
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.interpolator;
|
||||
|
||||
import jdk.incubator.vector.FloatVector;
|
||||
import jdk.incubator.vector.VectorOperators;
|
||||
import jdk.incubator.vector.VectorSpecies;
|
||||
|
||||
/**
|
||||
* Vector interpolator for 128 bit SIMD instructions.
|
||||
*/
|
||||
public class InterpolatorVector128 extends VectorInterpolator
|
||||
{
|
||||
private static final VectorSpecies<Float> VECTOR_SPECIES = FloatVector.SPECIES_128;
|
||||
|
||||
@Override
|
||||
protected float vectorFilter(float[] samples, int offset, int index)
|
||||
{
|
||||
FloatVector accumulator = FloatVector.zero(VECTOR_SPECIES);
|
||||
FloatVector tapsVector, sampleVector;
|
||||
|
||||
tapsVector = FloatVector.fromArray(VECTOR_SPECIES, TAPS[index], 0);
|
||||
sampleVector = FloatVector.fromArray(VECTOR_SPECIES, samples, offset);
|
||||
accumulator = tapsVector.fma(sampleVector, accumulator);
|
||||
|
||||
tapsVector = FloatVector.fromArray(VECTOR_SPECIES, TAPS[index], 4);
|
||||
sampleVector = FloatVector.fromArray(VECTOR_SPECIES, samples, offset + 4);
|
||||
accumulator = tapsVector.fma(sampleVector, accumulator);
|
||||
|
||||
return accumulator.reduceLanes(VectorOperators.ADD);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.interpolator;
|
||||
|
||||
import jdk.incubator.vector.FloatVector;
|
||||
import jdk.incubator.vector.VectorOperators;
|
||||
import jdk.incubator.vector.VectorSpecies;
|
||||
|
||||
/**
|
||||
* Vector interpolator for 256 bit SIMD instructions.
|
||||
*/
|
||||
public class InterpolatorVector256 extends VectorInterpolator
|
||||
{
|
||||
private static final VectorSpecies<Float> VECTOR_SPECIES = FloatVector.SPECIES_256;
|
||||
|
||||
@Override
|
||||
protected float vectorFilter(float[] samples, int offset, int index)
|
||||
{
|
||||
FloatVector tapsVector = FloatVector.fromArray(VECTOR_SPECIES, TAPS[index], 0);
|
||||
FloatVector sampleVector = FloatVector.fromArray(VECTOR_SPECIES, samples, offset);
|
||||
return sampleVector.mul(tapsVector).reduceLanes(VectorOperators.ADD);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.interpolator;
|
||||
|
||||
import jdk.incubator.vector.FloatVector;
|
||||
import jdk.incubator.vector.VectorOperators;
|
||||
import jdk.incubator.vector.VectorSpecies;
|
||||
|
||||
/**
|
||||
* Vector interpolator for 64 bit SIMD instructions.
|
||||
*/
|
||||
public class InterpolatorVector64 extends VectorInterpolator
|
||||
{
|
||||
private static final VectorSpecies<Float> VECTOR_SPECIES = FloatVector.SPECIES_64;
|
||||
|
||||
@Override
|
||||
protected float vectorFilter(float[] samples, int offset, int index)
|
||||
{
|
||||
FloatVector accumulator = FloatVector.zero(VECTOR_SPECIES);
|
||||
FloatVector tapsVector, sampleVector;
|
||||
|
||||
tapsVector = FloatVector.fromArray(VECTOR_SPECIES, TAPS[index], 0);
|
||||
sampleVector = FloatVector.fromArray(VECTOR_SPECIES, samples, offset);
|
||||
accumulator = tapsVector.fma(sampleVector, accumulator);
|
||||
|
||||
tapsVector = FloatVector.fromArray(VECTOR_SPECIES, TAPS[index], 2);
|
||||
sampleVector = FloatVector.fromArray(VECTOR_SPECIES, samples, offset + 2);
|
||||
accumulator = tapsVector.fma(sampleVector, accumulator);
|
||||
|
||||
tapsVector = FloatVector.fromArray(VECTOR_SPECIES, TAPS[index], 4);
|
||||
sampleVector = FloatVector.fromArray(VECTOR_SPECIES, samples, offset + 4);
|
||||
accumulator = tapsVector.fma(sampleVector, accumulator);
|
||||
|
||||
tapsVector = FloatVector.fromArray(VECTOR_SPECIES, TAPS[index], 6);
|
||||
sampleVector = FloatVector.fromArray(VECTOR_SPECIES, samples, offset + 6);
|
||||
accumulator = tapsVector.fma(sampleVector, accumulator);
|
||||
|
||||
return accumulator.reduceLanes(VectorOperators.ADD);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.interpolator;
|
||||
|
||||
/**
|
||||
* Linear interpolator for values in the range: -PI > 0 > PI with awareness of phase wrapping across the
|
||||
* (+/-) PI boundary.
|
||||
*/
|
||||
public class PhaseAwareLinearInterpolator
|
||||
{
|
||||
public static final float TWO_PI = (float)(Math.PI * 2.0);
|
||||
|
||||
/**
|
||||
* Calculates an interpolated value between x1 and x2 at a linear position mu between 0.0 and 1.0
|
||||
* @param x1 first value
|
||||
* @param x2 second value
|
||||
* @param mu offset between first and second values in range 0.0 to 1.0
|
||||
* @return interpolated value.
|
||||
*/
|
||||
public static float calculate(float x1, float x2, float mu)
|
||||
{
|
||||
//Detect phase wrap at the +PI/-PI boundary ... ignore opposite side of the unit circle at 0 axis
|
||||
if(x1 * x2 < -Math.PI)
|
||||
{
|
||||
if(x1 > 0)
|
||||
{
|
||||
float value = x1 + ((TWO_PI + x2 - x1) * mu);
|
||||
|
||||
if(value > Math.PI)
|
||||
{
|
||||
return -TWO_PI + value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float value = x1 + ((-TWO_PI + x2 - x1) * mu);
|
||||
|
||||
if(value < -Math.PI)
|
||||
{
|
||||
return TWO_PI + value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return x1 + ((x2 - x1) * mu);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2023 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.interpolator;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
/**
|
||||
* Base vector interpolator implementation.
|
||||
*/
|
||||
public abstract class VectorInterpolator extends Interpolator
|
||||
{
|
||||
@Override
|
||||
public float filter(float[] samples, int offset, float mu)
|
||||
{
|
||||
/* Ensure we have enough samples in the array */
|
||||
Validate.isTrue(samples.length >= offset + 7, "Offset [" + offset + "] must be 7 less than length[" + samples.length + "]");
|
||||
|
||||
//Identify the filter bank that corresponds to mu. Note: since we're not loading the TAPS in reverse order,
|
||||
//we select the inverse tap index that has the mirrored set of taps, by subtracting from 127.
|
||||
int index = 127 - (int)(NSTEPS * mu);
|
||||
return vectorFilter(samples, offset, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform vectorized interpolation to find the interpolated value from the samples where the 8-value sequence
|
||||
* starts at the offset into the array, using the filter coefficients specified by the index value.
|
||||
* @param samples to interpolate
|
||||
* @param offset to the start of the 8-value sequence
|
||||
* @param index into the TAPS coefficients array.
|
||||
* @return interpolated value.
|
||||
*/
|
||||
protected abstract float vectorFilter(float[] samples, int offset, int index);
|
||||
}
|
||||
@@ -1,23 +1,30 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
* 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.
|
||||
* 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/>
|
||||
*
|
||||
******************************************************************************/
|
||||
* 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.dsp.psk;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.interpolator.Interpolator;
|
||||
import io.github.dsheirer.dsp.filter.interpolator.InterpolatorFactory;
|
||||
import io.github.dsheirer.dsp.psk.pll.CostasLoop;
|
||||
import io.github.dsheirer.dsp.psk.pll.IPhaseLockedLoop;
|
||||
import io.github.dsheirer.dsp.symbol.Dibit;
|
||||
import io.github.dsheirer.sample.complex.Complex;
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
public class DQPSKDecisionDirectedDemodulator extends PSKDemodulator<Dibit>
|
||||
{
|
||||
@@ -29,6 +36,11 @@ public class DQPSKDecisionDirectedDemodulator extends PSKDemodulator<Dibit>
|
||||
private Complex mPrecedingSymbol = new Complex(0, 0);
|
||||
protected Complex mCurrentSymbol = new Complex(0, 0);
|
||||
|
||||
private final Interpolator mInterpolator = InterpolatorFactory.getInterpolator();
|
||||
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("+#0.00000;-#0.00000");
|
||||
private float[] mI = new float[15];
|
||||
private float[] mQ = new float[15];
|
||||
|
||||
/**
|
||||
* Decoder for Differential Quaternary Phase Shift Keying (DQPSK). This decoder uses both a Costas Loop (PLL) and
|
||||
* a decision-directed DQPSK symbol timing and phase error detector to automatically align to the incoming carrier
|
||||
@@ -44,6 +56,32 @@ public class DQPSKDecisionDirectedDemodulator extends PSKDemodulator<Dibit>
|
||||
super(interpolatingSampleBuffer, phaseLockedLoop);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(float inphase, float quadrature)
|
||||
{
|
||||
super.receive(inphase, quadrature);
|
||||
|
||||
System.arraycopy(mI, 1, mI, 0, mI.length - 1);
|
||||
System.arraycopy(mQ, 1, mQ, 0, mQ.length - 1);
|
||||
|
||||
//Rotate the sample and add to buffer
|
||||
Complex current = new Complex(inphase, quadrature);
|
||||
current.normalizeFast();
|
||||
current.multiply(getPLL().getCurrentVector());
|
||||
mI[mI.length - 1] = current.inphase();
|
||||
mQ[mQ.length - 1] = current.quadrature();
|
||||
float iTemp = mInterpolator.filter(mI, 6, .416f);
|
||||
float qTemp = mInterpolator.filter(mQ, 6, .416f);
|
||||
float iSymbol = (mI[0] * iTemp) - (-mQ[0] * qTemp);
|
||||
float qSymbol = (mI[0] * qTemp) + (iTemp * -mQ[0]);
|
||||
float radians = (float)Math.atan2(iSymbol, qSymbol);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(DECIMAL_FORMAT.format(radians)).append(",");
|
||||
sb.append(DECIMAL_FORMAT.format(((CostasLoop)getPLL()).getLoopFrequency()));
|
||||
// System.out.println(sb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates a symbol from the interpolating buffer
|
||||
*/
|
||||
@@ -79,7 +117,7 @@ public class DQPSKDecisionDirectedDemodulator extends PSKDemodulator<Dibit>
|
||||
getInterpolatingSampleBuffer().resetAndAdjust(mSymbolEvaluator.getTimingError());
|
||||
|
||||
//Update the costas loop (PLL) with any measured phase error
|
||||
getPLL().adjust(clip(mSymbolEvaluator.getPhaseError(), 0.5f));
|
||||
// getPLL().adjust(clip(mSymbolEvaluator.getPhaseError(), 0.5f));
|
||||
|
||||
//Store current samples/symbols to use for the next symbol period
|
||||
mPreviousPrecedingSample.setValues(mPrecedingSample);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 Dennis Sheirer
|
||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -18,7 +18,7 @@
|
||||
*/
|
||||
package io.github.dsheirer.dsp.psk;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.interpolator.RealInterpolator;
|
||||
import io.github.dsheirer.dsp.filter.interpolator.InterpolatorScalar;
|
||||
import io.github.dsheirer.sample.complex.Complex;
|
||||
import org.apache.commons.math3.util.FastMath;
|
||||
import org.slf4j.Logger;
|
||||
@@ -45,7 +45,7 @@ public class InterpolatingSampleBuffer
|
||||
private float mMaximumSamplesPerSymbol;
|
||||
private float mMinimumSamplesPerSymbol;
|
||||
|
||||
private RealInterpolator mInterpolator = new RealInterpolator(1.0f);
|
||||
private InterpolatorScalar mInterpolator = new InterpolatorScalar(1.0f);
|
||||
|
||||
/**
|
||||
* Buffer to store complex sample data and produce interpolated samples.
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.psk.dqpsk;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.interpolator.Interpolator;
|
||||
import io.github.dsheirer.dsp.filter.interpolator.InterpolatorFactory;
|
||||
import io.github.dsheirer.dsp.fm.IDemodulator;
|
||||
|
||||
/**
|
||||
* DQPSK demodulator base class
|
||||
*/
|
||||
public abstract class DQPSKDemodulator implements IDemodulator
|
||||
{
|
||||
private int mSymbolRate;
|
||||
private float mSampleRate;
|
||||
private float mSamplesPerSymbol;
|
||||
protected float[] mIBuffer = new float[20]; //Initial size 20 for array copy, but gets resized on first buffer
|
||||
protected float[] mQBuffer = new float[20];
|
||||
protected float mMu;
|
||||
protected int mBufferOverlap;
|
||||
protected int mInterpolationOffset;
|
||||
protected final Interpolator mInterpolator = InterpolatorFactory.getInterpolator();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param sampleRate in Hertz
|
||||
* @param symbolRate symbols per second
|
||||
*/
|
||||
public DQPSKDemodulator(double sampleRate, int symbolRate)
|
||||
{
|
||||
mSampleRate = (float) sampleRate;
|
||||
mSymbolRate = symbolRate;
|
||||
mSamplesPerSymbol = mSampleRate / mSymbolRate;
|
||||
mMu = mSamplesPerSymbol % 1; //Fractional part of the samples per symbol rate
|
||||
mInterpolationOffset = (int) Math.floor(mSamplesPerSymbol) - 4; //Interpolate at the middle of 8x samples
|
||||
mBufferOverlap = (int) Math.floor(mSamplesPerSymbol) + 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculated samples per symbol.
|
||||
* @return samples per symbol.
|
||||
*/
|
||||
public float getSamplesPerSymbol()
|
||||
{
|
||||
return mSamplesPerSymbol;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.psk.dqpsk;
|
||||
|
||||
import io.github.dsheirer.vector.calibrate.CalibrationManager;
|
||||
import io.github.dsheirer.vector.calibrate.CalibrationType;
|
||||
import io.github.dsheirer.vector.calibrate.Implementation;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Factory for creating DQPSK demodulators
|
||||
*/
|
||||
public class DQPSKDemodulatorFactory
|
||||
{
|
||||
private static final Logger mLog = LoggerFactory.getLogger(DQPSKDemodulatorFactory.class);
|
||||
|
||||
/**
|
||||
* Creates the optimal demodulator using calibration data to select the optimal implementation from scalar and
|
||||
* vector options, or defaults to the scalar implementation if the calibration wasn't executed.
|
||||
* @param sampleRate in Hertz
|
||||
* @param symbolRate in Hertz
|
||||
* @return demodulator instance
|
||||
*/
|
||||
public static DQPSKDemodulator getDemodulator(double sampleRate, int symbolRate)
|
||||
{
|
||||
Implementation implementation = CalibrationManager.getInstance().getImplementation(CalibrationType.DQPSK_DEMODULATOR);
|
||||
|
||||
return switch(implementation)
|
||||
{
|
||||
case VECTOR_SIMD_64 -> new DQPSKDemodulatorVector64(sampleRate, symbolRate);
|
||||
case VECTOR_SIMD_128 -> new DQPSKDemodulatorVector128(sampleRate, symbolRate);
|
||||
case VECTOR_SIMD_256 -> new DQPSKDemodulatorVector256(sampleRate, symbolRate);
|
||||
case VECTOR_SIMD_512 -> new DQPSKDemodulatorVector512(sampleRate, symbolRate);
|
||||
default -> new DQPSKDemodulatorScalar(sampleRate, symbolRate); //Includes SCALAR case
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.psk.dqpsk;
|
||||
|
||||
import java.util.Arrays;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* DQPSK demodulator that uses scalar calculations for demodulating the sample stream.
|
||||
*/
|
||||
public class DQPSKDemodulatorScalar extends DQPSKDemodulator
|
||||
{
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(DQPSKDemodulatorScalar.class);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param symbolRate symbols per second
|
||||
*/
|
||||
public DQPSKDemodulatorScalar(double sampleRate, int symbolRate)
|
||||
{
|
||||
super(sampleRate, symbolRate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] demodulate(float[] i, float[] q)
|
||||
{
|
||||
int sampleLength = i.length;
|
||||
int bufferOverlap = mBufferOverlap;
|
||||
float mu = mMu;
|
||||
|
||||
//Copy previous buffer residual samples to beginning of buffer.
|
||||
System.arraycopy(mIBuffer, mIBuffer.length - bufferOverlap, mIBuffer, 0, bufferOverlap);
|
||||
System.arraycopy(mQBuffer, mQBuffer.length - bufferOverlap, mQBuffer, 0, bufferOverlap);
|
||||
|
||||
//Resize I/Q buffers if necessary
|
||||
int requiredBufferLength = sampleLength + bufferOverlap;
|
||||
if(mIBuffer.length != requiredBufferLength)
|
||||
{
|
||||
mIBuffer = Arrays.copyOf(mIBuffer, requiredBufferLength);
|
||||
mQBuffer = Arrays.copyOf(mQBuffer, requiredBufferLength);
|
||||
}
|
||||
|
||||
//Append new samples to the residual samples from the previous buffer.
|
||||
System.arraycopy(i, 0, mIBuffer, bufferOverlap, sampleLength);
|
||||
System.arraycopy(q, 0, mQBuffer, bufferOverlap, sampleLength);
|
||||
//mIDecoded, mQDecoded and mPhase will be filled below during the decoding process.
|
||||
|
||||
float[] decodedPhases = new float[i.length];
|
||||
float iPrevious, qPreviousConjugate, iCurrent, qCurrent, differentialI, differentialQ;
|
||||
|
||||
//Differential demodulation.
|
||||
for(int x = 0; x < sampleLength; x++)
|
||||
{
|
||||
iPrevious = mIBuffer[x];
|
||||
qPreviousConjugate = -mQBuffer[x]; //Complex Conjugate
|
||||
|
||||
int offset = mInterpolationOffset + x;
|
||||
iCurrent = mInterpolator.filter(mIBuffer, offset, mu);
|
||||
qCurrent = mInterpolator.filter(mQBuffer, offset, mu);
|
||||
|
||||
//Multiply current complex sample by the complex conjugate of previous complex sample.
|
||||
differentialI = (iPrevious * iCurrent) - (qPreviousConjugate * qCurrent);
|
||||
differentialQ = (iPrevious * qCurrent) + (iCurrent * qPreviousConjugate);
|
||||
|
||||
decodedPhases[x] = (float)Math.atan2(differentialQ, differentialI);
|
||||
}
|
||||
|
||||
return decodedPhases;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.psk.dqpsk;
|
||||
|
||||
import java.util.Arrays;
|
||||
import jdk.incubator.vector.FloatVector;
|
||||
import jdk.incubator.vector.VectorOperators;
|
||||
import jdk.incubator.vector.VectorSpecies;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* DQPSK demodulator that uses Vector SIMD 128 calculations for demodulating the sample stream.
|
||||
*/
|
||||
public class DQPSKDemodulatorVector128 extends DQPSKDemodulator
|
||||
{
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(DQPSKDemodulatorVector128.class);
|
||||
private static final VectorSpecies<Float> VECTOR_SPECIES = FloatVector.SPECIES_128;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param sampleRate in Hertz
|
||||
* @param symbolRate symbols per second
|
||||
*/
|
||||
public DQPSKDemodulatorVector128(double sampleRate, int symbolRate)
|
||||
{
|
||||
super(sampleRate, symbolRate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] demodulate(float[] i, float[] q)
|
||||
{
|
||||
int sampleLength = i.length;
|
||||
int bufferOverlap = mBufferOverlap;
|
||||
float mu = mMu;
|
||||
|
||||
//Copy previous buffer residual samples to beginning of buffer.
|
||||
System.arraycopy(mIBuffer, mIBuffer.length - bufferOverlap, mIBuffer, 0, bufferOverlap);
|
||||
System.arraycopy(mQBuffer, mQBuffer.length - bufferOverlap, mQBuffer, 0, bufferOverlap);
|
||||
|
||||
//Resize I/Q buffers if necessary
|
||||
int requiredBufferLength = sampleLength + bufferOverlap;
|
||||
if(mIBuffer.length != requiredBufferLength)
|
||||
{
|
||||
if(i.length % VECTOR_SPECIES.length() != 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Buffer length must be a multiple of " + VECTOR_SPECIES.length());
|
||||
}
|
||||
mIBuffer = Arrays.copyOf(mIBuffer, requiredBufferLength);
|
||||
mQBuffer = Arrays.copyOf(mQBuffer, requiredBufferLength);
|
||||
}
|
||||
|
||||
//Append new samples to the residual samples from the previous buffer.
|
||||
System.arraycopy(i, 0, mIBuffer, bufferOverlap, sampleLength);
|
||||
System.arraycopy(q, 0, mQBuffer, bufferOverlap, sampleLength);
|
||||
//mIDecoded, mQDecoded and mPhase will be filled below during the decoding process.
|
||||
|
||||
float[] interpolatedI = new float[VECTOR_SPECIES.length()];
|
||||
float[] interpolatedQ = new float[VECTOR_SPECIES.length()];
|
||||
float[] decodedPhases = new float[i.length];
|
||||
FloatVector iPrevious, qPreviousConjugate, iCurrent, qCurrent, differentialI, differentialQ;
|
||||
|
||||
//Differential demodulation.
|
||||
for(int x = 0; x < sampleLength; x += VECTOR_SPECIES.length())
|
||||
{
|
||||
iPrevious = FloatVector.fromArray(VECTOR_SPECIES, mIBuffer, x);
|
||||
qPreviousConjugate = FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x).neg(); //Complex Conjugate
|
||||
|
||||
int offset = mInterpolationOffset + x;
|
||||
int index;
|
||||
for(int y = 0; y < VECTOR_SPECIES.length(); y++)
|
||||
{
|
||||
index = offset + y;
|
||||
interpolatedI[y] = mInterpolator.filter(mIBuffer, index, mu);
|
||||
interpolatedQ[y] = mInterpolator.filter(mQBuffer, index, mu);
|
||||
}
|
||||
iCurrent = FloatVector.fromArray(VECTOR_SPECIES, interpolatedI, 0);
|
||||
qCurrent = FloatVector.fromArray(VECTOR_SPECIES, interpolatedQ, 0);
|
||||
|
||||
//Multiply current complex sample by the complex conjugate of previous complex sample.
|
||||
differentialI = iPrevious.mul(iCurrent).sub(qPreviousConjugate.mul(qCurrent));
|
||||
differentialQ = iPrevious.mul(qCurrent).add(iCurrent.mul(qPreviousConjugate));
|
||||
|
||||
//Calculate phase angles using Arc Tangent and export to the decoded phases array.
|
||||
differentialQ.lanewise(VectorOperators.ATAN2, differentialI).intoArray(decodedPhases, x);
|
||||
}
|
||||
|
||||
return decodedPhases;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.psk.dqpsk;
|
||||
|
||||
import java.util.Arrays;
|
||||
import jdk.incubator.vector.FloatVector;
|
||||
import jdk.incubator.vector.VectorOperators;
|
||||
import jdk.incubator.vector.VectorSpecies;
|
||||
|
||||
/**
|
||||
* DQPSK demodulator that uses Vector SIMD calculations for demodulating the sample stream.
|
||||
*/
|
||||
public class DQPSKDemodulatorVector256 extends DQPSKDemodulator
|
||||
{
|
||||
private static final VectorSpecies<Float> VECTOR_SPECIES = FloatVector.SPECIES_256;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param sampleRate in Hertz
|
||||
* @param symbolRate symbols per second
|
||||
*/
|
||||
public DQPSKDemodulatorVector256(double sampleRate, int symbolRate)
|
||||
{
|
||||
super(sampleRate, symbolRate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] demodulate(float[] i, float[] q)
|
||||
{
|
||||
int sampleLength = i.length;
|
||||
int bufferOverlap = mBufferOverlap;
|
||||
float mu = mMu;
|
||||
|
||||
//Copy previous buffer residual samples to beginning of buffer.
|
||||
System.arraycopy(mIBuffer, mIBuffer.length - bufferOverlap, mIBuffer, 0, bufferOverlap);
|
||||
System.arraycopy(mQBuffer, mQBuffer.length - bufferOverlap, mQBuffer, 0, bufferOverlap);
|
||||
|
||||
//Resize I/Q buffers if necessary
|
||||
int requiredBufferLength = sampleLength + bufferOverlap;
|
||||
if(mIBuffer.length != requiredBufferLength)
|
||||
{
|
||||
if(i.length % VECTOR_SPECIES.length() != 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Buffer length must be a multiple of " + VECTOR_SPECIES.length());
|
||||
}
|
||||
mIBuffer = Arrays.copyOf(mIBuffer, requiredBufferLength);
|
||||
mQBuffer = Arrays.copyOf(mQBuffer, requiredBufferLength);
|
||||
}
|
||||
|
||||
//Append new samples to the residual samples from the previous buffer.
|
||||
System.arraycopy(i, 0, mIBuffer, bufferOverlap, sampleLength);
|
||||
System.arraycopy(q, 0, mQBuffer, bufferOverlap, sampleLength);
|
||||
//mIDecoded, mQDecoded and mPhase will be filled below during the decoding process.
|
||||
|
||||
float[] interpolatedI = new float[VECTOR_SPECIES.length()];
|
||||
float[] interpolatedQ = new float[VECTOR_SPECIES.length()];
|
||||
float[] decodedPhases = new float[sampleLength];
|
||||
FloatVector iPrevious, qPreviousConjugate, iCurrent, qCurrent, differentialI, differentialQ;
|
||||
|
||||
//Differential demodulation.
|
||||
for(int x = 0; x < sampleLength; x += VECTOR_SPECIES.length())
|
||||
{
|
||||
iPrevious = FloatVector.fromArray(VECTOR_SPECIES, mIBuffer, x);
|
||||
qPreviousConjugate = FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x).neg(); //Complex Conjugate
|
||||
|
||||
int offset = mInterpolationOffset + x;
|
||||
int index;
|
||||
for(int y = 0; y < VECTOR_SPECIES.length(); y++)
|
||||
{
|
||||
index = offset + y;
|
||||
interpolatedI[y] = mInterpolator.filter(mIBuffer, index, mu);
|
||||
interpolatedQ[y] = mInterpolator.filter(mQBuffer, index, mu);
|
||||
}
|
||||
iCurrent = FloatVector.fromArray(VECTOR_SPECIES, interpolatedI, 0);
|
||||
qCurrent = FloatVector.fromArray(VECTOR_SPECIES, interpolatedQ, 0);
|
||||
|
||||
//Multiply current complex sample by the complex conjugate of previous complex sample.
|
||||
differentialI = iPrevious.mul(iCurrent).sub(qPreviousConjugate.mul(qCurrent));
|
||||
differentialQ = iPrevious.mul(qCurrent).add(iCurrent.mul(qPreviousConjugate));
|
||||
|
||||
//Calculate phase angles using Arc Tangent and export to the decoded phases array.
|
||||
differentialQ.lanewise(VectorOperators.ATAN2, differentialI).intoArray(decodedPhases, x);
|
||||
}
|
||||
|
||||
return decodedPhases;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.psk.dqpsk;
|
||||
|
||||
import java.util.Arrays;
|
||||
import jdk.incubator.vector.FloatVector;
|
||||
import jdk.incubator.vector.VectorOperators;
|
||||
import jdk.incubator.vector.VectorSpecies;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* DQPSK demodulator that uses Vector SIMD 512 calculations for demodulating the sample stream.
|
||||
*/
|
||||
public class DQPSKDemodulatorVector512 extends DQPSKDemodulator
|
||||
{
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(DQPSKDemodulatorVector512.class);
|
||||
private static final VectorSpecies<Float> VECTOR_SPECIES = FloatVector.SPECIES_512;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param symbolRate symbols per second
|
||||
*/
|
||||
public DQPSKDemodulatorVector512(double sampleRate, int symbolRate)
|
||||
{
|
||||
super(sampleRate, symbolRate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] demodulate(float[] i, float[] q)
|
||||
{
|
||||
int sampleLength = i.length;
|
||||
int bufferOverlap = mBufferOverlap;
|
||||
float mu = mMu;
|
||||
|
||||
//Copy previous buffer residual samples to beginning of buffer.
|
||||
System.arraycopy(mIBuffer, mIBuffer.length - bufferOverlap, mIBuffer, 0, bufferOverlap);
|
||||
System.arraycopy(mQBuffer, mQBuffer.length - bufferOverlap, mQBuffer, 0, bufferOverlap);
|
||||
|
||||
//Resize I/Q buffers if necessary
|
||||
int requiredBufferLength = sampleLength + bufferOverlap;
|
||||
if(mIBuffer.length != requiredBufferLength)
|
||||
{
|
||||
if(i.length % VECTOR_SPECIES.length() != 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Buffer length must be a multiple of " + VECTOR_SPECIES.length());
|
||||
}
|
||||
mIBuffer = Arrays.copyOf(mIBuffer, requiredBufferLength);
|
||||
mQBuffer = Arrays.copyOf(mQBuffer, requiredBufferLength);
|
||||
}
|
||||
|
||||
//Append new samples to the residual samples from the previous buffer.
|
||||
System.arraycopy(i, 0, mIBuffer, bufferOverlap, sampleLength);
|
||||
System.arraycopy(q, 0, mQBuffer, bufferOverlap, sampleLength);
|
||||
|
||||
float[] interpolatedI = new float[VECTOR_SPECIES.length()];
|
||||
float[] interpolatedQ = new float[VECTOR_SPECIES.length()];
|
||||
float[] decodedPhases = new float[sampleLength];
|
||||
FloatVector iPrevious, qPreviousConjugate, iCurrent, qCurrent, differentialI, differentialQ;
|
||||
|
||||
//Differential demodulation.
|
||||
for(int x = 0; x < sampleLength; x += VECTOR_SPECIES.length())
|
||||
{
|
||||
iPrevious = FloatVector.fromArray(VECTOR_SPECIES, mIBuffer, x);
|
||||
qPreviousConjugate = FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x).neg(); //Complex Conjugate
|
||||
|
||||
int offset = mInterpolationOffset + x;
|
||||
int index;
|
||||
for(int y = 0; y < VECTOR_SPECIES.length(); y++)
|
||||
{
|
||||
index = offset + y;
|
||||
interpolatedI[y] = mInterpolator.filter(mIBuffer, index, mu);
|
||||
interpolatedQ[y] = mInterpolator.filter(mQBuffer, index, mu);
|
||||
}
|
||||
iCurrent = FloatVector.fromArray(VECTOR_SPECIES, interpolatedI, 0);
|
||||
qCurrent = FloatVector.fromArray(VECTOR_SPECIES, interpolatedQ, 0);
|
||||
|
||||
//Multiply current complex sample by the complex conjugate of previous complex sample.
|
||||
differentialI = iPrevious.mul(iCurrent).sub(qPreviousConjugate.mul(qCurrent));
|
||||
differentialQ = iPrevious.mul(qCurrent).add(iCurrent.mul(qPreviousConjugate));
|
||||
|
||||
//Calculate phase angles using Arc Tangent and export to the decoded phases array.
|
||||
differentialQ.lanewise(VectorOperators.ATAN2, differentialI).intoArray(decodedPhases, x);
|
||||
}
|
||||
|
||||
return decodedPhases;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.psk.dqpsk;
|
||||
|
||||
import java.util.Arrays;
|
||||
import jdk.incubator.vector.FloatVector;
|
||||
import jdk.incubator.vector.VectorOperators;
|
||||
import jdk.incubator.vector.VectorSpecies;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* DQPSK demodulator that uses Vector SIMD 64 calculations for demodulating the sample stream.
|
||||
*/
|
||||
public class DQPSKDemodulatorVector64 extends DQPSKDemodulator
|
||||
{
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(DQPSKDemodulatorVector64.class);
|
||||
private static final VectorSpecies<Float> VECTOR_SPECIES = FloatVector.SPECIES_64;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param sampleRate in Hertz
|
||||
* @param symbolRate symbols per second
|
||||
*/
|
||||
public DQPSKDemodulatorVector64(double sampleRate, int symbolRate)
|
||||
{
|
||||
super(sampleRate, symbolRate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] demodulate(float[] i, float[] q)
|
||||
{
|
||||
int sampleLength = i.length;
|
||||
int bufferOverlap = mBufferOverlap;
|
||||
float mu = mMu;
|
||||
|
||||
//Copy previous buffer residual samples to beginning of buffer.
|
||||
System.arraycopy(mIBuffer, mIBuffer.length - bufferOverlap, mIBuffer, 0, bufferOverlap);
|
||||
System.arraycopy(mQBuffer, mQBuffer.length - bufferOverlap, mQBuffer, 0, bufferOverlap);
|
||||
|
||||
//Resize I/Q buffers if necessary
|
||||
int requiredBufferLength = sampleLength + bufferOverlap;
|
||||
if(mIBuffer.length != requiredBufferLength)
|
||||
{
|
||||
if(i.length % VECTOR_SPECIES.length() != 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Buffer length must be a multiple of " + VECTOR_SPECIES.length());
|
||||
}
|
||||
mIBuffer = Arrays.copyOf(mIBuffer, requiredBufferLength);
|
||||
mQBuffer = Arrays.copyOf(mQBuffer, requiredBufferLength);
|
||||
}
|
||||
|
||||
//Append new samples to the residual samples from the previous buffer.
|
||||
System.arraycopy(i, 0, mIBuffer, bufferOverlap, sampleLength);
|
||||
System.arraycopy(q, 0, mQBuffer, bufferOverlap, sampleLength);
|
||||
//mIDecoded, mQDecoded and mPhase will be filled below during the decoding process.
|
||||
|
||||
float[] interpolatedI = new float[VECTOR_SPECIES.length()];
|
||||
float[] interpolatedQ = new float[VECTOR_SPECIES.length()];
|
||||
float[] decodedPhases = new float[i.length];
|
||||
FloatVector iPrevious, qPreviousConjugate, iCurrent, qCurrent, differentialI, differentialQ;
|
||||
|
||||
//Differential demodulation.
|
||||
for(int x = 0; x < sampleLength; x += VECTOR_SPECIES.length())
|
||||
{
|
||||
iPrevious = FloatVector.fromArray(VECTOR_SPECIES, mIBuffer, x);
|
||||
qPreviousConjugate = FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x).neg(); //Complex Conjugate
|
||||
|
||||
int offset = mInterpolationOffset + x;
|
||||
int index;
|
||||
for(int y = 0; y < VECTOR_SPECIES.length(); y++)
|
||||
{
|
||||
index = offset + y;
|
||||
interpolatedI[y] = mInterpolator.filter(mIBuffer, index, mu);
|
||||
interpolatedQ[y] = mInterpolator.filter(mQBuffer, index, mu);
|
||||
}
|
||||
iCurrent = FloatVector.fromArray(VECTOR_SPECIES, interpolatedI, 0);
|
||||
qCurrent = FloatVector.fromArray(VECTOR_SPECIES, interpolatedQ, 0);
|
||||
|
||||
//Multiply current complex sample by the complex conjugate of previous complex sample.
|
||||
differentialI = iPrevious.mul(iCurrent).sub(qPreviousConjugate.mul(qCurrent));
|
||||
differentialQ = iPrevious.mul(qCurrent).add(iCurrent.mul(qPreviousConjugate));
|
||||
|
||||
//Calculate phase angles using Arc Tangent and export to the decoded phases array.
|
||||
differentialQ.lanewise(VectorOperators.ATAN2, differentialI).intoArray(decodedPhases, x);
|
||||
}
|
||||
|
||||
return decodedPhases;
|
||||
}
|
||||
}
|
||||
@@ -1,47 +1,61 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 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/>
|
||||
* * *****************************************************************************
|
||||
* 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.dsp.symbol;
|
||||
|
||||
public enum Dibit
|
||||
{
|
||||
D01_PLUS_3(false, true, 1, 4, 1),
|
||||
D00_PLUS_1(false, false, 0, 0, 0),
|
||||
D10_MINUS_1(true, false, 2, 8, 2),
|
||||
D11_MINUS_3(true, true, 3, 12, 3);
|
||||
D01_PLUS_3(false, true, 1, 4, 1, (float)(Math.PI / 4 * 3), (float)-Math.sin(Math.toRadians(45)), (float)Math.sin(Math.toRadians(45))),
|
||||
D00_PLUS_1(false, false, 0, 0, 0, (float)(Math.PI / 4.0), (float)Math.sin(Math.toRadians(45)), (float)Math.sin(Math.toRadians(45))),
|
||||
D10_MINUS_1(true, false, 2, 8, 2, (float)(Math.PI / -4.0), (float)Math.sin(Math.toRadians(45)), (float)-Math.sin(Math.toRadians(45))),
|
||||
D11_MINUS_3(true, true, 3, 12, 3, (float)(Math.PI / 4 * -3), (float)-Math.sin(Math.toRadians(45)), (float)-Math.sin(Math.toRadians(45)));
|
||||
|
||||
private boolean mBit1;
|
||||
private boolean mBit2;
|
||||
private int mLowValue;
|
||||
private int mHighValue;
|
||||
private int mValue;
|
||||
private float mPhase;
|
||||
private float mIdealI;
|
||||
private float mIdealQ;
|
||||
|
||||
private Dibit(boolean bit1, boolean bit2, int lowValue, int highValue, int value)
|
||||
/**
|
||||
* Dibit constructor.
|
||||
* @param bit1 boolean value
|
||||
* @param bit2 boolean value
|
||||
* @param lowValue integer value of the low order bit
|
||||
* @param highValue integer value of the high order bit
|
||||
* @param value integer value combined of both bits.
|
||||
* @param phase optimal phase value for this symbol when transmitted.
|
||||
* @param idealI ideal inphase value for this symbol when transmitted.
|
||||
* @param idealQ ideal quadrature value for this symbol when transmitted.
|
||||
*/
|
||||
Dibit(boolean bit1, boolean bit2, int lowValue, int highValue, int value, float phase, float idealI, float idealQ)
|
||||
{
|
||||
mBit1 = bit1;
|
||||
mBit2 = bit2;
|
||||
mLowValue = lowValue;
|
||||
mHighValue = highValue;
|
||||
mValue = value;
|
||||
mPhase = phase;
|
||||
mIdealI = idealI;
|
||||
mIdealQ = idealQ;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,6 +66,33 @@ public enum Dibit
|
||||
return mValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ideal phase angle when this symbol is transmitted.
|
||||
* @return ideal phase angle in radians.
|
||||
*/
|
||||
public float getIdealPhase()
|
||||
{
|
||||
return mPhase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ideal inphase value when this symbol is transmitted.
|
||||
* @return ideal I
|
||||
*/
|
||||
public float getIdealI()
|
||||
{
|
||||
return mIdealI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ideal quadrature value when this symbol is transmitted.
|
||||
* @return ideal Q
|
||||
*/
|
||||
public float getIdealQ()
|
||||
{
|
||||
return mIdealQ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allowable transition state 1 for trellis coded modulation. Indicates
|
||||
* the dibit that differs from this dibit in the LSB bit position.
|
||||
|
||||
Reference in New Issue
Block a user