mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-14 17:47:32 -05:00
Merge pull request #187 from DSheirer/186-p25-c4fm-decoder-no-worky
Resolves #186 - p25 C4FM decoder wasn't working (at all).
This commit is contained in:
@@ -1,65 +1,64 @@
|
|||||||
package dsp.filter.design;
|
package dsp.filter.design;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import dsp.filter.fir.FIRFilterSpecification;
|
import dsp.filter.fir.FIRFilterSpecification;
|
||||||
import dsp.filter.fir.remez.RemezFIRFilterDesigner;
|
import dsp.filter.fir.remez.RemezFIRFilterDesigner;
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class FilterViewer extends Application
|
public class FilterViewer extends Application
|
||||||
{
|
{
|
||||||
private final static Logger mLog = LoggerFactory.getLogger( FilterViewer.class );
|
private final static Logger mLog = LoggerFactory.getLogger(FilterViewer.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Developer tool to visualize filter designs
|
* Developer tool to visualize filter designs
|
||||||
*/
|
*/
|
||||||
public FilterViewer()
|
public FilterViewer()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start( Stage primaryStage ) throws Exception
|
public void start(Stage primaryStage) throws Exception
|
||||||
{
|
{
|
||||||
Scene scene = new Scene( new FilterView( getFilter() ) );
|
Scene scene = new Scene(new FilterView(getFilter()));
|
||||||
|
|
||||||
primaryStage.setTitle( "Filter Viewer" );
|
primaryStage.setTitle("Filter Viewer");
|
||||||
primaryStage.setScene( scene );
|
primaryStage.setScene(scene);
|
||||||
primaryStage.show();
|
primaryStage.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main( String[] args )
|
public static void main(String[] args)
|
||||||
{
|
{
|
||||||
launch( args );
|
launch(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the filter to visualize. Modify this method to visualize your filter design.
|
* Provides the filter to visualize. Modify this method to visualize your filter design.
|
||||||
*/
|
*/
|
||||||
private float[] getFilter()
|
private float[] getFilter()
|
||||||
{
|
{
|
||||||
// FIRFilterSpecification specification = FIRFilterSpecification.lowPassBuilder()
|
FIRFilterSpecification specification = FIRFilterSpecification.lowPassBuilder()
|
||||||
// .sampleRate( 48000 )
|
.sampleRate(48000)
|
||||||
// .gridDensity( 16 )
|
.gridDensity(16)
|
||||||
// .passBandCutoff( 3200 )
|
.passBandCutoff(2500)
|
||||||
// .passBandAmplitude( 1.0 )
|
.passBandAmplitude(1.0)
|
||||||
// .passBandRipple( 0.02 )
|
.passBandRipple(0.01)
|
||||||
// .stopBandStart( 4000 )
|
.stopBandStart(4000)
|
||||||
// .stopBandAmplitude( 0.0 )
|
.stopBandAmplitude(0.0)
|
||||||
// .stopBandRipple( 0.03 )
|
.stopBandRipple(0.008)
|
||||||
// .build();
|
.build();
|
||||||
|
|
||||||
FIRFilterSpecification specification = FIRFilterSpecification.highPassBuilder()
|
// FIRFilterSpecification specification = FIRFilterSpecification.highPassBuilder()
|
||||||
.sampleRate( 24000 )
|
// .sampleRate(24000)
|
||||||
.stopBandCutoff( 800 )
|
// .stopBandCutoff(800)
|
||||||
.stopBandAmplitude( 0.0 )
|
// .stopBandAmplitude(0.0)
|
||||||
.stopBandRipple( 0.03 )
|
// .stopBandRipple(0.03)
|
||||||
.passBandStart( 1000 )
|
// .passBandStart(1000)
|
||||||
.passBandAmplitude( 1.0 )
|
// .passBandAmplitude(1.0)
|
||||||
.passBandRipple( 0.08 )
|
// .passBandRipple(0.08)
|
||||||
.build();
|
// .build();
|
||||||
|
|
||||||
// FIRFilterSpecification specification = FIRFilterSpecification.bandPassBuilder()
|
// FIRFilterSpecification specification = FIRFilterSpecification.bandPassBuilder()
|
||||||
// .sampleRate( 48000 )
|
// .sampleRate( 48000 )
|
||||||
@@ -71,24 +70,25 @@ public class FilterViewer extends Application
|
|||||||
// .passRipple( 0.008)
|
// .passRipple( 0.008)
|
||||||
// .build();
|
// .build();
|
||||||
|
|
||||||
float[] taps = null;
|
float[] taps = null;
|
||||||
|
|
||||||
// taps = FilterFactory.getLowPass( 16000, 2400, 73, WindowType.HANNING );
|
// taps = FilterFactory.getLowPass(48000, 6750, 7500, 60,
|
||||||
|
// Window.WindowType.HAMMING, true);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
RemezFIRFilterDesigner designer = new RemezFIRFilterDesigner( specification );
|
RemezFIRFilterDesigner designer = new RemezFIRFilterDesigner(specification);
|
||||||
|
|
||||||
if( designer.isValid() )
|
if(designer.isValid())
|
||||||
{
|
{
|
||||||
taps = designer.getImpulseResponse();
|
taps = designer.getImpulseResponse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch( FilterDesignException fde )
|
catch(FilterDesignException fde)
|
||||||
{
|
{
|
||||||
mLog.error( "Filter design error", fde );
|
mLog.error("Filter design error", fde);
|
||||||
}
|
}
|
||||||
|
|
||||||
return taps;
|
return taps;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,35 +103,35 @@ public class DecoderFactory
|
|||||||
|
|
||||||
//Low-pass filter with ~60 dB attenuation and 89 taps
|
//Low-pass filter with ~60 dB attenuation and 89 taps
|
||||||
private static final FIRFilterSpecification MPT1327_FILTER_SPECIFICATION = FIRFilterSpecification.lowPassBuilder()
|
private static final FIRFilterSpecification MPT1327_FILTER_SPECIFICATION = FIRFilterSpecification.lowPassBuilder()
|
||||||
.sampleRate( 48000 )
|
.sampleRate( 48000 ).gridDensity( 16 ).passBandCutoff( 3200 ).passBandAmplitude( 1.0 ).passBandRipple( 0.02 )
|
||||||
.gridDensity( 16 )
|
.stopBandStart( 4000 ).stopBandAmplitude( 0.0 ).stopBandRipple( 0.03 ).build();
|
||||||
.passBandCutoff( 3200 )
|
|
||||||
.passBandAmplitude( 1.0 )
|
private static final FIRFilterSpecification P25_C4FM_IQ_SPECIFICATION = FIRFilterSpecification.lowPassBuilder()
|
||||||
.passBandRipple( 0.02 )
|
.sampleRate(48000).gridDensity(16).passBandCutoff(6750).passBandAmplitude(1.0).passBandRipple(0.01)
|
||||||
.stopBandStart( 4000 )
|
.stopBandStart(7000).stopBandAmplitude(0.0).stopBandRipple(0.008).build();
|
||||||
.stopBandAmplitude( 0.0 )
|
|
||||||
.stopBandRipple( 0.03 )
|
private static final FIRFilterSpecification P25_C4FM_DEMOD_SPECIFICATION = FIRFilterSpecification.lowPassBuilder()
|
||||||
.build();
|
.sampleRate(48000).gridDensity(16).passBandCutoff(2500).passBandAmplitude(1.0).passBandRipple(0.01)
|
||||||
|
.stopBandStart(4000).stopBandAmplitude(0.0).stopBandRipple(0.008).build();
|
||||||
|
|
||||||
private static float[] MPT1327_LOWPASS_FILTER;
|
private static float[] MPT1327_LOWPASS_FILTER;
|
||||||
|
private static float[] P25_C4FM_IQ_FILTER;
|
||||||
|
private static float[] P25_C4FM_DEMOD_FILTER;
|
||||||
|
|
||||||
static
|
static
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
MPT1327_LOWPASS_FILTER = FilterFactory.getTaps(MPT1327_FILTER_SPECIFICATION);
|
MPT1327_LOWPASS_FILTER = FilterFactory.getTaps(MPT1327_FILTER_SPECIFICATION);
|
||||||
|
P25_C4FM_IQ_FILTER = FilterFactory.getTaps(P25_C4FM_IQ_SPECIFICATION);
|
||||||
|
P25_C4FM_DEMOD_FILTER = FilterFactory.getTaps(P25_C4FM_DEMOD_SPECIFICATION);
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
mLog.error("Couldn't design MPT1327 bandpass filter");
|
mLog.error("Couldn't design startup filter(s)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final boolean NO_REMOVE_DC = false;
|
|
||||||
public static final boolean REMOVE_DC = true;
|
|
||||||
|
|
||||||
public static final int NO_FREQUENCY_CORRECTION = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of one primary decoder and any auxiliary decoders, as
|
* Returns a list of one primary decoder and any auxiliary decoders, as
|
||||||
* specified in the configurations.
|
* specified in the configurations.
|
||||||
@@ -228,7 +228,7 @@ public class DecoderFactory
|
|||||||
}
|
}
|
||||||
|
|
||||||
modules.add(new FMDemodulatorModule(iqPass, iqStop));
|
modules.add(new FMDemodulatorModule(iqPass, iqStop));
|
||||||
modules.add(new DemodulatedAudioFilterModule(MPT1327_LOWPASS_FILTER, 1.0f));
|
modules.add(new DemodulatedAudioFilterModule(P25_C4FM_DEMOD_FILTER, 1.0f));
|
||||||
modules.add(new AudioModule(metadata));
|
modules.add(new AudioModule(metadata));
|
||||||
break;
|
break;
|
||||||
case PASSPORT:
|
case PASSPORT:
|
||||||
@@ -247,7 +247,8 @@ public class DecoderFactory
|
|||||||
switch(modulation)
|
switch(modulation)
|
||||||
{
|
{
|
||||||
case C4FM:
|
case C4FM:
|
||||||
modules.add(new FMDemodulatorModule(6750, 7500));
|
modules.add(new FMDemodulatorModule(P25_C4FM_IQ_FILTER));
|
||||||
|
modules.add(new DemodulatedAudioFilterModule(P25_C4FM_DEMOD_FILTER, 1.0f));
|
||||||
modules.add(new P25_C4FMDecoder(aliasList, decodeConfig.getAFCMaximumCorrection()));
|
modules.add(new P25_C4FMDecoder(aliasList, decodeConfig.getAFCMaximumCorrection()));
|
||||||
modules.add(new P25DecoderState(aliasList, channelType, Modulation.C4FM,
|
modules.add(new P25DecoderState(aliasList, channelType, Modulation.C4FM,
|
||||||
p25Config.getIgnoreDataCalls()));
|
p25Config.getIgnoreDataCalls()));
|
||||||
|
|||||||
@@ -47,12 +47,10 @@ public class P25_C4FMDecoder extends P25Decoder
|
|||||||
private final static Logger mLog = LoggerFactory.getLogger( P25_C4FMDecoder.class );
|
private final static Logger mLog = LoggerFactory.getLogger( P25_C4FMDecoder.class );
|
||||||
|
|
||||||
/* Instrumentation Taps */
|
/* Instrumentation Taps */
|
||||||
private static final String INSTRUMENT_FILTER_OUTPUT = "Tap Point: Pre-Filter Output";
|
|
||||||
private static final String INSTRUMENT_C4FM_SYMBOL_FILTER_OUTPUT = "Tap Point: Symbol Filter Output";
|
private static final String INSTRUMENT_C4FM_SYMBOL_FILTER_OUTPUT = "Tap Point: Symbol Filter Output";
|
||||||
private static final String INSTRUMENT_C4FM_SLICER_OUTPUT = "Tap Point: C4FM Slicer Output";
|
private static final String INSTRUMENT_C4FM_SLICER_OUTPUT = "Tap Point: C4FM Slicer Output";
|
||||||
|
|
||||||
private List<TapGroup> mAvailableTaps;
|
private List<TapGroup> mAvailableTaps;
|
||||||
private RealFIRFilter_RB_RB mC4FMPreFilter;
|
|
||||||
private C4FMSymbolFilter mSymbolFilter;
|
private C4FMSymbolFilter mSymbolFilter;
|
||||||
private C4FMSlicer mC4FMSlicer;
|
private C4FMSlicer mC4FMSlicer;
|
||||||
private P25MessageFramer mMessageFramer;
|
private P25MessageFramer mMessageFramer;
|
||||||
@@ -74,14 +72,8 @@ public class P25_C4FMDecoder extends P25Decoder
|
|||||||
{
|
{
|
||||||
super( aliasList );
|
super( aliasList );
|
||||||
|
|
||||||
/* Filter demodulated sample buffers */
|
|
||||||
float[] filter = FilterFactory.getLowPass( 48000, 2500, 4000, 80, WindowType.HANNING, true );
|
|
||||||
|
|
||||||
mC4FMPreFilter = new RealFIRFilter_RB_RB( filter, 1.0f );
|
|
||||||
|
|
||||||
/* Shape gain and frequency offsets to optimize sample stream */
|
/* Shape gain and frequency offsets to optimize sample stream */
|
||||||
mSymbolFilter = new C4FMSymbolFilter( frequencyCorrectionMaximum );
|
mSymbolFilter = new C4FMSymbolFilter( frequencyCorrectionMaximum );
|
||||||
mC4FMPreFilter.setListener( mSymbolFilter );
|
|
||||||
|
|
||||||
/* Convert samples to symbols */
|
/* Convert samples to symbols */
|
||||||
mC4FMSlicer = new C4FMSlicer();
|
mC4FMSlicer = new C4FMSlicer();
|
||||||
@@ -100,9 +92,6 @@ public class P25_C4FMDecoder extends P25Decoder
|
|||||||
{
|
{
|
||||||
super.dispose();
|
super.dispose();
|
||||||
|
|
||||||
mC4FMPreFilter.dispose();
|
|
||||||
mC4FMPreFilter = null;
|
|
||||||
|
|
||||||
mSymbolFilter.dispose();
|
mSymbolFilter.dispose();
|
||||||
mSymbolFilter = null;
|
mSymbolFilter = null;
|
||||||
|
|
||||||
@@ -121,7 +110,7 @@ public class P25_C4FMDecoder extends P25Decoder
|
|||||||
@Override
|
@Override
|
||||||
public Listener<RealBuffer> getFilteredRealBufferListener()
|
public Listener<RealBuffer> getFilteredRealBufferListener()
|
||||||
{
|
{
|
||||||
return mC4FMPreFilter;
|
return mSymbolFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -136,8 +125,6 @@ public class P25_C4FMDecoder extends P25Decoder
|
|||||||
|
|
||||||
TapGroup group = new TapGroup( "P25 C4FM Decoder" );
|
TapGroup group = new TapGroup( "P25 C4FM Decoder" );
|
||||||
|
|
||||||
group.add( new FloatBufferTap( INSTRUMENT_FILTER_OUTPUT, 0, 1.0f ) );
|
|
||||||
|
|
||||||
group.add( new FloatTap( INSTRUMENT_C4FM_SYMBOL_FILTER_OUTPUT, 0, 0.1f ) );
|
group.add( new FloatTap( INSTRUMENT_C4FM_SYMBOL_FILTER_OUTPUT, 0, 0.1f ) );
|
||||||
group.add( new DibitTap( INSTRUMENT_C4FM_SLICER_OUTPUT, 0, 0.1f ) );
|
group.add( new DibitTap( INSTRUMENT_C4FM_SLICER_OUTPUT, 0, 0.1f ) );
|
||||||
|
|
||||||
@@ -165,11 +152,6 @@ public class P25_C4FMDecoder extends P25Decoder
|
|||||||
|
|
||||||
switch( tap.getName() )
|
switch( tap.getName() )
|
||||||
{
|
{
|
||||||
case INSTRUMENT_FILTER_OUTPUT:
|
|
||||||
FloatBufferTap filterOutput = (FloatBufferTap)tap;
|
|
||||||
mC4FMPreFilter.setListener( filterOutput );
|
|
||||||
filterOutput.setListener( mSymbolFilter );
|
|
||||||
break;
|
|
||||||
case INSTRUMENT_C4FM_SYMBOL_FILTER_OUTPUT:
|
case INSTRUMENT_C4FM_SYMBOL_FILTER_OUTPUT:
|
||||||
FloatTap symbolTap = (FloatTap)tap;
|
FloatTap symbolTap = (FloatTap)tap;
|
||||||
mSymbolFilter.setListener( symbolTap );
|
mSymbolFilter.setListener( symbolTap );
|
||||||
@@ -201,9 +183,6 @@ public class P25_C4FMDecoder extends P25Decoder
|
|||||||
|
|
||||||
switch( tap.getName() )
|
switch( tap.getName() )
|
||||||
{
|
{
|
||||||
case INSTRUMENT_FILTER_OUTPUT:
|
|
||||||
mC4FMPreFilter.setListener( mSymbolFilter );
|
|
||||||
break;
|
|
||||||
case INSTRUMENT_C4FM_SYMBOL_FILTER_OUTPUT:
|
case INSTRUMENT_C4FM_SYMBOL_FILTER_OUTPUT:
|
||||||
mSymbolFilter.setListener( mC4FMSlicer );
|
mSymbolFilter.setListener( mC4FMSlicer );
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -62,6 +62,13 @@ public class FMDemodulatorModule extends Module implements IComplexBufferListene
|
|||||||
mIQFilter.setListener(mDemodulator);
|
mIQFilter.setListener(mDemodulator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FMDemodulatorModule(float[] filter)
|
||||||
|
{
|
||||||
|
mIQFilter = new ComplexFIRFilter_CB_CB(filter, 1.0f);
|
||||||
|
mDemodulator = new FMDemodulator_CB(1.0f);
|
||||||
|
mIQFilter.setListener(mDemodulator);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Listener<ComplexBuffer> getComplexBufferListener()
|
public Listener<ComplexBuffer> getComplexBufferListener()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user