dicklyon@534
|
1 % Copyright 2012, Google, Inc.
|
dicklyon@534
|
2 % Author: Richard F. Lyon
|
dicklyon@534
|
3 %
|
dicklyon@534
|
4 % This Matlab file is part of an implementation of Lyon's cochlear model:
|
dicklyon@534
|
5 % "Cascade of Asymmetric Resonators with Fast-Acting Compression"
|
dicklyon@534
|
6 % to supplement Lyon's upcoming book "Human and Machine Hearing"
|
dicklyon@534
|
7 %
|
dicklyon@534
|
8 % Licensed under the Apache License, Version 2.0 (the "License");
|
dicklyon@534
|
9 % you may not use this file except in compliance with the License.
|
dicklyon@534
|
10 % You may obtain a copy of the License at
|
dicklyon@534
|
11 %
|
dicklyon@534
|
12 % http://www.apache.org/licenses/LICENSE-2.0
|
dicklyon@534
|
13 %
|
dicklyon@534
|
14 % Unless required by applicable law or agreed to in writing, software
|
dicklyon@534
|
15 % distributed under the License is distributed on an "AS IS" BASIS,
|
dicklyon@534
|
16 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
dicklyon@534
|
17 % See the License for the specific language governing permissions and
|
dicklyon@534
|
18 % limitations under the License.
|
dicklyon@534
|
19
|
dicklyon@565
|
20 function [car_out, state] = CARFAC_CAR_Step(x_in, CAR_coeffs, state)
|
dicklyon@534
|
21 % function [zY, state] = CARFAC_CAR_Step(x_in, CAR_coeffs, state)
|
dicklyon@534
|
22 %
|
dicklyon@534
|
23 % One sample-time update step for the filter part of the CARFAC.
|
dicklyon@534
|
24
|
dicklyon@534
|
25 % Most of the update is parallel; finally we ripple inputs at the end.
|
dicklyon@534
|
26
|
dicklyon@565
|
27
|
dicklyon@565
|
28 % do the DOHC stuff:
|
dicklyon@565
|
29
|
dicklyon@565
|
30 g = state.g_memory + state.dg_memory; % interp g
|
dicklyon@565
|
31 zB = state.zB_memory + state.dzB_memory; % AGC interpolation state
|
dicklyon@565
|
32 % update the nonlinear function of "velocity", and zA (delay of z2):
|
dicklyon@534
|
33 zA = state.zA_memory;
|
dicklyon@565
|
34 v = state.z2_memory - zA;
|
dicklyon@565
|
35 % nlf = CARFAC_OHC_NLF(v .* widen, CAR_coeffs); % widen v with feedback
|
dicklyon@565
|
36 nlf = CARFAC_OHC_NLF(v, CAR_coeffs);
|
dicklyon@565
|
37 % zB * nfl is "undamping" delta r:
|
dicklyon@565
|
38 r = CAR_coeffs.r1_coeffs + zB .* nlf;
|
dicklyon@565
|
39 zA = state.z2_memory;
|
dicklyon@534
|
40
|
dicklyon@534
|
41
|
dicklyon@534
|
42 % now reduce state by r and rotate with the fixed cos/sin coeffs:
|
dicklyon@534
|
43 z1 = r .* (CAR_coeffs.a0_coeffs .* state.z1_memory - ...
|
dicklyon@534
|
44 CAR_coeffs.c0_coeffs .* state.z2_memory);
|
dicklyon@534
|
45 % z1 = z1 + inputs;
|
dicklyon@534
|
46 z2 = r .* (CAR_coeffs.c0_coeffs .* state.z1_memory + ...
|
dicklyon@534
|
47 CAR_coeffs.a0_coeffs .* state.z2_memory);
|
dicklyon@534
|
48
|
dicklyon@534
|
49 zY = CAR_coeffs.h_coeffs .* z2; % partial output
|
dicklyon@534
|
50
|
dicklyon@534
|
51 % Ripple input-output path, instead of parallel, to avoid delay...
|
dicklyon@534
|
52 % this is the only part that doesn't get computed "in parallel":
|
dicklyon@534
|
53 in_out = x_in;
|
dicklyon@534
|
54 for ch = 1:length(zY)
|
dicklyon@534
|
55 % could do this here, or later in parallel:
|
dicklyon@534
|
56 z1(ch) = z1(ch) + in_out;
|
dicklyon@534
|
57 % ripple, saving final channel outputs in zY
|
dicklyon@534
|
58 in_out = g(ch) * (in_out + zY(ch));
|
dicklyon@534
|
59 zY(ch) = in_out;
|
dicklyon@534
|
60 end
|
dicklyon@534
|
61
|
dicklyon@534
|
62 % put new state back in place of old
|
dicklyon@565
|
63 % (z1 is a genuine temp; the others can update by reference in C)
|
dicklyon@534
|
64 state.z1_memory = z1;
|
dicklyon@534
|
65 state.z2_memory = z2;
|
dicklyon@534
|
66 state.zA_memory = zA;
|
dicklyon@534
|
67 state.zB_memory = zB;
|
dicklyon@534
|
68 state.zY_memory = zY;
|
dicklyon@534
|
69 state.g_memory = g;
|
dicklyon@534
|
70
|
dicklyon@565
|
71 car_out = zY;
|
dicklyon@565
|
72
|
dicklyon@565
|
73
|