Skip to content

Commit

Permalink
#1633 DMR Decoder redesign. Uses new DQPSK vector/scalar demodulator …
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
Dennis Sheirer committed Dec 24, 2024
1 parent 5c9c3fa commit 7d9d40f
Show file tree
Hide file tree
Showing 188 changed files with 8,027 additions and 3,142 deletions.
9 changes: 9 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,15 @@ application {
}
}

test {
if(os.isWindows()) {
jvmArgs = jvmArgsWindows
}
else {
jvmArgs = jvmArgsLinux
}
}

jar {
manifest {
attributes (
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/io/github/dsheirer/bits/BinaryMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,20 @@ public void add(boolean value) throws BitSetFullException
}
}

/**
* Adds bit1 and bit2 to this bitset.
*
* Note: this method does not provide overfill protection.
*
* @param bit1 to add.
* @param bit2 to add.
*/
public void add(boolean bit1, boolean bit2)
{
set(mPointer++, bit1);
set(mPointer++, bit2);
}

public String toString()
{
StringBuilder sb = new StringBuilder();
Expand Down
62 changes: 35 additions & 27 deletions src/main/java/io/github/dsheirer/dsp/filter/FilterFactory.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -56,15 +56,14 @@
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.
*/
Expand Down Expand Up @@ -627,59 +626,61 @@ public static float[] getCICResponseArray(int sampleRate, int frequency, int len
* @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;

float[] coefficients = new float[taps];

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];
}
Expand Down Expand Up @@ -1210,13 +1211,20 @@ public static void main(String[] args)
{
DecimalFormat df = new DecimalFormat("0.000000");

int length = 15;
int length = 49;

float [] taps = FilterFactory.getHalfBand(length, WindowType.HAMMING);
try
{
float [] taps = FilterFactory.getSinc(0.5, length, WindowType.NONE);

for(int x = 0; x < length; x++)
for(int x = 0; x < length; x++)
{
mLog.debug("Tap: " + x + " Value: " + df.format(taps[x]));
}
}
catch(Exception e)
{
mLog.debug("Tap: " + x + " Value: " + df.format(taps[x]));
e.printStackTrace();
}

mLog.debug("Done!");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand All @@ -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;
Expand Down Expand Up @@ -62,9 +61,10 @@ private float[] getFilter()
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)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
/*
* *****************************************************************************
* 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;

/*******************************************************************************
* 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;
Expand Down Expand Up @@ -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);
}
Original file line number Diff line number Diff line change
@@ -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);
};
}
}
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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
Expand Down Expand Up @@ -68,7 +91,7 @@ public Complex filter(float[] iSamples, float[] qSamples, int offset, float mu)

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;
Expand Down
Loading

0 comments on commit 7d9d40f

Please sign in to comment.