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,17 +1,17 @@
/*******************************************************************************
* 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/>
******************************************************************************/
@@ -27,407 +27,424 @@ import java.io.Serializable;
*/
public class Complex implements Serializable
{
private final static Logger mLog =
LoggerFactory.getLogger( Complex.class );
private final static Logger mLog = LoggerFactory.getLogger(Complex.class);
private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 1L;
private float mLeft;
private float mRight;
public Complex( float left, float right )
{
mLeft = left;
mRight = right;
}
public Complex()
{
this( 0.0f, 0.0f );
}
public void setInphase( float inphase )
{
mLeft = inphase;
}
public void setQuadrature( float quadrature )
{
mRight = quadrature;
}
public void setValues( float inphase, float quadrature )
{
mLeft = inphase;
mRight = quadrature;
}
private float mRight;
public Complex copy()
{
return new Complex( mLeft, mRight );
}
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append( "I:" );
sb.append( mLeft );
sb.append( " Q:" );
sb.append( mRight );
return sb.toString();
}
/**
* Returns a new sample representing the conjugate of this one
*/
public Complex conjugate()
{
return new Complex( mLeft, -mRight );
}
public Complex(float left, float right)
{
mLeft = left;
mRight = right;
}
/**
* Multiplies this sample by the scalor value
*/
public void multiply( float scalor )
{
mLeft *= scalor;
mRight *= scalor;
}
public static Complex multiply( Complex sample, float scalor )
{
return new Complex( sample.left() * scalor,
sample.right() * scalor );
}
/**
* Calculates the inphase component of multiplying two complex numbers, A and B.
*/
public static float multiplyInphase( float inphaseA, float quadratureA, float inphaseB, float quadratureB )
{
return ( inphaseA * inphaseB ) - ( quadratureA * quadratureB );
}
/**
* Calculates the quadrature component of multiplying two complex numbers, A and B.
*/
public static float multiplyQuadrature( float inphaseA, float quadratureA, float inphaseB, float quadratureB )
{
return ( quadratureA * inphaseB ) + ( inphaseA * quadratureB );
}
/**
* Multiplies this sample by the multiplier sample
*/
public void multiply( Complex multiplier )
{
float inphase = multiplyInphase( inphase(), quadrature(),
multiplier.inphase(), multiplier.quadrature() );
float quadrature = multiplyQuadrature( inphase(), quadrature(),
multiplier.inphase(), multiplier.quadrature() );
mLeft = inphase;
mRight = quadrature;
}
/**
* Multiplies both samples returning a new sample with the results
*/
public static Complex multiply( Complex sample1, Complex sample2 )
{
float inphase = multiplyInphase( sample1.inphase(), sample1.quadrature(),
sample2.inphase(), sample2.quadrature() );
float quadrature = multiplyQuadrature( sample1.inphase(), sample1.quadrature(),
sample2.inphase(), sample2.quadrature() );
public Complex()
{
this(0.0f, 0.0f);
}
return new Complex( inphase, quadrature );
}
public void setInphase(float inphase)
{
mLeft = inphase;
}
public static Complex multiply( Complex sample,
Float inphase, Float quadrature )
{
float i = multiplyInphase( sample.inphase(), sample.quadrature(),
inphase, quadrature );
float q = multiplyQuadrature( sample.inphase(), sample.quadrature(),
inphase, quadrature );
return new Complex( i, q );
}
public static Complex multiply( Float inphase, Float quadrature, Complex sample )
{
float i = multiplyInphase( inphase, quadrature, sample.inphase(), sample.quadrature() );
float q = multiplyQuadrature( inphase, quadrature, sample.inphase(), sample.quadrature() );
return new Complex( i, q );
}
public void setQuadrature(float quadrature)
{
mRight = quadrature;
}
public static Complex multiply( float inphaseA, float quadratureA, float inphaseB, float quadratureB )
{
float i = multiplyInphase( inphaseA, quadratureA, inphaseB, quadratureB );
float q = multiplyQuadrature( inphaseA, quadratureA, inphaseB, quadratureB );
return new Complex( i, q );
}
/**
* Adds the adder sample value to this sample
*/
public void add( Complex adder )
{
mLeft += adder.left();
mRight += adder.right();
}
public void setValues(float inphase, float quadrature)
{
mLeft = inphase;
mRight = quadrature;
}
/**
* Adds the two complex samples returning a new complex sample with the result
*/
public static Complex add( Complex first, Complex second )
{
return new Complex( first.left() + second.left(),
first.right() + second.right() );
}
public void setValues(Complex sampleToCopy)
{
mLeft = sampleToCopy.left();
mRight = sampleToCopy.right();
}
/**
* Adds the two complex samples returning a new complex sample with the result
*/
public static Complex subtract( Complex first, Complex second )
{
return new Complex( first.left() - second.left(),
first.right() - second.right() );
}
public Complex copy()
{
return new Complex(mLeft, mRight);
}
/**
* Magnitude of this sample
*/
public float magnitude()
{
return (float)Math.sqrt( magnitudeSquared() );
}
public static float magnitude( float inphase, float quadrature )
{
return (float)Math.sqrt( ( inphase * inphase ) + ( quadrature * quadrature ) );
}
public String toString()
{
StringBuilder sb = new StringBuilder();
/**
* Magnitude squared of this sample
*/
public float magnitudeSquared()
{
return norm();
}
sb.append("I:");
sb.append(mLeft);
sb.append(" Q:");
sb.append(mRight);
/**
* Norm of this sample = ( i * i ) + ( q * q )
*/
public float norm()
{
return (float)( ( inphase() * inphase() ) +
( quadrature() * quadrature() ) );
}
/**
* Returns the vector length to 1 (unit circle)
*/
public void normalize()
{
float magnitude = magnitude();
if( magnitude != 0 )
{
multiply( (float)( 1.0f / magnitude() ) );
}
}
return sb.toString();
}
/**
* Returns the vector length to 1 (unit circle),
* avoiding square root multiplication
*/
public void fastNormalize()
{
multiply( (float)( 1.95f - magnitudeSquared() ) );
}
public float left()
{
return mLeft;
}
public float right()
{
return mRight;
}
/**
* Returns a new sample representing the conjugate of this one
*/
public Complex conjugate()
{
return new Complex(mLeft, -mRight);
}
public float inphase()
{
return mLeft;
}
/**
* Absolute value of in-phase component
*/
public float inPhaseAbsolute()
{
return Math.abs( mLeft );
}
/**
* Multiplies this sample by the scalor value
*/
public void multiply(float scalor)
{
mLeft *= scalor;
mRight *= scalor;
}
public float quadrature()
{
return mRight;
}
/**
* Absolute value of quadrature component
*/
public float quadratureAbsolute()
{
return Math.abs( mRight );
}
public static Complex multiply(Complex sample, float scalor)
{
return new Complex(sample.left() * scalor,
sample.right() * scalor);
}
public float x()
{
return mLeft;
}
public float y()
{
return mRight;
}
public float real()
{
return mLeft;
}
/**
* Calculates the inphase component of multiplying two complex numbers, A and B.
*/
public static float multiplyInphase(float inphaseA, float quadratureA, float inphaseB, float quadratureB)
{
return (inphaseA * inphaseB) - (quadratureA * quadratureB);
}
/**
* Absolute value of real component
*/
public float realAbsolute()
{
return Math.abs( mLeft );
}
/**
* Calculates the quadrature component of multiplying two complex numbers, A and B.
*/
public static float multiplyQuadrature(float inphaseA, float quadratureA, float inphaseB, float quadratureB)
{
return (quadratureA * inphaseB) + (inphaseA * quadratureB);
}
public float imaginary()
{
return mRight;
}
/**
* Multiplies this sample by the multiplier sample
*/
public void multiply(Complex multiplier)
{
float inphase = multiplyInphase(inphase(), quadrature(),
multiplier.inphase(), multiplier.quadrature());
float quadrature = multiplyQuadrature(inphase(), quadrature(),
multiplier.inphase(), multiplier.quadrature());
/**
* Absolute value of imaginary component
*/
public float imaginaryAbsolute()
{
return Math.abs( mRight );
}
mLeft = inphase;
mRight = quadrature;
}
/**
* Returns the greater absolute value between left and right values
*/
public float maximumAbsolute()
{
if( Math.abs( mLeft ) > Math.abs( mRight ) )
{
return Math.abs( mLeft );
}
else
{
return Math.abs( mRight );
}
}
/**
* Multiplies both samples returning a new sample with the results
*/
public static Complex multiply(Complex sample1, Complex sample2)
{
float inphase = multiplyInphase(sample1.inphase(), sample1.quadrature(),
sample2.inphase(), sample2.quadrature());
float quadrature = multiplyQuadrature(sample1.inphase(), sample1.quadrature(),
sample2.inphase(), sample2.quadrature());
/**
* Creates a new complex sample representing the angle with unit circle
* magnitude
* @param angle in radians
* @return
*/
public static Complex fromAngle( float angle )
{
return new Complex( (float)Math.cos( angle ),
(float)Math.sin( angle ) );
}
return new Complex(inphase, quadrature);
}
/**
* Angle of this sample in radians
*/
public float angle()
{
return (float)Math.atan2( y(), x() );
}
public static Complex multiply(Complex sample,
Float inphase, Float quadrature)
{
float i = multiplyInphase(sample.inphase(), sample.quadrature(),
inphase, quadrature);
float q = multiplyQuadrature(sample.inphase(), sample.quadrature(),
inphase, quadrature);
/**
* Constrains the i and q quantities to +/- value.
*
* @param value - maximum absolute value
*/
public void clip( float value )
{
if( mLeft > value )
{
mLeft = value;
}
else if( mLeft < -value )
{
mLeft = -value;
}
if( mRight > value )
{
mRight = value;
}
else if( mRight < -value )
{
mRight = -value;
}
}
return new Complex(i, q);
}
/**
* Angle of this sample in degrees
*/
public float polarAngle()
{
return (float)Math.toDegrees( angle() );
}
public static Complex multiply(Float inphase, Float quadrature, Complex sample)
{
float i = multiplyInphase(inphase, quadrature, sample.inphase(), sample.quadrature());
float q = multiplyQuadrature(inphase, quadrature, sample.inphase(), sample.quadrature());
/**
* Provides an approximate magnitude value for this sample.
*/
public float envelope()
{
return envelope( mLeft, mRight );
}
public static float envelope( float inphase, float quadrature )
{
float inphaseAbsolute = Math.abs( inphase );
float quadratureAbsolute = Math.abs( quadrature );
if( inphaseAbsolute > quadratureAbsolute )
{
return inphaseAbsolute + ( 0.4f * quadratureAbsolute );
}
else
{
return quadratureAbsolute + ( 0.4f * inphaseAbsolute );
}
}
public static void main( String[] args )
{
double angle = Math.PI; //180 degrees
Complex s1 = new Complex( (float)Math.sin( angle ), (float)Math.cos( angle ) );
return new Complex(i, q);
}
Complex tap = new Complex( 1.0f, -0.1f );
public static Complex multiply(float inphaseA, float quadratureA, float inphaseB, float quadratureB)
{
float i = multiplyInphase(inphaseA, quadratureA, inphaseB, quadratureB);
float q = multiplyQuadrature(inphaseA, quadratureA, inphaseB, quadratureB);
Complex convolved = Complex.multiply( s1, tap );
mLog.debug( "s: " + s1.toString() +
" t: " + tap.toString() +
" convolved: " + convolved.toString() );
}
return new Complex(i, q);
}
/**
* Adds the adder sample value to this sample
*/
public void add(Complex adder)
{
mLeft += adder.left();
mRight += adder.right();
}
/**
* Adds the two complex samples returning a new complex sample with the result
*/
public static Complex add(Complex first, Complex second)
{
return new Complex(first.left() + second.left(),
first.right() + second.right());
}
/**
* Adds the two complex samples returning a new complex sample with the result
*/
public static Complex subtract(Complex first, Complex second)
{
return new Complex(first.left() - second.left(),
first.right() - second.right());
}
/**
* Magnitude of this sample
*/
public float magnitude()
{
return (float)Math.sqrt(magnitudeSquared());
}
public static float magnitude(float inphase, float quadrature)
{
return (float)Math.sqrt((inphase * inphase) + (quadrature * quadrature));
}
/**
* Magnitude squared of this sample
*/
public float magnitudeSquared()
{
return norm();
}
/**
* Norm of this sample = ( i * i ) + ( q * q )
*/
public float norm()
{
return (float)((inphase() * inphase()) +
(quadrature() * quadrature()));
}
/**
* Returns the vector length to 1 (unit circle)
*/
public void normalize()
{
float magnitude = magnitude();
if(magnitude != 0)
{
multiply((float)(1.0f / magnitude()));
}
}
/**
* Returns the vector length to 1 (unit circle),
* avoiding square root multiplication
*/
public void fastNormalize()
{
multiply((float)(1.95f - magnitudeSquared()));
}
public float left()
{
return mLeft;
}
public float right()
{
return mRight;
}
public float inphase()
{
return mLeft;
}
/**
* Absolute value of in-phase component
*/
public float inPhaseAbsolute()
{
return Math.abs(mLeft);
}
public float quadrature()
{
return mRight;
}
/**
* Absolute value of quadrature component
*/
public float quadratureAbsolute()
{
return Math.abs(mRight);
}
public float x()
{
return mLeft;
}
public float y()
{
return mRight;
}
public float real()
{
return mLeft;
}
/**
* Absolute value of real component
*/
public float realAbsolute()
{
return Math.abs(mLeft);
}
public float imaginary()
{
return mRight;
}
/**
* Absolute value of imaginary component
*/
public float imaginaryAbsolute()
{
return Math.abs(mRight);
}
/**
* Returns the greater absolute value between left and right values
*/
public float maximumAbsolute()
{
if(Math.abs(mLeft) > Math.abs(mRight))
{
return Math.abs(mLeft);
}
else
{
return Math.abs(mRight);
}
}
/**
* Creates a new complex sample representing the angle with unit circle
* magnitude
*
* @param angle in radians
* @return
*/
public static Complex fromAngle(double angle)
{
return new Complex((float)Math.cos(angle), (float)Math.sin(angle));
}
/**
* Sets this complex instance with the specified angle in radians.
* @param angle in radians
*/
public void setAngle(double angle)
{
setInphase((float)Math.cos(angle));
setQuadrature((float)Math.sin(angle));
}
/**
* Angle of this sample in radians
*/
public float angle()
{
return (float)Math.atan2(y(), x());
}
public float angleDegrees()
{
return (float)Math.toDegrees(angle());
}
/**
* Constrains the i and q quantities to +/- value.
*
* @param value - maximum absolute value
*/
public void clip(float value)
{
if(mLeft > value)
{
mLeft = value;
}
else if(mLeft < -value)
{
mLeft = -value;
}
if(mRight > value)
{
mRight = value;
}
else if(mRight < -value)
{
mRight = -value;
}
}
/**
* Angle of this sample in degrees
*/
public float polarAngle()
{
return (float)Math.toDegrees(angle());
}
/**
* Provides an approximate magnitude value for this sample.
*/
public float envelope()
{
return envelope(mLeft, mRight);
}
public static float envelope(float inphase, float quadrature)
{
float inphaseAbsolute = Math.abs(inphase);
float quadratureAbsolute = Math.abs(quadrature);
if(inphaseAbsolute > quadratureAbsolute)
{
return inphaseAbsolute + (0.4f * quadratureAbsolute);
}
else
{
return quadratureAbsolute + (0.4f * inphaseAbsolute);
}
}
public static void main(String[] args)
{
Complex ROTATE_FROM_MINUS_45 = Complex.fromAngle(1.0 * Math.PI / 4.0);
Complex ROTATE_FROM_PLUS_135 = Complex.fromAngle(-3.0 * Math.PI / 4.0);
mLog.debug("REF: " + ROTATE_FROM_MINUS_45.toString());
Complex symbol = new Complex(0.7665009f, -0.6422432f);
mLog.debug("SYM: " + symbol.toString());
symbol.multiply(ROTATE_FROM_MINUS_45);
mLog.debug("DER: " + symbol.toString());
}
}