FreeCalypso > hg > efr-experiments
diff src/agc.c @ 0:56410792419a
src: original EFR source from ETSI
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Wed, 03 Apr 2024 05:31:37 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/agc.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,186 @@ +/************************************************************************* + * + * FUNCTION: agc + * + * PURPOSE: Scales the postfilter output on a subframe basis by automatic + * control of the subframe gain. + * + * DESCRIPTION: + * sig_out[n] = sig_out[n] * gain[n]; + * where gain[n] is the gain at the nth sample given by + * gain[n] = agc_fac * gain[n-1] + (1 - agc_fac) g_in/g_out + * g_in/g_out is the square root of the ratio of energy at the input + * and output of the postfilter. + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" +#include "sig_proc.h" +#include "cnst.h" + +Word16 past_gain; /* initial value of past_gain = 1.0 */ + +void agc ( + Word16 *sig_in, /* (i) : postfilter input signal */ + Word16 *sig_out, /* (i/o) : postfilter output signal */ + Word16 agc_fac, /* (i) : AGC factor */ + Word16 l_trm /* (i) : subframe size */ +) +{ + Word16 i, exp; + Word16 gain_in, gain_out, g0, gain; + Word32 s; + + Word16 temp; + + /* calculate gain_out with exponent */ + + temp = shr (sig_out[0], 2); + s = L_mult (temp, temp); + + for (i = 1; i < l_trm; i++) + { + temp = shr (sig_out[i], 2); + s = L_mac (s, temp, temp); + } + + test (); + if (s == 0) + { + past_gain = 0; move16 (); + return; + } + exp = sub (norm_l (s), 1); + gain_out = round (L_shl (s, exp)); + + /* calculate gain_in with exponent */ + + temp = shr (sig_in[0], 2); + s = L_mult (temp, temp); + + for (i = 1; i < l_trm; i++) + { + temp = shr (sig_in[i], 2); + s = L_mac (s, temp, temp); + } + + test (); + if (s == 0) + { + g0 = 0; move16 (); + } + else + { + i = norm_l (s); + gain_in = round (L_shl (s, i)); + exp = sub (exp, i); + + /*---------------------------------------------------* + * g0 = (1-agc_fac) * sqrt(gain_in/gain_out); * + *---------------------------------------------------*/ + + s = L_deposit_l (div_s (gain_out, gain_in)); + s = L_shl (s, 7); /* s = gain_out / gain_in */ + s = L_shr (s, exp); /* add exponent */ + + s = Inv_sqrt (s); + i = round (L_shl (s, 9)); + + /* g0 = i * (1-agc_fac) */ + g0 = mult (i, sub (32767, agc_fac)); + } + + /* compute gain[n] = agc_fac * gain[n-1] + + (1-agc_fac) * sqrt(gain_in/gain_out) */ + /* sig_out[n] = gain[n] * sig_out[n] */ + + gain = past_gain; move16 (); + + for (i = 0; i < l_trm; i++) + { + gain = mult (gain, agc_fac); + gain = add (gain, g0); + sig_out[i] = extract_h (L_shl (L_mult (sig_out[i], gain), 3)); + move16 (); + } + + past_gain = gain; move16 (); + + return; +} + +void agc2 ( + Word16 *sig_in, /* (i) : postfilter input signal */ + Word16 *sig_out, /* (i/o) : postfilter output signal */ + Word16 l_trm /* (i) : subframe size */ +) +{ + Word16 i, exp; + Word16 gain_in, gain_out, g0; + Word32 s; + + Word16 temp; + + /* calculate gain_out with exponent */ + + temp = shr (sig_out[0], 2); + s = L_mult (temp, temp); + for (i = 1; i < l_trm; i++) + { + temp = shr (sig_out[i], 2); + s = L_mac (s, temp, temp); + } + + test (); + if (s == 0) + { + return; + } + exp = sub (norm_l (s), 1); + gain_out = round (L_shl (s, exp)); + + /* calculate gain_in with exponent */ + + temp = shr (sig_in[0], 2); + s = L_mult (temp, temp); + for (i = 1; i < l_trm; i++) + { + temp = shr (sig_in[i], 2); + s = L_mac (s, temp, temp); + } + + test (); + if (s == 0) + { + g0 = 0; move16 (); + } + else + { + i = norm_l (s); + gain_in = round (L_shl (s, i)); + exp = sub (exp, i); + + /*---------------------------------------------------* + * g0 = sqrt(gain_in/gain_out); * + *---------------------------------------------------*/ + + s = L_deposit_l (div_s (gain_out, gain_in)); + s = L_shl (s, 7); /* s = gain_out / gain_in */ + s = L_shr (s, exp); /* add exponent */ + + s = Inv_sqrt (s); + g0 = round (L_shl (s, 9)); + } + + /* sig_out(n) = gain(n) sig_out(n) */ + + for (i = 0; i < l_trm; i++) + { + sig_out[i] = extract_h (L_shl (L_mult (sig_out[i], g0), 3)); + move16 (); + } + + return; +}