changeset 559:89b1fe5de60f

Simplify AGC_Step, moving multi-aural cross coupling to new function CARFAC_Cross_Couple
author dicklyon@google.com
date Tue, 10 Apr 2012 05:40:18 +0000
parents 8ca6eb401a03
children ab7fabe2af5d
files trunk/matlab/bmm/carfac/CARFAC_AGC_Step.m trunk/matlab/bmm/carfac/CARFAC_Cross_Couple.m trunk/matlab/bmm/carfac/CARFAC_Design.m trunk/matlab/bmm/carfac/CARFAC_Run_Segment.m trunk/matlab/bmm/carfac/CARFAC_hacking.m
diffstat 5 files changed, 89 insertions(+), 94 deletions(-) [+]
line wrap: on
line diff
--- a/trunk/matlab/bmm/carfac/CARFAC_AGC_Step.m	Mon Apr 09 13:22:28 2012 +0000
+++ b/trunk/matlab/bmm/carfac/CARFAC_AGC_Step.m	Tue Apr 10 05:40:18 2012 +0000
@@ -17,96 +17,53 @@
 % See the License for the specific language governing permissions and
 % limitations under the License.
 
-function [state, updated] = CARFAC_AGC_Step(AGC_coeffs, detects, state)
-% function [state, updated] = CARFAC_AGC_Step(AGC_coeffs, detects, state)
+function [state, updated] = CARFAC_AGC_Step(coeffs, detects, state)
+% function [state, updated] = CARFAC_AGC_Step(coeffs, detects, state)
 %
-% one time step (at decimated low AGC rate) of the AGC state update
-
-n_ears = length(state);
-[n_ch, n_AGC_stages] = size(state(1).AGC_memory);  % number of channels
-
-optimize_for_mono = n_ears == 1;  % mono optimization
+% one time step of the AGC state update; decimates internally
 
 stage = 1;
-ins = AGC_coeffs.detect_scale * detects;
-[state, updated] = CARFAC_AGC_Recurse(AGC_coeffs, ins, n_AGC_stages, ...
-  n_ears, n_ch, optimize_for_mono, stage, state);
+AGC_in = coeffs.detect_scale * detects;
+[state, updated] = CARFAC_AGC_Recurse(coeffs, AGC_in, stage, state);
 
 
+function [state, updated] = CARFAC_AGC_Recurse(coeffs, AGC_in, ...
+  stage, state)
+% function [state, updated] = CARFAC_AGC_Recurse(coeffs, AGC_in, ...
+%   stage, state)
 
-
-
-function [state, updated] = CARFAC_AGC_Recurse(coeffs, ins, n_stages, ...
-  n_ears, n_ch, mono, stage, state)
-% function [state, updated = CARFAC_AGC_Recurse(coeffs, ins, n_stages, ...
-%   n_ears, n_ch, mono, stage, state)
-
-decim = coeffs.decimation(stage);  % decim phase for this stage
+% decim factor for this stage, relative to input or prev. stage:
+decim = coeffs.decimation(stage);
+% decim phase of this stage (do work on phase 0 only):
 decim_phase = mod(state(1).decim_phase(stage) + 1, decim);
-state(1).decim_phase(stage) = decim_phase;
+state.decim_phase(stage) = decim_phase;
 
 % accumulate input for this stage from detect or previous stage:
-for ear = 1:n_ears
-  state(ear).input_accum(:, stage) = ...
-    state(ear).input_accum(:, stage) + ins(:, ear);
-end
+state.input_accum(:, stage) = state.input_accum(:, stage) + AGC_in;
 
 % nothing else to do if it's not the right decim_phase
 if decim_phase == 0
-  % do lots of work, at decimated rate
+  % do lots of work, at decimated rate.
+  % decimated inputs for this stage, and to be decimated more for next:
+  AGC_in = state.input_accum(:, stage) / decim;
+  state.input_accum(:, stage) = 0;  % reset accumulator
   
-  % decimated inputs for this stage, and to be decimated more for next:
-  for ear = 1:n_ears
-    ins(:,ear) = state(ear).input_accum(:, stage) / decim;
-    state(ear).input_accum(:, stage) = 0;  % reset accumulator
+  if stage < length(coeffs.decimation)  % recurse to evaluate next stage(s)
+    state = CARFAC_AGC_Recurse(coeffs, AGC_in, stage+1, state);
+    % and add its output to this stage input, whether it updated or not:
+    AGC_in = AGC_in + coeffs.AGC_stage_gain * state.AGC_memory(:, stage+1);
   end
   
-  if stage < n_stages  % recurse to evaluate next stage(s)
-    state = CARFAC_AGC_Recurse(coeffs, ins, n_stages, ...
-      n_ears, n_ch, mono, stage+1, state);
-  end
+  AGC_stage_state = state.AGC_memory(:, stage);
+  % first-order recursive smoothing filter update, in time:
+  AGC_stage_state = AGC_stage_state + ...
+    coeffs.AGC_epsilon(stage) * (AGC_in - AGC_stage_state);
+  % spatial smooth:
+  AGC_stage_state = ...
+    CARFAC_Spatial_Smooth(coeffs, stage, AGC_stage_state);
+  % and store the state back (in C++, do it all in place?)
+  state.AGC_memory(:, stage) = AGC_stage_state;
   
-  epsilon = coeffs.AGC_epsilon(stage);  % for this stage's LPF pole
-  stage_gain = coeffs.AGC_stage_gain;
-  
-  for ear = 1:n_ears
-    AGC_in = ins(:,ear);  % the newly decimated input for this ear
-        
-    %  add the latest output (state) of next stage...
-    if stage < n_stages
-      AGC_in = AGC_in + stage_gain * state(ear).AGC_memory(:, stage+1);
-    end
-    
-    AGC_stage_state = state(ear).AGC_memory(:, stage);
-    % first-order recursive smoothing filter update, in time:
-    AGC_stage_state = AGC_stage_state + ...
-                        epsilon * (AGC_in - AGC_stage_state);
-    % spatial smooth:
-    AGC_stage_state = ...
-                  CARFAC_Spatial_Smooth(coeffs, stage, AGC_stage_state);
-    % and store the state back (in C++, do it all in place?)
-    state(ear).AGC_memory(:, stage) = AGC_stage_state;
-    
-    if ~mono
-      if ear == 1
-        this_stage_sum =  AGC_stage_state;
-      else
-        this_stage_sum = this_stage_sum + AGC_stage_state;
-      end
-    end
-  end
-  if ~mono
-    mix_coeff = coeffs.AGC_mix_coeffs(stage);
-    if mix_coeff > 0
-      this_stage_mean = this_stage_sum / n_ears;
-      for ear = 1:n_ears
-        state(ear).AGC_memory(:, stage) = ...
-          state(ear).AGC_memory(:, stage) + ...
-            mix_coeff * ...
-              (this_stage_mean - state(ear).AGC_memory(:, stage));
-      end
-    end
-  end
   updated = 1;  % bool to say we have new state
 else
   updated = 0;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/trunk/matlab/bmm/carfac/CARFAC_Cross_Couple.m	Tue Apr 10 05:40:18 2012 +0000
@@ -0,0 +1,29 @@
+function AGC_state = CARFAC_Cross_Couple(AGC_coeffs, AGC_state);
+
+n_ears = length(AGC_state);
+mix_coeffs = AGC_coeffs.AGC_mix_coeffs;
+n_stages = length(mix_coeffs);
+
+% now cross-ear mix the stages that updated (leading stages at phase 0):
+for stage = 1:n_stages
+  if AGC_state(1).decim_phase(stage) > 0
+    break  % all recently updated stages are finished
+  else
+    mix_coeff = mix_coeffs(stage);
+    if mix_coeff > 0  % Typically stage 1 has 0 so no work on that one.
+      this_stage_sum = 0;
+      % sum up over the ears and get their mean:
+      for ear = 1:n_ears
+        stage_state = AGC_state(ear).AGC_memory(:, stage);
+        this_stage_sum = this_stage_sum + stage_state;
+      end
+      this_stage_mean = this_stage_sum / n_ears;
+      % now move them all toward the mean:
+      for ear = 1:n_ears
+        stage_state = AGC_state(ear).AGC_memory(:, stage);
+        AGC_state(ear).AGC_memory(:, stage) = ...
+          stage_state +  mix_coeff * (this_stage_mean - stage_state);
+      end
+    end
+  end
+end
--- a/trunk/matlab/bmm/carfac/CARFAC_Design.m	Mon Apr 09 13:22:28 2012 +0000
+++ b/trunk/matlab/bmm/carfac/CARFAC_Design.m	Tue Apr 10 05:40:18 2012 +0000
@@ -151,6 +151,8 @@
   'v_damp_max', CAR_params.v_damp_max ...
   );
 
+% don't really need these zero arrays, but it's a clue to what fields
+% and types are need in ohter language implementations:
 CAR_coeffs.r1_coeffs = zeros(n_ch, 1);
 CAR_coeffs.a0_coeffs = zeros(n_ch, 1);
 CAR_coeffs.c0_coeffs = zeros(n_ch, 1);
@@ -213,7 +215,7 @@
   '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
+% 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;
 
@@ -294,7 +296,6 @@
 % 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
--- a/trunk/matlab/bmm/carfac/CARFAC_Run_Segment.m	Mon Apr 09 13:22:28 2012 +0000
+++ b/trunk/matlab/bmm/carfac/CARFAC_Run_Segment.m	Tue Apr 10 05:40:18 2012 +0000
@@ -78,20 +78,27 @@
     [ihc_out, CF.IHC_state(ear)] = CARFAC_IHC_Step( ...
       car_out, CF.IHC_coeffs, CF.IHC_state(ear));
     
-    detects(:, ear) = ihc_out;  % for input to AGC, and out to SAI
-    naps(k, :, ear) = ihc_out;  % output to neural activity pattern  
+    % run the AGC update step, decimating internally,
+    [CF.AGC_state(ear), updated] = CARFAC_AGC_Step( ...
+      CF.AGC_coeffs, ihc_out, CF.AGC_state(ear));
+    
+    % save some output data:
+    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:
-  [CF.AGC_state, updated] = CARFAC_AGC_Step( ...
-    CF.AGC_coeffs, detects, CF.AGC_state);
   
-  % connect the feedback from AGC_state to CAR_state when it updates
-  if updated & ~open_loop
-    CF = CARFAC_Close_AGC_Loop(CF);
+  % connect the feedback from AGC_state to CAR_state when it updates;
+  % all ears together here due to mixing across them:
+  if updated 
+    if n_ears > 1
+      % do multi-aural cross-coupling:
+      CF.AGC_state = CARFAC_Cross_Couple(CF.AGC_coeffs, CF.AGC_state);
+    end
+    if ~open_loop
+      CF = CARFAC_Close_AGC_Loop(CF);
+    end
   end
 end
 
--- a/trunk/matlab/bmm/carfac/CARFAC_hacking.m	Mon Apr 09 13:22:28 2012 +0000
+++ b/trunk/matlab/bmm/carfac/CARFAC_hacking.m	Tue Apr 10 05:40:18 2012 +0000
@@ -22,7 +22,7 @@
 clear variables
 
 %%
-use_plan_file = 0;
+use_plan_file = 1;
 if use_plan_file
   
   file_signal = wavread('plan.wav');
@@ -48,7 +48,7 @@
 % make a long test signal by repeating at different levels:
 dB = -80;
 test_signal =  10^(dB/20)* file_signal(1:4000) % lead-in [];
-for dB =  -80:20:80
+for dB =  -80:20:60
   test_signal = [test_signal; file_signal * 10^(dB/20)];
 end
 
@@ -59,7 +59,12 @@
 
 agc_plot_fig_num = 6;
 
-for n_ears = 1  % 1:2
+for n_ears = 1:2
+  if n_ears == 2
+    % For the 2-channel pass, add a silent second channel:
+    test_signal = [test_signal, zeros(size(test_signal))];
+  end
+  
   CF_struct = CARFAC_Init(CF_struct, n_ears);
 
   [CF_struct, nap_decim, nap, BM] = CARFAC_Run(CF_struct, test_signal, ...
@@ -70,10 +75,8 @@
 %   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(dB_BM(5000:200:end, :, :), 1);
-%     MultiScaleSmooth(nap_decim, 4);
-  end
+  % only ear 1:
+  MultiScaleSmooth(dB_BM(5000:200:end, :, 1), 1);
 
   % Display results for 1 or 2 ears:
   for ear = 1:n_ears
@@ -93,8 +96,6 @@
   CF_struct.AGC_state
   min_max_decim = [min(nap_decim(:)), max(nap_decim(:))]
 
-  % For the 2-channel pass, add a silent second channel:
-  test_signal = [test_signal, zeros(size(test_signal))];
 end
 
 % Expected result:  Figure 3 looks like figure 2, a tiny bit darker.