Merge branch 'master' into 39-polyphase-channelizer

# Conflicts:
#	src/main/java/io/github/dsheirer/buffer/FloatCircularBuffer.java
#	src/main/java/io/github/dsheirer/dsp/filter/FilterFactory.java
#	src/main/java/io/github/dsheirer/dsp/filter/design/FilterView.java
#	src/main/java/io/github/dsheirer/dsp/filter/design/FilterViewer.java
#	src/main/java/io/github/dsheirer/dsp/filter/fir/complex/ComplexFIRFilter.java
#	src/main/java/io/github/dsheirer/dsp/gain/ComplexFeedForwardGainControl.java
#	src/main/java/io/github/dsheirer/dsp/mixer/Oscillator.java
#	src/main/java/io/github/dsheirer/dsp/psk/LSMDemodulator.java
#	src/main/java/io/github/dsheirer/module/decode/Decoder.java
#	src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java
#	src/main/java/io/github/dsheirer/module/decode/p25/P25Decoder.java
#	src/main/java/io/github/dsheirer/module/decode/p25/P25_C4FMDecoder.java
#	src/main/java/io/github/dsheirer/module/decode/p25/P25_LSMDecoder.java
#	src/main/java/io/github/dsheirer/source/tuner/TunerChannelSource.java
#	src/main/java/io/github/dsheirer/source/tuner/TunerModel.java
#	src/main/java/io/github/dsheirer/source/tuner/TunerSourceEditor.java
#	src/main/java/io/github/dsheirer/spectrum/ChannelSpectrumPanel.java
This commit is contained in:
Denny
2018-03-18 05:19:33 -04:00
89 changed files with 7253 additions and 2885 deletions

View File

@@ -1,112 +1,125 @@
/*******************************************************************************
* 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.
*
* 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.gain;
import io.github.dsheirer.buffer.RealCircularBuffer;
import io.github.dsheirer.buffer.FloatCircularBuffer;
import io.github.dsheirer.sample.complex.Complex;
import io.github.dsheirer.sample.complex.ComplexBuffer;
import io.github.dsheirer.sample.complex.ComplexSampleListener;
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2015 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 class is modeled using concepts detailed in the GNURadio
* implementation of feed forward AGC class located at:
* https://github.com/gnuradio/gnuradio/blob/master/gr-analog/lib/
* feedforward_agc_cc_impl.cc
*
******************************************************************************/
public class ComplexFeedForwardGainControl implements ComplexSampleListener
{
public static final float OBJECTIVE_ENVELOPE = 1.0f;
public static final float MINIMUM_ENVELOPE = 0.0001f;
public static final float OBJECTIVE_ENVELOPE = 1.0f;
public static final float MINIMUM_ENVELOPE = 0.0001f;
private ComplexSampleListener mListener;
private ComplexSampleListener mListener;
private RealCircularBuffer mEnvelopeHistory;
private float mMaxEnvelope = 0.0f;
private float mGain = 1.0f;
/**
* Dynamic gain control for incoming sample stream to amplify or attenuate
* all samples toward an objective unity)gain, using the maximum envelope
* value detected in the stream history window.
*
* Uses the specified damping factor to limit gain swings. Damping factor
* is applied against the delta between current gain value and a recalculated
* gain value to limit how quickly the gain value will increase or decrease.
*
* @param window - history size to use in detecting maximum envelope value
* @param damping - a value between 0 < damping <= 1.0;
*/
public ComplexFeedForwardGainControl( int window )
{
mEnvelopeHistory = new RealCircularBuffer( window );
}
public void dispose()
{
mListener = null;
}
private FloatCircularBuffer mEnvelopeHistory;
@Override
public void receive( float inphase, float quadrature )
{
float envelope = Complex.envelope( inphase, quadrature );
private float mMaxEnvelope = 0.0f;
private float mGain = 1.0f;
if( envelope > mMaxEnvelope )
{
mMaxEnvelope = envelope;
adjustGain();
}
/**
* Dynamic gain control for incoming sample stream to amplify or attenuate
* all samples toward an objective unity)gain, using the maximum envelope
* value detected in the stream history window.
*
* Uses the specified damping factor to limit gain swings. Damping factor
* is applied against the delta between current gain value and a recalculated
* gain value to limit how quickly the gain value will increase or decrease.
*
* @param window - history size to use in detecting maximum envelope value
*/
public ComplexFeedForwardGainControl(int window)
{
mEnvelopeHistory = new FloatCircularBuffer(window);
}
/* Replace oldest envelope value with current envelope value */
float oldestEnvelope = mEnvelopeHistory.putAndGet( envelope );
public void dispose()
{
mListener = null;
}
/* If the oldest envelope value was the max envelope value, then we
* have to rediscover the max value from the envelope history */
if( mMaxEnvelope == oldestEnvelope && mMaxEnvelope != envelope )
{
mMaxEnvelope = MINIMUM_ENVELOPE;
for( float value: mEnvelopeHistory.getBuffer() )
{
if( value > mMaxEnvelope )
{
mMaxEnvelope = value;
}
}
adjustGain();
}
/* Apply current gain value to the sample and send to the listener */
if( mListener != null )
{
mListener.receive( inphase *= mGain, quadrature *= mGain );
}
}
private void adjustGain()
{
mGain = OBJECTIVE_ENVELOPE / mMaxEnvelope;
}
@Override
public void receive(float inphase, float quadrature)
{
process(inphase, quadrature);
public void setListener( ComplexSampleListener listener )
{
mListener = listener;
}
/* Apply current gain value to the sample and send to the listener */
if(mListener != null)
{
mListener.receive(inphase *= mGain, quadrature *= mGain);
}
}
private void process(float inphase, float quadrature)
{
float envelope = Complex.envelope(inphase, quadrature);
if(envelope > mMaxEnvelope)
{
mMaxEnvelope = envelope;
adjustGain();
}
/* Replace oldest envelope value with current envelope value */
float oldestEnvelope = mEnvelopeHistory.get(envelope);
/* If the oldest envelope value was the max envelope value, then we
* have to rediscover the max value from the envelope history */
if(mMaxEnvelope == oldestEnvelope && mMaxEnvelope != envelope)
{
mMaxEnvelope = MINIMUM_ENVELOPE;
for(float value : mEnvelopeHistory.getBuffer())
{
if(value > mMaxEnvelope)
{
mMaxEnvelope = value;
}
}
adjustGain();
}
}
private void adjustGain()
{
mGain = OBJECTIVE_ENVELOPE / mMaxEnvelope;
}
public void setListener(ComplexSampleListener listener)
{
mListener = listener;
}
public ComplexBuffer filter(ComplexBuffer complexBuffer)
{
float[] samples = complexBuffer.getSamples();
float[] processed = new float[samples.length];
for(int x = 0; x < samples.length; x += 2)
{
process(samples[x], samples[x + 1]);
processed[x] = samples[x] * mGain;
processed[x + 1] = samples[x + 1] * mGain;
}
return new ComplexBuffer(processed);
}
}

View File

@@ -5,27 +5,34 @@ import io.github.dsheirer.sample.complex.Complex;
public class ComplexGain implements Listener<Complex>
{
private float mGain;
private Listener<Complex> mListener;
private float mGain;
private Listener<Complex> mListener;
public ComplexGain( float gain )
{
mGain = gain;
}
@Override
public void receive( Complex sample )
{
if( mListener != null )
{
sample.multiply( mGain );
mListener.receive( sample );
}
}
public ComplexGain(float gain)
{
mGain = gain;
}
public void setListener( Listener<Complex> listener )
{
mListener = listener;
}
public Complex apply(Complex sample)
{
sample.multiply(mGain);
return sample;
}
@Override
public void receive(Complex sample)
{
if(mListener != null)
{
apply(sample);
mListener.receive(sample);
}
}
public void setListener(Listener<Complex> listener)
{
mListener = listener;
}
}