P25 LSM decoder work in progress. Adds a CQPSK decoder based on Max's (KA1RBI) scope.py and gardner loop.

The CQPSK decoder is starting to take shape, but needs more tweaking and testing.  It's not keeping a good lock on strong P25 signals.  I have to add some more features to the intrumentation package to allow me to visualize the internals of the CQPSK decoder so that I can get a better sense of what needs fine tuning.

The CQPSK decoder may work for anyone that wants to sync the repo and run the build script.
This commit is contained in:
dennis.sheirer
2015-02-10 00:42:08 +00:00
parent 9310fb0daf
commit a65e821e85
43 changed files with 1996 additions and 413 deletions

View File

@@ -19,13 +19,19 @@ package sample.complex;
import java.io.Serializable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* ComplexSample for handling left/right channel audio, or inphase/quadrature
* samples, etc.
*/
public class ComplexSample implements Serializable
{
private static final long serialVersionUID = 1L;
private final static Logger mLog =
LoggerFactory.getLogger( ComplexSample.class );
private static final long serialVersionUID = 1L;
private float mLeft;
private float mRight;
@@ -35,6 +41,11 @@ public class ComplexSample implements Serializable
mLeft = left;
mRight = right;
}
public ComplexSample()
{
this( 0.0f, 0.0f );
}
public ComplexSample copy()
{
@@ -43,7 +54,14 @@ public class ComplexSample implements Serializable
public String toString()
{
return "I:" + mLeft + " Q:" + mRight;
StringBuilder sb = new StringBuilder();
sb.append( "I:" );
sb.append( mLeft );
sb.append( " Q:" );
sb.append( mRight );
return sb.toString();
}
/**
@@ -78,6 +96,9 @@ public class ComplexSample implements Serializable
mRight = quadrature;
}
/**
* Multiplies both samples returning a new sample with the results
*/
public static ComplexSample multiply( ComplexSample sample1,
ComplexSample sample2 )
{
@@ -91,16 +112,16 @@ public class ComplexSample implements Serializable
}
public static ComplexSample multiply( ComplexSample sample,
Float left, Float right )
Float inphase, Float quadrature )
{
float l = ( sample.left() * left ) - ( sample.right() * right );
float r = ( sample.right() * left ) + ( sample.left() * right );
float i = ( sample.inphase() * inphase ) - ( sample.quadrature() * quadrature );
float q = ( sample.quadrature() * inphase ) + ( sample.inphase() * quadrature );
return new ComplexSample( l, r );
return new ComplexSample( i, q );
}
/**
* Adds the adder sample values to this sample
* Adds the adder sample value to this sample
*/
public void add( ComplexSample adder )
{
@@ -108,6 +129,24 @@ public class ComplexSample implements Serializable
mRight += adder.right();
}
/**
* Adds the two complex samples returning a new complex sample with the result
*/
public static ComplexSample add( ComplexSample first, ComplexSample second )
{
return new ComplexSample( first.left() + second.left(),
first.right() + second.right() );
}
/**
* Adds the two complex samples returning a new complex sample with the result
*/
public static ComplexSample subtract( ComplexSample first, ComplexSample second )
{
return new ComplexSample( first.left() - second.left(),
first.right() - second.right() );
}
/**
* Magnitude of this sample
*/
@@ -130,7 +169,12 @@ public class ComplexSample implements Serializable
*/
public void normalize()
{
multiply( (float)( 1.0f / magnitude() ) );
float magnitude = magnitude();
if( magnitude != 0 )
{
multiply( (float)( 1.0f / magnitude() ) );
}
}
/**
@@ -176,12 +220,28 @@ public class ComplexSample implements Serializable
{
return mLeft;
}
public float imaginery()
/**
* 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
*/
@@ -208,4 +268,18 @@ public class ComplexSample implements Serializable
return new ComplexSample( (float)Math.cos( angle ),
(float)Math.sin( angle ) );
}
public float angle()
{
return (float)Math.atan2( y(), x() );
}
public static void main( String[] args )
{
ComplexSample sample1 = new ComplexSample( .45f, .45f );
ComplexSample sample2 = new ComplexSample( .25f, .25f );
ComplexSample sample1_2 = ComplexSample.subtract( sample1, sample2 );
mLog.debug( sample1_2.toString() );
}
}