SDRSharper/SDRSharper.Radio/SDRSharp.Radio/RdsDecoder.cs
SDRSharpR c07e6e6034 SDRSharper (SDRSharp Remake) Full Source (VS2017)
SDRSharper (SDRSharp Remake) Full Source (VS2017)
2018-03-26 14:02:05 -07:00

184 lines
4.9 KiB
C#

using System;
namespace SDRSharp.Radio
{
public class RdsDecoder
{
private const int PllDefaultFrequency = 57000;
private const int PllRange = 12;
private const int PllBandwith = 1;
private const float PllZeta = 0.707f;
private const float PllLockTime = 0.5f;
private const float PllLockThreshold = 3.2f;
private const float RdsBitRate = 1187.5f;
private readonly IQFirFilter _baseBandFilter = new IQFirFilter(null, false, 1);
private readonly FirFilter _matchedFilter = new FirFilter();
private readonly RdsDetectorBank _bitDecoder = new RdsDetectorBank();
private unsafe readonly Pll* _pll;
private readonly UnsafeBuffer _pllBuffer;
private unsafe readonly Oscillator* _osc;
private readonly UnsafeBuffer _oscBuffer;
private unsafe readonly IirFilter* _syncFilter;
private readonly UnsafeBuffer _syncFilterBuffer;
private UnsafeBuffer _rawBuffer;
private unsafe Complex* _rawPtr;
private UnsafeBuffer _magBuffer;
private unsafe float* _magPtr;
private UnsafeBuffer _dataBuffer;
private unsafe float* _dataPtr;
private IQDecimator _decimator;
private double _sampleRate;
private double _demodulationSampleRate;
private int _decimationFactor;
private float _lastSync;
private float _lastData;
private float _lastSyncSlope;
private bool _lastBit;
public double SampleRate
{
get
{
return this._sampleRate;
}
set
{
if (value != this._sampleRate)
{
this._sampleRate = value;
this.Configure();
}
}
}
public string RadioText => this._bitDecoder.RadioText;
public string ProgramService => this._bitDecoder.ProgramService;
public ushort PICode => this._bitDecoder.PICode;
public unsafe RdsDecoder()
{
this._pllBuffer = UnsafeBuffer.Create(sizeof(Pll));
this._pll = (Pll*)(void*)this._pllBuffer;
this._oscBuffer = UnsafeBuffer.Create(sizeof(Oscillator));
this._osc = (Oscillator*)(void*)this._oscBuffer;
this._syncFilterBuffer = UnsafeBuffer.Create(sizeof(IirFilter));
this._syncFilter = (IirFilter*)(void*)this._syncFilterBuffer;
}
private unsafe void Configure()
{
this._osc->SampleRate = this._sampleRate;
this._osc->Frequency = 57000.0;
int i;
for (i = 0; this._sampleRate >= 20000.0 * Math.Pow(2.0, (double)i); i++)
{
}
this._decimator = new IQDecimator(i, this._sampleRate, true, false);
this._decimationFactor = (int)Math.Pow(2.0, (double)i);
this._demodulationSampleRate = this._sampleRate / (double)this._decimationFactor;
float[] coefficients = FilterBuilder.MakeLowPassKernel(this._demodulationSampleRate, 200, 2500.0, WindowType.BlackmanHarris4);
this._baseBandFilter.SetCoefficients(coefficients);
this._pll->SampleRate = (float)this._demodulationSampleRate;
this._pll->DefaultFrequency = 0f;
this._pll->Range = 12f;
this._pll->Bandwidth = 1f;
this._pll->Zeta = 0.707f;
this._pll->LockTime = 0.5f;
this._pll->LockThreshold = 3.2f;
int length = (int)(this._demodulationSampleRate / 1187.5) | 1;
coefficients = FilterBuilder.MakeSin(this._demodulationSampleRate, 1187.5, length);
this._matchedFilter.SetCoefficients(coefficients);
this._syncFilter->Init(IirFilterType.BandPass, 1187.5, this._demodulationSampleRate, 500);
}
public unsafe void Reset()
{
this._bitDecoder.Reset();
this._syncFilter->Reset();
}
public unsafe void Process(float* baseBand, int length)
{
if (this._rawBuffer == null || this._rawBuffer.Length != length)
{
this._rawBuffer = UnsafeBuffer.Create(length, sizeof(Complex));
this._rawPtr = (Complex*)(void*)this._rawBuffer;
}
if (this._magBuffer == null || this._magBuffer.Length != length)
{
this._magBuffer = UnsafeBuffer.Create(length, 4);
this._magPtr = (float*)(void*)this._magBuffer;
}
if (this._dataBuffer == null || this._dataBuffer.Length != length)
{
this._dataBuffer = UnsafeBuffer.Create(length, 4);
this._dataPtr = (float*)(void*)this._dataBuffer;
}
for (int i = 0; i < length; i++)
{
this._osc->Tick();
Complex.Mul(ref this._rawPtr[i], this._osc->Out, baseBand[i]);
}
this._decimator.Process(this._rawPtr, length);
length /= this._decimationFactor;
this._baseBandFilter.Process(this._rawPtr, length);
for (int j = 0; j < length; j++)
{
this._dataPtr[j] = this._pll->Process(this._rawPtr[j]).Imag;
}
this._matchedFilter.Process(this._dataPtr, length);
for (int k = 0; k < length; k++)
{
this._magPtr[k] = Math.Abs(this._dataPtr[k]);
}
this._syncFilter->Process(this._magPtr, length);
for (int l = 0; l < length; l++)
{
float lastData = this._dataPtr[l];
float num = this._magPtr[l];
float num2 = num - this._lastSync;
this._lastSync = num;
if (num2 < 0f && this._lastSyncSlope * num2 < 0f)
{
bool flag = this._lastData > 0f;
this._bitDecoder.Process(flag ^ this._lastBit);
this._lastBit = flag;
}
this._lastData = lastData;
this._lastSyncSlope = num2;
}
}
}
}