tom@455: % Copyright 2012, Google, Inc. tom@455: % Author: Richard F. Lyon tom@455: % tom@455: % This Matlab file is part of an implementation of Lyon's cochlear model: tom@455: % "Cascade of Asymmetric Resonators with Fast-Acting Compression" tom@455: % to supplement Lyon's upcoming book "Human and Machine Hearing" tom@455: % tom@455: % Licensed under the Apache License, Version 2.0 (the "License"); tom@455: % you may not use this file except in compliance with the License. tom@455: % You may obtain a copy of the License at tom@455: % tom@455: % http://www.apache.org/licenses/LICENSE-2.0 tom@455: % tom@455: % Unless required by applicable law or agreed to in writing, software tom@455: % distributed under the License is distributed on an "AS IS" BASIS, tom@455: % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. tom@455: % See the License for the specific language governing permissions and tom@455: % limitations under the License. tom@455: dicklyon@456: function [sai_frame, sai_state, naps] = CARFAC_SAI(naps, k, sai_state, SAI_params) dicklyon@456: % function sai = CARFAC_SAI(naps, k, sai_state, SAI_params) tom@455: % dicklyon@474: % ...work in progress... dicklyon@474: % dicklyon@456: % Calculate the Stabilized Auditory Image from naps; dicklyon@456: % I think this is a binaural SAI by Steven Ness dicklyon@456: % dicklyon@456: % k seems to be a time index; it's an incremental update of the images... dicklyon@456: % but this doesn't sound like a proper incremental approach... tom@455: % tom@455: dicklyon@474: [n_samp, n_ch, n_ears] = size(naps); tom@455: dicklyon@456: if nargin < 4 dicklyon@456: SAI_params = struct( ... dicklyon@456: 'frame_jump', 200, ... dicklyon@456: 'sai_width', 500, ... dicklyon@456: 'threshold_alpha', 0.99, ... dicklyon@456: 'threshold_jump_factor', 1.2, ... dicklyon@456: 'threshold_jump_offset', 0.1}; dicklyon@456: end tom@455: dicklyon@456: threshold_alpha = SAI_params.threshold_alpha; dicklyon@456: threshold_jump = SAI_params.threshold_jump_factor; dicklyon@456: threshold_offset = SAI_params.threshold_jump_offset; tom@455: dicklyon@474: sai2 = reshape(sai_state.sai, SAI_params.sai_width * n_ch, n_ears); dicklyon@474: naps2 = reshape(naps, n_samp * n_ch, n_ears); tom@455: dicklyon@474: for ear = 1:n_ears dicklyon@474: data = naps(k, :, ear)'; dicklyon@474: above_threshold = (sai_state(ear).lastdata > ... dicklyon@474: sai_state(ear).thresholds) & ... dicklyon@474: (sai_state(ear).lastdata > data); dicklyon@474: sai_state(ear).thresholds(above_threshold) = ... dicklyon@456: data(above_threshold) * threshold_jump + threshold_offset; dicklyon@474: sai_state(ear).thresholds(~above_threshold) = ... dicklyon@474: sai_state(ear).thresholds(~above_threshold) * threshold_alpha; dicklyon@474: sai_state(ear).lastdata = data; dicklyon@456: dicklyon@456: % Update SAI image with strobe data. dicklyon@474: otherear = 3 - ear; dicklyon@456: dicklyon@456: % Channels that are above the threhsold dicklyon@456: above_ch = find(above_threshold); dicklyon@456: dicklyon@456: % If we are above the threshold, set the trigger index and reset the dicklyon@456: % sai_index dicklyon@474: sai_state(ear).trigger_index(above_ch) = k; dicklyon@474: sai_state(ear).sai_index(above_ch) = 1; dicklyon@456: dicklyon@456: % Copy the right data from the nap to the sai dicklyon@456: chans = (1:n_ch)'; dicklyon@474: fromindices = sai_state(ear).trigger_index() + (chans - 1) * n_samp; dicklyon@474: toindices = min((sai_state(ear).sai_index() + (chans - 1) * sai_params.sai_width), sai_params.sai_width * n_ch); dicklyon@474: sai2(toindices,ear) = naps2(fromindices, otherear); dicklyon@456: dicklyon@474: sai_state(ear).trigger_index(:) = sai_state(ear).trigger_index(:) + 1; dicklyon@474: sai_state(ear).sai_index(:) = sai_state(ear).sai_index(:) + 1; dicklyon@456: end tom@455: tom@455: dicklyon@474: sai_frame = reshape(sai2,sai_params.sai_width,n_ch,n_ears); dicklyon@456: sai_state.sai = sai; % probably this is not exactly what we want to store as state... tom@455: tom@455: