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: dicklyon@517: function [sai_frame, sai_state, naps] = CARFAC_SAI(naps, k, sai_state, SAI_params) dicklyon@517: % function sai = CARFAC_SAI(naps, k, sai_state, SAI_params) tom@516: % dicklyon@517: % Calculate the Stabilized Auditory Image from naps; dicklyon@517: % I think this is a binaural SAI by Steven Ness dicklyon@517: % dicklyon@517: % k seems to be a time index; it's an incremental update of the images... dicklyon@517: % but this doesn't sound like a proper incremental approach... tom@516: % tom@516: dicklyon@517: [n_samp, n_ch, n_mics] = size(naps); tom@516: dicklyon@517: if nargin < 4 dicklyon@517: SAI_params = struct( ... dicklyon@517: 'frame_jump', 200, ... dicklyon@517: 'sai_width', 500, ... dicklyon@517: 'threshold_alpha', 0.99, ... dicklyon@517: 'threshold_jump_factor', 1.2, ... dicklyon@517: 'threshold_jump_offset', 0.1}; dicklyon@517: end tom@516: dicklyon@517: threshold_alpha = SAI_params.threshold_alpha; dicklyon@517: threshold_jump = SAI_params.threshold_jump_factor; dicklyon@517: threshold_offset = SAI_params.threshold_jump_offset; tom@516: dicklyon@517: sai2 = reshape(sai_state.sai, SAI_params.sai_width * n_ch, n_mics); dicklyon@517: naps2 = reshape(naps, n_samp * n_ch, n_mics); tom@516: dicklyon@517: for mic = 1:n_mics dicklyon@517: data = naps(k, :, mic)'; dicklyon@517: above_threshold = (sai_state(mic).lastdata > ... dicklyon@517: sai_state(mic).thresholds) & ... dicklyon@517: (sai_state(mic).lastdata > data); dicklyon@517: sai_state(mic).thresholds(above_threshold) = ... dicklyon@517: data(above_threshold) * threshold_jump + threshold_offset; dicklyon@517: sai_state(mic).thresholds(~above_threshold) = ... dicklyon@517: sai_state(mic).thresholds(~above_threshold) * threshold_alpha; dicklyon@517: sai_state(mic).lastdata = data; dicklyon@517: dicklyon@517: % Update SAI image with strobe data. dicklyon@517: othermic = 3 - mic; dicklyon@517: dicklyon@517: % Channels that are above the threhsold dicklyon@517: above_ch = find(above_threshold); dicklyon@517: dicklyon@517: % If we are above the threshold, set the trigger index and reset the dicklyon@517: % sai_index dicklyon@517: sai_state(mic).trigger_index(above_ch) = k; dicklyon@517: sai_state(mic).sai_index(above_ch) = 1; dicklyon@517: dicklyon@517: % Copy the right data from the nap to the sai dicklyon@517: chans = (1:n_ch)'; dicklyon@517: fromindices = sai_state(mic).trigger_index() + (chans - 1) * n_samp; dicklyon@517: toindices = min((sai_state(mic).sai_index() + (chans - 1) * sai_params.sai_width), sai_params.sai_width * n_ch); dicklyon@517: sai2(toindices,mic) = naps2(fromindices, othermic); dicklyon@517: dicklyon@517: sai_state(mic).trigger_index(:) = sai_state(mic).trigger_index(:) + 1; dicklyon@517: sai_state(mic).sai_index(:) = sai_state(mic).sai_index(:) + 1; dicklyon@517: end tom@516: tom@516: dicklyon@517: sai_frame = reshape(sai2,sai_params.sai_width,n_ch,n_mics); dicklyon@517: sai_state.sai = sai; % probably this is not exactly what we want to store as state... tom@516: tom@516: