diff trunk/matlab/bmm/carfac/CARFAC_Design.m @ 534:95a11cca4619

Add CARFAC_Design_Doc.txt, CARFAC_Run_Segment.m, and some renames; rename various variables to be more parallel; clean up init code and such.
author dicklyon@google.com
date Fri, 16 Mar 2012 04:19:24 +0000
parents 55c46c01e522
children 2964a3b4a00a
line wrap: on
line diff
--- a/trunk/matlab/bmm/carfac/CARFAC_Design.m	Mon Mar 12 06:14:53 2012 +0000
+++ b/trunk/matlab/bmm/carfac/CARFAC_Design.m	Fri Mar 16 04:19:24 2012 +0000
@@ -17,9 +17,9 @@
 % See the License for the specific language governing permissions and
 % limitations under the License.
 
-function CF = CARFAC_Design(fs, CF_filter_params, ...
+function CF = CARFAC_Design(fs, CF_CAR_params, ...
   CF_AGC_params, ERB_break_freq, ERB_Q, CF_IHC_params)
-% function CF = CARFAC_Design(fs, CF_filter_params, ...
+% function CF = CARFAC_Design(fs, CF_CAR_params, ...
 %   CF_AGC_params, ERB_break_freq, ERB_Q, CF_IHC_params)
 %
 % This function designs the CARFAC (Cascade of Asymmetric Resonators with
@@ -27,7 +27,7 @@
 % computes all the filter coefficients needed to run it.
 %
 % fs is sample rate (per second)
-% CF_filter_params bundles all the pole-zero filter cascade parameters
+% CF_CAR_params bundles all the pole-zero filter cascade parameters
 % CF_AGC_params bundles all the automatic gain control parameters
 % CF_IHC_params bundles all the inner hair cell parameters
 %
@@ -91,7 +91,7 @@
 end
 
 if nargin < 2
-  CF_filter_params = struct( ...
+  CF_CAR_params = struct( ...
     'velocity_scale', 0.2, ...  % for the "cubic" velocity nonlinearity
     'v_offset', 0.01, ...  % offset gives a quadratic part
     'v2_corner', 0.2, ...  % corner for essential nonlin
@@ -109,20 +109,20 @@
 end
 
 % first figure out how many filter stages (PZFC/CARFAC channels):
-pole_Hz = CF_filter_params.first_pole_theta * fs / (2*pi);
+pole_Hz = CF_CAR_params.first_pole_theta * fs / (2*pi);
 n_ch = 0;
-while pole_Hz > CF_filter_params.min_pole_Hz
+while pole_Hz > CF_CAR_params.min_pole_Hz
   n_ch = n_ch + 1;
-  pole_Hz = pole_Hz - CF_filter_params.ERB_per_step * ...
+  pole_Hz = pole_Hz - CF_CAR_params.ERB_per_step * ...
     ERB_Hz(pole_Hz, ERB_break_freq, ERB_Q);
 end
 % Now we have n_ch, the number of channels, so can make the array
 % and compute all the frequencies again to put into it:
 pole_freqs = zeros(n_ch, 1);
-pole_Hz = CF_filter_params.first_pole_theta * fs / (2*pi);
+pole_Hz = CF_CAR_params.first_pole_theta * fs / (2*pi);
 for ch = 1:n_ch
   pole_freqs(ch) = pole_Hz;
-  pole_Hz = pole_Hz - CF_filter_params.ERB_per_step * ...
+  pole_Hz = pole_Hz - CF_CAR_params.ERB_per_step * ...
     ERB_Hz(pole_Hz, ERB_break_freq, ERB_Q);
 end
 % now we have n_ch, the number of channels, and pole_freqs array
@@ -132,45 +132,48 @@
 CF = struct( ...
   'fs', fs, ...
   'max_channels_per_octave', max_channels_per_octave, ...
-  'filter_params', CF_filter_params, ...
+  'CAR_params', CF_CAR_params, ...
   'AGC_params', CF_AGC_params, ...
   'IHC_params', CF_IHC_params, ...
   'n_ch', n_ch, ...
   'pole_freqs', pole_freqs, ...
-  'filter_coeffs', CARFAC_DesignFilters(CF_filter_params, fs, pole_freqs), ...
-  'AGC_coeffs', CARFAC_DesignAGC(CF_AGC_params, fs), ...
-  'IHC_coeffs', CARFAC_DesignIHC(CF_IHC_params, fs), ...
-  'n_mics', 0 );
+  'CAR_coeffs', CARFAC_DesignFilters(CF_CAR_params, fs, pole_freqs), ...
+  'AGC_coeffs', CARFAC_DesignAGC(CF_AGC_params, fs, n_ch), ...
+  '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:
-function filter_coeffs = CARFAC_DesignFilters(filter_params, fs, pole_freqs)
+function CAR_coeffs = CARFAC_DesignFilters(CAR_params, fs, pole_freqs)
 
 n_ch = length(pole_freqs);
 
 % the filter design coeffs:
 
-filter_coeffs = struct('velocity_scale', filter_params.velocity_scale, ...
-  'v_offset', filter_params.v_offset, ...
-  'v2_corner', filter_params.v2_corner, ...
-  'v_damp_max', filter_params.v_damp_max ...
+CAR_coeffs = struct( ...
+  'n_ch', n_ch, ...
+  'velocity_scale', CAR_params.velocity_scale, ...
+  'v_offset', CAR_params.v_offset, ...
+  'v2_corner', CAR_params.v2_corner, ...
+  'v_damp_max', CAR_params.v_damp_max ...
   );
 
-filter_coeffs.r1_coeffs = zeros(n_ch, 1);
-filter_coeffs.a0_coeffs = zeros(n_ch, 1);
-filter_coeffs.c0_coeffs = zeros(n_ch, 1);
-filter_coeffs.h_coeffs = zeros(n_ch, 1);
-filter_coeffs.g0_coeffs = zeros(n_ch, 1);
+CAR_coeffs.r1_coeffs = zeros(n_ch, 1);
+CAR_coeffs.a0_coeffs = zeros(n_ch, 1);
+CAR_coeffs.c0_coeffs = zeros(n_ch, 1);
+CAR_coeffs.h_coeffs = zeros(n_ch, 1);
+CAR_coeffs.g0_coeffs = zeros(n_ch, 1);
 
 % zero_ratio comes in via h.  In book's circuit D, zero_ratio is 1/sqrt(a),
 % and that a is here 1 / (1+f) where h = f*c.
 % solve for f:  1/zero_ratio^2 = 1 / (1+f)
 % zero_ratio^2 = 1+f => f = zero_ratio^2 - 1
-f = filter_params.zero_ratio^2 - 1;  % nominally 1 for half-octave
+f = CAR_params.zero_ratio^2 - 1;  % nominally 1 for half-octave
 
 % Make pole positions, s and c coeffs, h and g coeffs, etc.,
 % which mostly depend on the pole angle theta:
@@ -180,47 +183,50 @@
 a0 = cos(theta);
 
 % different possible interpretations for min-damping r:
-% r = exp(-theta * CF_filter_params.min_zeta).
+% r = exp(-theta * CF_CAR_params.min_zeta).
 % Compress theta to give somewhat higher Q at highest thetas:
-ff = filter_params.high_f_damping_compression;  % 0 to 1; typ. 0.5
+ff = CAR_params.high_f_damping_compression;  % 0 to 1; typ. 0.5
 x = theta/pi;
 zr_coeffs = pi * (x - ff * x.^3);  % when ff is 0, this is just theta,
 %                       and when ff is 1 it goes to zero at theta = pi.
-filter_coeffs.zr_coeffs = zr_coeffs;  % how r relates to zeta
+CAR_coeffs.zr_coeffs = zr_coeffs;  % how r relates to zeta
 
-min_zeta = filter_params.min_zeta;
+min_zeta = CAR_params.min_zeta;
 % increase the min damping where channels are spaced out more:
 min_zeta = min_zeta + 0.25*(ERB_Hz(pole_freqs) ./ pole_freqs - min_zeta);
 r1 = (1 - zr_coeffs .* min_zeta);  % "1" for the min-damping condition
 
-filter_coeffs.r1_coeffs = r1;
+CAR_coeffs.r1_coeffs = r1;
 
 % undamped coupled-form coefficients:
-filter_coeffs.a0_coeffs = a0;
-filter_coeffs.c0_coeffs = c0;
+CAR_coeffs.a0_coeffs = a0;
+CAR_coeffs.c0_coeffs = c0;
 
 % the zeros follow via the h_coeffs
 h = c0 .* f;
-filter_coeffs.h_coeffs = h;
+CAR_coeffs.h_coeffs = h;
 
 % for unity gain at min damping, radius r; only used in CARFAC_Init:
 extra_damping = zeros(size(r1));
-% this function needs to take filter_coeffs even if we haven't finished
+% this function needs to take CAR_coeffs even if we haven't finished
 % constucting it by putting in the g0_coeffs:
-filter_coeffs.g0_coeffs = CARFAC_Stage_g(filter_coeffs, extra_damping);
+CAR_coeffs.g0_coeffs = CARFAC_Stage_g(CAR_coeffs, extra_damping);
 
 
 %% the AGC design coeffs:
-function AGC_coeffs = CARFAC_DesignAGC(AGC_params, fs)
+function AGC_coeffs = CARFAC_DesignAGC(AGC_params, fs, n_ch)
 
-AGC_coeffs = struct('AGC_stage_gain', AGC_params.AGC_stage_gain);
+n_AGC_stages = AGC_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
 AGC1_scales = AGC_params.AGC1_scales;
 AGC2_scales = AGC_params.AGC2_scales;
 
-n_AGC_stages = AGC_params.n_stages;
 AGC_coeffs.AGC_epsilon = zeros(1, n_AGC_stages);  % the 1/(tau*fs) roughly
 decim = 1;
 AGC_coeffs.decimation = AGC_params.decimation;
@@ -327,14 +333,15 @@
 
 
 %% the IHC design coeffs:
-function IHC_coeffs = CARFAC_DesignIHC(IHC_params, fs)
+function IHC_coeffs = CARFAC_DesignIHC(IHC_params, fs, n_ch)
 
 if IHC_params.just_hwr
   IHC_coeffs = struct('just_hwr', 1);
   IHC_coeffs.saturation_output = 10;  % HACK: assume some max out
 else
   if IHC_params.one_cap
-    IHC_coeffs = struct(...
+    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), ...
@@ -342,6 +349,7 @@
       'one_cap', IHC_params.one_cap);
   else
     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), ...
@@ -361,9 +369,9 @@
     'lpf2_state', 0, ...
     'ihc_accum', 0);
   
-  IHC_in = 0;
-  for k = 1:30000
-    [IHC_out, IHC_state] = CARFAC_IHCStep(IHC_in, IHC_coeffs, IHC_state);
+  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;
@@ -373,8 +381,8 @@
   
   LARGE = 2;
   IHC_in = LARGE;  % "Large" saturating input to IHC; make it alternate
-  for k = 1:30000
-    [IHC_out, IHC_state] = CARFAC_IHCStep(IHC_in, IHC_coeffs, IHC_state);
+  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
@@ -388,24 +396,24 @@
 %
 %
 % CF = CARFAC_Design
-% CF.filter_params
+% CF.CAR_params
 % CF.AGC_params
-% CF.filter_coeffs
+% CF.CAR_coeffs
 % CF.AGC_coeffs
 % CF.IHC_coeffs
 %
 % CF = 
 %                          fs: 22050
 %     max_channels_per_octave: 12.1873
-%               filter_params: [1x1 struct]
+%               CAR_params: [1x1 struct]
 %                  AGC_params: [1x1 struct]
 %                  IHC_params: [1x1 struct]
 %                        n_ch: 66
 %                  pole_freqs: [66x1 double]
-%               filter_coeffs: [1x1 struct]
+%               CAR_coeffs: [1x1 struct]
 %                  AGC_coeffs: [1x1 struct]
 %                  IHC_coeffs: [1x1 struct]
-%                      n_mics: 0
+%                      n_ears: 0
 % ans = 
 %                 velocity_scale: 0.2000
 %                       v_offset: 0.0100