]> git.rkrishnan.org Git - dttsp.git/blob - jDttSP/digitalagc.c
c9fc7e50d6ddec02ceeda7629939fd2ece06dc4c
[dttsp.git] / jDttSP / digitalagc.c
1 /* digitalagc.c
2
3 This file is part of a program that implements a Software-Defined Radio.
4
5 Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
6
7 We appreciate the contributions to this subroutine by Gerald Youngblood,
8 AC5OG and Phil Harman, VK6APH.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23
24 The authors can be reached by email at
25
26 ab2kt@arrl.net
27 or
28 rwmcgwier@comcast.net
29
30 or by paper mail at
31
32 The DTTS Microwave Society
33 6 Kathleen Place
34 Bridgewater, NJ 08807
35 */
36
37 #include <common.h>
38
39 void
40 DigitalAgc(DIGITALAGC a, int tick) {
41
42   if (a->mode == agcOFF) {
43     int i;
44     for (i = 0; i < CXBsize(a->buff); i++)
45       CXBdata(a->buff, i) = Cscl(CXBdata(a->buff, i), a->gain.fix);
46
47   } else {
48     int i, k, hang;
49     REAL peak = 0.0;
50
51     hang = tick < a->over ? a->rcov : a->hang;
52     k = a->indx;
53
54     for (i = 0; i < CXBsize(a->buff); i++)
55       peak = max(peak, Cmag(CXBdata(a->buff, i)));
56
57     if (peak != 0) {
58       a->hist[a->indx] = a->gain.lim / peak;
59       for (i = 1, a->gain.now = a->hist[0]; i < hang; i++)
60         a->gain.now = min(a->hist[i], a->gain.now);
61     }
62     a->gain.raw = a->gain.now;
63     a->gain.now = min(a->gain.now, a->gain.top);
64
65     for (i = 0, k = (a->sndx + a->ramp) % a->mask;
66          i < CXBsize(a->buff);
67          i++, k = (k + 1) % a->mask)
68       a->circ[k] = CXBdata(a->buff, i);
69
70     if (a->gain.now != a->gain.old) {
71       REAL step = (a->gain.now - a->gain.old) / a->ramp;
72       for (i = 0, k = a->sndx;
73            i < a->ramp;
74            i++, k = (k + 1) % a->mask)
75         CXBdata(a->buff, i) = Cscl(a->circ[k], a->gain.old + i * step);
76       for (; i < CXBsize(a->buff); i++, k = (k + 1) % a->mask)
77         CXBdata(a->buff, i) = Cscl(a->circ[k], a->gain.now);
78       a->gain.old = a->gain.now;
79
80     } else {
81       for (i = 0, k = a->sndx;
82            i < CXBsize(a->buff);
83            i++, k = (k + 1) % a->mask)
84         CXBdata(a->buff, i) = Cscl(a->circ[k], a->gain.now);
85     }
86
87     a->sndx = (a->sndx + CXBsize(a->buff)) % a->mask;
88     a->indx = ((a->indx + 1) % hang);
89   }
90 }
91
92 /*
93  * Mode is gross agc mode: off, slow, med, fast; just info
94  * Hang is basic hang time
95  * Size is max hang time
96  * Over is recover period after TRX switch
97  * Rcov is hang value used during recovery period
98  * BufSize is length of sample buffer
99  */
100
101 DIGITALAGC
102 newDigitalAgc(int Mode,
103               int Hang,
104               int Ramp,
105               int Over,
106               int Rcov,
107               int BufSize,
108               REAL MaxGain, REAL Limit, REAL CurGain, COMPLEX * Vec) {
109   DIGITALAGC a = (DIGITALAGC) safealloc(1,
110                                         sizeof(digital_agc_state),
111                                         "new digital agc state");
112   assert((Ramp >= 2) && (Ramp < BufSize));
113   a->mode = Mode;
114   a->hang = Hang;
115   a->over = Over;
116   a->rcov = Rcov;
117   a->ramp = Ramp;
118   a->gain.top = MaxGain;
119   a->gain.lim = Limit;
120   a->gain.old = a->gain.now = CurGain;
121   a->buff = newCXB(BufSize, Vec, "agc buffer");
122   a->mask = 2 * CXBsize(a->buff);
123   a->circ = newvec_COMPLEX(2 * BufSize, "circular agc buffer");
124   memset((void *) a->hist, 0, sizeof(a->hist));
125   a->indx = 0;
126   a->sndx = a->mask - Ramp;
127   a->gain.fix = 10.0;
128   return a;
129 }
130
131 void
132 delDigitalAgc(DIGITALAGC a) {
133   if (a) {
134     delCXB(a->buff);
135     delvec_COMPLEX(a->circ);
136     safefree((void *) a);
137   }
138 }