mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
Co-authored-by: denny <dennis.sheirer@gmail.com>
This commit is contained in:
@@ -21,20 +21,14 @@ package io.github.dsheirer.module.decode.am;
|
||||
import io.github.dsheirer.channel.state.DecoderStateEvent;
|
||||
import io.github.dsheirer.channel.state.IDecoderStateEventProvider;
|
||||
import io.github.dsheirer.channel.state.State;
|
||||
import io.github.dsheirer.dsp.am.ISquelchingDemodulator;
|
||||
import io.github.dsheirer.dsp.am.SquelchingAMDemodulator;
|
||||
import io.github.dsheirer.dsp.filter.ChannelFilterDesigner;
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.decimate.DecimationFilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.decimate.IRealDecimationFilter;
|
||||
import io.github.dsheirer.dsp.filter.design.FilterDesignException;
|
||||
import io.github.dsheirer.dsp.filter.fir.FIRFilterSpecification;
|
||||
import io.github.dsheirer.dsp.filter.fir.real.IRealFilter;
|
||||
import io.github.dsheirer.dsp.filter.resample.RealResampler;
|
||||
import io.github.dsheirer.dsp.fm.ISquelchingDemodulator;
|
||||
import io.github.dsheirer.dsp.gain.AudioGainAndDcFilter;
|
||||
import io.github.dsheirer.dsp.squelch.INoiseSquelchController;
|
||||
import io.github.dsheirer.dsp.squelch.NoiseSquelch;
|
||||
import io.github.dsheirer.dsp.squelch.NoiseSquelchState;
|
||||
import io.github.dsheirer.dsp.window.WindowType;
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
import io.github.dsheirer.module.decode.SquelchControlDecoder;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
@@ -52,15 +46,9 @@ import org.slf4j.LoggerFactory;
|
||||
*/
|
||||
public class AMDecoder extends SquelchControlDecoder implements ISourceEventListener, ISourceEventProvider,
|
||||
IComplexSamplesListener, Listener<ComplexSamples>, IRealBufferProvider,
|
||||
IDecoderStateEventProvider, INoiseSquelchController
|
||||
IDecoderStateEventProvider
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(AMDecoder.class);
|
||||
private static final float DEMODULATOR_GAIN = 150.0f;
|
||||
private static final float SQUELCH_ALPHA_DECAY = 0.0004f;
|
||||
private static final float MINIMUM_GAIN = 0.5f;
|
||||
private static final float MAXIMUM_GAIN = 16.0f;
|
||||
private static final float OBJECTIVE_AUDIO_AMPLITUDE = 0.75f;
|
||||
private AudioGainAndDcFilter mAGC = new AudioGainAndDcFilter(MINIMUM_GAIN, MAXIMUM_GAIN, OBJECTIVE_AUDIO_AMPLITUDE);
|
||||
private static final double DEMODULATED_AUDIO_SAMPLE_RATE = 8000.0;
|
||||
private IRealFilter mIBasebandFilter;
|
||||
private IRealFilter mQBasebandFilter;
|
||||
@@ -73,7 +61,6 @@ public class AMDecoder extends SquelchControlDecoder implements ISourceEventList
|
||||
private Listener<DecoderStateEvent> mDecoderStateEventListener;
|
||||
private final double mChannelBandwidth;
|
||||
protected boolean mSquelch = true;
|
||||
private final NoiseSquelch mNoiseSquelch = new NoiseSquelch(0.1f, 0.2f, 4, 6);
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
@@ -83,8 +70,8 @@ public class AMDecoder extends SquelchControlDecoder implements ISourceEventList
|
||||
public AMDecoder(DecodeConfigAM config)
|
||||
{
|
||||
super(config);
|
||||
mDemodulator = new SquelchingAMDemodulator(DEMODULATOR_GAIN, SQUELCH_ALPHA_DECAY, config.getSquelchThreshold(),
|
||||
config.isSquelchAutoTrack());
|
||||
mDemodulator = new SquelchingAMDemodulator(config.getSquelchThreshold(), config.isSquelchAutoTrack(),
|
||||
config.getBandwidth().getValue());
|
||||
mChannelBandwidth = config.getBandwidth().getValue();
|
||||
}
|
||||
|
||||
@@ -94,30 +81,6 @@ public class AMDecoder extends SquelchControlDecoder implements ISourceEventList
|
||||
return DecoderType.AM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSquelchOverride(boolean override)
|
||||
{
|
||||
mNoiseSquelch.setSquelchOverride(override);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHysteresisThreshold(int open, int close)
|
||||
{
|
||||
mNoiseSquelch.setHysteresisThreshold(open, close);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNoiseThreshold(float open, float close)
|
||||
{
|
||||
mNoiseSquelch.setNoiseThreshold(open, close);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNoiseSquelchStateListener(Listener<NoiseSquelchState> listener)
|
||||
{
|
||||
mNoiseSquelch.setNoiseSquelchStateListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the ISourceEventListener interface
|
||||
*/
|
||||
@@ -154,8 +117,6 @@ public class AMDecoder extends SquelchControlDecoder implements ISourceEventList
|
||||
if(mResampledBufferListener != null)
|
||||
{
|
||||
mResampledBufferListener.receive(demodulatedSamples);
|
||||
// //Apply audio gain and rebroadcast
|
||||
// super.broadcast(mAGC.process(demodulatedSamples));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,7 +157,7 @@ public class AMDecoder extends SquelchControlDecoder implements ISourceEventList
|
||||
{
|
||||
if(mIDecimationFilter == null || mQDecimationFilter == null)
|
||||
{
|
||||
throw new IllegalStateException("NBFM demodulator module must receive a sample rate change source " +
|
||||
throw new IllegalStateException("AM demodulator module must receive a sample rate change source " +
|
||||
"event before it can process complex sample buffers");
|
||||
}
|
||||
|
||||
@@ -208,8 +169,6 @@ public class AMDecoder extends SquelchControlDecoder implements ISourceEventList
|
||||
|
||||
float[] demodulated = mDemodulator.demodulate(filteredI, filteredQ);
|
||||
|
||||
mNoiseSquelch.process(demodulated);
|
||||
|
||||
if(mResampler != null)
|
||||
{
|
||||
//Squelch changed while processing this audio buffer
|
||||
@@ -225,6 +184,8 @@ public class AMDecoder extends SquelchControlDecoder implements ISourceEventList
|
||||
//Demodulator says to mute and we are unmuted = Squelch and End Call
|
||||
else
|
||||
{
|
||||
//Process the final audio and flush the resampler so that audio doesn't carry into the next call
|
||||
mResampler.resample(demodulated, true);
|
||||
mSquelch = true;
|
||||
notifyCallEnd();
|
||||
}
|
||||
@@ -275,7 +236,6 @@ public class AMDecoder extends SquelchControlDecoder implements ISourceEventList
|
||||
*/
|
||||
protected void notifyCallStart()
|
||||
{
|
||||
mAGC.reset();
|
||||
broadcast(new DecoderStateEvent(this, DecoderStateEvent.Event.START, State.CALL, 0));
|
||||
}
|
||||
|
||||
@@ -398,53 +358,17 @@ public class AMDecoder extends SquelchControlDecoder implements ISourceEventList
|
||||
mIDecimationFilter = DecimationFilterFactory.getRealDecimationFilter(decimationRate);
|
||||
mQDecimationFilter = DecimationFilterFactory.getRealDecimationFilter(decimationRate);
|
||||
|
||||
if((decimatedSampleRate < (2.0 * mChannelBandwidth)))
|
||||
//The complex sample rate must span the two-sided channel bandwidth.
|
||||
if(decimatedSampleRate < mChannelBandwidth)
|
||||
{
|
||||
throw new IllegalStateException(getDecoderType().name() + " demodulator with channel bandwidth [" +
|
||||
mChannelBandwidth + "] requires a channel sample rate of [" + (2.0 * mChannelBandwidth +
|
||||
"] - sample rate of [" + decimatedSampleRate + "] is not supported"));
|
||||
mChannelBandwidth + "] requires a channel sample rate of at least [" + mChannelBandwidth +
|
||||
"] - sample rate of [" + decimatedSampleRate + "] is not supported");
|
||||
}
|
||||
|
||||
mDemodulator.setSampleRate((int) decimatedSampleRate);
|
||||
|
||||
mNoiseSquelch.setSampleRate(decimatedSampleRate);
|
||||
|
||||
int passBandStop = (int) (mChannelBandwidth * .8);
|
||||
int stopBandStart = (int) mChannelBandwidth;
|
||||
|
||||
float[] coefficients = null;
|
||||
|
||||
FIRFilterSpecification specification = FIRFilterSpecification.lowPassBuilder()
|
||||
.sampleRate(decimatedSampleRate * 2)
|
||||
.gridDensity(16)
|
||||
.oddLength(true)
|
||||
.passBandCutoff(passBandStop)
|
||||
.passBandAmplitude(1.0)
|
||||
.passBandRipple(0.01)
|
||||
.stopBandStart(stopBandStart)
|
||||
.stopBandAmplitude(0.0)
|
||||
.stopBandRipple(0.005) //Approximately 90 dB attenuation
|
||||
.build();
|
||||
|
||||
try
|
||||
{
|
||||
coefficients = FilterFactory.getTaps(specification);
|
||||
}
|
||||
catch(FilterDesignException fde)
|
||||
{
|
||||
mLog.error("Couldn't design demodulator remez filter for sample rate [" + sampleRate +
|
||||
"] pass frequency [" + passBandStop + "] and stop frequency [" + stopBandStart +
|
||||
"] - will proceed using sinc (low-pass) filter");
|
||||
}
|
||||
|
||||
if(coefficients == null)
|
||||
{
|
||||
mLog.info("Unable to use remez filter designer for sample rate [" + decimatedSampleRate +
|
||||
"] pass band stop [" + passBandStop +
|
||||
"] and stop band start [" + stopBandStart + "] - will proceed using simple low pass filter design");
|
||||
coefficients = FilterFactory.getLowPass(decimatedSampleRate, passBandStop, stopBandStart, 60,
|
||||
WindowType.HAMMING, true);
|
||||
}
|
||||
float[] coefficients = ChannelFilterDesigner.design(decimatedSampleRate, mChannelBandwidth);
|
||||
|
||||
mIBasebandFilter = FilterFactory.getRealFilter(coefficients);
|
||||
mQBasebandFilter = FilterFactory.getRealFilter(coefficients);
|
||||
|
||||
@@ -30,6 +30,7 @@ import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
|
||||
*/
|
||||
public class DecodeConfigAM extends DecodeConfigAnalog implements ISquelchConfiguration
|
||||
{
|
||||
public static final Bandwidth DEFAULT_BANDWIDTH = Bandwidth.BW_6_0;
|
||||
private int mSquelchThreshold = -78;
|
||||
private boolean mSquelchAutoTrack = true;
|
||||
|
||||
@@ -46,7 +47,7 @@ public class DecodeConfigAM extends DecodeConfigAnalog implements ISquelchConfig
|
||||
@Override
|
||||
protected Bandwidth getDefaultBandwidth()
|
||||
{
|
||||
return Bandwidth.BW_15_0;
|
||||
return DEFAULT_BANDWIDTH;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,12 +63,14 @@ public class DecodeConfigAM extends DecodeConfigAnalog implements ISquelchConfig
|
||||
return new ChannelSpecification(25000.0, 3000, 1500.0, 1700.0);
|
||||
case BW_5_0:
|
||||
return new ChannelSpecification(25000.0, 5000, 2500.0, 2700.0);
|
||||
case BW_6_0:
|
||||
return new ChannelSpecification(25000.0, 6000, 3000.0, 3200.0);
|
||||
case BW_8_33:
|
||||
return new ChannelSpecification(25000.0, 10000, 5000.0, 7000.0);
|
||||
case BW_15_0:
|
||||
return new ChannelSpecification(25000.0, 15000, 7500.0, 9500.0);
|
||||
return new ChannelSpecification(30000.0, 15000, 7500.0, 9500.0);
|
||||
case BW_25_0:
|
||||
return new ChannelSpecification(25000.0, 25000, 12500.0, 14500.0);
|
||||
return new ChannelSpecification(50000.0, 25000, 12500.0, 14500.0);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unrecognized AM bandwidth value: " + getBandwidth());
|
||||
}
|
||||
|
||||
@@ -100,6 +100,7 @@ public abstract class DecodeConfigAnalog extends DecodeConfiguration
|
||||
{
|
||||
BW_3_0("3.0 kHz", 3000.0),
|
||||
BW_5_0("5.0 kHz", 5000.0),
|
||||
BW_6_0("6.0 kHz", 6000.0),
|
||||
BW_7_5("7.5 kHz", 7500.0),
|
||||
BW_8_33("8.33 kHz", 8333.0),
|
||||
BW_12_5("12.5 kHz", 12500.0),
|
||||
@@ -121,7 +122,7 @@ public abstract class DecodeConfigAnalog extends DecodeConfiguration
|
||||
}
|
||||
|
||||
//AM demodulator channel bandwidth options
|
||||
public static EnumSet<Bandwidth> AM_BANDWIDTHS = EnumSet.of(BW_3_0, BW_5_0, BW_8_33, BW_15_0, BW_25_0);
|
||||
public static EnumSet<Bandwidth> AM_BANDWIDTHS = EnumSet.of(BW_3_0, BW_5_0, BW_6_0, BW_8_33, BW_15_0, BW_25_0);
|
||||
|
||||
//FM demodulator channel bandwidth options
|
||||
public static EnumSet<Bandwidth> FM_BANDWIDTHS = EnumSet.of(BW_7_5, BW_12_5, BW_25_0);
|
||||
|
||||
@@ -22,11 +22,10 @@ import io.github.dsheirer.audio.squelch.SquelchState;
|
||||
import io.github.dsheirer.channel.state.DecoderStateEvent;
|
||||
import io.github.dsheirer.channel.state.IDecoderStateEventProvider;
|
||||
import io.github.dsheirer.channel.state.State;
|
||||
import io.github.dsheirer.dsp.filter.ChannelFilterDesigner;
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.decimate.DecimationFilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.decimate.IRealDecimationFilter;
|
||||
import io.github.dsheirer.dsp.filter.design.FilterDesignException;
|
||||
import io.github.dsheirer.dsp.filter.fir.FIRFilterSpecification;
|
||||
import io.github.dsheirer.dsp.filter.fir.real.IRealFilter;
|
||||
import io.github.dsheirer.dsp.filter.resample.RealResampler;
|
||||
import io.github.dsheirer.dsp.fm.FmDemodulatorFactory;
|
||||
@@ -34,7 +33,6 @@ import io.github.dsheirer.dsp.fm.IDemodulator;
|
||||
import io.github.dsheirer.dsp.squelch.INoiseSquelchController;
|
||||
import io.github.dsheirer.dsp.squelch.NoiseSquelch;
|
||||
import io.github.dsheirer.dsp.squelch.NoiseSquelchState;
|
||||
import io.github.dsheirer.dsp.window.WindowType;
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
import io.github.dsheirer.module.decode.SquelchControlDecoder;
|
||||
import io.github.dsheirer.module.decode.squelch.SquelchCodeState;
|
||||
@@ -456,37 +454,7 @@ public class NBFMDecoder extends SquelchControlDecoder implements ISourceEventLi
|
||||
|
||||
mNoiseSquelch.setSampleRate(decimatedSampleRate);
|
||||
|
||||
int passBandStop = (int) (mChannelBandwidth * .8);
|
||||
int stopBandStart = (int) mChannelBandwidth;
|
||||
|
||||
float[] coefficients = null;
|
||||
|
||||
FIRFilterSpecification specification = FIRFilterSpecification.lowPassBuilder()
|
||||
.sampleRate(decimatedSampleRate * 2)
|
||||
.gridDensity(16)
|
||||
.oddLength(true)
|
||||
.passBandCutoff(passBandStop)
|
||||
.passBandAmplitude(1.0)
|
||||
.passBandRipple(0.01)
|
||||
.stopBandStart(stopBandStart)
|
||||
.stopBandAmplitude(0.0)
|
||||
.stopBandRipple(0.005)
|
||||
.build();
|
||||
|
||||
try
|
||||
{
|
||||
coefficients = FilterFactory.getTaps(specification);
|
||||
}
|
||||
catch(FilterDesignException fde)
|
||||
{
|
||||
mLog.error("Couldn't design demodulator remez filter for sample rate [" + sampleRate + "] pass frequency [" + passBandStop + "] and stop frequency [" + stopBandStart + "] - will proceed using sinc (low-pass) filter");
|
||||
}
|
||||
|
||||
if(coefficients == null)
|
||||
{
|
||||
mLog.info("Unable to use remez filter designer for sample rate [" + decimatedSampleRate + "] pass band stop [" + passBandStop + "] and stop band start [" + stopBandStart + "] - will proceed using simple low pass filter design");
|
||||
coefficients = FilterFactory.getLowPass(decimatedSampleRate, passBandStop, stopBandStart, 60, WindowType.HAMMING, true);
|
||||
}
|
||||
float[] coefficients = ChannelFilterDesigner.design(decimatedSampleRate, mChannelBandwidth);
|
||||
|
||||
mIBasebandFilter = FilterFactory.getRealFilter(coefficients);
|
||||
mQBasebandFilter = FilterFactory.getRealFilter(coefficients);
|
||||
|
||||
Reference in New Issue
Block a user