dicklyon@615
|
1 % Copyright 2013, Google, Inc.
|
dicklyon@615
|
2 % Author: Richard F. Lyon
|
dicklyon@615
|
3 %
|
dicklyon@615
|
4 % This Matlab file is part of an implementation of Lyon's cochlear model:
|
dicklyon@615
|
5 % "Cascade of Asymmetric Resonators with Fast-Acting Compression"
|
dicklyon@615
|
6 % to supplement Lyon's upcoming book "Human and Machine Hearing"
|
dicklyon@615
|
7 %
|
dicklyon@615
|
8 % Licensed under the Apache License, Version 2.0 (the "License");
|
dicklyon@615
|
9 % you may not use this file except in compliance with the License.
|
dicklyon@615
|
10 % You may obtain a copy of the License at
|
dicklyon@615
|
11 %
|
dicklyon@615
|
12 % http://www.apache.org/licenses/LICENSE-2.0
|
dicklyon@615
|
13 %
|
dicklyon@615
|
14 % Unless required by applicable law or agreed to in writing, software
|
dicklyon@615
|
15 % distributed under the License is distributed on an "AS IS" BASIS,
|
dicklyon@615
|
16 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
dicklyon@615
|
17 % See the License for the specific language governing permissions and
|
dicklyon@615
|
18 % limitations under the License.
|
dicklyon@615
|
19
|
dicklyon@615
|
20 function layer_array = SAI_UpdateBuffers(layer_array, seg_naps, seg_num)
|
dicklyon@615
|
21 % function layer_array = SAI_UpdateBuffers(layer_array, seg_naps, seg_num)
|
dicklyon@615
|
22 %
|
dicklyon@615
|
23 % Input/Output: layer_array contains all the coefficients and state for
|
dicklyon@615
|
24 % the layer of different time scales of SAI;
|
dicklyon@615
|
25 % we might want to separate these as in CARFAC.
|
dicklyon@615
|
26 %
|
dicklyon@615
|
27 % seg_naps is a new segmeent of NAP from the CAR-FAC to shift into the
|
dicklyon@615
|
28 % first layer. Each subsequent layer gets input off the input end of the
|
dicklyon@615
|
29 % previous layer, with smoothing and decimation.
|
dicklyon@615
|
30 %
|
dicklyon@615
|
31 % The segment index seg_num is used to control sub-sampled updates of
|
dicklyon@615
|
32 % the larger-scale layers.
|
dicklyon@615
|
33
|
dicklyon@615
|
34 n_layers = length(layer_array);
|
dicklyon@615
|
35 [seg_len, n_nap_ch] = size(seg_naps);
|
dicklyon@615
|
36
|
dicklyon@615
|
37 % Array of what to shift in to first or next layer.
|
dicklyon@615
|
38 new_chunk = seg_naps;
|
dicklyon@615
|
39
|
dicklyon@619
|
40 gain = 1.05; % gain from layer to layer; could be layer dependent.
|
dicklyon@615
|
41
|
dicklyon@615
|
42 %%
|
dicklyon@615
|
43 % Decimate using a 2-3-4-filter and partial differencing emphasize onsets:
|
dicklyon@615
|
44 kernel = filter([1 1]/2, 1, filter([1 1 1]/3, 1, [1 1 1 1 0 0 0 0]/4));
|
dicklyon@665
|
45 % kernel = kernel + 2*diff([0, kernel]);
|
dicklyon@615
|
46 % figure(1)
|
dicklyon@615
|
47 % plot(kernel)
|
dicklyon@615
|
48
|
dicklyon@615
|
49 %%
|
dicklyon@615
|
50 for layer = 1:n_layers
|
dicklyon@615
|
51 [n_lags, n_ch] = size(layer_array(layer).nap_buffer);
|
dicklyon@615
|
52 if (n_nap_ch ~= n_ch)
|
dicklyon@615
|
53 error('Wrong number of channels in nap_buffer.');
|
dicklyon@615
|
54 end
|
dicklyon@615
|
55
|
dicklyon@615
|
56 interval = layer_array(layer).update_interval;
|
dicklyon@615
|
57 if (0 == mod(seg_num, interval))
|
dicklyon@615
|
58 % Account for 2X decimation and infrequent updates; find number of time
|
dicklyon@615
|
59 % points to shift in. Tolerate slip of a fraction of a sample.
|
dicklyon@615
|
60 n_shift = seg_len * interval / (2.0^(layer - 1));
|
dicklyon@615
|
61 if layer > 1
|
dicklyon@615
|
62 % Add the leftover fraction before floor.
|
dicklyon@615
|
63 n_shift = n_shift + layer_array(layer).nap_fraction;
|
dicklyon@615
|
64 layer_array(layer).nap_fraction = n_shift - floor(n_shift);
|
dicklyon@615
|
65 n_shift = floor(n_shift);
|
dicklyon@615
|
66 % Grab new stuff from new end (big time indices) of previous layer.
|
dicklyon@615
|
67 % Take twice as many times as we need, + 5, for decimation, and do
|
dicklyon@665
|
68 % smoothing to get new points.
|
dicklyon@615
|
69 new_chunk = ...
|
dicklyon@615
|
70 layer_array(layer - 1).nap_buffer((end - 2*n_shift - 4):end, :);
|
dicklyon@615
|
71 new_chunk = filter(kernel, 1, new_chunk);
|
dicklyon@665
|
72 % new_chunk = gain * new_chunk(7:2:end, :);
|
dicklyon@665
|
73 % try a little extra smoothing:
|
dicklyon@665
|
74 new_chunk = gain * (new_chunk(7:2:end, :) + new_chunk(6:2:(end-1), :))/2;
|
dicklyon@615
|
75
|
dicklyon@615
|
76 end
|
dicklyon@615
|
77 % Put new stuff in at latest time indices.
|
dicklyon@615
|
78 layer_array(layer).nap_buffer = ...
|
dicklyon@615
|
79 [layer_array(layer).nap_buffer((1 + n_shift):end, :); ...
|
dicklyon@615
|
80 new_chunk]; % this should fit just right if we have n_shift new times.
|
dicklyon@615
|
81 end
|
dicklyon@615
|
82 end
|
dicklyon@615
|
83
|
dicklyon@615
|
84 return
|
dicklyon@615
|
85
|