-
Notifications
You must be signed in to change notification settings - Fork 11
/
agc.cpp
137 lines (114 loc) · 4.19 KB
/
agc.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
// soft AGC and S meter display by Loftur E. Jónasson TF3LJ/VE2LJX 6/14
//
#include <Metro.h>
#include <Audio.h>
#include <Adafruit_GFX.h> // LCD Core graphics library
//#include <Adafruit_QDTech.h> // 1.8" TFT Module using Samsung S6D02A1 chip
#include <Adafruit_ST7735.h> // Hardware-specific library
//extern Adafruit_QDTech tft;
extern Adafruit_ST7735 tft;
extern AudioMixer4 Audioselector_I; // Summer (add inputs)
extern AudioMixer4 Audioselector_Q; // Summer (add inputs)
extern AudioAnalyzePeak AGCpeak; // Measure Audio Peak for AGC use
extern AudioAnalyzePeak Smeter; // Measure Audio Peak for S meter
Metro l_ms = Metro(1); // Set up a 1ms Metro
Metro lcd_upd2=Metro(500); // Set up a Metro for S-meter display
float sample[10]; // A ringbuffer of samples (has to be larger than AGCattack)
float AGCgain=1; // Initial AGC gain. 1 = unity gain, 32768.0 max, 0.00004 min
#define AGCMAX 2
float AGCnomVal = 0.5; // Nominal Output (32768 max)
const int32_t AGCattack = 2; // AGC Hang time (milliseconds) before reducing gain
const int32_t AGChang = 30; // AGC Hang time before increasing gain
const double AGCslope = 1.05; // Relative gain change
//
// Automatic Gain Control function
//
void agc(void)
{
static uint8_t i;
static uint16_t hangtimer;
uint8_t j,k;
float s_sample; // Raw signal strength (max per 1ms)
float samp; // AGC feedback loop sample strength (max per 1ms)
float temp; // yeah, just a temp value
float uv, dbuv, s, v, dbm;// microvolts, db-microvolts, s-units, volts, dbm, sold = old S-meter value, deltas = abs difference between sold and s
char string[80]; // print format stuff
if (l_ms.check() == 1)
{
// R this code is probably broken with the new audio library
// Collect S-meter data
if (Smeter.available()) s_sample = Smeter.read(); // Highest sample within 1 millisecond
// AGC: Collect current 1ms peak at output and feed to a ringbuffer
sample[i++] = samp = AGCpeak.read();
if (i >= AGCattack) i=0;
// Check if we need to reduce gain
for(j=0,k=0;j<AGCattack;j++)
{
if (sample[j] > AGCnomVal) k++;
}
// We need to reduce gain
if ((k == AGCattack) || ((k>0) && (hangtimer>=AGChang))) // Activate AGCattack
{
// find largest value
temp = 0;
for(j=0;j<AGCattack;j++)
{
if (sample[j]> temp) temp = sample[j];
}
// Instant reduction to appropriate value
AGCgain = AGCgain * AGCnomVal/temp;
// Reset hang timer
hangtimer = 0;
}
// Increment hangtimer while level is lower than nominal
else if(samp < AGCnomVal) hangtimer++;
if (hangtimer >= AGChang) // We need to ramp up the gain
{
Audioselector_I.gain(0, AGCgain * AGCslope);
Audioselector_Q.gain(0, AGCgain * AGCslope);
}
if (AGCgain > AGCMAX) AGCgain=AGCMAX; // limit the gain
Audioselector_I.gain(0,AGCgain); // Adjust AGC gain
Audioselector_Q.gain(0,AGCgain); // Adjust AGC gain
//
// Print stuff to LCD
//
if (lcd_upd2.check() == 1)
{
// Calculate S units. 50uV = S9
uv = s_sample*1000; // microvolts, roughly calibrated
v = s_sample / 1000;
dbm = 10 * log10 (v*v*20);
if (v==0) {dbm=-143;};
dbuv = 20.0*log10(uv);
s = 1.0 + (14.0 + dbuv)/6.0;
if (s <0.0) s=0.0;
if (s>9.0)
{
dbuv = dbuv - 34.0;
s = 9.0;
}
else dbuv = 0;
// Print S units
tft.fillRect(0, 105, 70, 7,ST7735_BLACK);
tft.setCursor(0, 105);
if (dbuv == 0) sprintf(string,"S:%1.0f",s);
else {
sprintf(string,"S:9+%02.0f dB",dbuv);
}
tft.print(string);
tft.fillRect(100,105, 50, 7,ST7735_BLACK);
tft.setCursor(100,105);
sprintf(string,"%04.0f dBm",dbm);
tft.print(string);
if(0) // Debug stuff
{
// Print AGC loop parameters
tft.fillRect(0, 105, 159, 7,ST7735_BLACK);
tft.setCursor(0, 105);
sprintf(string,"pk:%f g:%f",Smeter.read(), AGCgain);
tft.print(string);
}
}
}
}