DSPRelated.com
Forums

AGC circuit from Fred Harris

Started by Rick Lyons September 10, 2003

Hi Guys,
    I've been trying to implement the following 
AGC (automatic gain control) that Fred Harris 
included in the notes of one of his DSP classes.

But darn, I can only get this circuit to work over 
a small frequency range (centered at Fs/10).

[In the below drawing, the "(x)" is a multiplier,
          the "(+)" is an adder, the "o" is 
          merely a connection point, and the 
          "[z^-1]" is a single delay.]

Xin -->(x)----------------------------------o--> Yout   
        ^                                   |
        |                                   |
        |                                   |
        o--[Z^-1]--<--(+)--<--(x)--<--(+)-<--
        |              ^       ^       ^
        |              |       |       |
        ------>--------        |       |
                             alpha     -R


My input is a single sinusoid whose peak amplitude 
varies (slightly) about the value of 1.
(I want the AGC to minimize those amplitude 
variations.)

I've set R to 1  (so that control parameter into the 
one adder is -1), and am keeping alpha between 0 and 
0.5.  Anyway, I sure can't get this AGC circuit to 
work very well at all in my MATLAB modeling.

Have any of you guys ever been able to make this
AGC structure work?   Just thought I'd ask.
Maybe my MATLAB code is screwed up.

Thanks,
[-Rick-]


"Rick Lyons" <ricklyon@REMOVE.onemain.com> wrote in message
news:3f5f419e.21154140@news.west.earthlink.net...
> > > Hi Guys, > I've been trying to implement the following > AGC (automatic gain control) that Fred Harris > included in the notes of one of his DSP classes. > > But darn, I can only get this circuit to work over > a small frequency range (centered at Fs/10). > > [In the below drawing, the "(x)" is a multiplier, > the "(+)" is an adder, the "o" is > merely a connection point, and the > "[z^-1]" is a single delay.] > > Xin -->(x)----------------------------------o--> Yout > ^ | > | | > | | > o--[Z^-1]--<--(+)--<--(x)--<--(+)-<-- > | ^ ^ ^ > | | | | > ------>-------- | | > alpha -R > > > My input is a single sinusoid whose peak amplitude > varies (slightly) about the value of 1. > (I want the AGC to minimize those amplitude > variations.) > > I've set R to 1 (so that control parameter into the > one adder is -1), and am keeping alpha between 0 and > 0.5. Anyway, I sure can't get this AGC circuit to > work very well at all in my MATLAB modeling. > > Have any of you guys ever been able to make this > AGC structure work? Just thought I'd ask. > Maybe my MATLAB code is screwed up.
Rick, Well, I see at least a couple of problems with it. First, the delay has positive feedback - so it's unstable from the get go. Think what would happen if it were an analog delay line. The output would grow indefinitely with a constant input. I don't think that's what you want here. A more suitable thing would be to have a coefficient in the feedback and for the feedback to be negative. Then a constant input would result in a stable output. I think the purpose of the the delay block is to implement an integrator or a simple lowpass. I can't tell what alpha and R are supposed to represent. It does seem clear that the input to the adder with R has to be |Yout| and not Yout for an AGC. Then, maybe R is a threshold below which there is no gain reduction. Maybe this implies that the output of the adder with R is never negative. Let's see the code, eh? Fred
On Wed, 10 Sep 2003 17:25:51 -0700, "Fred Marshall"
<fmarshallx@remove_the_x.acm.org> wrote:

> >"Rick Lyons" <ricklyon@REMOVE.onemain.com> wrote in message >news:3f5f419e.21154140@news.west.earthlink.net... >> >> >> Hi Guys, >> I've been trying to implement the following >> AGC (automatic gain control) that Fred Harris >> included in the notes of one of his DSP classes. >> >> But darn, I can only get this circuit to work over >> a small frequency range (centered at Fs/10). >> >> [In the below drawing, the "(x)" is a multiplier, >> the "(+)" is an adder, the "o" is >> merely a connection point, and the >> "[z^-1]" is a single delay.] >> >> Xin -->(x)----------------------------------o--> Yout >> ^ | >> | | >> | | >> o--[Z^-1]--<--(+)--<--(x)--<--(+)-<-- >> | ^ ^ ^ >> | | | | >> ------>-------- | | >> alpha -R >> >> >> My input is a single sinusoid whose peak amplitude >> varies (slightly) about the value of 1. >> (I want the AGC to minimize those amplitude >> variations.) >> >> I've set R to 1 (so that control parameter into the >> one adder is -1), and am keeping alpha between 0 and >> 0.5. Anyway, I sure can't get this AGC circuit to >> work very well at all in my MATLAB modeling. >> >> Have any of you guys ever been able to make this >> AGC structure work? Just thought I'd ask. >> Maybe my MATLAB code is screwed up. > >Rick, > >Well, I see at least a couple of problems with it. > >First, the delay has positive feedback - so it's unstable from the get go. >Think what would happen if it were an analog delay line. The output would >grow indefinitely with a constant input. I don't think that's what you want >here. A more suitable thing would be to have a coefficient in the feedback >and for the feedback to be negative. Then a constant input would result in >a stable output. I think the purpose of the the delay block is to implement >an integrator or a simple lowpass. > >I can't tell what alpha and R are supposed to represent. It does seem clear >that the input to the adder with R has to be |Yout| and not Yout for an AGC. >Then, maybe R is a threshold below which there is no gain reduction. Maybe >this implies that the output of the adder with R is never negative. > >Let's see the code, eh? > >Fred
Hi Fred, thanks for your thoughts. Because I'm working with real-valued samples (I didn't specify that fact), Yout = |Yout|. You make me think I should stick some minus signs in the equations (meaning subtractions in the block diagram) and keep experimenting. I'll keep in touch. Thanks, [-Rick-] (Hope you caught some tuna!!)
Hi Rick,

It looks like that diagram was translated from an analog circuit, and that
some pretty important points have been left out.

According to your diagram, the gain factor is produced by integrating a gain
direction signal that is calculated as alpha*(Yout-R).

That doesn't quite make any sense -- you must be missing a rectifier.
Putting a full wave rectifier on the Yout feedback gives us gain direction
alpha*(abs(Yout)-R).

Now the gain direction won't be switching sign every cycle.  The real
circuit may have just used a single-sided power supply for the AGC circuit.

Next, note that alpha must be *negative*, so that the gain decreases when
Yout is too big.

Also, the gain direction is strongly biased by subtracting R. That will make
the gain increase far more readily than it decreases, making the equilibrium
gain way too high.  You need to limit the minimum value of the gain
direction.  Calculating the gain direction signal as
max(L,alpha*abs(Yout)-R) makes sense.  With L a small negative number, the
gain will reduce quickly when abs(Yout)>R, and slowly decay toward zero at
other times.

Finally, you need to limit the gain output to positive values.  If L is
negative, you need the integrator to be gain[t]=max(0,gain[t-1]+dir[-1])
instead of gain[t]=gain[t-1]+dir[t-1].

Alternatively, you can make L=0 and make the integrator leaky.  This will
cause the gain decay to have a constant slope in dB instead of volts.  This
is likely how it would have been done in an analog circuit, because all
analog integrators leak, and the L=0 limit can again be accomplished with a
single-sided supply.  That's why it looks like this diagram was captured
naively from an analog circuit -- an analog version, with a leaky
integrator, a single-sided supply for the AGC circuitry, and alpha<0,
actually works fine!


Hi Rick,

As I write this, it occurs to me that almost all of the usenet posts I've
made in the past couple months have contained significant errors that I
recognize an hour later.

In this case, my brain swapped a sign half-way through the diagram and I
messed up the explanation.  A quick fix follows:

gain direction:

dir=alpha*max(L,abs(Yout-R)),

alpha is negative and L is negative.  L is much smaller than R.

gain[t]=max(0,gain[t-1]+dir[t-1])

You can still set L=0 by using a leaky integrator, but it has to drift
upwards, which isn't very satisfying, and doesn't result in a constant slope
in dB, but it does put a softer limit on the maximum gain than just
clipping, so that may be useful.


"Rick Lyons" <ricklyon@REMOVE.onemain.com> wrote in message
news:3f60635e.6222234@news.west.earthlink.net...
> On Wed, 10 Sep 2003 17:25:51 -0700, "Fred Marshall" > <fmarshallx@remove_the_x.acm.org> wrote: > > > > >"Rick Lyons" <ricklyon@REMOVE.onemain.com> wrote in message > >news:3f5f419e.21154140@news.west.earthlink.net... > >> > >> > >> Hi Guys, > >> I've been trying to implement the following > >> AGC (automatic gain control) that Fred Harris > >> included in the notes of one of his DSP classes. > >> > >> But darn, I can only get this circuit to work over > >> a small frequency range (centered at Fs/10). > >> > >> [In the below drawing, the "(x)" is a multiplier, > >> the "(+)" is an adder, the "o" is > >> merely a connection point, and the > >> "[z^-1]" is a single delay.] > >> > >> Xin -->(x)----------------------------------o--> Yout > >> ^ | > >> | | > >> | | > >> o--[Z^-1]--<--(+)--<--(x)--<--(+)-<-- > >> | ^ ^ ^ > >> | | | | > >> ------>-------- | | > >> alpha -R > >> > >> > >> My input is a single sinusoid whose peak amplitude > >> varies (slightly) about the value of 1. > >> (I want the AGC to minimize those amplitude > >> variations.) > >> > >> I've set R to 1 (so that control parameter into the > >> one adder is -1), and am keeping alpha between 0 and > >> 0.5. Anyway, I sure can't get this AGC circuit to > >> work very well at all in my MATLAB modeling. > >> > >> Have any of you guys ever been able to make this > >> AGC structure work? Just thought I'd ask. > >> Maybe my MATLAB code is screwed up. > > > >Rick, > > > >Well, I see at least a couple of problems with it. > > > >First, the delay has positive feedback - so it's unstable from the get
go.
> >Think what would happen if it were an analog delay line. The output
would
> >grow indefinitely with a constant input. I don't think that's what you
want
> >here. A more suitable thing would be to have a coefficient in the
feedback
> >and for the feedback to be negative. Then a constant input would result
in
> >a stable output. I think the purpose of the the delay block is to
implement
> >an integrator or a simple lowpass. > > > >I can't tell what alpha and R are supposed to represent. It does seem
clear
> >that the input to the adder with R has to be |Yout| and not Yout for an
AGC.
> >Then, maybe R is a threshold below which there is no gain reduction.
Maybe
> >this implies that the output of the adder with R is never negative. > > > >Let's see the code, eh? > > > >Fred > > Hi Fred, > thanks for your thoughts. Because I'm working > with real-valued samples (I didn't specify that fact), > Yout = |Yout|. > > You make me think I should stick some minus signs > in the equations (meaning subtractions in the > block diagram) and keep experimenting. > I'll keep in touch. >
Rick, Well, tuna fishing turned out to be Chinook salmon fishing and we did very well. Limited two days running. The tuna were just too far off shore and the sea conditions didn't combine well to transit that far. Anyway, back to work: I just recalled that you'd mentioned sinusoids. Combining this with my comment about |Yout|, I realize I should have said something more like max[|Yout|]. The idea is to get the peak of the sinusoid as a measure of the amplitude and go from there. As Matt points out, there is generally a rectifier function - thus "max". One method for doing this assuming that Yout is always positive would be something like: ymax=0 if y>ymax ymax=y end This much captures the peak values and increasing amplitude but obviously gets "stuck" at the greatest value ever reached. Then, you need to deal with decreasing peaks somehow. If the signal is really a sinusoid, you can detect the peaks with something like: ymaxold=0 ymaxnew=0 %in the signal loop .... if y>ymaxold ymaxold=y %set old peak end if y>=ymaxnew ymaxnew=y %set new peak end if y<ymaxnew %found new peak if ymaxnew<ymaxold %new peak is less than old peak ymaxold=ymaxnew %redefine old peak as the new peak which is less end end %use ymaxold for agc..... I just jotted this off so it could have errors of logic and I didn't try to adhere to any language convention. It's like Octave I guess. Of course, this has no filters on ymaxold which may be unacceptable. A bit of lowpass on it might be better to ward off noise spikes, etc. Common convention has the "attack" faster than the "decay". So, you might have a nonlinear filter which increases ymaxold faster than it allows it to decrease. Something like: %define agc as maximum gain for agc0=1.0 agc0=1.0 agc=agc0 ymaxold=0 ymaxnew=0 attack=0.5 decay=0.2 %in the signal loop .... if y>ymaxold ymaxold=y+(y-ymaxold)*attack %move upward toward a higher peak value end if y>=ymaxnew ymaxnew=y %set new peak else %y<ymaxnew and found new peak if ymaxnew<ymaxold %new peak is less than old peak ymaxold=ymaxold - (ymaxold-ymaxnew)*decay %move downward toward the lower peak value end ymaxnew=0 end If any part of this is patented, use at your own risk. I have no idea. Fred
Rick Lyons wrote:
>
...
> > Hi Fred, > thanks for your thoughts. Because I'm working > with real-valued samples (I didn't specify that fact), > Yout = |Yout|. > > You make me think I should stick some minus signs > in the equations (meaning subtractions in the > block diagram) and keep experimenting. > I'll keep in touch. > > Thanks, > [-Rick-] (Hope you caught some tuna!!)
Oh? so -3.2 isn't real? We haven't been taught that since the Middle Ages! Seriously, |X| simply means absolute_value(X) or X&#4294967295;sgn(X) here, not magnitude(X). For AGC, you need at least a half-wave peak detector, and full-wave is better. Jerry -- Engineering is the art of making what you want from things you can get. &#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;
On Thu, 11 Sep 2003 15:47:40 -0400, Jerry Avins <jya@ieee.org> wrote:

>Rick Lyons wrote: >> > ... >> >> Hi Fred, >> thanks for your thoughts. Because I'm working >> with real-valued samples (I didn't specify that fact), >> Yout = |Yout|. >> >> You make me think I should stick some minus signs >> in the equations (meaning subtractions in the >> block diagram) and keep experimenting. >> I'll keep in touch. >> >> Thanks, >> [-Rick-] (Hope you caught some tuna!!) > >Oh? so -3.2 isn't real? We haven't been taught that since the Middle >Ages! Seriously, |X| simply means absolute_value(X) or X&#4294967295;sgn(X) here, >not magnitude(X). For AGC, you need at least a half-wave peak detector, >and full-wave is better. > >Jerry
Well, Ah, I missed Fred's point completely!! Thanks. [-Rick-]
On Thu, 11 Sep 2003 12:12:42 -0400, "Matt Timmermans"
<mt0000@sympatico.nospam-remove.ca> wrote:

>Hi Rick, > >As I write this, it occurs to me that almost all of the usenet posts I've >made in the past couple months have contained significant errors that I >recognize an hour later. > >In this case, my brain swapped a sign half-way through the diagram and I >messed up the explanation. A quick fix follows: > >gain direction: > >dir=alpha*max(L,abs(Yout-R)), > >alpha is negative and L is negative. L is much smaller than R. > >gain[t]=max(0,gain[t-1]+dir[t-1]) > >You can still set L=0 by using a leaky integrator, but it has to drift >upwards, which isn't very satisfying, and doesn't result in a constant slope >in dB, but it does put a softer limit on the maximum gain than just >clipping, so that may be useful. >
Hi Matt, thanks for your thoughts. I'll go through your post, very carefully, this weekend. I'm workin' on a 2nd edition of my DSP book, and just thought that Harris' AGC process may deserve some discussion. (If I can just make the 'bugger' work.) Just for giggles, a few days ago I E-mailed Prof. Harris a request to let me know if the block diagram is correct. We'll see if he answers my request. I met Fred a couple of times at a few DSP seminars. (We were both lecturing.) My guess is that he'll not remember me. Thanks again Matt, [-Rick-]
On Thu, 11 Sep 2003 12:12:42 -0400, "Matt Timmermans"
<mt0000@sympatico.nospam-remove.ca> wrote:

>Hi Rick,
Hi Matt,
>As I write this, it occurs to me that almost all of the usenet posts I've >made in the past couple months have contained significant errors that I >recognize an hour later. >
Ha. Don't feel bad. I misunderstood the meaning of "|Yout|" from Fred. Daoh!!! Fred Harris (fred harris) answered my E-mail. Anyway, you and Fred were "right on the mark" concerning feeding back the absolute value of Yout, and that it should negative. So the corrected block diagram should have a '-|Yout|' going into the rightmost adder. The other input to that adder should be '+R'. Good goin' you guys. Thanks, [-Rick-]