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