changeset 495:69955736f586

update how loop gain gets calculated, to remove dependency of AGC coeffs on IHC behavior, and speech up design by replacing iterations to convergence with DC models.
author dicklyon@google.com
date Mon, 09 Apr 2012 06:15:05 +0000
parents 9a8334232633
children 056df17e0898
files matlab/bmm/carfac/CARFAC_Design.m matlab/bmm/carfac/CARFAC_IHC_Step.m matlab/bmm/carfac/CARFAC_Init.m
diffstat 3 files changed, 119 insertions(+), 94 deletions(-) [+]
line wrap: on
line diff
--- a/matlab/bmm/carfac/CARFAC_Design.m	Sun Apr 08 04:15:27 2012 +0000
+++ b/matlab/bmm/carfac/CARFAC_Design.m	Mon Apr 09 06:15:05 2012 +0000
@@ -60,9 +60,9 @@
         'just_hwr', just_hwr, ...        % not just a simple HWR
         'one_cap', one_cap, ...   % bool; 0 for new two-cap hack
         'tau_lpf', 0.000080, ...  % 80 microseconds smoothing twice
-        'tau1_out', 0.020, ...    % depletion tau is pretty fast
+        'tau1_out', 0.010, ...    % depletion tau is pretty fast
         'tau1_in', 0.020, ...     % recovery tau is slower
-        'tau2_out', 0.005, ...   % depletion tau is pretty fast
+        'tau2_out', 0.0025, ...   % depletion tau is pretty fast
         'tau2_in', 0.005 );        % recovery tau is slower
     end
   end
@@ -134,10 +134,6 @@
   'IHC_coeffs', CARFAC_DesignIHC(CF_IHC_params, fs, n_ch), ...
   'n_ears', 0 );
 
-% adjust the AGC_coeffs to account for IHC saturation level to get right
-% damping change as specified in CF.AGC_params.detect_scale
-CF.AGC_coeffs.detect_scale = CF.AGC_params.detect_scale / ...
-  (CF.IHC_coeffs.saturation_output * CF.AGC_coeffs.AGC_gain);
 
 
 %% Design the filter coeffs:
@@ -295,6 +291,10 @@
 
 AGC_coeffs.AGC_gain = total_DC_gain;
 
+% adjust the detect_scale by the total DC gain of the AGC filters:
+AGC_coeffs.detect_scale = AGC_params.detect_scale / total_DC_gain;
+
+
 % % print some results
 AGC_coeffs
 AGC_spatial_FIR = AGC_coeffs.AGC_spatial_FIR
@@ -333,57 +333,68 @@
 
 if IHC_params.just_hwr
   IHC_coeffs = struct('just_hwr', 1);
-  IHC_coeffs.saturation_output = 10;  % HACK: assume some max out
+  saturation_output = 10;  % HACK: assume some max out
 else
   if IHC_params.one_cap
+    ro = 1 / CARFAC_Detect(2);  % output resistance
+    c = IHC_params.tau_out / ro;
+    ri = IHC_params.tau_in / c;
+    % to get steady-state average, double ro for 50% duty cycle
+    saturation_output = 1 / (2*ro + ri);
+    % also consider the zero-signal equilibrium:
+    r0 = 1 / CARFAC_Detect(0);
+    current = 1 / (ri + r0);
+    cap_voltage = 1 - current * ri;
+      IHC_coeffs.rest_output = IHC_out;
     IHC_coeffs = struct( ...
       'n_ch', n_ch, ...
       'just_hwr', 0, ...
       'lpf_coeff', 1 - exp(-1/(IHC_params.tau_lpf * fs)), ...
-      'out_rate', 1 / (IHC_params.tau_out * fs), ...
+      'out_rate', ro / (IHC_params.tau_out * fs), ...
       'in_rate', 1 / (IHC_params.tau_in * fs), ...
-      'one_cap', IHC_params.one_cap);
-  else
+      'one_cap', IHC_params.one_cap, ...
+      'output_gain', 1/ (saturation_output - current), ...
+      'rest_output', current / (saturation_output - current), ...
+      'rest_cap', cap_voltage);
+    % one-channel state for testing/verification:
+    IHC_state = struct( ...
+      'cap_voltage', IHC_coeffs.rest_cap, ...
+      'lpf1_state', 0, ...
+      'lpf2_state', 0, ...
+      'ihc_accum', 0);  else
+    ro = 1 / CARFAC_Detect(2);  % output resistance
+    c2 = IHC_params.tau2_out / ro;
+    r2 = IHC_params.tau2_in / c2;
+    c1 = IHC_params.tau1_out / r2;
+    r1 = IHC_params.tau1_in / c1;
+    % to get steady-state average, double ro for 50% duty cycle
+    saturation_output = 1 / (2*ro + r2 + r1);
+    % also consider the zero-signal equilibrium:
+    r0 = 1 / CARFAC_Detect(0);
+    current = 1 / (r1 + r2 + r0);
+    cap1_voltage = 1 - current * r1;
+    cap2_voltage = cap1_voltage - current * r2;
     IHC_coeffs = struct(...
       'n_ch', n_ch, ...
       'just_hwr', 0, ...
       'lpf_coeff', 1 - exp(-1/(IHC_params.tau_lpf * fs)), ...
       'out1_rate', 1 / (IHC_params.tau1_out * fs), ...
       'in1_rate', 1 / (IHC_params.tau1_in * fs), ...
-      'out2_rate', 1 / (IHC_params.tau2_out * fs), ...
+      'out2_rate', ro / (IHC_params.tau2_out * fs), ...
       'in2_rate', 1 / (IHC_params.tau2_in * fs), ...
-      'one_cap', IHC_params.one_cap);
+      'one_cap', IHC_params.one_cap, ...
+      'output_gain', 1/ (saturation_output - current), ...
+      'rest_output', current / (saturation_output - current), ...
+      'rest_cap2', cap2_voltage, ...
+      'rest_cap1', cap1_voltage);
+    % one-channel state for testing/verification:
+    IHC_state = struct( ...
+      'cap1_voltage', IHC_coeffs.rest_cap1, ...
+      'cap2_voltage', IHC_coeffs.rest_cap2, ...
+      'lpf1_state', 0, ...
+      'lpf2_state', 0, ...
+      'ihc_accum', 0);
   end
-  
-  % run one channel to convergence to get rest state:
-  IHC_coeffs.rest_output = 0;
-  IHC_state = struct( ...
-    'cap_voltage', 0, ...
-    'cap1_voltage', 0, ...
-    'cap2_voltage', 0, ...
-    'lpf1_state', 0, ...
-    'lpf2_state', 0, ...
-    'ihc_accum', 0);
-  
-  IHC_in = 0;  % the get the IHC output rest level
-  for k = 1:20000
-    [IHC_out, IHC_state] = CARFAC_IHC_Step(IHC_in, IHC_coeffs, IHC_state);
-  end
-  
-  IHC_coeffs.rest_output = IHC_out;
-  IHC_coeffs.rest_cap = IHC_state.cap_voltage;
-  IHC_coeffs.rest_cap1 = IHC_state.cap1_voltage;
-  IHC_coeffs.rest_cap2 = IHC_state.cap2_voltage;
-  
-  LARGE = 2;
-  IHC_in = LARGE;  % "Large" saturating input to IHC; make it alternate
-  for k = 1:20000
-    [IHC_out, IHC_state] = CARFAC_IHC_Step(IHC_in, IHC_coeffs, IHC_state);
-    prev_IHC_out = IHC_out;
-    IHC_in = -IHC_in;
-  end
-  
-  IHC_coeffs.saturation_output = (IHC_out + prev_IHC_out) / 2;
 end
 
 %%
@@ -397,16 +408,15 @@
 % CF.CAR_coeffs
 % CF.AGC_coeffs
 % CF.IHC_coeffs
-%
 % CF = 
 %                          fs: 22050
-%     max_channels_per_octave: 12.1873
-%               CAR_params: [1x1 struct]
+%     max_channels_per_octave: 12.2709
+%                  CAR_params: [1x1 struct]
 %                  AGC_params: [1x1 struct]
 %                  IHC_params: [1x1 struct]
-%                        n_ch: 66
-%                  pole_freqs: [66x1 double]
-%               CAR_coeffs: [1x1 struct]
+%                        n_ch: 71
+%                  pole_freqs: [71x1 double]
+%                  CAR_coeffs: [1x1 struct]
 %                  AGC_coeffs: [1x1 struct]
 %                  IHC_coeffs: [1x1 struct]
 %                      n_ears: 0
@@ -421,49 +431,53 @@
 %     high_f_damping_compression: 0.5000
 %                   ERB_per_step: 0.5000
 %                    min_pole_Hz: 30
+%                 ERB_break_freq: 165.3000
+%                          ERB_Q: 9.2645
 % ans = 
 %           n_stages: 4
 %     time_constants: [0.0020 0.0080 0.0320 0.1280]
 %     AGC_stage_gain: 2
 %         decimation: [8 2 2 2]
-%        AGC1_scales: [1 2 4 6]
-%        AGC2_scales: [1.5000 3 6 9]
-%       detect_scale: 0.1500
+%        AGC1_scales: [1 1.4000 2 2.8000]
+%        AGC2_scales: [1.6000 2.2500 3.2000 4.5000]
+%       detect_scale: 0.2500
 %      AGC_mix_coeff: 0.5000
 % ans = 
+%               n_ch: 71
 %     velocity_scale: 0.2000
 %           v_offset: 0.0100
 %          v2_corner: 0.2000
 %         v_damp_max: 0.0100
-%          r1_coeffs: [66x1 double]
-%          a0_coeffs: [66x1 double]
-%          c0_coeffs: [66x1 double]
-%           h_coeffs: [66x1 double]
-%          g0_coeffs: [66x1 double]
-%          zr_coeffs: [66x1 double]
+%          r1_coeffs: [71x1 double]
+%          a0_coeffs: [71x1 double]
+%          c0_coeffs: [71x1 double]
+%           h_coeffs: [71x1 double]
+%          g0_coeffs: [71x1 double]
+%          zr_coeffs: [71x1 double]
 % ans = 
+%                       n_ch: 71
+%               n_AGC_stages: 4
 %             AGC_stage_gain: 2
 %                AGC_epsilon: [0.1659 0.0867 0.0443 0.0224]
 %                 decimation: [8 2 2 2]
-%                 AGC_polez1: [0.1627 0.2713 0.3944 0.4194]
-%                 AGC_polez2: [0.2219 0.3165 0.4260 0.4414]
-%     AGC_spatial_iterations: [1 1 2 2]
+%                 AGC_polez1: [0.1699 0.1780 0.1872 0.1903]
+%                 AGC_polez2: [0.2388 0.2271 0.2216 0.2148]
+%     AGC_spatial_iterations: [1 1 1 1]
 %            AGC_spatial_FIR: [3x4 double]
-%         AGC_spatial_n_taps: [3 5 5 5]
+%         AGC_spatial_n_taps: [3 3 3 3]
 %             AGC_mix_coeffs: [0 0.0454 0.0227 0.0113]
 %                   AGC_gain: 15
-%               detect_scale: 0.0664
+%               detect_scale: 0.0167
 % ans = 
-%              just_hwr: 0
-%             lpf_coeff: 0.4327
-%             out1_rate: 0.0023
-%              in1_rate: 0.0023
-%             out2_rate: 0.0091
-%              in2_rate: 0.0091
-%               one_cap: 0
-%           rest_output: 0.0365
-%              rest_cap: 0
-%             rest_cap1: 0.9635
-%             rest_cap2: 0.9269
-%     saturation_output: 0.1507
-
+%            n_ch: 71
+%        just_hwr: 0
+%       lpf_coeff: 0.4327
+%       out1_rate: 0.0045
+%        in1_rate: 0.0023
+%       out2_rate: 0.0267
+%        in2_rate: 0.0091
+%         one_cap: 0
+%     output_gain: 17.9162
+%     rest_output: 0.5240
+%       rest_cap2: 0.7421
+%       rest_cap1: 0.8281
--- a/matlab/bmm/carfac/CARFAC_IHC_Step.m	Sun Apr 08 04:15:27 2012 +0000
+++ b/matlab/bmm/carfac/CARFAC_IHC_Step.m	Mon Apr 09 06:15:05 2012 +0000
@@ -29,17 +29,15 @@
   ihc_out = max(0, filters_out);
   state.ihc_accum = state.ihc_accum + ihc_out;
 else
-  one_cap = coeffs.one_cap;
-
-  detect = CARFAC_Detect(filters_out);  % detect with HWR or so
-
-  if one_cap
-    ihc_out = detect .* state.cap_voltage;
+  conductance = CARFAC_Detect(filters_out);  % detect with HWR or so
+  
+  if coeffs.one_cap;
+    ihc_out = conductance .* state.cap_voltage;
     state.cap_voltage = state.cap_voltage - ihc_out .* coeffs.out_rate + ...
       (1 - state.cap_voltage) .* coeffs.in_rate;
   else
     % change to 2-cap version more like Meddis's:
-    ihc_out = detect .* state.cap2_voltage;
+    ihc_out = conductance .* state.cap2_voltage;
     state.cap1_voltage = state.cap1_voltage - ...
       (state.cap1_voltage - state.cap2_voltage) .* coeffs.out1_rate + ...
       (1 - state.cap1_voltage) .* coeffs.in1_rate;
@@ -56,7 +54,7 @@
   state.lpf2_state = state.lpf2_state + coeffs.lpf_coeff * ...
     (state.lpf1_state - state.lpf2_state);
 
-  ihc_out = state.lpf2_state - coeffs.rest_output;
-
-  state.ihc_accum = state.ihc_accum + max(0, ihc_out);
+  ihc_out = state.lpf2_state * coeffs.output_gain - coeffs.rest_output;
+  
+  state.ihc_accum = state.ihc_accum + ihc_out;  % for where decimated output is useful
 end
--- a/matlab/bmm/carfac/CARFAC_Init.m	Sun Apr 08 04:15:27 2012 +0000
+++ b/matlab/bmm/carfac/CARFAC_Init.m	Mon Apr 09 06:15:05 2012 +0000
@@ -81,13 +81,26 @@
 
 function state = IHC_Init_State(coeffs)
 n_ch = coeffs.n_ch;
-state = struct( ...
-  'ihc_accum', zeros(n_ch, 1), ...
-  'cap_voltage', coeffs.rest_cap * ones(n_ch, 1), ...
-  'cap1_voltage', coeffs.rest_cap1 * ones(n_ch, 1), ...
-  'cap2_voltage', coeffs.rest_cap2* ones(n_ch, 1), ...
-  'lpf1_state', coeffs.rest_output * ones(n_ch, 1), ...
-  'lpf2_state', coeffs.rest_output * ones(n_ch, 1) ...
-  );
+if coeffs.just_hwr
+  state = struct('ihc_accum', zeros(n_ch, 1));
+else
+  if coeffs.one_cap
+    state = struct( ...
+      'ihc_accum', zeros(n_ch, 1), ...
+      'cap_voltage', coeffs.rest_cap * ones(n_ch, 1), ...
+      'lpf1_state', coeffs.rest_output * ones(n_ch, 1), ...
+      'lpf2_state', coeffs.rest_output * ones(n_ch, 1) ...
+      );
+  else
+    state = struct( ...
+      'ihc_accum', zeros(n_ch, 1), ...
+      'cap1_voltage', coeffs.rest_cap1 * ones(n_ch, 1), ...
+      'cap2_voltage', coeffs.rest_cap2* ones(n_ch, 1), ...
+      'lpf1_state', coeffs.rest_output * ones(n_ch, 1), ...
+      'lpf2_state', coeffs.rest_output * ones(n_ch, 1) ...
+      );
+  end
+end
 
-  
+
+