-
Notifications
You must be signed in to change notification settings - Fork 7
/
rm_iqcorrection.pas
128 lines (101 loc) · 2.94 KB
/
rm_iqcorrection.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
unit rm_iqcorrection;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, UComplex, Math, RadioModule, RadioSystem;
{
THIS IS EXPERIMENTAL!
correct signal is s_i, s_q, then desorted signal u_i, u_q are:
[ u_i ] [ 1 0 ] [ s_i ]
| | = | | | |
[ u_q ] [ -g sin(phi) g cos(phi) ] [ s_q ]
u_i = s_i
u_q = -g sin(phi) s_i + g cos(phi) s_q
assume phi is small, sin(phi) << 1, g = sqrt((sum u_q ^2) / (sum u_i ^2))
assume g = 1, then u_i * u_q = -sin(phi) s_i^2 + cos(phi) s_i s_q,
if E[s_i s_q] = 0, then sin(phi) can be estimated as:
phi = -arcsin(sum(u_i * u_q)/sum(s_i ^2))
}
type
{ TRadioIQCorrecter }
TRadioIQCorrecter = class(TRadioModule)
private
FAlpha: Double;
FRegulator: TStreamRegulator;
FGain: Double;
FPhi: Double;
procedure ReceiveRegulatedData(const P: PComplex; const Len: Integer);
protected
procedure Describe(Strs: TStrings); override;
public
constructor Create(RunQueue: TRadioRunQueue); override;
destructor Destroy; override;
procedure ReceiveData(const P: PComplex; const Len: Integer); override;
end;
implementation
uses
SignalBasic;
{ TRadioIQCorrecter }
procedure TRadioIQCorrecter.ReceiveRegulatedData(const P: PComplex;
const Len: Integer);
var
CI: Double = 0.0;
CQ: Double = 0.0;
I: Integer;
O: PComplex;
CosPhiRep, TanPhi: Double;
begin
CancelDC(P, Len);
for I := 0 to Len - 1 do
begin
CI := CI + P[I].re * P[I].re;
CQ := CQ + P[I].im * P[I].im;
end;
if CQ > 0 then FGain := FAlpha * (CI / CQ) + (1 - FAlpha) * FGain;
CQ := 0;
for I := 0 to Len - 1 do
begin
P[I].im := FGain * P[I].im;
CQ := CQ + P[I].re * P[I].im;
end;
FPhi := FAlpha * (-arcsin(EnsureRange(CQ / CI, -0.99999, 0.99999))) + (1 - FAlpha) * FPhi;
CosPhiRep := 1 / Cos(FPhi);
TanPhi := Tan(FPhi);
for I := 0 to Len - 1 do
P[I].im := TanPhi * P[I].re + CosPhiRep * P[I].Im;
O := Alloc(DefOutput, I);
if not Assigned(O) then
begin
TRadioLogger.Report(llWarn, 'TRadioIQCorrecter.ReceiveRegulatedData: data lost');
Exit;
end;
Move(P^, O^, Len * SizeOf(P^));
DefOutput.Broadcast(I, FDataListeners);
end;
procedure TRadioIQCorrecter.Describe(Strs: TStrings);
begin
Strs.Add(Format('^bGain: ^n%.3f', [FGain]));
Strs.Add(Format('^bPhi : ^n%.3f', [FPhi]));
end;
constructor TRadioIQCorrecter.Create(RunQueue: TRadioRunQueue);
begin
inherited Create(RunQueue);
FGain := 1.0;
FAlpha := 0.1;
FRegulator := TStreamRegulator.Create;
FRegulator.Size := DefOutput.BufferSize;
FRegulator.OnRegulatedData := @ReceiveRegulatedData;
FHasConfig := False;
end;
destructor TRadioIQCorrecter.Destroy;
begin
FRegulator.Free;
inherited Destroy;
end;
procedure TRadioIQCorrecter.ReceiveData(const P: PComplex; const Len: Integer);
begin
FRegulator.ReceiveData(P, Len);
end;
initialization
RegisterModule(TRadioModuleClass(TRadioIQCorrecter.ClassType));
end.