#90 [WIP] Resolves issue with MPT-1327 decoder which has apparently been broken for a long time.

This commit is contained in:
Denny
2017-01-21 11:05:30 -05:00
parent 6b67a74055
commit 26837b8a68
13 changed files with 1499 additions and 1459 deletions

View File

@@ -30,6 +30,8 @@ import controller.channel.ChannelModel;
import controller.channel.ChannelProcessingManager;
import controller.channel.map.ChannelMap;
import controller.channel.map.ChannelMapModel;
import dsp.filter.FilterFactory;
import dsp.filter.fir.FIRFilterSpecification;
import filter.AllPassFilter;
import filter.FilterSet;
import filter.IFilter;
@@ -89,12 +91,34 @@ import module.decode.tait.Tait1200DecoderState;
import module.demodulate.am.AMDemodulatorModule;
import module.demodulate.audio.DemodulatedAudioFilterModule;
import module.demodulate.fm.FMDemodulatorModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
public class DecoderFactory
{
private final static Logger mLog = LoggerFactory.getLogger(DecoderFactory.class);
private static final FIRFilterSpecification MPT1327_FILTER_SPECIFICATION = FIRFilterSpecification.bandPassBuilder()
.sampleRate(48000).stopFrequency1(200).passFrequencyBegin(400).passFrequencyEnd(3200)
.stopFrequency2(3400).stopRipple(0.0003).passRipple(0.008).build();
private static float[] MPT1327_BANDPASS_FILTER;
static
{
try
{
MPT1327_BANDPASS_FILTER = FilterFactory.getTaps(MPT1327_FILTER_SPECIFICATION);
}
catch(Exception e)
{
mLog.error("Couldn't design MPT1327 bandpass filter");
}
}
public static final boolean NO_REMOVE_DC = false;
public static final boolean REMOVE_DC = true;
@@ -197,7 +221,7 @@ public class DecoderFactory
}
modules.add(new FMDemodulatorModule(iqPass, iqStop));
modules.add(new DemodulatedAudioFilterModule(4000, 6000));
modules.add(new DemodulatedAudioFilterModule(MPT1327_BANDPASS_FILTER, 2.0f));
modules.add(new AudioModule(metadata));
break;
case PASSPORT:

View File

@@ -1,322 +1,290 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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/>
* sdrtrunk
* Copyright (C) 2014-2017 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 module.decode.mpt1327;
import alias.AliasList;
import bits.MessageFramer;
import bits.SyncPattern;
import dsp.filter.Filters;
import dsp.filter.dc.DCRemovalFilterLyons;
import dsp.filter.fir.real.RealFIRFilter_RB_RB;
import dsp.filter.halfband.real.HalfBandFilter_RB_RB;
import dsp.fsk.FSK2Decoder;
import dsp.fsk.FSK2Decoder.Output;
import instrument.Instrumentable;
import instrument.tap.Tap;
import instrument.tap.TapGroup;
import instrument.tap.stream.BinaryTap;
import instrument.tap.stream.FloatBufferTap;
import instrument.tap.stream.FloatTap;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import module.decode.Decoder;
import module.decode.DecoderType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.Broadcaster;
import sample.Listener;
import sample.real.IFilteredRealBufferListener;
import sample.real.RealBuffer;
import alias.AliasList;
import bits.MessageFramer;
import bits.SyncPattern;
import dsp.filter.FilterFactory;
import dsp.filter.Filters;
import dsp.filter.Window.WindowType;
import dsp.filter.dc.DCRemovalFilterLyons;
import dsp.filter.fir.real.RealFIRFilter_RB_RB;
import dsp.filter.halfband.real.HalfBandFilter_RB_RB;
import dsp.fsk.FSK2Decoder;
import dsp.fsk.FSK2Decoder.Output;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
/**
* MPT1327 Decoder - 1200 baud 2FSK decoder that can process 48k sample rate
* complex or floating point samples and output fully framed MPT1327 control and
* traffic messages.
*/
public class MPT1327Decoder extends Decoder
implements IFilteredRealBufferListener, Instrumentable
public class MPT1327Decoder extends Decoder implements IFilteredRealBufferListener, Instrumentable
{
private final static Logger mLog = LoggerFactory.getLogger( MPT1327Decoder.class );
/* Decimated sample rate ( 48,000 / 2 = 24,000 ) feeding the decoder */
private static final int sDECIMATED_SAMPLE_RATE = 24000;
/* Baud or Symbol Rate */
private static final int sSYMBOL_RATE = 1200;
private final static Logger mLog = LoggerFactory.getLogger(MPT1327Decoder.class);
/* Message length -- longest possible message is:
* 4xREVS + 16xSYNC + 64xADD1 + 64xDCW1 + 64xDCW2 + 64xDCW3 + 64xDCW4 */
/* Decimated sample rate ( 48,000 / 2 = 24,000 ) feeding the decoder */
private static final int sDECIMATED_SAMPLE_RATE = 24000;
/* Baud or Symbol Rate */
private static final int sSYMBOL_RATE = 1200;
/* Message length -- longest possible message is:
* 4xREVS + 16xSYNC + 64xADD1 + 64xDCW1 + 64xDCW2 + 64xDCW3 + 64xDCW4 */
private static final int sMESSAGE_LENGTH = 350;
/* Instrumentation Taps */
private static final String INSTRUMENT_HB1_FILTER_TO_LOW_PASS =
"Tap Point: Half-band Decimation Filter > < Low Pass Filter";
private static final String INSTRUMENT_LOW_PASS_TO_DECODER =
"Tap Point: Low Pass Filter > < Decoder";
private static final String INSTRUMENT_DECODER_TO_FRAMER =
"Tap Point: Decoder > < Sync Detect/Message Framer";
private static final String INSTRUMENT_HB1_FILTER_TO_LOW_PASS =
"Tap Point: Half-band Decimation Filter > < Low Pass Filter";
private static final String INSTRUMENT_LOW_PASS_TO_DECODER =
"Tap Point: Low Pass Filter > < Decoder";
private static final String INSTRUMENT_DECODER_TO_FRAMER =
"Tap Point: Decoder > < Sync Detect/Message Framer";
private List<TapGroup> mAvailableTaps;
private HalfBandFilter_RB_RB mDecimationFilter;
private RealFIRFilter_RB_RB mLowPassFilter;
private DCRemovalFilterLyons mDCRemovalFilter;
private FSK2Decoder mFSKDecoder;
private Broadcaster<Boolean> mSymbolBroadcaster;
private HalfBandFilter_RB_RB mDecimationFilter;
private RealFIRFilter_RB_RB mLowPassFilter;
private DCRemovalFilterLyons mDCRemovalFilter;
private FSK2Decoder mFSKDecoder;
private Broadcaster<Boolean> mSymbolBroadcaster;
private MessageFramer mControlMessageFramer;
private MessageFramer mTrafficMessageFramer;
private MPT1327MessageProcessor mMessageProcessor;
public MPT1327Decoder( AliasList aliasList, Sync sync )
{
public MPT1327Decoder(AliasList aliasList, Sync sync)
{
/* Decimation filter - 48000 / 2 = 24000 output */
mDecimationFilter = new HalfBandFilter_RB_RB(Filters.FIR_HALF_BAND_31T_ONE_EIGHTH_FCO.getCoefficients(), 1.0002f, true);
/* Decimation filter - 48000 / 2 = 24000 output */
mDecimationFilter = new HalfBandFilter_RB_RB(
Filters.FIR_HALF_BAND_31T_ONE_EIGHTH_FCO.getCoefficients(), 1.0002f, true );
/* Low pass filter: 2kHz to pass the 1200 & 1800 Hz FSK */
mLowPassFilter = new RealFIRFilter_RB_RB(
FilterFactory.getLowPass( 24000, //sampleRate,
2000, //passFrequency,
4000, //stopFrequency,
60, //attenuation,
WindowType.HANNING, //windowType,
true ) //forceOddLength
, 2.0f ); //Gain
mDecimationFilter.setListener( mLowPassFilter );
/**
* Normal: 2FSK Decoder with inverted output
* French: 2FSK Decoder with normal output
*/
if(sync == Sync.NORMAL)
{
mFSKDecoder = new FSK2Decoder(24000, 1200, Output.INVERTED);
}
else if(sync == Sync.FRENCH)
{
mFSKDecoder = new FSK2Decoder(24000, 1200, Output.NORMAL);
}
else
{
throw new IllegalArgumentException("MPT1327 Decoder - unrecognized Sync type");
}
/**
* Normal: 2FSK Decoder with inverted output
* French: 2FSK Decoder with normal output
*/
if( sync == Sync.NORMAL )
{
mFSKDecoder = new FSK2Decoder( 24000, 1200, Output.INVERTED );
}
else if( sync == Sync.FRENCH )
{
mFSKDecoder = new FSK2Decoder( 24000, 1200, Output.NORMAL );
}
else
{
throw new IllegalArgumentException( "MPT1327 Decoder - unrecognized Sync type" );
}
mLowPassFilter.setListener( mFSKDecoder );
mSymbolBroadcaster = new Broadcaster<Boolean>();
mFSKDecoder.setListener( mSymbolBroadcaster );
mDecimationFilter.setListener(mFSKDecoder);
mSymbolBroadcaster = new Broadcaster<Boolean>();
mFSKDecoder.setListener(mSymbolBroadcaster);
/* Message framer for control channel messages */
mControlMessageFramer =
new MessageFramer( sync.getControlSyncPattern().getPattern(),
sMESSAGE_LENGTH );
mSymbolBroadcaster.addListener( mControlMessageFramer );
mControlMessageFramer = new MessageFramer(sync.getControlSyncPattern().getPattern(), sMESSAGE_LENGTH);
mSymbolBroadcaster.addListener(mControlMessageFramer);
/* Message framer for traffic channel massages */
mTrafficMessageFramer =
new MessageFramer( sync.getTrafficSyncPattern().getPattern(),
sMESSAGE_LENGTH );
mSymbolBroadcaster.addListener( mTrafficMessageFramer );
mTrafficMessageFramer = new MessageFramer(sync.getTrafficSyncPattern().getPattern(), sMESSAGE_LENGTH);
mSymbolBroadcaster.addListener(mTrafficMessageFramer);
/* Fully decoded and framed messages processor */
mMessageProcessor = new MPT1327MessageProcessor( aliasList );
mMessageProcessor.setMessageListener( this );
mControlMessageFramer.addMessageListener( mMessageProcessor );
mTrafficMessageFramer.addMessageListener( mMessageProcessor );
}
@Override
public Listener<RealBuffer> getFilteredRealBufferListener()
{
return mDecimationFilter;
}
mMessageProcessor = new MPT1327MessageProcessor(aliasList);
mMessageProcessor.setMessageListener(this);
mControlMessageFramer.addMessageListener(mMessageProcessor);
mTrafficMessageFramer.addMessageListener(mMessageProcessor);
}
@Override
public DecoderType getDecoderType()
{
return DecoderType.MPT1327;
}
/**
* Cleanup method
*/
public void dispose()
{
super.dispose();
@Override
public Listener<RealBuffer> getFilteredRealBufferListener()
{
return mDecimationFilter;
}
mSymbolBroadcaster.dispose();
mControlMessageFramer.dispose();
@Override
public DecoderType getDecoderType()
{
return DecoderType.MPT1327;
}
if( mDCRemovalFilter != null )
{
mDCRemovalFilter.dispose();
}
/**
* Cleanup method
*/
public void dispose()
{
super.dispose();
mFSKDecoder.dispose();
mSymbolBroadcaster.dispose();
mDecimationFilter.dispose();
mControlMessageFramer.dispose();
mLowPassFilter.dispose();
mMessageProcessor.dispose();
if(mDCRemovalFilter != null)
{
mDCRemovalFilter.dispose();
}
mTrafficMessageFramer.dispose();
}
mFSKDecoder.dispose();
/* Instrumentation Taps */
@Override
mDecimationFilter.dispose();
mLowPassFilter.dispose();
mMessageProcessor.dispose();
mTrafficMessageFramer.dispose();
}
/* Instrumentation Taps */
@Override
public List<TapGroup> getTapGroups()
{
if( mAvailableTaps == null )
{
mAvailableTaps = new ArrayList<TapGroup>();
if(mAvailableTaps == null)
{
mAvailableTaps = new ArrayList<TapGroup>();
TapGroup group = new TapGroup( "MPT-1327 Decoder" );
group.add(
new FloatTap( INSTRUMENT_HB1_FILTER_TO_LOW_PASS, 0, 0.5f ) );
group.add(
new FloatTap( INSTRUMENT_LOW_PASS_TO_DECODER, 0, 0.5f ) );
group.add(
new BinaryTap( INSTRUMENT_DECODER_TO_FRAMER, 0, 0.025f ) );
TapGroup group = new TapGroup("MPT-1327 Decoder");
mAvailableTaps.add( group );
group.add(new FloatTap(INSTRUMENT_HB1_FILTER_TO_LOW_PASS, 0, 0.5f));
group.add(new FloatTap(INSTRUMENT_LOW_PASS_TO_DECODER, 0, 0.5f));
group.add(new BinaryTap(INSTRUMENT_DECODER_TO_FRAMER, 0, 0.025f));
mAvailableTaps.add(group);
/* Add the taps from the FSK decoder */
mAvailableTaps.addAll( mFSKDecoder.getTapGroups() );
}
return mAvailableTaps;
mAvailableTaps.addAll(mFSKDecoder.getTapGroups());
}
return mAvailableTaps;
}
@Override
public void registerTap( Tap tap )
@Override
public void registerTap(Tap tap)
{
/* Send request to decoder */
mFSKDecoder.registerTap( tap );
switch( tap.getName() )
{
case INSTRUMENT_HB1_FILTER_TO_LOW_PASS:
FloatBufferTap hb1Tap = (FloatBufferTap)tap;
mDecimationFilter.setListener( hb1Tap );
hb1Tap.setListener( mLowPassFilter );
break;
case INSTRUMENT_LOW_PASS_TO_DECODER:
FloatBufferTap lowTap = (FloatBufferTap)tap;
mLowPassFilter.setListener( lowTap );
lowTap.setListener( mFSKDecoder );
break;
case INSTRUMENT_DECODER_TO_FRAMER:
BinaryTap decoderTap = (BinaryTap)tap;
mFSKDecoder.setListener( decoderTap );
decoderTap.setListener( mSymbolBroadcaster );
break;
}
/* Send request to decoder */
mFSKDecoder.registerTap(tap);
switch(tap.getName())
{
case INSTRUMENT_HB1_FILTER_TO_LOW_PASS:
FloatBufferTap hb1Tap = (FloatBufferTap) tap;
mDecimationFilter.setListener(hb1Tap);
hb1Tap.setListener(mLowPassFilter);
break;
case INSTRUMENT_LOW_PASS_TO_DECODER:
FloatBufferTap lowTap = (FloatBufferTap) tap;
mLowPassFilter.setListener(lowTap);
lowTap.setListener(mFSKDecoder);
break;
case INSTRUMENT_DECODER_TO_FRAMER:
BinaryTap decoderTap = (BinaryTap) tap;
mFSKDecoder.setListener(decoderTap);
decoderTap.setListener(mSymbolBroadcaster);
break;
}
}
@Override
public void unregisterTap( Tap tap )
@Override
public void unregisterTap(Tap tap)
{
mFSKDecoder.unregisterTap( tap );
switch( tap.getName() )
{
case INSTRUMENT_HB1_FILTER_TO_LOW_PASS:
mDecimationFilter.setListener( mLowPassFilter );
break;
case INSTRUMENT_LOW_PASS_TO_DECODER:
mLowPassFilter.setListener( mFSKDecoder );
break;
case INSTRUMENT_DECODER_TO_FRAMER:
mFSKDecoder.setListener( mSymbolBroadcaster );
break;
}
mFSKDecoder.unregisterTap(tap);
switch(tap.getName())
{
case INSTRUMENT_HB1_FILTER_TO_LOW_PASS:
mDecimationFilter.setListener(mLowPassFilter);
break;
case INSTRUMENT_LOW_PASS_TO_DECODER:
mLowPassFilter.setListener(mFSKDecoder);
break;
case INSTRUMENT_DECODER_TO_FRAMER:
mFSKDecoder.setListener(mSymbolBroadcaster);
break;
}
}
public enum Sync
{
NORMAL( "Normal",
SyncPattern.MPT1327_CONTROL,
SyncPattern.MPT1327_TRAFFIC ),
FRENCH( "French",
SyncPattern.MPT1327_CONTROL_FRENCH,
SyncPattern.MPT1327_TRAFFIC_FRENCH );
private String mLabel;
private SyncPattern mControlSyncPattern;
private SyncPattern mTrafficSyncPattern;
public enum Sync
{
NORMAL("Normal", SyncPattern.MPT1327_CONTROL, SyncPattern.MPT1327_TRAFFIC),
FRENCH("French", SyncPattern.MPT1327_CONTROL_FRENCH, SyncPattern.MPT1327_TRAFFIC_FRENCH);
private Sync( String label,
SyncPattern controlPattern,
SyncPattern trafficPattern )
{
mLabel = label;
mControlSyncPattern = controlPattern;
mTrafficSyncPattern = trafficPattern;
}
public String getLabel()
{
return mLabel;
}
public SyncPattern getControlSyncPattern()
{
return mControlSyncPattern;
}
public SyncPattern getTrafficSyncPattern()
{
return mTrafficSyncPattern;
}
public String toString()
{
return getLabel();
}
}
private String mLabel;
private SyncPattern mControlSyncPattern;
private SyncPattern mTrafficSyncPattern;
@Override
public void reset()
{
mControlMessageFramer.reset();
mTrafficMessageFramer.reset();
}
private Sync(String label, SyncPattern controlPattern, SyncPattern trafficPattern)
{
mLabel = label;
mControlSyncPattern = controlPattern;
mTrafficSyncPattern = trafficPattern;
}
@Override
public void start( ScheduledExecutorService executor )
{
// TODO Auto-generated method stub
}
public String getLabel()
{
return mLabel;
}
@Override
public void stop()
{
// TODO Auto-generated method stub
}
public SyncPattern getControlSyncPattern()
{
return mControlSyncPattern;
}
public SyncPattern getTrafficSyncPattern()
{
return mTrafficSyncPattern;
}
public String toString()
{
return getLabel();
}
}
@Override
public void reset()
{
mControlMessageFramer.reset();
mTrafficMessageFramer.reset();
}
@Override
public void start(ScheduledExecutorService executor)
{
// TODO Auto-generated method stub
}
@Override
public void stop()
{
// TODO Auto-generated method stub
}
}

View File

@@ -1,102 +1,118 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 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/>
* sdrtrunk
* Copyright (C) 2014-2017 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 module.demodulate.audio;
import java.util.concurrent.ScheduledExecutorService;
import module.Module;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.Listener;
import sample.real.IFilteredRealBufferProvider;
import sample.real.IUnFilteredRealBufferListener;
import sample.real.RealBuffer;
import dsp.filter.FilterFactory;
import dsp.filter.Window.WindowType;
import dsp.filter.dc.DCRemovalFilter_RealBuffer;
import dsp.filter.fir.real.RealFIRFilter_RB_RB;
import module.Module;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.Listener;
import sample.real.IFilteredRealBufferProvider;
import sample.real.IUnFilteredRealBufferListener;
import sample.real.RealBuffer;
public class DemodulatedAudioFilterModule extends Module
implements IUnFilteredRealBufferListener, IFilteredRealBufferProvider
import java.util.concurrent.ScheduledExecutorService;
public class DemodulatedAudioFilterModule extends Module implements IUnFilteredRealBufferListener, IFilteredRealBufferProvider
{
private final static Logger mLog = LoggerFactory.getLogger( DemodulatedAudioFilterModule.class );
private final static Logger mLog = LoggerFactory.getLogger(DemodulatedAudioFilterModule.class);
private DCRemovalFilter_RealBuffer mDCFilter = new DCRemovalFilter_RealBuffer();
private RealFIRFilter_RB_RB mBandPassFilter;
/**
* Filters demodulated audio and removes any DC component from the buffer
*
* @param pass - audio pass band pass frequency
* @param stop - audio pass band stop frequency
*/
public DemodulatedAudioFilterModule( int pass, int stop )
{
assert( stop > pass );
//TODO: change this to a band pass filter
mBandPassFilter = new RealFIRFilter_RB_RB( FilterFactory.getLowPass( 48000, pass, stop, 60,
WindowType.HANNING, true ), 1.0f );
mDCFilter.setListener( mBandPassFilter );
}
private DCRemovalFilter_RealBuffer mDCFilter;
private RealFIRFilter_RB_RB mBandPassFilter;
@Override
public void dispose()
{
mBandPassFilter.dispose();
mBandPassFilter = null;
mDCFilter.dispose();
mDCFilter = null;
}
/**
* Filters demodulated audio and removes any DC component from the buffer
*
* @param pass - audio pass band pass frequency
* @param stop - audio pass band stop frequency
*/
public DemodulatedAudioFilterModule(int pass, int stop)
{
assert (stop > pass);
@Override
public void reset()
{
}
mDCFilter = new DCRemovalFilter_RealBuffer();
@Override
public void setFilteredRealBufferListener( Listener<RealBuffer> listener )
{
mBandPassFilter.setListener( listener );
}
//TODO: change this to a band pass filter
mBandPassFilter = new RealFIRFilter_RB_RB(FilterFactory.getLowPass(48000, pass, stop, 60,
WindowType.HANNING, true), 1.0f);
@Override
public void removeFilteredRealBufferListener()
{
mBandPassFilter.removeListener();
}
mDCFilter.setListener(mBandPassFilter);
}
@Override
public void start( ScheduledExecutorService executor )
{
}
/**
* Constructs a demodulated audio filter using the filter taps and gain provided
*/
public DemodulatedAudioFilterModule(float[] taps, float gain)
{
mBandPassFilter = new RealFIRFilter_RB_RB(taps, gain);
}
@Override
public void stop()
{
}
@Override
public void dispose()
{
mBandPassFilter.dispose();
mBandPassFilter = null;
@Override
public Listener<RealBuffer> getUnFilteredRealBufferListener()
{
return mDCFilter;
}
mDCFilter.dispose();
mDCFilter = null;
}
@Override
public void reset()
{
}
@Override
public void setFilteredRealBufferListener(Listener<RealBuffer> listener)
{
mBandPassFilter.setListener(listener);
}
@Override
public void removeFilteredRealBufferListener()
{
mBandPassFilter.removeListener();
}
@Override
public void start(ScheduledExecutorService executor)
{
}
@Override
public void stop()
{
}
@Override
public Listener<RealBuffer> getUnFilteredRealBufferListener()
{
if(mDCFilter != null)
{
return mDCFilter;
}
else
{
return mBandPassFilter;
}
}
}

View File

@@ -1,112 +1,108 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 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 module.demodulate.fm;
import java.util.concurrent.ScheduledExecutorService;
import dsp.filter.FilterFactory;
import dsp.filter.Window.WindowType;
import dsp.filter.fir.complex.ComplexFIRFilter_CB_CB;
import dsp.fm.FMDemodulator_CB;
import module.Module;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.Listener;
import sample.complex.ComplexBuffer;
import sample.complex.IComplexBufferListener;
import sample.real.IUnFilteredRealBufferProvider;
import sample.real.RealBuffer;
import dsp.filter.FilterFactory;
import dsp.filter.Window.WindowType;
import dsp.filter.fir.complex.ComplexFIRFilter_CB_CB;
import dsp.fm.FMDemodulator_CB;
public class FMDemodulatorModule extends Module
implements IComplexBufferListener, IUnFilteredRealBufferProvider
import java.util.concurrent.ScheduledExecutorService;
public class FMDemodulatorModule extends Module implements IComplexBufferListener, IUnFilteredRealBufferProvider
{
private final static Logger mLog = LoggerFactory.getLogger( FMDemodulatorModule.class );
private static final int SAMPLE_RATE = 48000;
private ComplexFIRFilter_CB_CB mIQFilter;
private FMDemodulator_CB mDemodulator;
/**
* FM Demodulator with I/Q filter. Demodulated output is unfiltered and
* may contain a DC component.
*
* @param pass - pass frequency for IQ filtering prior to demodulation. This
* frequency should be half of the signal bandwidth since the filter will
* be applied against each of the inphase and quadrature signals and the
* combined pass bandwidth will be twice this value.
*
* @param stop - stop frequency for IQ filtering prior to demodulation.
*/
public FMDemodulatorModule( int pass, int stop )
{
assert( stop > pass );
private final static Logger mLog = LoggerFactory.getLogger(FMDemodulatorModule.class);
mIQFilter = new ComplexFIRFilter_CB_CB( FilterFactory.getLowPass(
SAMPLE_RATE, pass, stop, 60, WindowType.HAMMING, true ), 1.0f );
mDemodulator = new FMDemodulator_CB( 1.0f );
mIQFilter.setListener( mDemodulator );
}
private static final int SAMPLE_RATE = 48000;
@Override
public Listener<ComplexBuffer> getComplexBufferListener()
{
return mIQFilter;
}
private ComplexFIRFilter_CB_CB mIQFilter;
private FMDemodulator_CB mDemodulator;
@Override
public void dispose()
{
mIQFilter.dispose();
mIQFilter = null;
mDemodulator.dispose();
mDemodulator = null;
}
/**
* FM Demodulator with I/Q filter. Demodulated output is unfiltered and
* may contain a DC component.
*
* @param pass - pass frequency for IQ filtering prior to demodulation. This
* frequency should be half of the signal bandwidth since the filter will
* be applied against each of the inphase and quadrature signals and the
* combined pass bandwidth will be twice this value.
* @param stop - stop frequency for IQ filtering prior to demodulation.
*/
public FMDemodulatorModule(int pass, int stop)
{
assert (stop > pass);
@Override
public void reset()
{
mDemodulator.reset();
}
mIQFilter = new ComplexFIRFilter_CB_CB(FilterFactory.getLowPass(
SAMPLE_RATE, pass, stop, 60, WindowType.HAMMING, true), 1.0f);
@Override
public void setUnFilteredRealBufferListener( Listener<RealBuffer> listener )
{
mDemodulator.setListener( listener );
}
mDemodulator = new FMDemodulator_CB(1.0f);
mIQFilter.setListener(mDemodulator);
}
@Override
public void removeUnFilteredRealBufferListener()
{
mDemodulator.removeListener();
}
@Override
public Listener<ComplexBuffer> getComplexBufferListener()
{
return mIQFilter;
}
@Override
public void start( ScheduledExecutorService executor )
{
}
@Override
public void dispose()
{
mIQFilter.dispose();
mIQFilter = null;
@Override
public void stop()
{
}
mDemodulator.dispose();
mDemodulator = null;
}
@Override
public void reset()
{
mDemodulator.reset();
}
@Override
public void setUnFilteredRealBufferListener(Listener<RealBuffer> listener)
{
mDemodulator.setListener(listener);
}
@Override
public void removeUnFilteredRealBufferListener()
{
mDemodulator.removeListener();
}
@Override
public void start(ScheduledExecutorService executor)
{
}
@Override
public void stop()
{
}
}