#296 APCO25 Phase II Decoder Implementation (#589)

P25 Phase 2 Decoder implementation.
This commit is contained in:
Denny Sheirer
2019-11-17 06:56:52 -05:00
committed by GitHub
parent d5b802e794
commit f934676bd0
561 changed files with 35609 additions and 6215 deletions

View File

@@ -1,3 +1,25 @@
/*
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 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.design;
import io.github.dsheirer.dsp.filter.fir.FIRFilterSpecification;
@@ -62,13 +84,12 @@ public class FilterViewer extends Application
// .build();
FIRFilterSpecification specification = FIRFilterSpecification.lowPassBuilder()
.sampleRate(25000.0)
.gridDensity(16)
.passBandCutoff(11800)
.sampleRate(50000.0)
.passBandCutoff(6500)
.passBandAmplitude(1.0)
.passBandRipple(0.01)
.stopBandStart(12400)
.passBandRipple(0.005)
.stopBandAmplitude(0.0)
.stopBandStart(7200)
.stopBandRipple(0.01)
.build();

View File

@@ -1,23 +1,30 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2018 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.
* * ******************************************************************************
* * Copyright (C) 2014-2019 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 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;
import io.github.dsheirer.dsp.psk.pll.CostasLoop;
import io.github.dsheirer.dsp.psk.pll.IPhaseLockedLoop;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
import io.github.dsheirer.sample.complex.Complex;
public class DQPSKDecisionDirectedDemodulatorInstrumented extends DQPSKDecisionDirectedDemodulator
@@ -27,6 +34,7 @@ public class DQPSKDecisionDirectedDemodulatorInstrumented extends DQPSKDecisionD
private Listener<Complex> mComplexSymbolListener;
private Listener<Double> mPLLErrorListener;
private Listener<Double> mPLLFrequencyListener;
private Listener<ReusableComplexBuffer> mFilteredGainAppliedComplexBufferListener;
private double mSampleRate;
/**
@@ -48,6 +56,18 @@ public class DQPSKDecisionDirectedDemodulatorInstrumented extends DQPSKDecisionD
mSampleRate = sampleRate;
}
@Override
public void receive(ReusableComplexBuffer reusableComplexBuffer)
{
if(mFilteredGainAppliedComplexBufferListener != null)
{
reusableComplexBuffer.incrementUserCount();
mFilteredGainAppliedComplexBufferListener.receive(reusableComplexBuffer);
}
super.receive(reusableComplexBuffer);
}
/**
* Overrides the parent class symbol calculation to capture eye diagram data
*/
@@ -128,4 +148,11 @@ public class DQPSKDecisionDirectedDemodulatorInstrumented extends DQPSKDecisionD
mPLLFrequencyListener = listener;
}
/**
* Regsiters the listener to receive complex sample buffers that have been filtered with automatic gain control applied
*/
public void setFilteredGainAppliedComplexBufferListener(Listener<ReusableComplexBuffer> listener)
{
mFilteredGainAppliedComplexBufferListener = listener;
}
}

View File

@@ -1,23 +1,30 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2018 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.
* * ******************************************************************************
* * Copyright (C) 2014-2019 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 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;
import io.github.dsheirer.dsp.psk.pll.CostasLoop;
import io.github.dsheirer.dsp.psk.pll.IPhaseLockedLoop;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
import io.github.dsheirer.sample.complex.Complex;
public class DQPSKGardnerDemodulatorInstrumented extends DQPSKGardnerDemodulator
@@ -27,6 +34,7 @@ public class DQPSKGardnerDemodulatorInstrumented extends DQPSKGardnerDemodulator
private Listener<Complex> mComplexSymbolListener;
private Listener<Double> mPLLErrorListener;
private Listener<Double> mPLLFrequencyListener;
private Listener<ReusableComplexBuffer> mFilteredGainAppliedComplexBufferListener;
private double mSampleRate;
/**
@@ -45,6 +53,18 @@ public class DQPSKGardnerDemodulatorInstrumented extends DQPSKGardnerDemodulator
mSampleRate = sampleRate;
}
@Override
public void receive(ReusableComplexBuffer reusableComplexBuffer)
{
if(mFilteredGainAppliedComplexBufferListener != null)
{
reusableComplexBuffer.incrementUserCount();
mFilteredGainAppliedComplexBufferListener.receive(reusableComplexBuffer);
}
super.receive(reusableComplexBuffer);
}
/**
* Overrides the parent class symbol calculation to capture eye diagram data
*/
@@ -124,4 +144,12 @@ public class DQPSKGardnerDemodulatorInstrumented extends DQPSKGardnerDemodulator
{
mPLLFrequencyListener = listener;
}
/**
* Registers the listener to receive complex sample buffers that have been filtered with automatic gain control applied
*/
public void setFilteredGainAppliedComplexBufferListener(Listener<ReusableComplexBuffer> listener)
{
mFilteredGainAppliedComplexBufferListener = listener;
}
}

View File

@@ -1,34 +1,43 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2018 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.
* * ******************************************************************************
* * Copyright (C) 2014-2019 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 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;
import io.github.dsheirer.dsp.filter.interpolator.RealInterpolator;
import io.github.dsheirer.sample.complex.Complex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class InterpolatingSampleBuffer
{
private final static Logger mLog = LoggerFactory.getLogger(InterpolatingSampleBuffer.class);
private static final float MAXIMUM_DEVIATION_SAMPLES_PER_SYMBOL = 0.02f; // +/- 2% deviation
private Complex mPrecedingSample = new Complex(0,0);
private Complex mCurrentSample = new Complex(0,0);
private Complex mMiddleSample = new Complex(0,0);
private float[] mDelayLineInphase;
private float[] mDelayLineQuadrature;
private int mDelayLinePointer = 0;
protected float[] mDelayLineInphase;
protected float[] mDelayLineQuadrature;
protected int mDelayLinePointer = 0;
private int mTwiceSamplesPerSymbol;
private float mSamplingPoint;

View File

@@ -1,36 +1,54 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2018 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.
* * ******************************************************************************
* * Copyright (C) 2014-2019 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 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;
import io.github.dsheirer.sample.complex.Complex;
import io.github.dsheirer.sample.complex.ComplexSampleListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class InterpolatingSampleBufferInstrumented extends InterpolatingSampleBuffer
{
private final static Logger mLog = LoggerFactory.getLogger(InterpolatingSampleBufferInstrumented.class);
private SymbolDecisionData mSymbolDecisionData;
private ComplexSampleListener mSampleListener;
private int mBufferLength;
public InterpolatingSampleBufferInstrumented(float samplesPerSymbol, float symbolTimingGain)
{
super(samplesPerSymbol, symbolTimingGain);
mSymbolDecisionData = new SymbolDecisionData((int)samplesPerSymbol);
mBufferLength = (int)Math.ceil(samplesPerSymbol);
mSymbolDecisionData = new SymbolDecisionData(mBufferLength);
}
public void receive(Complex sample)
{
super.receive(sample);
mSymbolDecisionData.receive(sample);
if(mSampleListener != null)
{
mSampleListener.receive(sample.inphase(), sample.quadrature());
}
}
/**
@@ -40,8 +58,22 @@ public class InterpolatingSampleBufferInstrumented extends InterpolatingSampleBu
*/
public SymbolDecisionData getSymbolDecisionData()
{
for(int x = mDelayLinePointer; x < mDelayLinePointer + mBufferLength; x++)
{
mSymbolDecisionData.receive(mDelayLineInphase[x], mDelayLineQuadrature[x]);
}
mSymbolDecisionData.setSamplingPoint(getSamplingPoint());
return mSymbolDecisionData;
}
/**
* Sets the listener to receive samples being sent to this buffer. Note: these samples have
* already been corrected by the PLL, so this provides an ideal tap point for PLL corrected samples.
* @param listener to receive samples.
*/
public void setSampleListener(ComplexSampleListener listener)
{
mSampleListener = listener;
}
}

View File

@@ -1,18 +1,24 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2018 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.
* * ******************************************************************************
* * Copyright (C) 2014-2019 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 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;
import io.github.dsheirer.buffer.ComplexCircularBuffer;
@@ -25,14 +31,16 @@ public class SymbolDecisionData
private ComplexCircularBuffer mBuffer;
private float mSamplingPoint;
private float mSamplesPerSymbol;
/**
* Circular buffer for capturing two symbols worth of sample data for use in instrumentation.
* @param samplesPerSymbol to size the buffer
*/
public SymbolDecisionData(int samplesPerSymbol)
public SymbolDecisionData(float samplesPerSymbol)
{
mBuffer = new ComplexCircularBuffer(2 * samplesPerSymbol);
mSamplesPerSymbol = samplesPerSymbol;
mBuffer = new ComplexCircularBuffer(8);
}
/**
@@ -68,7 +76,20 @@ public class SymbolDecisionData
}
/**
* Array of demodulated samples representing the current symbol where each current sample is demodulated against
* Raw samples
*/
public Complex[] getSamples()
{
return mBuffer.getAll();
}
public Complex[] getSamples(int length)
{
return mBuffer.get(length);
}
/**
* Array of (FM) demodulated samples representing the current symbol where each current sample is demodulated against
* the previous symbol's sample to produce the differential demodulated sample. Samples are in time order.
*
* Note: differential decoding is on an integral samples-per-symbol basis and does not use fractional interpolation.

View File

@@ -1,22 +1,26 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2018 Dennis Sheirer
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2019 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.pll;
import io.github.dsheirer.dsp.symbol.ISyncDetectListener;
import io.github.dsheirer.module.decode.p25.P25Decoder;
import io.github.dsheirer.module.decode.p25.phase1.P25P1Decoder;
import io.github.dsheirer.source.SourceEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -30,7 +34,7 @@ public class AdaptivePLLGainMonitor implements ISyncDetectListener, IFrequencyEr
private static final int MAX_SYNC_COUNT = 6;
private CostasLoop mCostasLoop;
private P25Decoder mP25Decoder;
private P25P1Decoder mP25P1Decoder;
private PLLGain mPLLGain = PLLGain.LEVEL_1;
private int mSyncCount;
@@ -39,14 +43,14 @@ public class AdaptivePLLGainMonitor implements ISyncDetectListener, IFrequencyEr
* level of the costas loop accordingly.
*
* @param costasLoop to receive adaptive gain updates.
* @param p25Decoder to receive frequency error source events
* @param p25P1Decoder to receive frequency error source events
*/
public AdaptivePLLGainMonitor(CostasLoop costasLoop, P25Decoder p25Decoder)
public AdaptivePLLGainMonitor(CostasLoop costasLoop, P25P1Decoder p25P1Decoder)
{
mCostasLoop = costasLoop;
mCostasLoop.setPLLGain(mPLLGain);
mCostasLoop.setFrequencyErrorProcessor(this);
mP25Decoder = p25Decoder;
mP25P1Decoder = p25P1Decoder;
}
/**
@@ -113,7 +117,7 @@ public class AdaptivePLLGainMonitor implements ISyncDetectListener, IFrequencyEr
//default gain of 1, meaning that we have received at least 2 sync events
if(mPLLGain != PLLGain.LEVEL_1)
{
mP25Decoder.broadcast(SourceEvent.frequencyErrorMeasurement(frequencyError));
mP25P1Decoder.broadcast(SourceEvent.frequencyErrorMeasurement(frequencyError));
}
}
}

View File

@@ -1,18 +1,24 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2018 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.
* * ******************************************************************************
* * Copyright (C) 2014-2019 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 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.pll;
/**
@@ -22,11 +28,18 @@ public enum PLLGain
{
//NOTE: static gain level of 200 produced the best results for releases prior to 0.3.4b2
LEVEL_0(100.0, 0, 0),
LEVEL_1(150.0, 0, 1),
LEVEL_2(170.0, 2, 4),
LEVEL_3(190.0, 5, 6),
LEVEL_4(200.0, 7, 8),
LEVEL_5(200.0, 9, 10);
LEVEL_5(200.0, 9, 10),
LEVEL_6(250.0, 11, 12),
LEVEL_7(275.0, 12,13),
LEVEL_8(325.0, 14, 15),
LEVEL_9(350.0, 16,17),
LEVEL_10(375.0, 18, 19),
LEVEL_11(400.0, 19,20);
private double mLoopBandwidth;
private int mRangeStart;

View File

@@ -1,3 +1,25 @@
/*
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 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.symbol;
public enum FrameSync
@@ -5,11 +27,13 @@ public enum FrameSync
P25_PHASE1_ERROR_90_CCW( 0xFFEFAFAAEEAAl ),
P25_PHASE1_NORMAL( 0x5575F5FF77FFl ), // +33333 -3 +33 -33 +33 -3333 +3 -3 +3 -33333
P25_PHASE1_ERROR_90_CW( 0x001050551155l ),
P25_PHASE1_ERROR_180( 0xAA8A0A008800l );
P25_PHASE1_ERROR_180( 0xAA8A0A008800l ),
P25_PHASE2_NORMAL(0x575D57F7FFl);
private long mSync;
private FrameSync( long sync )
FrameSync( long sync )
{
mSync = sync;
}