tom@516: % Copyright 2012, Google, Inc. tom@516: % Author: Richard F. Lyon tom@516: % tom@516: % This Matlab file is part of an implementation of Lyon's cochlear model: tom@516: % "Cascade of Asymmetric Resonators with Fast-Acting Compression" tom@516: % to supplement Lyon's upcoming book "Human and Machine Hearing" tom@516: % tom@516: % Licensed under the Apache License, Version 2.0 (the "License"); tom@516: % you may not use this file except in compliance with the License. tom@516: % You may obtain a copy of the License at tom@516: % tom@516: % http://www.apache.org/licenses/LICENSE-2.0 tom@516: % tom@516: % Unless required by applicable law or agreed to in writing, software tom@516: % distributed under the License is distributed on an "AS IS" BASIS, tom@516: % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. tom@516: % See the License for the specific language governing permissions and tom@516: % limitations under the License. tom@516: tom@516: function state = CARFAC_AGCStep(AGC_coeffs, avg_detects, state) tom@516: % function state = CARFAC_AGCStep(AGC_coeffs, avg_detects, state) tom@516: % tom@516: % one time step (at decimated low AGC rate) of the AGC state update tom@516: tom@516: n_AGC_stages = length(AGC_coeffs.AGC_epsilon); tom@516: n_mics = length(state); tom@516: n_ch = size(state(1).AGC_sum, 1); % number of channels tom@516: tom@516: optimize_for_mono = n_mics == 1; % mono optimization tom@516: if ~optimize_for_mono tom@516: stage_sum = zeros(n_ch, 1); tom@516: end tom@516: tom@516: for stage = 1:n_AGC_stages tom@516: if ~optimize_for_mono % skip if mono tom@516: if stage > 1 tom@516: prev_stage_mean = stage_sum / n_mics; tom@516: end tom@516: stage_sum(:) = 0; % sum accumulating over mics at this stage tom@516: end tom@516: epsilon = AGC_coeffs.AGC_epsilon(stage); % for this stage's LPF pole tom@516: polez1 = AGC_coeffs.AGC1_polez(stage); tom@516: polez2 = AGC_coeffs.AGC2_polez(stage); tom@516: for mic = 1:n_mics tom@516: if stage == 1 tom@516: AGC_in = AGC_coeffs.detect_scale * avg_detects(:,mic); tom@516: AGC_in = max(0, AGC_in); % don't let neg inputs in tom@516: else tom@516: % prev. stage mixed with prev_stage_sum tom@516: if optimize_for_mono tom@516: % Mono optimization ignores AGC_mix_coeff, tom@516: % assuming all(prev_stage_mean == AGC_memory(:, stage - 1)); tom@516: % but we also don't even allocate or compute the sum or mean. tom@516: AGC_in = AGC_coeffs.AGC_stage_gain * ... tom@516: state(mic).AGC_memory(:, stage - 1); tom@516: else tom@516: AGC_in = AGC_coeffs.AGC_stage_gain * ... tom@516: (AGC_coeffs.AGC_mix_coeff * prev_stage_mean + ... tom@516: (1 - AGC_coeffs.AGC_mix_coeff) * ... tom@516: state(mic).AGC_memory(:, stage - 1)); tom@516: end tom@516: end tom@516: AGC_stage = state(mic).AGC_memory(:, stage); tom@516: % first-order recursive smooting filter update: tom@516: AGC_stage = AGC_stage + epsilon * (AGC_in - AGC_stage); tom@516: tom@516: % spatially spread it; using diffusion coeffs like in smooth1d tom@516: AGC_stage = SmoothDoubleExponential(AGC_stage, polez1, polez2); tom@516: tom@516: state(mic).AGC_memory(:, stage) = AGC_stage; tom@516: if stage == 1 tom@516: state(mic).sum_AGC = AGC_stage; tom@516: else tom@516: state(mic).sum_AGC = state(mic).sum_AGC + AGC_stage; tom@516: end tom@516: if ~optimize_for_mono tom@516: stage_sum = stage_sum + AGC_stage; tom@516: end tom@516: end tom@516: end tom@516: tom@516: