dicklyon@534: % Copyright 2012, Google, Inc. dicklyon@534: % Author: Richard F. Lyon dicklyon@534: % dicklyon@534: % This Matlab file is part of an implementation of Lyon's cochlear model: dicklyon@534: % "Cascade of Asymmetric Resonators with Fast-Acting Compression" dicklyon@534: % to supplement Lyon's upcoming book "Human and Machine Hearing" dicklyon@534: % dicklyon@534: % Licensed under the Apache License, Version 2.0 (the "License"); dicklyon@534: % you may not use this file except in compliance with the License. dicklyon@534: % You may obtain a copy of the License at dicklyon@534: % dicklyon@534: % http://www.apache.org/licenses/LICENSE-2.0 dicklyon@534: % dicklyon@534: % Unless required by applicable law or agreed to in writing, software dicklyon@534: % distributed under the License is distributed on an "AS IS" BASIS, dicklyon@534: % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. dicklyon@534: % See the License for the specific language governing permissions and dicklyon@534: % limitations under the License. dicklyon@534: dicklyon@534: function [state, updated] = CARFAC_AGC_Step(AGC_coeffs, detects, state) dicklyon@534: % function [state, updated] = CARFAC_AGC_Step(AGC_coeffs, detects, state) dicklyon@534: % dicklyon@534: % one time step (at decimated low AGC rate) of the AGC state update dicklyon@534: dicklyon@534: n_ears = length(state); dicklyon@534: [n_ch, n_AGC_stages] = size(state(1).AGC_memory); % number of channels dicklyon@534: dicklyon@534: optimize_for_mono = n_ears == 1; % mono optimization dicklyon@534: dicklyon@534: stage = 1; dicklyon@534: ins = AGC_coeffs.detect_scale * detects; dicklyon@534: [state, updated] = CARFAC_AGC_Recurse(AGC_coeffs, ins, n_AGC_stages, ... dicklyon@534: n_ears, n_ch, optimize_for_mono, stage, state); dicklyon@534: dicklyon@534: dicklyon@534: dicklyon@534: dicklyon@534: dicklyon@534: function [state, updated] = CARFAC_AGC_Recurse(coeffs, ins, n_stages, ... dicklyon@534: n_ears, n_ch, mono, stage, state) dicklyon@534: % function [state, updated = CARFAC_AGC_Recurse(coeffs, ins, n_stages, ... dicklyon@534: % n_ears, n_ch, mono, stage, state) dicklyon@534: dicklyon@534: decim = coeffs.decimation(stage); % decim phase for this stage dicklyon@534: decim_phase = mod(state(1).decim_phase(stage) + 1, decim); dicklyon@534: state(1).decim_phase(stage) = decim_phase; dicklyon@534: dicklyon@534: % accumulate input for this stage from detect or previous stage: dicklyon@534: for ear = 1:n_ears dicklyon@534: state(ear).input_accum(:, stage) = ... dicklyon@534: state(ear).input_accum(:, stage) + ins(:, ear); dicklyon@534: end dicklyon@534: dicklyon@534: % nothing else to do if it's not the right decim_phase dicklyon@534: if decim_phase == 0 dicklyon@534: % do lots of work, at decimated rate dicklyon@534: dicklyon@534: % decimated inputs for this stage, and to be decimated more for next: dicklyon@534: for ear = 1:n_ears dicklyon@534: ins(:,ear) = state(ear).input_accum(:, stage) / decim; dicklyon@534: state(ear).input_accum(:, stage) = 0; % reset accumulator dicklyon@534: end dicklyon@534: dicklyon@534: if stage < n_stages % recurse to evaluate next stage(s) dicklyon@534: state = CARFAC_AGC_Recurse(coeffs, ins, n_stages, ... dicklyon@534: n_ears, n_ch, mono, stage+1, state); dicklyon@534: end dicklyon@534: dicklyon@534: epsilon = coeffs.AGC_epsilon(stage); % for this stage's LPF pole dicklyon@534: stage_gain = coeffs.AGC_stage_gain; dicklyon@534: dicklyon@534: for ear = 1:n_ears dicklyon@534: AGC_in = ins(:,ear); % the newly decimated input for this ear dicklyon@536: dicklyon@534: % add the latest output (state) of next stage... dicklyon@534: if stage < n_stages dicklyon@534: AGC_in = AGC_in + stage_gain * state(ear).AGC_memory(:, stage+1); dicklyon@534: end dicklyon@534: dicklyon@534: AGC_stage_state = state(ear).AGC_memory(:, stage); dicklyon@534: % first-order recursive smoothing filter update, in time: dicklyon@534: AGC_stage_state = AGC_stage_state + ... dicklyon@534: epsilon * (AGC_in - AGC_stage_state); dicklyon@534: % spatial smooth: dicklyon@534: AGC_stage_state = ... dicklyon@534: CARFAC_Spatial_Smooth(coeffs, stage, AGC_stage_state); dicklyon@534: % and store the state back (in C++, do it all in place?) dicklyon@534: state(ear).AGC_memory(:, stage) = AGC_stage_state; dicklyon@534: dicklyon@534: if ~mono dicklyon@534: if ear == 1 dicklyon@534: this_stage_sum = AGC_stage_state; dicklyon@534: else dicklyon@534: this_stage_sum = this_stage_sum + AGC_stage_state; dicklyon@534: end dicklyon@534: end dicklyon@534: end dicklyon@534: if ~mono dicklyon@534: mix_coeff = coeffs.AGC_mix_coeffs(stage); dicklyon@534: if mix_coeff > 0 dicklyon@534: this_stage_mean = this_stage_sum / n_ears; dicklyon@534: for ear = 1:n_ears dicklyon@534: state(ear).AGC_memory(:, stage) = ... dicklyon@534: state(ear).AGC_memory(:, stage) + ... dicklyon@534: mix_coeff * ... dicklyon@534: (this_stage_mean - state(ear).AGC_memory(:, stage)); dicklyon@534: end dicklyon@534: end dicklyon@534: end dicklyon@534: updated = 1; % bool to say we have new state dicklyon@534: else dicklyon@534: updated = 0; dicklyon@534: end