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@534
|
20 function [state, updated] = CARFAC_AGC_Step(AGC_coeffs, detects, state)
|
dicklyon@534
|
21 % function [state, updated] = CARFAC_AGC_Step(AGC_coeffs, detects, state)
|
dicklyon@534
|
22 %
|
dicklyon@534
|
23 % one time step (at decimated low AGC rate) of the AGC state update
|
dicklyon@534
|
24
|
dicklyon@534
|
25 n_ears = length(state);
|
dicklyon@534
|
26 [n_ch, n_AGC_stages] = size(state(1).AGC_memory); % number of channels
|
dicklyon@534
|
27
|
dicklyon@534
|
28 optimize_for_mono = n_ears == 1; % mono optimization
|
dicklyon@534
|
29
|
dicklyon@534
|
30 stage = 1;
|
dicklyon@534
|
31 ins = AGC_coeffs.detect_scale * detects;
|
dicklyon@534
|
32 [state, updated] = CARFAC_AGC_Recurse(AGC_coeffs, ins, n_AGC_stages, ...
|
dicklyon@534
|
33 n_ears, n_ch, optimize_for_mono, stage, state);
|
dicklyon@534
|
34
|
dicklyon@534
|
35
|
dicklyon@534
|
36
|
dicklyon@534
|
37
|
dicklyon@534
|
38
|
dicklyon@534
|
39 function [state, updated] = CARFAC_AGC_Recurse(coeffs, ins, n_stages, ...
|
dicklyon@534
|
40 n_ears, n_ch, mono, stage, state)
|
dicklyon@534
|
41 % function [state, updated = CARFAC_AGC_Recurse(coeffs, ins, n_stages, ...
|
dicklyon@534
|
42 % n_ears, n_ch, mono, stage, state)
|
dicklyon@534
|
43
|
dicklyon@534
|
44 decim = coeffs.decimation(stage); % decim phase for this stage
|
dicklyon@534
|
45 decim_phase = mod(state(1).decim_phase(stage) + 1, decim);
|
dicklyon@534
|
46 state(1).decim_phase(stage) = decim_phase;
|
dicklyon@534
|
47
|
dicklyon@534
|
48 % accumulate input for this stage from detect or previous stage:
|
dicklyon@534
|
49 for ear = 1:n_ears
|
dicklyon@534
|
50 state(ear).input_accum(:, stage) = ...
|
dicklyon@534
|
51 state(ear).input_accum(:, stage) + ins(:, ear);
|
dicklyon@534
|
52 end
|
dicklyon@534
|
53
|
dicklyon@534
|
54 % nothing else to do if it's not the right decim_phase
|
dicklyon@534
|
55 if decim_phase == 0
|
dicklyon@534
|
56 % do lots of work, at decimated rate
|
dicklyon@534
|
57
|
dicklyon@534
|
58 % decimated inputs for this stage, and to be decimated more for next:
|
dicklyon@534
|
59 for ear = 1:n_ears
|
dicklyon@534
|
60 ins(:,ear) = state(ear).input_accum(:, stage) / decim;
|
dicklyon@534
|
61 state(ear).input_accum(:, stage) = 0; % reset accumulator
|
dicklyon@534
|
62 end
|
dicklyon@534
|
63
|
dicklyon@534
|
64 if stage < n_stages % recurse to evaluate next stage(s)
|
dicklyon@534
|
65 state = CARFAC_AGC_Recurse(coeffs, ins, n_stages, ...
|
dicklyon@534
|
66 n_ears, n_ch, mono, stage+1, state);
|
dicklyon@534
|
67 end
|
dicklyon@534
|
68
|
dicklyon@534
|
69 epsilon = coeffs.AGC_epsilon(stage); % for this stage's LPF pole
|
dicklyon@534
|
70 stage_gain = coeffs.AGC_stage_gain;
|
dicklyon@534
|
71
|
dicklyon@534
|
72 for ear = 1:n_ears
|
dicklyon@534
|
73 AGC_in = ins(:,ear); % the newly decimated input for this ear
|
dicklyon@536
|
74
|
dicklyon@534
|
75 % add the latest output (state) of next stage...
|
dicklyon@534
|
76 if stage < n_stages
|
dicklyon@534
|
77 AGC_in = AGC_in + stage_gain * state(ear).AGC_memory(:, stage+1);
|
dicklyon@534
|
78 end
|
dicklyon@534
|
79
|
dicklyon@534
|
80 AGC_stage_state = state(ear).AGC_memory(:, stage);
|
dicklyon@534
|
81 % first-order recursive smoothing filter update, in time:
|
dicklyon@534
|
82 AGC_stage_state = AGC_stage_state + ...
|
dicklyon@534
|
83 epsilon * (AGC_in - AGC_stage_state);
|
dicklyon@534
|
84 % spatial smooth:
|
dicklyon@534
|
85 AGC_stage_state = ...
|
dicklyon@534
|
86 CARFAC_Spatial_Smooth(coeffs, stage, AGC_stage_state);
|
dicklyon@534
|
87 % and store the state back (in C++, do it all in place?)
|
dicklyon@534
|
88 state(ear).AGC_memory(:, stage) = AGC_stage_state;
|
dicklyon@534
|
89
|
dicklyon@534
|
90 if ~mono
|
dicklyon@534
|
91 if ear == 1
|
dicklyon@534
|
92 this_stage_sum = AGC_stage_state;
|
dicklyon@534
|
93 else
|
dicklyon@534
|
94 this_stage_sum = this_stage_sum + AGC_stage_state;
|
dicklyon@534
|
95 end
|
dicklyon@534
|
96 end
|
dicklyon@534
|
97 end
|
dicklyon@534
|
98 if ~mono
|
dicklyon@534
|
99 mix_coeff = coeffs.AGC_mix_coeffs(stage);
|
dicklyon@534
|
100 if mix_coeff > 0
|
dicklyon@534
|
101 this_stage_mean = this_stage_sum / n_ears;
|
dicklyon@534
|
102 for ear = 1:n_ears
|
dicklyon@534
|
103 state(ear).AGC_memory(:, stage) = ...
|
dicklyon@534
|
104 state(ear).AGC_memory(:, stage) + ...
|
dicklyon@534
|
105 mix_coeff * ...
|
dicklyon@534
|
106 (this_stage_mean - state(ear).AGC_memory(:, stage));
|
dicklyon@534
|
107 end
|
dicklyon@534
|
108 end
|
dicklyon@534
|
109 end
|
dicklyon@534
|
110 updated = 1; % bool to say we have new state
|
dicklyon@534
|
111 else
|
dicklyon@534
|
112 updated = 0;
|
dicklyon@534
|
113 end
|