tom@516
|
1 % Copyright 2012, Google, Inc.
|
tom@516
|
2 % Author: Richard F. Lyon
|
tom@516
|
3 %
|
tom@516
|
4 % This Matlab file is part of an implementation of Lyon's cochlear model:
|
tom@516
|
5 % "Cascade of Asymmetric Resonators with Fast-Acting Compression"
|
tom@516
|
6 % to supplement Lyon's upcoming book "Human and Machine Hearing"
|
tom@516
|
7 %
|
tom@516
|
8 % Licensed under the Apache License, Version 2.0 (the "License");
|
tom@516
|
9 % you may not use this file except in compliance with the License.
|
tom@516
|
10 % You may obtain a copy of the License at
|
tom@516
|
11 %
|
tom@516
|
12 % http://www.apache.org/licenses/LICENSE-2.0
|
tom@516
|
13 %
|
tom@516
|
14 % Unless required by applicable law or agreed to in writing, software
|
tom@516
|
15 % distributed under the License is distributed on an "AS IS" BASIS,
|
tom@516
|
16 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
tom@516
|
17 % See the License for the specific language governing permissions and
|
tom@516
|
18 % limitations under the License.
|
tom@516
|
19
|
dicklyon@517
|
20 function [sai_frame, sai_state, naps] = CARFAC_SAI(naps, k, sai_state, SAI_params)
|
dicklyon@517
|
21 % function sai = CARFAC_SAI(naps, k, sai_state, SAI_params)
|
tom@516
|
22 %
|
dicklyon@535
|
23 % ...work in progress...
|
dicklyon@535
|
24 %
|
dicklyon@517
|
25 % Calculate the Stabilized Auditory Image from naps;
|
dicklyon@517
|
26 % I think this is a binaural SAI by Steven Ness
|
dicklyon@517
|
27 %
|
dicklyon@517
|
28 % k seems to be a time index; it's an incremental update of the images...
|
dicklyon@517
|
29 % but this doesn't sound like a proper incremental approach...
|
tom@516
|
30 %
|
tom@516
|
31
|
dicklyon@535
|
32 [n_samp, n_ch, n_ears] = size(naps);
|
tom@516
|
33
|
dicklyon@517
|
34 if nargin < 4
|
dicklyon@517
|
35 SAI_params = struct( ...
|
dicklyon@517
|
36 'frame_jump', 200, ...
|
dicklyon@517
|
37 'sai_width', 500, ...
|
dicklyon@517
|
38 'threshold_alpha', 0.99, ...
|
dicklyon@517
|
39 'threshold_jump_factor', 1.2, ...
|
dicklyon@517
|
40 'threshold_jump_offset', 0.1};
|
dicklyon@517
|
41 end
|
tom@516
|
42
|
dicklyon@517
|
43 threshold_alpha = SAI_params.threshold_alpha;
|
dicklyon@517
|
44 threshold_jump = SAI_params.threshold_jump_factor;
|
dicklyon@517
|
45 threshold_offset = SAI_params.threshold_jump_offset;
|
tom@516
|
46
|
dicklyon@535
|
47 sai2 = reshape(sai_state.sai, SAI_params.sai_width * n_ch, n_ears);
|
dicklyon@535
|
48 naps2 = reshape(naps, n_samp * n_ch, n_ears);
|
tom@516
|
49
|
dicklyon@535
|
50 for ear = 1:n_ears
|
dicklyon@535
|
51 data = naps(k, :, ear)';
|
dicklyon@535
|
52 above_threshold = (sai_state(ear).lastdata > ...
|
dicklyon@535
|
53 sai_state(ear).thresholds) & ...
|
dicklyon@535
|
54 (sai_state(ear).lastdata > data);
|
dicklyon@535
|
55 sai_state(ear).thresholds(above_threshold) = ...
|
dicklyon@517
|
56 data(above_threshold) * threshold_jump + threshold_offset;
|
dicklyon@535
|
57 sai_state(ear).thresholds(~above_threshold) = ...
|
dicklyon@535
|
58 sai_state(ear).thresholds(~above_threshold) * threshold_alpha;
|
dicklyon@535
|
59 sai_state(ear).lastdata = data;
|
dicklyon@517
|
60
|
dicklyon@517
|
61 % Update SAI image with strobe data.
|
dicklyon@535
|
62 otherear = 3 - ear;
|
dicklyon@517
|
63
|
dicklyon@517
|
64 % Channels that are above the threhsold
|
dicklyon@517
|
65 above_ch = find(above_threshold);
|
dicklyon@517
|
66
|
dicklyon@517
|
67 % If we are above the threshold, set the trigger index and reset the
|
dicklyon@517
|
68 % sai_index
|
dicklyon@535
|
69 sai_state(ear).trigger_index(above_ch) = k;
|
dicklyon@535
|
70 sai_state(ear).sai_index(above_ch) = 1;
|
dicklyon@517
|
71
|
dicklyon@517
|
72 % Copy the right data from the nap to the sai
|
dicklyon@517
|
73 chans = (1:n_ch)';
|
dicklyon@535
|
74 fromindices = sai_state(ear).trigger_index() + (chans - 1) * n_samp;
|
dicklyon@535
|
75 toindices = min((sai_state(ear).sai_index() + (chans - 1) * sai_params.sai_width), sai_params.sai_width * n_ch);
|
dicklyon@535
|
76 sai2(toindices,ear) = naps2(fromindices, otherear);
|
dicklyon@517
|
77
|
dicklyon@535
|
78 sai_state(ear).trigger_index(:) = sai_state(ear).trigger_index(:) + 1;
|
dicklyon@535
|
79 sai_state(ear).sai_index(:) = sai_state(ear).sai_index(:) + 1;
|
dicklyon@517
|
80 end
|
tom@516
|
81
|
tom@516
|
82
|
dicklyon@535
|
83 sai_frame = reshape(sai2,sai_params.sai_width,n_ch,n_ears);
|
dicklyon@517
|
84 sai_state.sai = sai; % probably this is not exactly what we want to store as state...
|
tom@516
|
85
|
tom@516
|
86
|