diff matlab/bmm/carfac/CARFAC_CAR_Step.m @ 473:b4da807f4318

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
children 52f659be9008
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/matlab/bmm/carfac/CARFAC_CAR_Step.m	Fri Mar 16 04:19:24 2012 +0000
@@ -0,0 +1,77 @@
+% 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 [zY, state] = CARFAC_CAR_Step(x_in, CAR_coeffs, state)
+% function [zY, state] = CARFAC_CAR_Step(x_in, CAR_coeffs, state)
+%
+% One sample-time update step for the filter part of the CARFAC.
+
+% 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;
+zB = state.zB_memory + state.dzB_memory; % AGC interpolation
+r1 = CAR_coeffs.r1_coeffs;
+g = state.g_memory + state.dg_memory;  % interp g
+v_offset  = CAR_coeffs.v_offset;
+v2_corner = CAR_coeffs.v2_corner;
+v_damp_max = CAR_coeffs.v_damp_max;
+
+% zB and zA are "extra damping", and multiply zr (compressed theta):
+r = r1 - CAR_coeffs.zr_coeffs .* (zA + zB); 
+
+% now reduce state by r and rotate with the fixed cos/sin coeffs:
+z1 = r .* (CAR_coeffs.a0_coeffs .* state.z1_memory - ...
+  CAR_coeffs.c0_coeffs .* state.z2_memory);
+% z1 = z1 + inputs;
+z2 = r .* (CAR_coeffs.c0_coeffs .* state.z1_memory + ...
+  CAR_coeffs.a0_coeffs .* state.z2_memory);
+
+% update the "velocity" for cubic nonlinearity, into zA:
+zA = (((state.z2_memory - z2) .* CAR_coeffs.velocity_scale) + ...
+  v_offset) .^ 2;
+% soft saturation to make it more like an "essential" nonlinearity:
+zA = v_damp_max * zA ./ (v2_corner + zA);
+
+zY = CAR_coeffs.h_coeffs .* z2;  % partial output
+
+% Ripple input-output path, instead of parallel, to avoid delay...
+% this is the only part 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 final channel outputs in zY
+  in_out = g(ch) * (in_out + zY(ch));
+  zY(ch) = in_out;
+end
+
+% put new state back in place of old
+% (z1 and z2 are genuine temps; the others can update by reference in C)
+state.z1_memory = z1;
+state.z2_memory = z2;
+state.zA_memory = zA;
+state.zB_memory = zB;
+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;
+