-
Notifications
You must be signed in to change notification settings - Fork 7
/
Agc_class.cpp
191 lines (160 loc) · 3.37 KB
/
Agc_class.cpp
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#include "Agc_class.h"
#include "gui_agc.h"
#include <complex.h>
void Agc_class::execute(std::complex<float> in, std::complex<float> &out)
{
// apply gain to input sample
out = in * gain * e0;
// compute output signal energy
float y2 = std::real(out * std::conj(out));
// smooth energy estimate using single-pole low-pass filter
prime = (1.0 - alpha)* prime + alpha*y2*slope;
//printf("in %12.4f y2 = %12.4f gain %12.4f\n", y1, y2, gain * expf(-0.5f * alpha * logf(prime)));
// return if locked
if (is_locked)
return ;
// update gain according to output energy
if (prime > 1e-6)
gain *= expf(-0.5f * alpha * logf(prime));
// clamp to 120 dB gain
if (gain > max_gain)
gain = max_gain;
out *= scale;
}
void Agc_class::set_threshold(int t)
{
e0 = pow(10.0, (float)t / 20);
}
void Agc_class::set_slope(int s)
{
if (s < 0 || s > 20)
s = 0;
slope = pow(10.0, (float)s / 20);
}
void Agc_class::execute_vector(std::vector<std::complex<float>> &vec)
{
std::complex<float> out;
for (auto& col : vec)
{
execute(col, out);
col = out;
}
}
int Agc_class::set_enery_levels(float _e0, float _e1)
{
if (_e0 < 0)
return -1;
if (_e0 > 1.0f)
return -1;
if (_e1 < 0)
return -1;
if (_e1 > 1.0f)
return -1;
e0 = _e0;
e1 = _e1;
return 0;
}
int Agc_class::set_bandwidth(float b)
{
// check to ensure bandwidth is reasonable
if (b < 0)
return -1;
if (b > 1.0f)
return -1;
bandwidth = b;
alpha = b;
return 0;
}
float Agc_class::get_signal_level()
{
return 1.0f / gain;
}
void Agc_class::set_signal_level(float s)
{
if (s < 0.0)
return ;
gain = 1.0f / s;
prime = 1.0f;
}
float Agc_class::get_rssi()
{
return -20*log10(gain);
}
float Agc_class::get_urssi()
{
return -20*log10(gain_unlimted);
}
// set estimated signal level (dB)
void Agc_class::set_rssi(float rssi)
{
// set internal gain appropriately
gain = powf(10.0f, rssi / 20.0f);
// ensure resulting gain is not arbitrarily low
if (gain < min_gain)
gain = min_gain;
// reset internal output signal level
prime = 1.0f;
}
float Agc_class::get_gain()
{
return gain;
}
float Agc_class::get_scale()
{
return scale;
}
int Agc_class::set_scale(float _scale)
{
// check to ensure gain is reasonable
if (scale <= 0)
return -1;
// set internal gain appropriately
scale = _scale;
return 0;
}
// _x : input data vector, [size: _n x 1]
// _n : number of input, output samples
int Agc_class::init(std::vector<std::complex<float>> _x)
{
// ensure number of samples is greater than zero
if (_x.size() == 0)
return -1;
// compute sum squares on input
float x2 = 0;
for (auto col : _x)
x2 += real(col*conj(col));
// compute RMS level and ensure result is positive
x2 = sqrtf(x2 / (float) _x.size()) + 1e-16f;
// set internal gain based on estimated signal level
set_signal_level(x2);
return 0;
}
int Agc_class::set_gain_limits(float max, float min)
{
if (max < 1e-6 || max > 1e6)
return - 1;
if (min < 1e-6 || min > 1e6)
return -1;
max_gain = max;
min_gain = min;
return 0;
}
int Agc_class::reset()
{
// reset gain estimate
gain = 1.0f;
// reset signal level estimate
prime = 1.0f;
return 0;
}
void Agc_class::print()
{
printf("agc [slope %12.4f e0: %12.4f rssi: %12.4f dB, urssi: %12.4f dB , output gain: %.3f dB, bw: %12.4e, locked: %s]:\n",
slope,
e0,
get_rssi(),
get_urssi(),
scale > 0 ? 10.*log10f(scale) : -100.0f,
bandwidth,
is_locked ? "yes" : "no");
}