mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 16:47:31 -05:00
Implements a complex sample delay buffer integrated into the tuner
channel manager so that channel source requests can have a start timestamp specified and the channel can be preloaded with samples from the delay buffer. If no timestamp is specified, current time is assumed. This feature requires corresponding updates to any decoder that wishes to implement the timestamped sample preloading functionality.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
package io.github.dsheirer.dsp.filter.design;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.fir.FIRFilterSpecification;
|
||||
import io.github.dsheirer.dsp.filter.fir.remez.RemezFIRFilterDesigner;
|
||||
import javafx.application.Application;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
@@ -61,14 +61,15 @@ public class FilterViewer extends Application
|
||||
// .passBandRipple(0.01)
|
||||
// .build();
|
||||
|
||||
FIRFilterSpecification specification = FIRFilterSpecification.bandPassBuilder()
|
||||
.sampleRate(8000)
|
||||
.stopFrequency1(1000)
|
||||
.passFrequencyBegin(1100)
|
||||
.passFrequencyEnd(1900)
|
||||
.stopFrequency2(2000)
|
||||
.stopRipple(0.000001)
|
||||
.passRipple(0.00001)
|
||||
FIRFilterSpecification specification = FIRFilterSpecification.lowPassBuilder()
|
||||
.sampleRate(50000.0)
|
||||
.gridDensity(16)
|
||||
.passBandCutoff(6000)
|
||||
.passBandAmplitude(1.0)
|
||||
.passBandRipple(0.01)
|
||||
.stopBandStart(6700)
|
||||
.stopBandAmplitude(0.0)
|
||||
.stopBandRipple(0.01)
|
||||
.build();
|
||||
|
||||
float[] taps = null;
|
||||
@@ -81,37 +82,25 @@ public class FilterViewer extends Application
|
||||
// catch(FilterDesignException fde)
|
||||
// {
|
||||
// mLog.error("Error");
|
||||
// }
|
||||
|
||||
// try
|
||||
// {
|
||||
// RemezFIRFilterDesigner designer = new RemezFIRFilterDesigner(specification);
|
||||
//
|
||||
// if(designer.isValid())
|
||||
// {
|
||||
// taps = designer.getImpulseResponse();
|
||||
// }
|
||||
// }
|
||||
// catch(FilterDesignException fde)
|
||||
// {
|
||||
// mLog.error("Filter design error", fde);
|
||||
// }
|
||||
//
|
||||
// if(taps == null)
|
||||
// {
|
||||
// throw new IllegalStateException("Couldn't design filter");
|
||||
// }
|
||||
|
||||
try
|
||||
{
|
||||
// taps = FilterFactory.getSincM2Synthesizer(0.25, 2, 9);
|
||||
// taps = FilterFactory.getSincM2Channelizer(12500.0, 2, 9, true);
|
||||
taps = FilterFactory.getSincM2Synthesizer( 25000.0, 12500.0, 2, 9);
|
||||
RemezFIRFilterDesigner designer = new RemezFIRFilterDesigner(specification);
|
||||
|
||||
if(designer.isValid())
|
||||
{
|
||||
taps = designer.getImpulseResponse();
|
||||
}
|
||||
}
|
||||
catch(FilterDesignException e)
|
||||
catch(FilterDesignException fde)
|
||||
{
|
||||
e.printStackTrace();
|
||||
mLog.error("Filter design error", fde);
|
||||
}
|
||||
|
||||
if(taps == null)
|
||||
{
|
||||
throw new IllegalStateException("Couldn't design filter");
|
||||
}
|
||||
|
||||
return taps;
|
||||
|
||||
@@ -95,10 +95,45 @@ public class DQPSKDecisionDirectedSymbolEvaluator implements IPSKSymbolEvaluator
|
||||
|
||||
//Since we've rotated the error symbol back to 0 radians, the quadrature value closely approximates the
|
||||
//arctan of the error angle relative to 0 radians and this provides our error value
|
||||
mPhaseError = -mEvaluationSymbol.quadrature();
|
||||
float errorNormalized = normalize(mEvaluationSymbol.quadrature(), 0.3f);
|
||||
|
||||
mPhaseError = -errorNormalized;
|
||||
|
||||
//Timing error is the same as phase error with the sign corrected according to the vector's angular rotation
|
||||
mTimingError = mEvaluationSymbol.quadrature() * mTimingErrorPolarity;
|
||||
mTimingError = errorNormalized * mTimingErrorPolarity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constrains value to the range of ( -maximum <> maximum )
|
||||
*/
|
||||
private static float clip(float value, float maximum)
|
||||
{
|
||||
if(value > maximum)
|
||||
{
|
||||
return maximum;
|
||||
}
|
||||
else if(value < -maximum)
|
||||
{
|
||||
return -maximum;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constrains timing error to +/- the maximum value and corrects any
|
||||
* floating point invalid numbers
|
||||
*/
|
||||
private float normalize(float error, float maximum)
|
||||
{
|
||||
if(Float.isNaN(error))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
return clip(error, maximum);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -100,7 +100,7 @@ public class DQPSKGardnerSymbolEvaluator implements IPSKSymbolEvaluator<Dibit>
|
||||
|
||||
//Since we've rotated the error symbol back to 0 radians, the quadrature value closely approximates the
|
||||
//arctan of the error angle relative to 0 radians and this provides our error value
|
||||
mPhaseError = -mEvaluationSymbol.quadrature();
|
||||
mPhaseError = normalize(-mEvaluationSymbol.quadrature(), 0.3f);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user