annotate trunk/matlab/bmm/carfac/CARFAC_Run.m @ 516:68c15d43fcc8

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 aa282a2b61bb
rev   line source
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
tom@516 20 function [naps, CF, decim_naps] = CARFAC_Run ...
tom@516 21 (CF, input_waves, AGC_plot_fig_num)
tom@516 22 % function [naps, CF, CF.cum_k, decim_naps] = CARFAC_Run ...
tom@516 23 % (CF, input_waves, CF.cum_k, AGC_plot_fig_num)
tom@516 24 % This function runs the CARFAC; that is, filters a 1 or more channel
tom@516 25 % sound input to make one or more neural activity patterns (naps).
tom@516 26 %
tom@516 27 % The CF struct holds the filterbank design and state; if you want to
tom@516 28 % break the input up into segments, you need to use the updated CF
tom@516 29 % to keep the state between segments.
tom@516 30 %
tom@516 31 % input_waves is a column vector if there's just one audio channel;
tom@516 32 % more generally, it has a row per time sample, a column per audio channel.
tom@516 33 %
tom@516 34 % naps has a row per time sample, a column per filterbank channel, and
tom@516 35 % a layer per audio channel if more than 1.
tom@516 36 % decim_naps is like naps but time-decimated by the int CF.decimation.
tom@516 37 %
tom@516 38 % the input_waves are assumed to be sampled at the same rate as the
tom@516 39 % CARFAC is designed for; a resampling may be needed before calling this.
tom@516 40 %
tom@516 41 % The function works as an outer iteration on time, updating all the
tom@516 42 % filters and AGC states concurrently, so that the different channels can
tom@516 43 % interact easily. The inner loops are over filterbank channels, and
tom@516 44 % this level should be kept efficient.
tom@516 45 %
tom@516 46 % See other functions for designing and characterizing the CARFAC:
tom@516 47 % CF = CARFAC_Design(fs, CF_filter_params, CF_AGC_params, n_mics)
tom@516 48 % transfns = CARFAC_Transfer_Functions(CF, to_chans, from_chans)
tom@516 49
tom@516 50 [n_samp, n_mics] = size(input_waves);
tom@516 51 n_ch = CF.n_ch;
tom@516 52
tom@516 53 if nargin < 3
tom@516 54 AGC_plot_fig_num = 0;
tom@516 55 end
tom@516 56
tom@516 57 if n_mics ~= CF.n_mics
tom@516 58 error('bad number of input_waves channels passed to CARFAC_Run')
tom@516 59 end
tom@516 60
tom@516 61 % pull coeffs out of struct first, into local vars for convenience
tom@516 62 decim = CF.AGC_params.decimation;
tom@516 63
tom@516 64 naps = zeros(n_samp, n_ch, n_mics);
tom@516 65 if nargout > 2
tom@516 66 % make decimated detect output:
tom@516 67 decim_naps = zeros(ceil(n_samp/decim), CF.n_ch, CF.n_mics);
tom@516 68 else
tom@516 69 decim_naps = [];
tom@516 70 end
tom@516 71
tom@516 72 decim_k = 0;
tom@516 73
tom@516 74 sum_abs_response = 0;
tom@516 75
tom@516 76 for k = 1:n_samp
tom@516 77 CF.k_mod_decim = mod(CF.k_mod_decim + 1, decim); % global time phase
tom@516 78 % at each time step, possibly handle multiple channels
tom@516 79 for mic = 1:n_mics
tom@516 80 [filters_out, CF.filter_state(mic)] = CARFAC_FilterStep( ...
tom@516 81 input_waves(k, mic), CF.filter_coeffs, CF.filter_state(mic));
tom@516 82
tom@516 83 % update IHC state & output on every time step, too
tom@516 84 [ihc_out, CF.IHC_state(mic)] = CARFAC_IHCStep( ...
tom@516 85 filters_out, CF.IHC_coeffs, CF.IHC_state(mic));
tom@516 86
tom@516 87 % sum_abs_response = sum_abs_response + abs(filters_out);
tom@516 88
tom@516 89 naps(k, :, mic) = ihc_out; % output to neural activity pattern
tom@516 90 end
tom@516 91
tom@516 92 % conditionally update all the AGC stages and channels now:
tom@516 93 if CF.k_mod_decim == 0
tom@516 94 % just for the plotting option:
tom@516 95 decim_k = decim_k + 1; % index of decimated signal for display
tom@516 96 if ~isempty(decim_naps)
tom@516 97 for mic = 1:n_mics
tom@516 98 % this is HWR out of filters, not IHCs
tom@516 99 avg_detect = CF.filter_state(mic).detect_accum / decim;
tom@516 100 % This HACK is the IHC version:
tom@516 101 avg_detect = CF.IHC_state(mic).ihc_accum / decim; % for cochleagram
tom@516 102 decim_naps(decim_k, :, mic) = avg_detect; % for cochleagram
tom@516 103 % decim_naps(decim_k, :, mic) = sum_abs_response / decim; % HACK for mechanical out ABS
tom@516 104 % sum_abs_response(:) = 0;
tom@516 105 end
tom@516 106 end
tom@516 107
tom@516 108 % get the avg_detects to connect filter_state to AGC_state:
tom@516 109 avg_detects = zeros(n_ch, n_mics);
tom@516 110 for mic = 1:n_mics
tom@516 111 % % mechanical response from filter output through HWR as AGC in:
tom@516 112 % avg_detects(:, mic) = CF.filter_state(mic).detect_accum / decim;
tom@516 113 CF.filter_state(mic).detect_accum(:) = 0; % zero the detect accumulator
tom@516 114 % New HACK, IHC output relative to rest as input to AGC:
tom@516 115 avg_detects(:, mic) = CF.IHC_state(mic).ihc_accum / decim;
tom@516 116 CF.IHC_state(mic).ihc_accum(:) = 0; % zero the detect accumulator
tom@516 117 end
tom@516 118
tom@516 119 % run the AGC update step:
tom@516 120 CF.AGC_state = CARFAC_AGCStep(CF.AGC_coeffs, avg_detects, CF.AGC_state);
tom@516 121
tom@516 122 % connect the feedback from AGC_state to filter_state:
tom@516 123 for mic = 1:n_mics
tom@516 124 new_damping = CF.AGC_state(mic).sum_AGC;
tom@516 125 % max_damping = 0.15; % HACK
tom@516 126 % new_damping = min(new_damping, max_damping);
tom@516 127 % set the delta needed to get to new_damping:
tom@516 128 CF.filter_state(mic).dzB_memory = ...
tom@516 129 (new_damping - CF.filter_state(mic).zB_memory) ...
tom@516 130 / decim;
tom@516 131 end
tom@516 132
tom@516 133 if AGC_plot_fig_num
tom@516 134 figure(AGC_plot_fig_num); hold off
tom@516 135 maxsum = 0;
tom@516 136 for mic = 1:n_mics
tom@516 137 plot(CF.AGC_state(mic).AGC_memory)
tom@516 138 agcsum = sum(CF.AGC_state(mic).AGC_memory, 2);
tom@516 139 maxsum(mic) = max(maxsum, max(agcsum));
tom@516 140 hold on
tom@516 141 plot(agcsum, 'k-')
tom@516 142 end
tom@516 143 axis([0, CF.n_ch, 0, max(0.001, maxsum)]);
tom@516 144 drawnow
tom@516 145 end
tom@516 146 end
tom@516 147 end
tom@516 148