changeset 601:d838de2ce1b1

Added AGC::designAGC() This new method is not debugged ... that is the next step.
author flatmax
date Tue, 02 Apr 2013 08:38:23 +0000
parents 2d18671876c8
children 256caa099e32
files C++/AGC.C C++/AGC.H C++/AGCCoeff.H C++/CAR.H C++/CARFACCommon.H C++/Ear.C C++/codeblocks/CARFAC.layout
diffstat 7 files changed, 164 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/C++/AGC.C	Tue Feb 26 10:43:26 2013 +0000
+++ b/C++/AGC.C	Tue Apr 02 08:38:23 2013 +0000
@@ -23,12 +23,129 @@
 
 #include "AGC.H"
 
-AGC::AGC()
-{
-    //ctor
+AGC::AGC() {
 }
 
-AGC::~AGC()
-{
-    //dtor
+AGC::~AGC() {
 }
+
+void AGC::designAGC(FP_TYPE fs, int n_ch) {
+    int n_AGC_stages = params.n_stages;
+//AGC_coeffs = struct( ...
+//  'n_ch', n_ch, ...
+//  'n_AGC_stages', n_AGC_stages, ...
+//  'AGC_stage_gain', AGC_params.AGC_stage_gain);
+
+// AGC1 pass is smoothing from base toward apex;
+// AGC2 pass is back, which is done first now (in double exp. version)
+//AGC1_scales = AGC_params.AGC1_scales;
+//AGC2_scales = AGC_params.AGC2_scales;
+
+    coeffs.AGC_epsilon = Array<FP_TYPE, 1, Dynamic>::Zero(1, n_AGC_stages);  // the 1/(tau*fs) roughly
+    FP_TYPE decim = 1.;
+//AGC_coeffs.decimation = AGC_params.decimation;
+
+    FP_TYPE total_DC_gain = 0.;
+    for (int stage = 1; stage<=n_AGC_stages; stage++) {
+        FP_TYPE tau = params.time_constants(stage-1); // time constant in seconds
+        decim = decim * params.decimation(stage-1); // net decim to this stage
+        // epsilon is how much new input to take at each update step:
+        coeffs.AGC_epsilon(stage-1) = 1. - exp(-decim / (tau * fs));
+        // effective number of smoothings in a time constant:
+        FP_TYPE ntimes = tau * (fs / decim);  // typically 5 to 50
+
+        // decide on target spread (variance) and delay (mean) of impulse
+        // response as a distribution to be convolved ntimes:
+        // TODO (dicklyon): specify spread and delay instead of scales???
+        FP_TYPE delay = (param.AGC2_scales(stage-1) - param.AGC1_scales(stage-1)) / ntimes;
+        FP_TYPE spread_sq = (param.AGC1_scales(stage-1).pow(2.) + param.AGC2_scales(stage-1).pow(2)) / ntimes;
+
+        // get pole positions to better match intended spread and delay of
+        // [[geometric distribution]] in each direction (see wikipedia)
+        FP_TYPE u = 1. + 1. / spread_sq; // these are based on off-line algebra hacking.
+        FP_TYPE p = u - sqrt(pow(u,2.) - 1.); // pole that would give spread if used twice.
+        FP_TYPE dp = delay * (1. - 2.*p +pow(p,2.))/2.;
+                              FP_TYPE polez1 = p - dp;
+                              FP_TYPE polez2 = p + dp;
+                              coeffs.AGC_polez1(stage) = polez1;
+                              coeffs.AGC_polez2(stage) = polez2;
+
+                              // try a 3- or 5-tap FIR as an alternative to the double exponential:
+                              Array<FP_TYPE,1, Dynamic> AGC_spatial_FIR;
+                              int n_taps = 0;
+                              int FIR_OK = 0;
+                              int n_iterations = 1;
+        while (~FIR_OK) {
+        switch (n_taps) {
+            case 0:
+                // first attempt a 3-point FIR to apply once:
+                n_taps = 3;
+                break;
+            case 3:
+                // second time through, go wider but stick to 1 iteration
+                n_taps = 5;
+                break;
+            case 5:
+                // apply FIR multiple times instead of going wider:
+                n_iterations = n_iterations + 1;
+                if (n_iterations > 16) {
+                    cerr<<"Too many n_iterations in CARFAC_DesignAGC"<<endl;
+                    exit(AGC_DESIGN_ITERATION_ERROR);
+                }
+                break;
+            default:
+                // to do other n_taps would need changes in CARFAC_Spatial_Smooth
+                // and in Design_FIR_coeffs
+                cerr<<"Bad n_taps in CARFAC_DesignAGC"<<endl;
+                exit(AGC_DESIGN_TAPS_OOB_ERROR);
+                break;
+            }
+            FIR_OK = Design_FIR_coeffs(n_taps, spread_sq, delay, n_iterations,AGC_spatial_FIR);
+        }
+        // when FIR_OK, store the resulting FIR design in coeffs:
+        coeff.AGC_spatial_iterations(stage-1) = n_iterations;
+        coeff.AGC_spatial_FIR.col(stage-1).block(0,AGC_spatial_FIR.size()) = AGC_spatial_FIR;
+        coeff.AGC_spatial_n_taps(stage-1) = n_taps;
+
+        // accumulate DC gains from all the stages, accounting for stage_gain:
+        total_DC_gain = total_DC_gain + params.AGC_stage_gain.pow(stage-1);
+
+        // TODO (dicklyon) -- is this the best binaural mixing plan?
+        if (stage == 1)
+        coeff.AGC_mix_coeffs(stage-1) = 0.;
+        else
+            coeff.AGC_mix_coeffs(stage-1) = param.AGC_mix_coeff / (tau * (fs / decim));
+        }
+
+coeff.AGC_gain = total_DC_gain;
+
+// adjust the detect_scale to be the reciprocal DC gain of the AGC filters:
+AGC_coeffs.detect_scale = 1. / total_DC_gain;
+
+}
+
+int OK AGC::Design_FIR_coeffs(int n_taps, FP_TYPE var, FP_TYPE mn, int n_iter, Array<FP_TYPE,Dynamic,1> &FIR) {
+// reduce mean and variance of smoothing distribution by n_iterations:
+    mn = mn / (FP_TYPE)n_iter;
+    var = var / (FP_TYPE)n_iter;
+    switch (n_taps) {
+    case 3:
+        // based on solving to match mean and variance of [a, 1-a-b, b]:
+        a = (var + mn*mn - mn) / 2.;
+        b = (var + mn*mn + mn) / 2.;
+        FIR.resize(3,1);
+        FIR<<a, 1. - a - b, b;
+        OK = FIR(2) >= 0.2;
+    case 5
+            // based on solving to match [a/2, a/2, 1-a-b, b/2, b/2]:
+            a = ((var + mn*mn)*2./5. - mn*2./3.) / 2.;
+        b = ((var + mn*mn)*2./5. + mn*2./3.) / 2.;
+        // first and last coeffs are implicitly duplicated to make 5-point FIR:
+        FIR.resize(5,1);
+        FIR<<a/2., 1. - a - b, b/2.;
+        OK = FIR(2) >= 0.1;
+    default:
+        cerr<<"Bad n_taps in AGC_spatial_FIR"<<endl;
+        exit(AGC_FIR_TAP_COUNT_ERROR);
+    }
+}
--- a/C++/AGC.H	Tue Feb 26 10:43:26 2013 +0000
+++ b/C++/AGC.H	Tue Apr 02 08:38:23 2013 +0000
@@ -31,6 +31,12 @@
     public:
         AGC();
         virtual ~AGC();
+
+    /** Method to design the automatic gain control coefficients
+    \param fs The sample rate in Hz
+    \param n_ch The number of channels. The CAR.coeff are one row per channel
+    */
+    void designAGC(FP_TYPE fs, int n_ch);
 };
 
 #endif // AGC_H_
--- a/C++/AGCCoeff.H	Tue Feb 26 10:43:26 2013 +0000
+++ b/C++/AGCCoeff.H	Tue Apr 02 08:38:23 2013 +0000
@@ -1,5 +1,5 @@
 // Copyright 2013 Matt R. Flax <flatmax\@> All Rights Reserved.
-// Author Matt Flax <flatmax@>
+// Author Matt Flax <flatmax@>s
 //
 // This C++ file is part of an implementation of Lyon's cochlear model:
 // "Cascade of Asymmetric Resonators with Fast-Acting Compression"
@@ -29,6 +29,8 @@
 */
 class AGCCoeff : public Coefficients {
 public:
+    Array<FP_TYPE, 1, Dynamic> AGC_epsilon; ///< the 1/(tau*fs) roughly
+
     AGCCoeff();
     virtual ~AGCCoeff();
 };
--- a/C++/CAR.H	Tue Feb 26 10:43:26 2013 +0000
+++ b/C++/CAR.H	Tue Apr 02 08:38:23 2013 +0000
@@ -36,6 +36,7 @@
 
     /** Method to design the auditory filter coefficients
     \param fs The sample rate in Hz
+    \param n_ch The number of channels. The CAR.coeff are one row per channel
     */
     void designFilters(FP_TYPE fs, int n_ch);
 
--- a/C++/CARFACCommon.H	Tue Feb 26 10:43:26 2013 +0000
+++ b/C++/CARFACCommon.H	Tue Apr 02 08:38:23 2013 +0000
@@ -30,6 +30,10 @@
 
 #include "PsychoAcoustics.H"
 
+#define AGC_DESIGN_ITERATION_ERROR -100 ///< Error when designing the AGC filter taps
+#define AGC_DESIGN_TAPS_OOB_ERROR -101 ///< The number of taps requested have not been accounted for in the code yet.
+#define AGC_FIR_TAP_COUNT_ERROR -102 ///< The number of taps passed to the AGC::Design_FIR_coeffs method are not handled
+
 /**
     \mainpage CARFAC C++
 
--- a/C++/Ear.C	Tue Feb 26 10:43:26 2013 +0000
+++ b/C++/Ear.C	Tue Apr 02 08:38:23 2013 +0000
@@ -60,7 +60,7 @@
     max_channels_per_octave = (FP_TYPE)(log(2.) / log(car.pole_freqs[0]/car.pole_freqs[1]));
 
     // convert to include an ear_array, each w coeffs and state...
-    car.designFilters(fs, n_ch); //(car.param. fs, car.pole_freqs);
-    //AGC.designAGC(CF_AGC_params, fs, n_ch);
+    car.designFilters(fs, n_ch);
+    AGC.designAGC(fs, n_ch);
     //IHC.designIHC(CF_IHC_params, fs, n_ch);
 }
--- a/C++/codeblocks/CARFAC.layout	Tue Feb 26 10:43:26 2013 +0000
+++ b/C++/codeblocks/CARFAC.layout	Tue Apr 02 08:38:23 2013 +0000
@@ -1,23 +1,23 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
 <CodeBlocks_layout_file>
 	<ActiveTarget name="Debug" />
-	<File name="../AGC.C" open="0" top="0" tabpos="2">
-		<Cursor position="94" topLine="0" />
+	<File name="../AGC.C" open="1" top="1" tabpos="7">
+		<Cursor position="6353" topLine="125" />
 	</File>
-	<File name="../AGC.H" open="0" top="0" tabpos="3">
-		<Cursor position="94" topLine="0" />
+	<File name="../AGC.H" open="1" top="0" tabpos="6">
+		<Cursor position="1419" topLine="14" />
 	</File>
 	<File name="../AGCCoeff.C" open="0" top="0" tabpos="4">
 		<Cursor position="94" topLine="0" />
 	</File>
-	<File name="../AGCCoeff.H" open="0" top="0" tabpos="5">
-		<Cursor position="94" topLine="0" />
+	<File name="../AGCCoeff.H" open="1" top="0" tabpos="9">
+		<Cursor position="1122" topLine="10" />
 	</File>
 	<File name="../AGCParam.C" open="0" top="0" tabpos="5">
 		<Cursor position="94" topLine="1" />
 	</File>
-	<File name="../AGCParam.H" open="0" top="0" tabpos="5">
-		<Cursor position="1149" topLine="13" />
+	<File name="../AGCParam.H" open="1" top="0" tabpos="8">
+		<Cursor position="2004" topLine="25" />
 	</File>
 	<File name="../AGCState.C" open="0" top="0" tabpos="8">
 		<Cursor position="94" topLine="0" />
@@ -25,23 +25,23 @@
 	<File name="../AGCState.H" open="0" top="0" tabpos="9">
 		<Cursor position="94" topLine="0" />
 	</File>
-	<File name="../CAR.C" open="1" top="1" tabpos="1">
-		<Cursor position="3388" topLine="65" />
+	<File name="../CAR.C" open="0" top="0" tabpos="1">
+		<Cursor position="2218" topLine="46" />
 	</File>
-	<File name="../CAR.H" open="1" top="0" tabpos="2">
-		<Cursor position="1679" topLine="26" />
+	<File name="../CAR.H" open="0" top="0" tabpos="2">
+		<Cursor position="1537" topLine="21" />
 	</File>
 	<File name="../CARCoeff.C" open="0" top="0" tabpos="12">
 		<Cursor position="94" topLine="0" />
 	</File>
-	<File name="../CARCoeff.H" open="1" top="0" tabpos="8">
+	<File name="../CARCoeff.H" open="0" top="0" tabpos="8">
 		<Cursor position="1171" topLine="20" />
 	</File>
-	<File name="../CARFACCommon.H" open="1" top="0" tabpos="7">
-		<Cursor position="2156" topLine="46" />
+	<File name="../CARFACCommon.H" open="1" top="0" tabpos="5">
+		<Cursor position="1559" topLine="15" />
 	</File>
 	<File name="../CARParam.C" open="0" top="0" tabpos="7">
-		<Cursor position="94" topLine="16" />
+		<Cursor position="1321" topLine="16" />
 	</File>
 	<File name="../CARParam.H" open="0" top="0" tabpos="3">
 		<Cursor position="2340" topLine="31" />
@@ -55,19 +55,19 @@
 	<File name="../Coefficients.C" open="0" top="0" tabpos="18">
 		<Cursor position="94" topLine="0" />
 	</File>
-	<File name="../Coefficients.H" open="1" top="0" tabpos="10">
+	<File name="../Coefficients.H" open="0" top="0" tabpos="10">
 		<Cursor position="1139" topLine="12" />
 	</File>
-	<File name="../Ear.C" open="1" top="0" tabpos="3">
-		<Cursor position="1709" topLine="40" />
+	<File name="../Ear.C" open="1" top="0" tabpos="1">
+		<Cursor position="2303" topLine="40" />
 	</File>
-	<File name="../Ear.H" open="1" top="0" tabpos="4">
+	<File name="../Ear.H" open="1" top="0" tabpos="2">
 		<Cursor position="1086" topLine="18" />
 	</File>
 	<File name="../EarComponent.C" open="0" top="0" tabpos="6">
 		<Cursor position="94" topLine="0" />
 	</File>
-	<File name="../EarComponent.H" open="1" top="0" tabpos="9">
+	<File name="../EarComponent.H" open="0" top="0" tabpos="9">
 		<Cursor position="1541" topLine="26" />
 	</File>
 	<File name="../Ears.C" open="0" top="0" tabpos="24">
@@ -100,13 +100,13 @@
 	<File name="../IHCState.H" open="0" top="0" tabpos="33">
 		<Cursor position="94" topLine="0" />
 	</File>
-	<File name="../Makefile" open="1" top="0" tabpos="6">
+	<File name="../Makefile" open="1" top="0" tabpos="4">
 		<Cursor position="1159" topLine="9" />
 	</File>
 	<File name="../Parameters.C" open="0" top="0" tabpos="35">
 		<Cursor position="94" topLine="0" />
 	</File>
-	<File name="../Parameters.H" open="1" top="0" tabpos="11">
+	<File name="../Parameters.H" open="0" top="0" tabpos="11">
 		<Cursor position="1125" topLine="12" />
 	</File>
 	<File name="../PsychoAcoustics.C" open="0" top="0" tabpos="8">
@@ -118,10 +118,10 @@
 	<File name="../State.C" open="0" top="0" tabpos="37">
 		<Cursor position="94" topLine="0" />
 	</File>
-	<File name="../State.H" open="1" top="0" tabpos="12">
+	<File name="../State.H" open="0" top="0" tabpos="12">
 		<Cursor position="1095" topLine="12" />
 	</File>
-	<File name="../test/EarTest.C" open="1" top="0" tabpos="5">
+	<File name="../test/EarTest.C" open="1" top="0" tabpos="3">
 		<Cursor position="989" topLine="4" />
 	</File>
 </CodeBlocks_layout_file>