diff --git a/src/dsp/filter/design/FilterViewer.java b/src/dsp/filter/design/FilterViewer.java index 3044ae3c..85c710ca 100644 --- a/src/dsp/filter/design/FilterViewer.java +++ b/src/dsp/filter/design/FilterViewer.java @@ -1,65 +1,64 @@ package dsp.filter.design; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import dsp.filter.fir.FIRFilterSpecification; import dsp.filter.fir.remez.RemezFIRFilterDesigner; import javafx.application.Application; import javafx.scene.Scene; import javafx.stage.Stage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; 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 - */ - public FilterViewer() - { - } - - @Override - public void start( Stage primaryStage ) throws Exception - { - Scene scene = new Scene( new FilterView( getFilter() ) ); - - primaryStage.setTitle( "Filter Viewer" ); - primaryStage.setScene( scene ); - primaryStage.show(); - } - - public static void main( String[] args ) - { - launch( args ); - } + /** + * Developer tool to visualize filter designs + */ + public FilterViewer() + { + } - /** - * Provides the filter to visualize. Modify this method to visualize your filter design. - */ - private float[] getFilter() - { -// FIRFilterSpecification specification = FIRFilterSpecification.lowPassBuilder() -// .sampleRate( 48000 ) -// .gridDensity( 16 ) -// .passBandCutoff( 3200 ) -// .passBandAmplitude( 1.0 ) -// .passBandRipple( 0.02 ) -// .stopBandStart( 4000 ) -// .stopBandAmplitude( 0.0 ) -// .stopBandRipple( 0.03 ) -// .build(); - - FIRFilterSpecification specification = FIRFilterSpecification.highPassBuilder() - .sampleRate( 24000 ) - .stopBandCutoff( 800 ) - .stopBandAmplitude( 0.0 ) - .stopBandRipple( 0.03 ) - .passBandStart( 1000 ) - .passBandAmplitude( 1.0 ) - .passBandRipple( 0.08 ) - .build(); + @Override + public void start(Stage primaryStage) throws Exception + { + Scene scene = new Scene(new FilterView(getFilter())); + + primaryStage.setTitle("Filter Viewer"); + primaryStage.setScene(scene); + primaryStage.show(); + } + + public static void main(String[] args) + { + launch(args); + } + + /** + * Provides the filter to visualize. Modify this method to visualize your filter design. + */ + private float[] getFilter() + { + FIRFilterSpecification specification = FIRFilterSpecification.lowPassBuilder() + .sampleRate(48000) + .gridDensity(16) + .passBandCutoff(2500) + .passBandAmplitude(1.0) + .passBandRipple(0.01) + .stopBandStart(4000) + .stopBandAmplitude(0.0) + .stopBandRipple(0.008) + .build(); + +// FIRFilterSpecification specification = FIRFilterSpecification.highPassBuilder() +// .sampleRate(24000) +// .stopBandCutoff(800) +// .stopBandAmplitude(0.0) +// .stopBandRipple(0.03) +// .passBandStart(1000) +// .passBandAmplitude(1.0) +// .passBandRipple(0.08) +// .build(); // FIRFilterSpecification specification = FIRFilterSpecification.bandPassBuilder() // .sampleRate( 48000 ) @@ -71,24 +70,25 @@ public class FilterViewer extends Application // .passRipple( 0.008) // .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 - { - RemezFIRFilterDesigner designer = new RemezFIRFilterDesigner( specification ); - - if( designer.isValid() ) - { - taps = designer.getImpulseResponse(); - } - } - catch( FilterDesignException fde ) - { - mLog.error( "Filter design error", fde ); - } - - return taps; - } + try + { + RemezFIRFilterDesigner designer = new RemezFIRFilterDesigner(specification); + + if(designer.isValid()) + { + taps = designer.getImpulseResponse(); + } + } + catch(FilterDesignException fde) + { + mLog.error("Filter design error", fde); + } + + return taps; + } } diff --git a/src/module/decode/DecoderFactory.java b/src/module/decode/DecoderFactory.java index 645af4bc..cce17e65 100644 --- a/src/module/decode/DecoderFactory.java +++ b/src/module/decode/DecoderFactory.java @@ -103,35 +103,35 @@ public class DecoderFactory //Low-pass filter with ~60 dB attenuation and 89 taps private static final FIRFilterSpecification MPT1327_FILTER_SPECIFICATION = FIRFilterSpecification.lowPassBuilder() - .sampleRate( 48000 ) - .gridDensity( 16 ) - .passBandCutoff( 3200 ) - .passBandAmplitude( 1.0 ) - .passBandRipple( 0.02 ) - .stopBandStart( 4000 ) - .stopBandAmplitude( 0.0 ) - .stopBandRipple( 0.03 ) - .build(); + .sampleRate( 48000 ).gridDensity( 16 ).passBandCutoff( 3200 ).passBandAmplitude( 1.0 ).passBandRipple( 0.02 ) + .stopBandStart( 4000 ).stopBandAmplitude( 0.0 ).stopBandRipple( 0.03 ).build(); + + private static final FIRFilterSpecification P25_C4FM_IQ_SPECIFICATION = FIRFilterSpecification.lowPassBuilder() + .sampleRate(48000).gridDensity(16).passBandCutoff(6750).passBandAmplitude(1.0).passBandRipple(0.01) + .stopBandStart(7000).stopBandAmplitude(0.0).stopBandRipple(0.008).build(); + + private static final FIRFilterSpecification P25_C4FM_DEMOD_SPECIFICATION = FIRFilterSpecification.lowPassBuilder() + .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[] P25_C4FM_IQ_FILTER; + private static float[] P25_C4FM_DEMOD_FILTER; static { try { 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) { - 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 * specified in the configurations. @@ -228,7 +228,7 @@ public class DecoderFactory } 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)); break; case PASSPORT: @@ -247,7 +247,8 @@ public class DecoderFactory switch(modulation) { 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 P25DecoderState(aliasList, channelType, Modulation.C4FM, p25Config.getIgnoreDataCalls())); diff --git a/src/module/decode/p25/P25_C4FMDecoder.java b/src/module/decode/p25/P25_C4FMDecoder.java index 650c0cc2..94f2be56 100644 --- a/src/module/decode/p25/P25_C4FMDecoder.java +++ b/src/module/decode/p25/P25_C4FMDecoder.java @@ -47,12 +47,10 @@ public class P25_C4FMDecoder extends P25Decoder private final static Logger mLog = LoggerFactory.getLogger( P25_C4FMDecoder.class ); /* 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_SLICER_OUTPUT = "Tap Point: C4FM Slicer Output"; private List mAvailableTaps; - private RealFIRFilter_RB_RB mC4FMPreFilter; private C4FMSymbolFilter mSymbolFilter; private C4FMSlicer mC4FMSlicer; private P25MessageFramer mMessageFramer; @@ -74,15 +72,9 @@ public class P25_C4FMDecoder extends P25Decoder { 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 */ mSymbolFilter = new C4FMSymbolFilter( frequencyCorrectionMaximum ); - mC4FMPreFilter.setListener( mSymbolFilter ); - + /* Convert samples to symbols */ mC4FMSlicer = new C4FMSlicer(); mSymbolFilter.setListener( mC4FMSlicer ); @@ -100,9 +92,6 @@ public class P25_C4FMDecoder extends P25Decoder { super.dispose(); - mC4FMPreFilter.dispose(); - mC4FMPreFilter = null; - mSymbolFilter.dispose(); mSymbolFilter = null; @@ -121,7 +110,7 @@ public class P25_C4FMDecoder extends P25Decoder @Override public Listener getFilteredRealBufferListener() { - return mC4FMPreFilter; + return mSymbolFilter; } /** @@ -136,8 +125,6 @@ public class P25_C4FMDecoder extends P25Decoder 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 DibitTap( INSTRUMENT_C4FM_SLICER_OUTPUT, 0, 0.1f ) ); @@ -165,11 +152,6 @@ public class P25_C4FMDecoder extends P25Decoder switch( tap.getName() ) { - case INSTRUMENT_FILTER_OUTPUT: - FloatBufferTap filterOutput = (FloatBufferTap)tap; - mC4FMPreFilter.setListener( filterOutput ); - filterOutput.setListener( mSymbolFilter ); - break; case INSTRUMENT_C4FM_SYMBOL_FILTER_OUTPUT: FloatTap symbolTap = (FloatTap)tap; mSymbolFilter.setListener( symbolTap ); @@ -201,9 +183,6 @@ public class P25_C4FMDecoder extends P25Decoder switch( tap.getName() ) { - case INSTRUMENT_FILTER_OUTPUT: - mC4FMPreFilter.setListener( mSymbolFilter ); - break; case INSTRUMENT_C4FM_SYMBOL_FILTER_OUTPUT: mSymbolFilter.setListener( mC4FMSlicer ); break; diff --git a/src/module/demodulate/fm/FMDemodulatorModule.java b/src/module/demodulate/fm/FMDemodulatorModule.java index 8bac1bc4..8b7646de 100644 --- a/src/module/demodulate/fm/FMDemodulatorModule.java +++ b/src/module/demodulate/fm/FMDemodulatorModule.java @@ -62,6 +62,13 @@ public class FMDemodulatorModule extends Module implements IComplexBufferListene 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 public Listener getComplexBufferListener() {