annotate matlab/bmm/carfac/CARFAC_Run.m @ 455:f8ba7ad93fa9

Added MATLAB code for Lyon's CAR-FAC filter cascade.
author tom@acousticscale.org
date Wed, 15 Feb 2012 21:26:40 +0000
parents
children 6ddf64b38211
rev   line source
tom@455 1 % Copyright 2012, Google, Inc.
tom@455 2 % Author: Richard F. Lyon
tom@455 3 %
tom@455 4 % This Matlab file is part of an implementation of Lyon's cochlear model:
tom@455 5 % "Cascade of Asymmetric Resonators with Fast-Acting Compression"
tom@455 6 % to supplement Lyon's upcoming book "Human and Machine Hearing"
tom@455 7 %
tom@455 8 % Licensed under the Apache License, Version 2.0 (the "License");
tom@455 9 % you may not use this file except in compliance with the License.
tom@455 10 % You may obtain a copy of the License at
tom@455 11 %
tom@455 12 % http://www.apache.org/licenses/LICENSE-2.0
tom@455 13 %
tom@455 14 % Unless required by applicable law or agreed to in writing, software
tom@455 15 % distributed under the License is distributed on an "AS IS" BASIS,
tom@455 16 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
tom@455 17 % See the License for the specific language governing permissions and
tom@455 18 % limitations under the License.
tom@455 19
tom@455 20 function [naps, CF, decim_naps] = CARFAC_Run ...
tom@455 21 (CF, input_waves, AGC_plot_fig_num)
tom@455 22 % function [naps, CF, CF.cum_k, decim_naps] = CARFAC_Run ...
tom@455 23 % (CF, input_waves, CF.cum_k, AGC_plot_fig_num)
tom@455 24 % This function runs the CARFAC; that is, filters a 1 or more channel
tom@455 25 % sound input to make one or more neural activity patterns (naps).
tom@455 26 %
tom@455 27 % The CF struct holds the filterbank design and state; if you want to
tom@455 28 % break the input up into segments, you need to use the updated CF
tom@455 29 % to keep the state between segments.
tom@455 30 %
tom@455 31 % input_waves is a column vector if there's just one audio channel;
tom@455 32 % more generally, it has a row per time sample, a column per audio channel.
tom@455 33 %
tom@455 34 % naps has a row per time sample, a column per filterbank channel, and
tom@455 35 % a layer per audio channel if more than 1.
tom@455 36 % decim_naps is like naps but time-decimated by the int CF.decimation.
tom@455 37 %
tom@455 38 % the input_waves are assumed to be sampled at the same rate as the
tom@455 39 % CARFAC is designed for; a resampling may be needed before calling this.
tom@455 40 %
tom@455 41 % The function works as an outer iteration on time, updating all the
tom@455 42 % filters and AGC states concurrently, so that the different channels can
tom@455 43 % interact easily. The inner loops are over filterbank channels, and
tom@455 44 % this level should be kept efficient.
tom@455 45 %
tom@455 46 % See other functions for designing and characterizing the CARFAC:
tom@455 47 % CF = CARFAC_Design(fs, CF_filter_params, CF_AGC_params, n_mics)
tom@455 48 % transfns = CARFAC_Transfer_Functions(CF, to_chans, from_chans)
tom@455 49
tom@455 50 [n_samp, n_mics] = size(input_waves);
tom@455 51 n_ch = CF.n_ch;
tom@455 52
tom@455 53 if nargin < 3
tom@455 54 AGC_plot_fig_num = 0;
tom@455 55 end
tom@455 56
tom@455 57 if n_mics ~= CF.n_mics
tom@455 58 error('bad number of input_waves channels passed to CARFAC_Run')
tom@455 59 end
tom@455 60
tom@455 61 % pull coeffs out of struct first, into local vars for convenience
tom@455 62 decim = CF.AGC_params.decimation;
tom@455 63
tom@455 64 naps = zeros(n_samp, n_ch, n_mics);
tom@455 65 if nargout > 2
tom@455 66 % make decimated detect output:
tom@455 67 decim_naps = zeros(ceil(n_samp/decim), CF.n_ch, CF.n_mics);
tom@455 68 else
tom@455 69 decim_naps = [];
tom@455 70 end
tom@455 71
tom@455 72 decim_k = 0;
tom@455 73
tom@455 74 sum_abs_response = 0;
tom@455 75
tom@455 76 for k = 1:n_samp
tom@455 77 CF.k_mod_decim = mod(CF.k_mod_decim + 1, decim); % global time phase
tom@455 78 % at each time step, possibly handle multiple channels
tom@455 79 for mic = 1:n_mics
tom@455 80 [filters_out, CF.filter_state(mic)] = CARFAC_FilterStep( ...
tom@455 81 input_waves(k, mic), CF.filter_coeffs, CF.filter_state(mic));
tom@455 82
tom@455 83 % update IHC state & output on every time step, too
tom@455 84 [ihc_out, CF.IHC_state(mic)] = CARFAC_IHCStep( ...
tom@455 85 filters_out, CF.IHC_coeffs, CF.IHC_state(mic));
tom@455 86
tom@455 87 % sum_abs_response = sum_abs_response + abs(filters_out);
tom@455 88
tom@455 89 naps(k, :, mic) = ihc_out; % output to neural activity pattern
tom@455 90 end
tom@455 91
tom@455 92 % conditionally update all the AGC stages and channels now:
tom@455 93 if CF.k_mod_decim == 0
tom@455 94 % just for the plotting option:
tom@455 95 decim_k = decim_k + 1; % index of decimated signal for display
tom@455 96 if ~isempty(decim_naps)
tom@455 97 for mic = 1:n_mics
tom@455 98 % this is HWR out of filters, not IHCs
tom@455 99 avg_detect = CF.filter_state(mic).detect_accum / decim;
tom@455 100 % This HACK is the IHC version:
tom@455 101 avg_detect = CF.IHC_state(mic).ihc_accum / decim; % for cochleagram
tom@455 102 decim_naps(decim_k, :, mic) = avg_detect; % for cochleagram
tom@455 103 % decim_naps(decim_k, :, mic) = sum_abs_response / decim; % HACK for mechanical out ABS
tom@455 104 % sum_abs_response(:) = 0;
tom@455 105 end
tom@455 106 end
tom@455 107
tom@455 108 % get the avg_detects to connect filter_state to AGC_state:
tom@455 109 avg_detects = zeros(n_ch, n_mics);
tom@455 110 for mic = 1:n_mics
tom@455 111 % % mechanical response from filter output through HWR as AGC in:
tom@455 112 % avg_detects(:, mic) = CF.filter_state(mic).detect_accum / decim;
tom@455 113 CF.filter_state(mic).detect_accum(:) = 0; % zero the detect accumulator
tom@455 114 % New HACK, IHC output relative to rest as input to AGC:
tom@455 115 avg_detects(:, mic) = CF.IHC_state(mic).ihc_accum / decim;
tom@455 116 CF.IHC_state(mic).ihc_accum(:) = 0; % zero the detect accumulator
tom@455 117 end
tom@455 118
tom@455 119 % run the AGC update step:
tom@455 120 CF.AGC_state = CARFAC_AGCStep(CF.AGC_coeffs, avg_detects, CF.AGC_state);
tom@455 121
tom@455 122 % connect the feedback from AGC_state to filter_state:
tom@455 123 for mic = 1:n_mics
tom@455 124 new_damping = CF.AGC_state(mic).sum_AGC;
tom@455 125 % max_damping = 0.15; % HACK
tom@455 126 % new_damping = min(new_damping, max_damping);
tom@455 127 % set the delta needed to get to new_damping:
tom@455 128 CF.filter_state(mic).dzB_memory = ...
tom@455 129 (new_damping - CF.filter_state(mic).zB_memory) ...
tom@455 130 / decim;
tom@455 131 end
tom@455 132
tom@455 133 if AGC_plot_fig_num
tom@455 134 figure(AGC_plot_fig_num); hold off
tom@455 135 maxsum = 0;
tom@455 136 for mic = 1:n_mics
tom@455 137 plot(CF.AGC_state(mic).AGC_memory)
tom@455 138 agcsum = sum(CF.AGC_state(mic).AGC_memory, 2);
tom@455 139 maxsum(mic) = max(maxsum, max(agcsum));
tom@455 140 hold on
tom@455 141 plot(agcsum, 'k-')
tom@455 142 end
tom@455 143 axis([0, CF.n_ch, 0, max(0.001, maxsum)]);
tom@455 144 drawnow
tom@455 145 end
tom@455 146 end
tom@455 147 end
tom@455 148