Skip to content

Commit 47b4edf

Browse files
committed
Revert decision-directed carrier recovery to no longer use phase angle derivative in error calculation
Change carrier phase angle calculation to use complex multiplication and a single atan2, instead of two atan2 calls and a subtraction Fix changing Vco phase offset causing the current phase position to be advanced It appears the carrier recovery improvements observed previously were masking the decimator operating improperly, which has since been fixed
1 parent 93ff076 commit 47b4edf

File tree

2 files changed

+49
-99
lines changed

2 files changed

+49
-99
lines changed

SignalTest/Program.cs

Lines changed: 48 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -950,8 +950,8 @@ static void GenerateQPSK()
950950
// preambleCounter = 1;
951951

952952
bitI = lastBit == symbols[0] ? symbols[symbols.Length-1] : symbols[0];
953-
//bitQ = 1f;
954-
bitQ = bitI;
953+
bitQ = 1f;
954+
//bitQ = bitI;
955955

956956
lastBit = bitI;
957957

@@ -1562,7 +1562,7 @@ static void Const()
15621562
//dc.DrawRectangle(dotBrush, null, new System.Windows.Rect(x, y, 5, 5));
15631563
if (i < 500 * channels)
15641564
dc.DrawEllipse(dotBrushSync, null, new System.Windows.Point(x, y), 2, 2);
1565-
else if (i > samples.Length / 2)
1565+
else if (i > (samples.Length - (500 * channels)) / 2)
15661566
dc.DrawEllipse(dotBrush2, null, new System.Windows.Point(x, y), 2, 2);
15671567
else
15681568
dc.DrawEllipse(dotBrush, null, new System.Windows.Point(x, y), 2, 2);
@@ -1611,7 +1611,7 @@ static void AWGN()
16111611
// 18.0 dB @ 16000Hz
16121612
// 21.0 dB @ 8000Hz
16131613
int sampleRate = 8000;
1614-
double snrDbBase = 38.0f;
1614+
double snrDbBase = 24.0f;
16151615
double snrDb = 10.0 * Math.Log10((1.0 / sampleRate) * (Math.Pow(10, snrDbBase / 10.0)) / (1.0 / 8000));
16161616
double snrLin = (float)Math.Pow(10, (snrDb / 10.0));
16171617

@@ -1807,6 +1807,7 @@ static void DecisionDirected()
18071807
Integrator intAngle = new Integrator(0.2f, (1f / baud) * 5f);
18081808
Integrator intMagnitude = new Integrator(0.1f, (1f / baud) * 20f);
18091809
intMagnitude.SetValue(1f);
1810+
18101811
//BiQuadraticFilter bandpass = new BiQuadraticFilter(BiQuadraticFilter.Type.LOWPASS, 5000, sampleRate, 0.707);
18111812
AGC agc = new AGC(0.707f, 15f);
18121813

@@ -1835,11 +1836,10 @@ static void DecisionDirected()
18351836
bool isSyncMode = true;
18361837

18371838
double avgErr = 0f;
1839+
double lastAvgErr = 0f;
1840+
double errDeriv = 0f;
18381841
long symbolCount = 0;
1839-
float angleDiv = 1f;
18401842
float phaseAngleDiff = 0f;
1841-
float lastAngleDiff = 0f;
1842-
float lastLastAngleDiff = 0f;
18431843

18441844
using (Stream fs = File.Create(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "SignalTest", "SignalTest_1.pcm32f")))
18451845
{
@@ -1938,7 +1938,7 @@ static void DecisionDirected()
19381938

19391939
if (flipFlop ^= true)
19401940
{
1941-
1941+
19421942

19431943
//bitOutI = Math.Max(Math.Min(bitOutI, 1.2f), -1.2f);
19441944
//bitOutQ = Math.Max(Math.Min(bitOutQ, 1.2f), -1.2f);
@@ -1951,7 +1951,7 @@ static void DecisionDirected()
19511951
fs.Write(BitConverter.GetBytes((float)avgErr), 0, 4);
19521952
//fs.Write(BitConverter.GetBytes(agc.AverageAmplitude), 0, 4);
19531953
//fs.Write(BitConverter.GetBytes(isSyncMode ? 0f : 0.707f), 0, 4);
1954-
fs.Write(BitConverter.GetBytes(phaseAngleDiff), 0, 4);
1954+
fs.Write(BitConverter.GetBytes((float)errDeriv), 0, 4);
19551955

19561956

19571957
// Find the closest constellation point
@@ -1975,14 +1975,20 @@ static void DecisionDirected()
19751975
double magDiff = (constMag - curMag) * 1f;
19761976
//magDiff -= (magDiff < 0 ? -1f : 1f) * ((magDiff * magDiff) / 1f);
19771977

1978+
// Calculate phase angle difference
1979+
double tempX, tempY;
1980+
ComplexMultiply(bitOutI, bitOutQ, constPt.I, -constPt.Q, out tempX, out tempY);
1981+
1982+
double phaseAngle = Math.Atan2(tempY, tempX);
1983+
19781984

19791985
constGain = intMagnitude.Process((float)(magDiff));
19801986
//constGain = 1.29f;
19811987
if (constGain < 0.01f)
19821988
constGain = 0.01f;
19831989
if (constGain > 2.0f)
19841990
constGain = 2.0f;
1985-
1991+
19861992

19871993
curMag = Math.Sqrt((bitOutI * bitOutI) + (bitOutQ * bitOutQ));
19881994
Console.WriteLine("M {0,5:F2} {1,5:F2} {2,5:F2}", curMag, constMag, constGain);
@@ -1994,100 +2000,35 @@ static void DecisionDirected()
19942000
//distance /= 0.09123958466923193863236701446514;
19952001

19962002
avgErr = (avgErr * 0.95) + (distance * 0.05);
1997-
Console.WriteLine("E {0,7:F4} {1,7:F4}", distance, avgErr);
1998-
1999-
if (Math.Sign(curAngle) == Math.Sign(constAngle))// && (!isSyncMode || (bitOutI > 0.5f || bitOutQ > 0.5f)))
2000-
{
2001-
double angleDiff = (curAngle - constAngle) * 1f;// / 3.1419526535897932384;
2002-
2003-
double angleDiffDiff = angleDiff - lastAngleDiff;
2004-
//double lastAngleDiffDiff = lastAngleDiff - lastLastAngleDiff;
2005-
2006-
//if (angleDiffDiff > 1.2f)
2007-
// angleDiffDiff -= 1.57079632f;
2008-
//if (angleDiffDiff < 1.3f)
2009-
// angleDiffDiff += 1.57079632f;
2010-
2011-
//angleDiffDiff = Math.Min(Math.Max(angleDiffDiff, -1.2), 1.2);
2012-
2013-
double diffRatio = Math.Abs(angleDiffDiff) / Math.Abs(lastLastAngleDiff);
2014-
2015-
// Correct for phase angle polarity swaps
2016-
if (Math.Abs(angleDiffDiff) > 0.6f && Math.Sign(angleDiffDiff) != Math.Sign(lastLastAngleDiff))
2017-
angleDiffDiff += 1.57079632f * Math.Sign(lastAngleDiff);
2018-
2019-
2020-
2021-
//if ((angleDiffDiff - lastAngleDiffDiff) > 1.3f)
2022-
// angleDiffDiff -= 1.57079632f;
2023-
2024-
//phaseAngleDiff = (float)angleDiff / 3.1415926535897932384f;
2025-
2026-
//if (Math.Abs(angleDiffDiff) > 0.6)
2027-
{
2028-
angleDiffDiff -= Math.Sign(angleDiffDiff) * ((angleDiffDiff * angleDiffDiff) * 0.5f);
2029-
2030-
}
2031-
phaseAngleDiff = (float)angleDiffDiff;
2003+
errDeriv = (errDeriv * 0.90) + ((avgErr - lastAvgErr) * 0.10);
2004+
lastAvgErr = avgErr;
2005+
Console.WriteLine("E {0,7:F4} {1,7:F4} {2,7:F4}", distance, avgErr, errDeriv);
20322006

2007+
phaseAngleDiff = (float)phaseAngle;
20332008

2034-
//angleDiffDiff *= 1.5f;
2035-
//angleDiffDiffCounter += (float)angleDiffDiff;
2036-
//diffCount++;
2037-
lastLastAngleDiff = (float)angleDiffDiff;
2038-
lastAngleDiff = (float)angleDiff;
2039-
//angleDiff -= (angleDiff < 0 ? -1f : 1f) * ((angleDiff * angleDiff) / 3f);
2040-
//angleDiff = Math.Min(Math.Max(angleDiff, -0.25f), 0.25f);
2041-
//if (i >= 2000)
2042-
// angleDiff /= 2;
2043-
2044-
// TODO: Add actual sync/preamble detector
2045-
if (isSyncMode && symbolCount >= 400)
2046-
//if (isSyncMode && symbolCount > 10 && avgErr < 0.2f)
2047-
//if (isSyncMode && i >= 30000)
2048-
{
2049-
isSyncMode = false;
2050-
agc.AdaptGain = false;
2051-
2052-
// Once we have a good estimate of carrier offset, only allow small tweaks
2053-
intAngle.IntegratorGain = (1f / baud) * 0.5f;
2054-
intAngle.ProportionalGain = 0.1f;
2055-
//intRatio.IntegratorGain *= 0.5f;
2056-
//intRatio.ProportionalGain *= 0.5f;
2057-
//ratioScale *= 0.5f;
2058-
}
2059-
//if (sampleCount >= 500)
2060-
// angleDiff /= 2f;
2061-
2062-
//phaseAngleDiff = (float)angleDiff / 3.1415926535897932384f;
2063-
//phaseAngleDiff = (float)angleDiffDiff;
2064-
2065-
//angleDiff -= Math.Sign(angleDiff) * ((angleDiff * angleDiff) * 0.7f);
2066-
2067-
// NOTE: It appears the divisor on angleDiff should be higher for lower baud rates?
2068-
// Actually, it seems to not have a linear relation to baud rate
2069-
float phaseError = (float)angleDiffDiff + (float)angleDiff * 1.0f;
2070-
//phaseError -= Math.Sign(phaseError) * ((phaseError * phaseError) * 0.7f);
2071-
2072-
float angleFilter = intAngle.Process((float)phaseError);
2073-
2074-
//angleFilter += (float)(rTest.NextDouble() * 2 - 1) * 5f;
2075-
2076-
Console.WriteLine("A {0,5:F2} {1,5:F2} {2,9:F6}", angleDiff, angleFilter, angleDiffDiff);
2077-
Console.WriteLine("S {0,5} {1,9:N0}", isSyncMode, symbolCount);
2009+
// TODO: Add actual sync/preamble detector
2010+
if (isSyncMode && symbolCount >= 400)
2011+
//if (isSyncMode && symbolCount > 10 && avgErr < 0.2f)
2012+
//if (isSyncMode && i >= 30000)
2013+
{
2014+
isSyncMode = false;
2015+
agc.AdaptGain = false;
2016+
2017+
// Once we have a good estimate of carrier offset, only allow small tweaks
2018+
//intAngle.IntegratorGain = (1f / baud) * 0.5f;
2019+
intAngle.IntegratorGain *= 0.5f;
2020+
//intAngle.ProportionalGain = 0.1f;
2021+
//intRatio.IntegratorGain *= 0.5f;
2022+
//intRatio.ProportionalGain *= 0.5f;
2023+
//ratioScale *= 0.5f;
2024+
}
20782025

2079-
carrier.Tune(angleFilter);
2080-
//carrier.SetCenterFrequency(angleFilter);
2026+
float angleFilter = intAngle.Process((float)phaseAngle);
20812027

2082-
//if (i % 10 == 0)
2083-
//{
2084-
// //Console.WriteLine(carrier.GetFrequency(0));
2085-
//}
2086-
}
2087-
else
2088-
{
2028+
Console.WriteLine("A {0,5:F2} {1,5:F2}", phaseAngle, angleFilter);
2029+
Console.WriteLine("S {0,5} {1,9:N0}", isSyncMode, symbolCount);
20892030

2090-
}
2031+
carrier.Tune(angleFilter);
20912032
symbolCount++;
20922033
}
20932034
}
@@ -2201,6 +2142,14 @@ static double Sinc(double x, double scale)
22012142
return Math.Sin(phi * x) / (phi * x);
22022143
}
22032144

2145+
static void ComplexMultiply(double aR, double aI, double bR, double bI, out double resultR, out double resultI)
2146+
{
2147+
//resultR = (aR * bR) - (aI * bI);
2148+
//resultI = (aR + aI) * (bR + bI) - (aR * bR) - (aI * bI);
2149+
resultR = (aR * bR) - (aI * bI);
2150+
resultI = (aR * bI) + (aI * bR);
2151+
}
2152+
22042153

22052154
static double[] _rrcImpulse;
22062155
static void GenerateImpulseRRC(double sampleRate, double symbolLengthSec, int symbolSpan, double rolloff)

SignalTest/Vco.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ public void SetPhaseOffset(int phaseIndex, double offsetRadians)
161161
if (phaseIndex >= _states.Length || phaseIndex < 0)
162162
throw new IndexOutOfRangeException("The specified phase index is out of range");
163163

164+
_states[phaseIndex].Phase -= _states[phaseIndex].PhaseOffset;
164165
_states[phaseIndex].PhaseOffset = offsetRadians;
165166
_states[phaseIndex].Phase += offsetRadians;
166167
}

0 commit comments

Comments
 (0)