changeset 536:2964a3b4a00a

New design params, including narrower AGC, Greenwood map for more channels, default 71, some renaming, open loop feature, ...
author dicklyon@google.com
date Thu, 22 Mar 2012 22:37:56 +0000
parents dcf18d03d608
children 43c5664a00ec
files trunk/matlab/bmm/carfac/CARFAC_AGC_Step.m trunk/matlab/bmm/carfac/CARFAC_CAR_Step.m trunk/matlab/bmm/carfac/CARFAC_Design.m trunk/matlab/bmm/carfac/CARFAC_Init.m trunk/matlab/bmm/carfac/CARFAC_Run.m trunk/matlab/bmm/carfac/CARFAC_Run_Linear.m trunk/matlab/bmm/carfac/CARFAC_Run_Open_Loop.m trunk/matlab/bmm/carfac/CARFAC_Run_Segment.m trunk/matlab/bmm/carfac/CARFAC_Spatial_Smooth.m trunk/matlab/bmm/carfac/CARFAC_hacking.m trunk/matlab/bmm/carfac/MultiScaleSmooth.m
diffstat 11 files changed, 209 insertions(+), 77 deletions(-) [+]
line wrap: on
line diff
--- a/trunk/matlab/bmm/carfac/CARFAC_AGC_Step.m	Fri Mar 16 04:31:56 2012 +0000
+++ b/trunk/matlab/bmm/carfac/CARFAC_AGC_Step.m	Thu Mar 22 22:37:56 2012 +0000
@@ -71,9 +71,7 @@
   
   for ear = 1:n_ears
     AGC_in = ins(:,ear);  % the newly decimated input for this ear
-    
-%     AGC_in = max(0, AGC_in);  % don't let neg inputs in
-    
+        
     %  add the latest output (state) of next stage...
     if stage < n_stages
       AGC_in = AGC_in + stage_gain * state(ear).AGC_memory(:, stage+1);
--- a/trunk/matlab/bmm/carfac/CARFAC_CAR_Step.m	Fri Mar 16 04:31:56 2012 +0000
+++ b/trunk/matlab/bmm/carfac/CARFAC_CAR_Step.m	Thu Mar 22 22:37:56 2012 +0000
@@ -71,7 +71,3 @@
 state.zY_memory = zY;
 state.g_memory = g;
 
-% accum the straight hwr version in case someone wants it:
-hwr_detect = max(0, zY);  % detect with HWR
-state.detect_accum = state.detect_accum + hwr_detect;
-
--- a/trunk/matlab/bmm/carfac/CARFAC_Design.m	Fri Mar 16 04:31:56 2012 +0000
+++ b/trunk/matlab/bmm/carfac/CARFAC_Design.m	Thu Mar 22 22:37:56 2012 +0000
@@ -74,7 +74,8 @@
   % ERB = 24.7 * (1 + 4.37 * CF_Hz / 1000);
   ERB_Q = 1000/(24.7*4.37);  % 9.2645
   if nargin < 4
-    ERB_break_freq = 1000/4.37;  % 228.833
+%     ERB_break_freq = 1000/4.37;  % 228.833 G&M
+    ERB_break_freq = 165.3;  % Greenwood map's break freq.
   end
 end
 
@@ -84,9 +85,9 @@
     'time_constants', [1, 4, 16, 64]*0.002, ...
     'AGC_stage_gain', 2, ...  % gain from each stage to next slower stage
     'decimation', [8, 2, 2, 2], ...  % how often to update the AGC states
-    'AGC1_scales', [1, 2, 4, 6]*1, ...   % in units of channels
-    'AGC2_scales', [1, 2, 4, 6]*1.5, ... % spread more toward base
-    'detect_scale', 0.15, ...  % the desired damping range
+    'AGC1_scales', [1.0, 1.4,  2.0, 2.8], ...   % in units of channels
+    'AGC2_scales', [1.6, 2.25, 3.2, 4.5], ... % spread more toward base
+    'detect_scale', 0.25, ...  % the desired damping range
     'AGC_mix_coeff', 0.5);
 end
 
@@ -285,7 +286,7 @@
   % when FIR_OK, store the resulting FIR design in coeffs:
   AGC_coeffs.AGC_spatial_iterations(stage) = n_iterations;
   AGC_coeffs.AGC_spatial_FIR(:,stage) = AGC_spatial_FIR;
-  AGC_coeffs.AGC_n_taps(stage) = n_taps;
+  AGC_coeffs.AGC_spatial_n_taps(stage) = n_taps;
   
   % accumulate DC gains from all the stages, accounting for stage_gain:
   total_DC_gain = total_DC_gain + AGC_params.AGC_stage_gain^(stage-1);
@@ -302,8 +303,10 @@
 AGC_coeffs.AGC_gain = total_DC_gain;
 
 % % print some results
-% AGC_coeffs
-% AGC_spatial_FIR = AGC_coeffs.AGC_spatial_FIR
+AGC_coeffs
+AGC_spatial_FIR = AGC_coeffs.AGC_spatial_FIR
+AGC_spatial_iterations = AGC_coeffs.AGC_spatial_iterations
+AGC_spatial_n_taps = AGC_coeffs.AGC_spatial_n_taps
 
 
 %%
@@ -453,7 +456,7 @@
 %                 AGC_polez2: [0.2219 0.3165 0.4260 0.4414]
 %     AGC_spatial_iterations: [1 1 2 2]
 %            AGC_spatial_FIR: [3x4 double]
-%                 AGC_n_taps: [3 5 5 5]
+%         AGC_spatial_n_taps: [3 5 5 5]
 %             AGC_mix_coeffs: [0 0.0454 0.0227 0.0113]
 %                   AGC_gain: 15
 %               detect_scale: 0.0664
--- a/trunk/matlab/bmm/carfac/CARFAC_Init.m	Fri Mar 16 04:31:56 2012 +0000
+++ b/trunk/matlab/bmm/carfac/CARFAC_Init.m	Thu Mar 22 22:37:56 2012 +0000
@@ -28,7 +28,7 @@
 % level of object.  I like fewer structs and class types.
 
 if nargin < 2
-  n_ears = 1;  % monaural
+  n_ears = 1;  % monaural default
 end
 
 % % this is probably what I'd do in the C++ version:
@@ -54,38 +54,6 @@
   CF_struct.AGC_state(ear) = AGC_Init_State(CF_struct.AGC_coeffs);
 end
 
-% for ear = 1:n_ears
-%   CF_struct.CAR_state(ear).z1_memory = zeros(n_ch, 1);
-%   CF_struct.CAR_state(ear).z2_memory = zeros(n_ch, 1);
-%   CF_struct.CAR_state(ear).zA_memory = zeros(n_ch, 1);  % cubic loop
-%   CF_struct.CAR_state(ear).zB_memory = zeros(n_ch, 1);  % AGC interp
-%   CF_struct.CAR_state(ear).dzB_memory = zeros(n_ch, 1);  % AGC incr
-%   CF_struct.CAR_state(ear).zY_memory = zeros(n_ch, 1);
-%   CF_struct.CAR_state(ear).detect_accum = zeros(n_ch, 1);
-%   CF_struct.CAR_state(ear).g_memory = ...
-%     CF_struct.CAR_coeffs(ear).g0_coeffs;  % initial g for min_zeta
-%   CF_struct.CAR_state(ear).dg_memory = zeros(n_ch, 1);    % g interp
-%   % AGC loop filters' state:
-%   CF_struct.AGC_state(ear).AGC_memory = zeros(n_ch, n_AGC_stages);  % HACK init
-%   CF_struct.AGC_state(ear).input_accum = zeros(n_ch, n_AGC_stages);  % HACK init
-%   % IHC state:
-%   if CF_struct.IHC_coeffs.just_hwr
-%     CF_struct.IHC_state(ear).ihc_accum = zeros(n_ch, 1);
-%   else
-%     CF_struct.IHC_state(ear).cap_voltage = ...
-%       CF_struct.IHC_coeffs.rest_cap * ones(n_ch, 1);
-%     CF_struct.IHC_state(ear).cap1_voltage = ...
-%       CF_struct.IHC_coeffs.rest_cap1 * ones(n_ch, 1);
-%     CF_struct.IHC_state(ear).cap2_voltage = ...
-%       CF_struct.IHC_coeffs.rest_cap2 * ones(n_ch, 1);
-%     CF_struct.IHC_state(ear).lpf1_state = ...
-%       CF_struct.IHC_coeffs.rest_output * zeros(n_ch, 1);
-%     CF_struct.IHC_state(ear).lpf2_state = ...
-%       CF_struct.IHC_coeffs.rest_output * zeros(n_ch, 1);
-%     CF_struct.IHC_state(ear).ihc_accum = zeros(n_ch, 1);
-%   end
-% end
-
 
 function state = CAR_Init_State(coeffs)
 n_ch = coeffs.n_ch;
@@ -96,7 +64,6 @@
   'zB_memory', zeros(n_ch, 1), ...
   'dzB_memory', zeros(n_ch, 1), ...
   'zY_memory', zeros(n_ch, 1), ...
-  'detect_accum', zeros(n_ch, 1), ...
   'g_memory', coeffs.g0_coeffs, ...
   'dg_memory', zeros(n_ch, 1) ...
   );
--- a/trunk/matlab/bmm/carfac/CARFAC_Run.m	Fri Mar 16 04:31:56 2012 +0000
+++ b/trunk/matlab/bmm/carfac/CARFAC_Run.m	Thu Mar 22 22:37:56 2012 +0000
@@ -17,7 +17,7 @@
 % See the License for the specific language governing permissions and
 % limitations under the License.
 
-function [CF, decim_naps, naps] = CARFAC_Run ...
+function [CF, decim_naps, naps, BM] = CARFAC_Run ...
   (CF, input_waves, AGC_plot_fig_num)
 % function [CF, decim_naps, naps] = CARFAC_Run ...
 %   (CF, input_waves, AGC_plot_fig_num)
@@ -50,6 +50,12 @@
   AGC_plot_fig_num = 0;
 end
 
+if nargout > 3
+  BM = zeros(n_samp, n_ch, n_ears);
+else
+  BM = [];
+end
+
 if n_ears ~= CF.n_ears
   error('bad number of input_waves channels passed to CARFAC_Run')
 end
@@ -57,7 +63,7 @@
 
 naps = zeros(n_samp, n_ch, n_ears);
 
-seglen = 16;
+seglen = 256;
 n_segs = ceil(n_samp / seglen);
 
 if nargout > 1
@@ -82,7 +88,18 @@
     k_range = seglen*(seg_num - 1) + (1:seglen);
   end
   % Process a segment to get a slice of decim_naps, and plot AGC state:
-  [seg_naps, CF] = CARFAC_Run_Segment(CF, input_waves(k_range, :));
+  if ~isempty(BM)
+    [seg_naps, CF, seg_BM] = CARFAC_Run_Segment(CF, input_waves(k_range, :));
+  else
+    [seg_naps, CF] = CARFAC_Run_Segment(CF, input_waves(k_range, :));
+  end
+  
+  if ~isempty(BM)
+    for ear = 1:n_ears
+      % Accumulate segment BM to make full BM
+      BM(k_range, :, ear) = seg_BM(:, :, ear);
+    end
+  end
   
   if ~isempty(naps)
     for ear = 1:n_ears
@@ -109,11 +126,14 @@
       for stage = 1:3;
         plot(2^(stage-1) * (CF.AGC_state(ear).AGC_memory(:, stage) - ...
           2 * CF.AGC_state(ear).AGC_memory(:, stage+1)));
+        plot(2^(stage-1) * (CF.AGC_state(ear).AGC_memory(:, stage) - ...
+          0 * CF.AGC_state(ear).AGC_memory(:, stage+1)), 'r--');
       end
       stage = 4;
       plot(2^(stage-1) * CF.AGC_state(ear).AGC_memory(:, stage));
+      plot(2^(stage-1) * CF.AGC_state(ear).AGC_memory(:, stage), 'r--');
     end
-    axis([0, CF.n_ch+1, 0.0, max(maxes) + 0.01]);
+    axis([0, CF.n_ch+1, 0.0, max(maxes) * 1.01 + 0.002]);
     drawnow
   end
 
--- a/trunk/matlab/bmm/carfac/CARFAC_Run_Linear.m	Fri Mar 16 04:31:56 2012 +0000
+++ b/trunk/matlab/bmm/carfac/CARFAC_Run_Linear.m	Thu Mar 22 22:37:56 2012 +0000
@@ -49,7 +49,7 @@
 for k = 1:n_samp
   % at each time step, possibly handle multiple channels
   for ear = 1:n_ears
-    [filters_out, CF.CAR_state(ear)] = CARFAC_FilterStep( ...
+    [filters_out, CF.CAR_state(ear)] = CARFAC_CAR_Step( ...
       input_waves(k, ear), CF.CAR_coeffs, CF.CAR_state(ear));
     naps(k, :, ear) = filters_out;  % linear
   end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/trunk/matlab/bmm/carfac/CARFAC_Run_Open_Loop.m	Thu Mar 22 22:37:56 2012 +0000
@@ -0,0 +1,119 @@
+% Copyright 2012, Google, Inc.
+% Author Richard F. Lyon
+%
+% This Matlab file is part of an implementation of Lyon's cochlear model:
+% "Cascade of Asymmetric Resonators with Fast-Acting Compression"
+% to supplement Lyon's upcoming book "Human and Machine Hearing"
+%
+% Licensed under the Apache License, Version 2.0 (the "License");
+% you may not use this file except in compliance with the License.
+% You may obtain a copy of the License at
+%
+%     http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS,
+% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+% See the License for the specific language governing permissions and
+% limitations under the License.
+
+function [CF, decim_naps, naps] = CARFAC_Run_Open_Loop ...
+  (CF, input_waves, AGC_plot_fig_num)
+% function [CF, decim_naps, naps] = CARFAC_Run_Open_Loop ...
+%   (CF, input_waves, AGC_plot_fig_num)
+%
+% Freeze the damping by disabling AGC feedback, and run so we can
+% see what the filters and AGC do in that frozen state.  And zap the
+% stage gain in the AGC so we can see the state filters without combining
+% them.
+
+[n_samp, n_ears] = size(input_waves);
+n_ch = CF.n_ch;
+
+if nargin < 3
+  AGC_plot_fig_num = 0;
+end
+
+if n_ears ~= CF.n_ears
+  error('bad number of input_waves channels passed to CARFAC_Run')
+end
+
+
+naps = zeros(n_samp, n_ch, n_ears);
+
+seglen = 16;
+n_segs = ceil(n_samp / seglen);
+
+if nargout > 1
+  % make decimated detect output:
+  decim_naps = zeros(n_segs, CF.n_ch, CF.n_ears);
+else
+  decim_naps = [];
+end
+
+if nargout > 2
+  % make decimated detect output:
+  naps = zeros(n_samp, CF.n_ch, CF.n_ears);
+else
+  naps = [];
+end
+
+% zero the deltas:
+for ear = 1:CF.n_ears
+  CF.CAR_state(ear).dzB_memory = 0;
+  CF.CAR_state(ear).dg_memory = 0;
+end
+open_loop = 1;
+CF.AGC_coeffs.AGC_stage_gain = 0;  % HACK to see the stages separately
+
+smoothed_state = 0;
+
+for seg_num = 1:n_segs
+  if seg_num == n_segs
+    % The last segement may be short of seglen, but do it anyway:
+    k_range = (seglen*(seg_num - 1) + 1):n_samp;
+  else
+    k_range = seglen*(seg_num - 1) + (1:seglen);
+  end
+  % Process a segment to get a slice of decim_naps, and plot AGC state:
+  [seg_naps, CF] = CARFAC_Run_Segment(CF, input_waves(k_range, :), ...
+    open_loop);
+  
+  if ~isempty(naps)
+    for ear = 1:n_ears
+      % Accumulate segment naps to make full naps
+      naps(k_range, :, ear) = seg_naps(:, :, ear);
+    end
+  end
+  
+  if ~isempty(decim_naps)
+    for ear = 1:n_ears
+      decim_naps(seg_num, :, ear) = CF.IHC_state(ear).ihc_accum / seglen;
+      CF.IHC_state(ear).ihc_accum = zeros(n_ch,1);
+    end
+  end
+  
+  if AGC_plot_fig_num
+    figure(AGC_plot_fig_num); hold off; clf
+    set(gca, 'Position', [.25, .25, .5, .5])
+    smoothed_state = (3*smoothed_state + CF.AGC_state(1).AGC_memory) / 4;
+    for ear = 1
+      total_state = 0;
+      for stage = 1:4;
+        weighted_state = smoothed_state(:, stage) * 2^(stage-1);
+        plot(weighted_state, 'k-', 'LineWidth', 0.4);
+        hold on
+        total_state = total_state + weighted_state;
+      end
+      maxes(ear) = max(total_state);
+      plot(total_state, 'k-', 'LineWidth', 1.1)
+    end
+    
+    axis([0, CF.n_ch+1, 0.0, max(maxes) * 1.01 + 0.002]);
+    drawnow
+  end
+  
+end
+
+
+
--- a/trunk/matlab/bmm/carfac/CARFAC_Run_Segment.m	Fri Mar 16 04:31:56 2012 +0000
+++ b/trunk/matlab/bmm/carfac/CARFAC_Run_Segment.m	Thu Mar 22 22:37:56 2012 +0000
@@ -17,8 +17,8 @@
 % See the License for the specific language governing permissions and
 % limitations under the License.
 
-function [naps, CF] = CARFAC_Run_Segment(CF, input_waves)
-% function [naps, CF, decim_naps] = CARFAC_Run_Segment(CF, input_waves)
+function [naps, CF, BM] = CARFAC_Run_Segment(CF, input_waves, open_loop)
+% function [naps, CF, BM] = CARFAC_Run_Segment(CF, input_waves, open_loop)
 % 
 % This function runs the CARFAC; that is, filters a 1 or more channel
 % sound input segment to make one or more neural activity patterns (naps);
@@ -31,7 +31,7 @@
 %
 % naps has a row per time sample, a column per filterbank channel, and
 % a layer per audio channel if more than 1.
-% decim_naps is like naps but time-decimated by the int CF.decimation.
+% BM is basilar membrane motion (filter outputs before detection).
 %
 % the input_waves are assumed to be sampled at the same rate as the
 % CARFAC is designed for; a resampling may be needed before calling this.
@@ -45,6 +45,16 @@
 % CF = CARFAC_Design(fs, CF_CAR_params, CF_AGC_params, n_ears)
 % transfns = CARFAC_Transfer_Functions(CF, to_chans, from_chans)
 
+if nargin < 3
+  open_loop = 0;
+end
+
+if nargout > 2
+  do_BM = 1;
+else
+  do_BM = 0;
+end
+
 [n_samp, n_ears] = size(input_waves);
 
 if n_ears ~= CF.n_ears
@@ -53,6 +63,9 @@
 
 n_ch = CF.n_ch;
 naps = zeros(n_samp, n_ch, n_ears);  % allocate space for result
+if do_BM
+  BM = zeros(n_samp, n_ch, n_ears);
+end
 
 detects = zeros(n_ch, n_ears);
 for k = 1:n_samp
@@ -67,6 +80,9 @@
     
     detects(:, ear) = ihc_out;  % for input to AGC, and out to SAI
     naps(k, :, ear) = ihc_out;  % output to neural activity pattern  
+    if do_BM
+      BM(k, :, ear) = car_out;
+    end
   end
   % run the AGC update step, taking input from IHC_state, 
   % decimating internally, all ears at once due to mixing across them:
@@ -74,7 +90,7 @@
     CF.AGC_coeffs, detects, CF.AGC_state);
   
   % connect the feedback from AGC_state to CAR_state when it updates
-  if updated
+  if updated & ~open_loop
     CF = CARFAC_Close_AGC_Loop(CF);
   end
 end
--- a/trunk/matlab/bmm/carfac/CARFAC_Spatial_Smooth.m	Fri Mar 16 04:31:56 2012 +0000
+++ b/trunk/matlab/bmm/carfac/CARFAC_Spatial_Smooth.m	Thu Mar 22 22:37:56 2012 +0000
@@ -27,7 +27,7 @@
 
 if use_FIR
   FIR_coeffs = coeffs.AGC_spatial_FIR(:,stage);
-  switch coeffs.AGC_n_taps(stage)
+  switch coeffs.AGC_spatial_n_taps(stage)
     case 3
       for iter = 1:n_iterations
         stage_state = ...
@@ -45,10 +45,10 @@
           stage_state([3:end, end, end-1], :));
       end
     otherwise
-      error('Bad n_taps in CARFAC_Spatial_Smooth');
+      error('Bad AGC_spatial_n_taps in CARFAC_Spatial_Smooth');
   end
 else
-  % use IIR method, back-and-forth firt-order smoothers:
+  % use IIR method, back-and-forth first-order smoothers:
   stage_state = SmoothDoubleExponential(stage_state, ...
     coeffs.AGC_polez1(stage), coeffs.AGC_polez2(stage));
 end
--- a/trunk/matlab/bmm/carfac/CARFAC_hacking.m	Fri Mar 16 04:31:56 2012 +0000
+++ b/trunk/matlab/bmm/carfac/CARFAC_hacking.m	Thu Mar 22 22:37:56 2012 +0000
@@ -22,17 +22,33 @@
 clear variables
 
 %%
-file_signal = wavread('plan.wav');
-
-% file_signal = file_signal(9000+(1:10000));  % trim for a faster test
-file_signal = file_signal(9300+(1:5000));  % trim for a faster test
+use_plan_file = 0;
+if use_plan_file
+  
+  file_signal = wavread('plan.wav');
+  file_signal = file_signal(8100+(1:20000));  % trim for a faster test
+  
+else
+    flist = [1000];
+    alist = [1];
+    flist = 1000;
+    alist = 1;
+    sine_signal = 0;
+    times = (0:19999)' / 22050;
+    for fno = 1:length(flist)
+      sine_signal = sine_signal + alist(fno)*sin(flist(fno)*2*pi*times);
+    end
+    growth_power = 0;  % use 0 for flat, 4 or more for near exponential
+    file_signal = 1.0 * (sine_signal .* (times/max(times)).^growth_power);
+end
 
 % repeat with negated signal to compare responses:
 % file_signal = [file_signal; -file_signal];
 
 % make a long test signal by repeating at different levels:
-test_signal = [];
-for dB = -40:20:0  % -60:20:40  % -80:20:60
+dB = -80;
+test_signal =  10^(dB/20)* file_signal(1:4000) % lead-in [];
+for dB =  -80:20:80
   test_signal = [test_signal; file_signal * 10^(dB/20)];
 end
 
@@ -43,16 +59,20 @@
 
 agc_plot_fig_num = 6;
 
-for n_ears = 1:2
+for n_ears = 1  % 1:2
   CF_struct = CARFAC_Init(CF_struct, n_ears);
 
-  [CF_struct, nap_decim, nap] = CARFAC_Run(CF_struct, test_signal, ...
+  [CF_struct, nap_decim, nap, BM] = CARFAC_Run(CF_struct, test_signal, ...
     agc_plot_fig_num);
 
 %   nap = deskew(nap);  % deskew doesn't make much difference
 
+%   dB_BM = 10/log(10) * log(filter(1, [1, -0.995], BM(:, 38:40, :).^2));
+  dB_BM = 10/log(10) * log(filter(1, [1, -0.995], BM(:, 20:50, :).^2));
+
   if n_ears == 1  % because this hack doesn't work for binarual yet
-    MultiScaleSmooth(nap_decim, 4);
+    MultiScaleSmooth(dB_BM(5000:200:end, :, :), 1);
+%     MultiScaleSmooth(nap_decim, 4);
   end
 
   % Display results for 1 or 2 ears:
--- a/trunk/matlab/bmm/carfac/MultiScaleSmooth.m	Fri Mar 16 04:31:56 2012 +0000
+++ b/trunk/matlab/bmm/carfac/MultiScaleSmooth.m	Thu Mar 22 22:37:56 2012 +0000
@@ -61,10 +61,3 @@
 
 end
 
-
-function waves = deskew(waves)
-
-for col = 1:size(waves, 2)
-  waves(1:(end-col+1), col) = waves(col:end, col);
-end
-