# HG changeset patch # User dicklyon@google.com # Date 1335221920 0 # Node ID 3dff17554c6d9e8aa57b0075e72d57629f61efdc # Parent ab7fabe2af5dfd2a8726c79bf942512db9383ba8 add an ears array level everywhere diff -r ab7fabe2af5d -r 3dff17554c6d trunk/matlab/bmm/carfac/CARFAC_Close_AGC_Loop.m --- a/trunk/matlab/bmm/carfac/CARFAC_Close_AGC_Loop.m Mon Apr 23 21:02:04 2012 +0000 +++ b/trunk/matlab/bmm/carfac/CARFAC_Close_AGC_Loop.m Mon Apr 23 22:58:40 2012 +0000 @@ -24,12 +24,12 @@ decim1 = CF.AGC_params.decimation(1); for ear = 1:CF.n_ears - extra_damping = CF.AGC_state(ear).AGC_memory(:, 1); % stage 1 result + extra_damping = CF.ears(ear).AGC_state.AGC_memory(:, 1); % stage 1 result % Update the target stage gain for the new damping: - new_g = CARFAC_Stage_g(CF.CAR_coeffs, extra_damping); + new_g = CARFAC_Stage_g(CF.ears(ear).CAR_coeffs, extra_damping); % set the deltas needed to get to the new damping: - CF.CAR_state(ear).dzB_memory = ... - (extra_damping - CF.CAR_state(ear).zB_memory) / decim1; - CF.CAR_state(ear).dg_memory = ... - (new_g - CF.CAR_state(ear).g_memory) / decim1; + CF.ears(ear).CAR_state.dzB_memory = ... + (extra_damping - CF.ears(ear).CAR_state.zB_memory) / decim1; + CF.ears(ear).CAR_state.dg_memory = ... + (new_g - CF.ears(ear).CAR_state.g_memory) / decim1; end diff -r ab7fabe2af5d -r 3dff17554c6d trunk/matlab/bmm/carfac/CARFAC_Cross_Couple.m --- a/trunk/matlab/bmm/carfac/CARFAC_Cross_Couple.m Mon Apr 23 21:02:04 2012 +0000 +++ b/trunk/matlab/bmm/carfac/CARFAC_Cross_Couple.m Mon Apr 23 22:58:40 2012 +0000 @@ -1,25 +1,26 @@ -function AGC_state = CARFAC_Cross_Couple(AGC_coeffs, AGC_state); +function ears = CARFAC_Cross_Couple(ears); -n_ears = length(AGC_state); +n_ears = length(ears); if n_ears > 1 + n_stages = ears(1).AGC_coeffs.n_AGC_stages; % now cross-ear mix the stages that updated (leading stages at phase 0): - for stage = 1:AGC_coeffs.n_AGC_stages - if AGC_state(1).decim_phase(stage) > 0 + for stage = 1:n_stages + if ears(1).AGC_state.decim_phase(stage) > 0 break % all recently updated stages are finished else - mix_coeff = AGC_coeffs.AGC_mix_coeffs(stage); + mix_coeff = ears(1).AGC_coeffs.AGC_mix_coeffs(stage); if mix_coeff > 0 % Typically stage 1 has 0 so no work on that one. this_stage_sum = 0; % sum up over the ears and get their mean: for ear = 1:n_ears - stage_state = AGC_state(ear).AGC_memory(:, stage); + stage_state = ears(ear).AGC_state.AGC_memory(:, stage); this_stage_sum = this_stage_sum + stage_state; end this_stage_mean = this_stage_sum / n_ears; % now move them all toward the mean: for ear = 1:n_ears - stage_state = AGC_state(ear).AGC_memory(:, stage); - AGC_state(ear).AGC_memory(:, stage) = ... + stage_state = ears(ear).AGC_state.AGC_memory(:, stage); + ears(ear).AGC_state.AGC_memory(:, stage) = ... stage_state + mix_coeff * (this_stage_mean - stage_state); end end diff -r ab7fabe2af5d -r 3dff17554c6d trunk/matlab/bmm/carfac/CARFAC_Design.m --- a/trunk/matlab/bmm/carfac/CARFAC_Design.m Mon Apr 23 21:02:04 2012 +0000 +++ b/trunk/matlab/bmm/carfac/CARFAC_Design.m Mon Apr 23 22:58:40 2012 +0000 @@ -17,7 +17,7 @@ % See the License for the specific language governing permissions and % limitations under the License. -function CF = CARFAC_Design(fs, CF_CAR_params, CF_AGC_params, CF_IHC_params) +function CF = CARFAC_Design(n_ears, fs, CF_CAR_params, CF_AGC_params, CF_IHC_params) % function CF = CARFAC_Design(fs, CF_CAR_params, ... % CF_AGC_params, ERB_break_freq, ERB_Q, CF_IHC_params) % @@ -41,7 +41,44 @@ % All args are defaultable; for sample/default args see the code; they % make 96 channels at default fs = 22050, 114 channels at 44100. +if nargin < 1 + n_ears = 1; % if more than 1, make them identical channels; + % then modify the design if necessary for different reasons +end + +if nargin < 2 + fs = 22050; +end + +if nargin < 3 + CF_CAR_params = struct( ... + 'velocity_scale', 0.2, ... % for the "cubic" velocity nonlinearity + 'v_offset', 0.01, ... % offset gives a quadratic part + 'v2_corner', 0.2, ... % corner for essential nonlin + 'v_damp_max', 0.01, ... % damping delta damping from velocity nonlin + 'min_zeta', 0.10, ... % minimum damping factor in mid-freq channels + 'first_pole_theta', 0.85*pi, ... + 'zero_ratio', sqrt(2), ... % how far zero is above pole + 'high_f_damping_compression', 0.5, ... % 0 to 1 to compress zeta + 'ERB_per_step', 0.5, ... % assume G&M's ERB formula + 'min_pole_Hz', 30, ... + 'ERB_break_freq', 165.3, ... % Greenwood map's break freq. + 'ERB_Q', 1000/(24.7*4.37)); % Glasberg and Moore's high-cf ratio +end + if nargin < 4 + CF_AGC_params = struct( ... + 'n_stages', 4, ... + 'time_constants', [1, 4, 16, 64]*0.002, ... + 'AGC_stage_gain', 2, ... % gain from each stage to next slower stage + 'decimation', [8, 2, 2, 2], ... % how often to update the AGC states + 'AGC1_scales', [1.0, 1.4, 2.0, 2.8], ... % in units of channels + 'AGC2_scales', [1.6, 2.25, 3.2, 4.5], ... % spread more toward base + 'detect_scale', 0.25, ... % the desired damping range + 'AGC_mix_coeff', 0.5); +end + +if nargin < 5 % HACK: these constant control the defaults one_cap = 0; % bool; 0 for new two-cap hack just_hwr = 0; % book; 0 for normal/fancy IHC; 1 for HWR @@ -68,37 +105,7 @@ end end -if nargin < 3 - CF_AGC_params = struct( ... - 'n_stages', 4, ... - 'time_constants', [1, 4, 16, 64]*0.002, ... - 'AGC_stage_gain', 2, ... % gain from each stage to next slower stage - 'decimation', [8, 2, 2, 2], ... % how often to update the AGC states - 'AGC1_scales', [1.0, 1.4, 2.0, 2.8], ... % in units of channels - 'AGC2_scales', [1.6, 2.25, 3.2, 4.5], ... % spread more toward base - 'detect_scale', 0.25, ... % the desired damping range - 'AGC_mix_coeff', 0.5); -end -if nargin < 2 - CF_CAR_params = struct( ... - 'velocity_scale', 0.2, ... % for the "cubic" velocity nonlinearity - 'v_offset', 0.01, ... % offset gives a quadratic part - 'v2_corner', 0.2, ... % corner for essential nonlin - 'v_damp_max', 0.01, ... % damping delta damping from velocity nonlin - 'min_zeta', 0.10, ... % minimum damping factor in mid-freq channels - 'first_pole_theta', 0.85*pi, ... - 'zero_ratio', sqrt(2), ... % how far zero is above pole - 'high_f_damping_compression', 0.5, ... % 0 to 1 to compress zeta - 'ERB_per_step', 0.5, ... % assume G&M's ERB formula - 'min_pole_Hz', 30, ... - 'ERB_break_freq', 165.3, ... % Greenwood map's break freq. - 'ERB_Q', 1000/(24.7*4.37)); % Glasberg and Moore's high-cf ratio -end - -if nargin < 1 - fs = 22050; -end % first figure out how many filter stages (PZFC/CARFAC channels): pole_Hz = CF_CAR_params.first_pole_theta * fs / (2*pi); @@ -121,6 +128,18 @@ max_channels_per_octave = log(2) / log(pole_freqs(1)/pole_freqs(2)); +% convert to include an ear_array, each w coeffs and state... +CAR_coeffs = CARFAC_DesignFilters(CF_CAR_params, fs, pole_freqs); +AGC_coeffs = CARFAC_DesignAGC(CF_AGC_params, fs, n_ch); +IHC_coeffs = CARFAC_DesignIHC(CF_IHC_params, fs, n_ch); +% copy same designed coeffs into each ear (can do differently in the +% future: +for ear = 1:n_ears + ears(ear).CAR_coeffs = CAR_coeffs; + ears(ear).AGC_coeffs = AGC_coeffs; + ears(ear).IHC_coeffs = IHC_coeffs; +end + CF = struct( ... 'fs', fs, ... 'max_channels_per_octave', max_channels_per_octave, ... @@ -129,10 +148,8 @@ 'IHC_params', CF_IHC_params, ... 'n_ch', n_ch, ... 'pole_freqs', pole_freqs, ... - 'CAR_coeffs', CARFAC_DesignFilters(CF_CAR_params, fs, pole_freqs), ... - 'AGC_coeffs', CARFAC_DesignAGC(CF_AGC_params, fs, n_ch), ... - 'IHC_coeffs', CARFAC_DesignIHC(CF_IHC_params, fs, n_ch), ... - 'n_ears', 0 ); + 'ears', ears, ... + 'n_ears', n_ears ); @@ -238,7 +255,7 @@ delay = (AGC2_scales(stage) - AGC1_scales(stage)) / ntimes; spread_sq = (AGC1_scales(stage)^2 + AGC2_scales(stage)^2) / ntimes; - % get pole positions to better match intended spread and delay of + % get pole positions to better match intended spread and delay of % [[geometric distribution]] in each direction (see wikipedia) u = 1 + 1 / spread_sq; % these are based on off-line algebra hacking. p = u - sqrt(u^2 - 1); % pole that would give spread if used twice. @@ -333,9 +350,9 @@ function IHC_coeffs = CARFAC_DesignIHC(IHC_params, fs, n_ch) if IHC_params.just_hwr - IHC_coeffs = struct( ... - 'n_ch', n_ch, ... - 'just_hwr', 1); + IHC_coeffs = struct( ... + 'n_ch', n_ch, ... + 'just_hwr', 1); else if IHC_params.one_cap ro = 1 / CARFAC_Detect(2); % output resistance @@ -362,7 +379,7 @@ 'cap_voltage', IHC_coeffs.rest_cap, ... 'lpf1_state', 0, ... 'lpf2_state', 0, ... - 'ihc_accum', 0); + 'ihc_accum', 0); else ro = 1 / CARFAC_Detect(2); % output resistance c2 = IHC_params.tau2_out / ro; @@ -410,7 +427,7 @@ % CF.CAR_coeffs % CF.AGC_coeffs % CF.IHC_coeffs -% CF = +% CF = % fs: 22050 % max_channels_per_octave: 12.2709 % CAR_params: [1x1 struct] @@ -422,7 +439,7 @@ % AGC_coeffs: [1x1 struct] % IHC_coeffs: [1x1 struct] % n_ears: 0 -% ans = +% ans = % velocity_scale: 0.2000 % v_offset: 0.0100 % v2_corner: 0.2000 @@ -435,7 +452,7 @@ % min_pole_Hz: 30 % ERB_break_freq: 165.3000 % ERB_Q: 9.2645 -% ans = +% ans = % n_stages: 4 % time_constants: [0.0020 0.0080 0.0320 0.1280] % AGC_stage_gain: 2 @@ -444,7 +461,7 @@ % AGC2_scales: [1.6000 2.2500 3.2000 4.5000] % detect_scale: 0.2500 % AGC_mix_coeff: 0.5000 -% ans = +% ans = % n_ch: 71 % velocity_scale: 0.2000 % v_offset: 0.0100 @@ -456,7 +473,7 @@ % h_coeffs: [71x1 double] % g0_coeffs: [71x1 double] % zr_coeffs: [71x1 double] -% ans = +% ans = % n_ch: 71 % n_AGC_stages: 4 % AGC_stage_gain: 2 @@ -470,7 +487,7 @@ % AGC_mix_coeffs: [0 0.0454 0.0227 0.0113] % AGC_gain: 15 % detect_scale: 0.0167 -% ans = +% ans = % n_ch: 71 % just_hwr: 0 % lpf_coeff: 0.4327 diff -r ab7fabe2af5d -r 3dff17554c6d trunk/matlab/bmm/carfac/CARFAC_Init.m --- a/trunk/matlab/bmm/carfac/CARFAC_Init.m Mon Apr 23 21:02:04 2012 +0000 +++ b/trunk/matlab/bmm/carfac/CARFAC_Init.m Mon Apr 23 22:58:40 2012 +0000 @@ -17,41 +17,19 @@ % See the License for the specific language governing permissions and % limitations under the License. -function CF_struct = CARFAC_Init(CF_struct, n_ears) -% function CF_struct = CARFAC_Init(CF_struct, n_ears) +function CF = CARFAC_Init(CF) +% function CF = CARFAC_Init(CF) % -% Initialize state for n_ears channels (default 1). -% This allocates and zeros all the state vector storage in the CF_struct. +% Initialize state for one or more ears of CF. +% This allocates and zeros all the state vector storage in the CF struct. -% TODO (dicklyon): Review whether storing state in the same struct as -% the design is a good thing, or whether we want another -% level of object. I like fewer structs and class types. +n_ears = CF.n_ears; -if nargin < 2 - n_ears = 1; % monaural default -end - -% % this is probably what I'd do in the C++ version: -% if CF_struct.n_ears ~= n_ears; -% % free the state and make new number of channels -% % make a struct arrray, one element per ear channel, numbered: -% for k = 1:n_ears -% CF_struct.state(k) = struct('ear_number', k); -% end -% end -% But this code doesn't work because I don't understand struct arrays. - -% For now I don't ever free anything if n_ears is reduced; -% so be sure to respect n_ears, not the size of the state struct array. - -CF_struct.n_ears = n_ears; - -% These inits grow the struct arrays as needed: for ear = 1:n_ears % for now there's only one coeffs, not one per ear - CF_struct.CAR_state(ear) = CAR_Init_State(CF_struct.CAR_coeffs); - CF_struct.IHC_state(ear) = IHC_Init_State(CF_struct.IHC_coeffs); - CF_struct.AGC_state(ear) = AGC_Init_State(CF_struct.AGC_coeffs); + CF.ears(ear).CAR_state = CAR_Init_State(CF.ears(ear).CAR_coeffs); + CF.ears(ear).IHC_state = IHC_Init_State(CF.ears(ear).IHC_coeffs); + CF.ears(ear).AGC_state = AGC_Init_State(CF.ears(ear).AGC_coeffs); end diff -r ab7fabe2af5d -r 3dff17554c6d trunk/matlab/bmm/carfac/CARFAC_Run.m --- a/trunk/matlab/bmm/carfac/CARFAC_Run.m Mon Apr 23 21:02:04 2012 +0000 +++ b/trunk/matlab/bmm/carfac/CARFAC_Run.m Mon Apr 23 22:58:40 2012 +0000 @@ -110,18 +110,18 @@ if ~isempty(decim_naps) for ear = 1:n_ears - decim_naps(seg_num, :, ear) = CF.IHC_state(ear).ihc_accum / seglen; - CF.IHC_state(ear).ihc_accum = zeros(n_ch,1); + decim_naps(seg_num, :, ear) = CF.ears(ear).IHC_state.ihc_accum / seglen; + CF.ears(ear).IHC_state.ihc_accum = zeros(n_ch,1); end end if AGC_plot_fig_num figure(AGC_plot_fig_num); hold off; clf for ear = 1:n_ears - maxes(ear) = max(CF.AGC_state(ear).AGC_memory(:)); + maxes(ear) = max(CF.ears(ear).AGC_state.AGC_memory(:)); hold on for stage = 1:4; - plot(2^(stage-1) * CF.AGC_state(ear).AGC_memory(:, stage)); + plot(2^(stage-1) * CF.ears(ear).AGC_state.AGC_memory(:, stage)); end end axis([0, CF.n_ch+1, 0.0, max(maxes) * 1.01 + 0.002]); diff -r ab7fabe2af5d -r 3dff17554c6d trunk/matlab/bmm/carfac/CARFAC_Run_Linear.m --- a/trunk/matlab/bmm/carfac/CARFAC_Run_Linear.m Mon Apr 23 21:02:04 2012 +0000 +++ b/trunk/matlab/bmm/carfac/CARFAC_Run_Linear.m Mon Apr 23 22:58:40 2012 +0000 @@ -25,8 +25,11 @@ % however, unlike CARFAC_Run, it forces it to be linear, and gives a % linear (not detected) output. -saved_v_damp_max = CF.CAR_coeffs.v_damp_max; -CF.CAR_coeffs.v_damp_max = 0.00; % make it linear for now +% only saving one of these, really: +saved_v_damp_max = CF.ears(1).CAR_coeffs.v_damp_max; +for ear = 1:CF.n_ears + CF.ears(ear).CAR_coeffs.v_damp_max = 0.00; % make it linear for now +end [n_samp, n_ears] = size(input_waves); n_ch = CF.n_ch; @@ -41,11 +44,11 @@ for ear = 1:CF.n_ears % Set the state of damping, and prevent interpolation from there: - CF.CAR_state(ear).zB_memory(:) = extra_damping; % interpolator state - CF.CAR_state(ear).dzB_memory(:) = 0; % interpolator slope - CF.CAR_state(ear).g_memory = CARFAC_Stage_g( ... - CF.CAR_coeffs(ear), extra_damping); - CF.CAR_state(ear).dg_memory(:) = 0; % interpolator slope + CF.ears(ear).CAR_state.zB_memory(:) = extra_damping; % interpolator state + CF.ears(ear).CAR_state.dzB_memory(:) = 0; % interpolator slope + CF.ears(ear).CAR_state.g_memory = CARFAC_Stage_g( ... + CF.ears(ear).CAR_coeffs(ear), extra_damping); + CF.ears(ear).CAR_state.dg_memory(:) = 0; % interpolator slope end naps = zeros(n_samp, n_ch, n_ears); @@ -53,12 +56,14 @@ for k = 1:n_samp % at each time step, possibly handle multiple channels for ear = 1:n_ears - [filters_out, CF.CAR_state(ear)] = CARFAC_CAR_Step( ... - input_waves(k, ear), CF.CAR_coeffs, CF.CAR_state(ear)); + [filters_out, CF.ears(ear).CAR_state] = CARFAC_CAR_Step( ... + input_waves(k, ear), CF.ears(ear).CAR_coeffs, CF.ears(ear).CAR_state); naps(k, :, ear) = filters_out; % linear end % skip IHC and AGC updates end -CF.CAR_coeffs.v_damp_max = saved_v_damp_max; +for ear = 1:CF.n_ears + CF.ears(ear).CAR_coeffs.v_damp_max = saved_v_damp_max; +end diff -r ab7fabe2af5d -r 3dff17554c6d trunk/matlab/bmm/carfac/CARFAC_Run_Segment.m --- a/trunk/matlab/bmm/carfac/CARFAC_Run_Segment.m Mon Apr 23 21:02:04 2012 +0000 +++ b/trunk/matlab/bmm/carfac/CARFAC_Run_Segment.m Mon Apr 23 22:58:40 2012 +0000 @@ -71,16 +71,16 @@ for k = 1:n_samp % at each time step, possibly handle multiple channels for ear = 1:n_ears - [car_out, CF.CAR_state(ear)] = CARFAC_CAR_Step( ... - input_waves(k, ear), CF.CAR_coeffs, CF.CAR_state(ear)); + [car_out, CF.ears(ear).CAR_state] = CARFAC_CAR_Step( ... + input_waves(k, ear), CF.ears(ear).CAR_coeffs, CF.ears(ear).CAR_state); % update IHC state & output on every time step, too - [ihc_out, CF.IHC_state(ear)] = CARFAC_IHC_Step( ... - car_out, CF.IHC_coeffs, CF.IHC_state(ear)); + [ihc_out, CF.ears(ear).IHC_state] = CARFAC_IHC_Step( ... + car_out, CF.ears(ear).IHC_coeffs, CF.ears(ear).IHC_state); % run the AGC update step, decimating internally, - [CF.AGC_state(ear), updated] = CARFAC_AGC_Step( ... - CF.AGC_coeffs, ihc_out, CF.AGC_state(ear)); + [CF.ears(ear).AGC_state, updated] = CARFAC_AGC_Step( ... + CF.ears(ear).AGC_coeffs, ihc_out, CF.ears(ear).AGC_state); % save some output data: naps(k, :, ear) = ihc_out; % output to neural activity pattern @@ -94,7 +94,7 @@ if updated if n_ears > 1 % do multi-aural cross-coupling: - CF.AGC_state = CARFAC_Cross_Couple(CF.AGC_coeffs, CF.AGC_state); + CF.ears = CARFAC_Cross_Couple(CF.ears); end if ~open_loop CF = CARFAC_Close_AGC_Loop(CF); diff -r ab7fabe2af5d -r 3dff17554c6d trunk/matlab/bmm/carfac/CARFAC_Transfer_Functions.m --- a/trunk/matlab/bmm/carfac/CARFAC_Transfer_Functions.m Mon Apr 23 21:02:04 2012 +0000 +++ b/trunk/matlab/bmm/carfac/CARFAC_Transfer_Functions.m Mon Apr 23 22:58:40 2012 +0000 @@ -30,7 +30,7 @@ % complex_transfns_freqs has a row of complex gains per to_channel. % always start with the rational functions, whether we want to return -% them or not: +% them or not; this defaults to ear 1 only: [stage_numerators, stage_denominators] = CARFAC_Rational_Functions(CF); if nargin >= 2 @@ -96,13 +96,17 @@ function [stage_numerators, stage_denominators] = ... - CARFAC_Rational_Functions(CF) + CARFAC_Rational_Functions(CF, ear) % function [stage_z_numerators, stage_z_denominators] = ... -% CARFAC_Rational_Functions(CF, chans) +% CARFAC_Rational_Functions(CF, ear) % Return transfer functions of all stages as rational functions. +if nargin < 2 + ear = 1; +end + n_ch = CF.n_ch; -coeffs = CF.CAR_coeffs; +coeffs = CF.ears(ear).CAR_coeffs; min_zeta = CF.CAR_params.min_zeta; a0 = coeffs.a0_coeffs; @@ -111,8 +115,8 @@ % get r, adapted if we have state: r = coeffs.r1_coeffs; -if isfield(CF, 'CAR_state') - state = CF.CAR_state; +if isfield(CF.ears(ear), 'CAR_state') + state = CF.ears(ear).CAR_state; zB = state.zB_memory; % current extra damping r = r - zr .* zB; else diff -r ab7fabe2af5d -r 3dff17554c6d trunk/matlab/bmm/carfac/CARFAC_hacking.m --- a/trunk/matlab/bmm/carfac/CARFAC_hacking.m Mon Apr 23 21:02:04 2012 +0000 +++ b/trunk/matlab/bmm/carfac/CARFAC_hacking.m Mon Apr 23 22:58:40 2012 +0000 @@ -52,20 +52,21 @@ test_signal = [test_signal; file_signal * 10^(dB/20)]; end -%% -CF_struct = CARFAC_Design; % default design %% Run mono, then stereo test: agc_plot_fig_num = 6; for n_ears = 1:2 + + CF_struct = CARFAC_Design(n_ears); % default design + if n_ears == 2 % For the 2-channel pass, add a silent second channel: test_signal = [test_signal, zeros(size(test_signal))]; end - CF_struct = CARFAC_Init(CF_struct, n_ears); + CF_struct = CARFAC_Init(CF_struct); [CF_struct, nap_decim, nap, BM] = CARFAC_Run(CF_struct, test_signal, ... agc_plot_fig_num);