changeset 529:75b33fd139db

Remove extra sample delay in CARFAC_FilterStep.m
author dicklyon@google.com
date Sat, 10 Mar 2012 06:22:56 +0000
parents 741187dc780f
children fb60ea429bb8
files trunk/matlab/bmm/carfac/CARFAC_FilterStep.m
diffstat 1 files changed, 21 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/trunk/matlab/bmm/carfac/CARFAC_FilterStep.m	Sat Mar 10 05:05:35 2012 +0000
+++ b/trunk/matlab/bmm/carfac/CARFAC_FilterStep.m	Sat Mar 10 06:22:56 2012 +0000
@@ -22,8 +22,7 @@
 %
 % One sample-time update step for the filter part of the CARFAC.
 
-% Use each stage previous Y as input to next:
-inputs = [x_in; state.zY_memory(1:(end-1))];
+% Most of the update is parallel; finally we ripple inputs at the end.
 
 % Local nonlinearity zA and AGC feedback zB reduce pole radius:
 zA = state.zA_memory;
@@ -39,21 +38,34 @@
 % now reduce state by r and rotate with the fixed cos/sin coeffs:
 z1 = r .* (filter_coeffs.a_coeffs .* state.z1_memory - ...
   filter_coeffs.c_coeffs .* state.z2_memory);
-z1 = z1 + inputs;
+% z1 = z1 + inputs;
 z2 = r .* (filter_coeffs.c_coeffs .* state.z1_memory + ...
   filter_coeffs.a_coeffs .* state.z2_memory);
 
 % update the "velocity" for cubic nonlinearity, into zA:
 zA = (((state.z2_memory - z2) .* filter_coeffs.velocity_scale) + ...
   v_offset) .^ 2;
-zA = v_damp_max * zA ./ (v2_corner + zA);  % make it more like an "essential" nonlinearity
+% soft saturation to make it more like an "essential" nonlinearity:
+zA = v_damp_max * zA ./ (v2_corner + zA);
 
 % Adjust gain for r variation:
 g = filter_coeffs.g_coeffs;
 g = g .* (1 + filter_coeffs.gr_coeffs .* (1 - r).^2);
 
-% Get outputs from inputs and new z2 values:
-zY = g .* (inputs + filter_coeffs.h_coeffs .* z2);
+gh = g .* filter_coeffs.h_coeffs;
+zY = gh .* z2;  % partial output; still need to ripple in_out
+% ripples input-output path instead of parallel, to avoid delay...
+% this is the only path that doesn't get computed "in parallel":
+in_out = x_in;
+for ch = 1:length(zY)
+  % could do this here, or later in parallel:
+  z1(ch) = z1(ch) + in_out;
+  % ripple, saving output in zY
+  in_out = g(ch) * in_out + zY(ch);
+  zY(ch) = in_out;
+end
+% % final parallel step is the effect of inputs on state z1:
+% z1 = z1 + [x_in; zY(1:(end-1))];
 
 % put new state back in place of old
 state.z1_memory = z1;
@@ -62,7 +74,7 @@
 state.zB_memory = zB;
 state.zY_memory = zY;
 
-% % accum the straight hwr version for the sake of AGC range:
-% hwr_detect = max(0, zY);  % detect with HWR
-% state.detect_accum = state.detect_accum + hwr_detect;
+% 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;