Mercurial > hg > aimc
changeset 504:a0869cb1c99b
Major update to how the DOHC works; like in recent book OHC chapter; Design Doc update (a bit)
author | dicklyon@google.com |
---|---|
date | Thu, 24 May 2012 22:26:56 +0000 |
parents | 37c007925536 |
children | db0e5e86fddd |
files | matlab/bmm/carfac/CARFAC_AGC_Step.m matlab/bmm/carfac/CARFAC_CAR_Step.m matlab/bmm/carfac/CARFAC_Close_AGC_Loop.m matlab/bmm/carfac/CARFAC_Design.m matlab/bmm/carfac/CARFAC_Design_Doc.txt matlab/bmm/carfac/CARFAC_IHC_Step.m matlab/bmm/carfac/CARFAC_Init.m matlab/bmm/carfac/CARFAC_OHC_NLF.m matlab/bmm/carfac/CARFAC_Run.m matlab/bmm/carfac/CARFAC_Run_Linear.m matlab/bmm/carfac/CARFAC_Run_Segment.m matlab/bmm/carfac/CARFAC_Stage_g.m matlab/bmm/carfac/CARFAC_Transfer_Functions.m matlab/bmm/carfac/CARFAC_hacking.m matlab/bmm/carfac/MultiScaleSmooth.m |
diffstat | 15 files changed, 188 insertions(+), 199 deletions(-) [+] |
line wrap: on
line diff
--- a/matlab/bmm/carfac/CARFAC_AGC_Step.m Sat May 12 04:31:59 2012 +0000 +++ b/matlab/bmm/carfac/CARFAC_AGC_Step.m Thu May 24 22:26:56 2012 +0000 @@ -17,8 +17,8 @@ % See the License for the specific language governing permissions and % limitations under the License. -function [state, updated] = CARFAC_AGC_Step(coeffs, detects, state) -% function [state, updated] = CARFAC_AGC_Step(coeffs, detects, state) +function [state, updated] = CARFAC_AGC_Step(detects, coeffs, state) +% function [state, updated] = CARFAC_AGC_Step(detects, coeffs, state) % % one time step of the AGC state update; decimates internally
--- a/matlab/bmm/carfac/CARFAC_CAR_Step.m Sat May 12 04:31:59 2012 +0000 +++ b/matlab/bmm/carfac/CARFAC_CAR_Step.m Thu May 24 22:26:56 2012 +0000 @@ -17,21 +17,27 @@ % See the License for the specific language governing permissions and % limitations under the License. -function [zY, state] = CARFAC_CAR_Step(x_in, CAR_coeffs, state) +function [car_out, state] = CARFAC_CAR_Step(x_in, CAR_coeffs, state) % function [zY, state] = CARFAC_CAR_Step(x_in, CAR_coeffs, state) % % One sample-time update step for the filter part of the CARFAC. % Most of the update is parallel; finally we ripple inputs at the end. -% Local nonlinearity zA and AGC feedback zB reduce pole radius: + +% do the DOHC stuff: + +g = state.g_memory + state.dg_memory; % interp g +zB = state.zB_memory + state.dzB_memory; % AGC interpolation state +% update the nonlinear function of "velocity", and zA (delay of z2): zA = state.zA_memory; -zB = state.zB_memory + state.dzB_memory; % AGC interpolation -r1 = CAR_coeffs.r1_coeffs; -g = state.g_memory + state.dg_memory; % interp g +v = state.z2_memory - zA; +% nlf = CARFAC_OHC_NLF(v .* widen, CAR_coeffs); % widen v with feedback +nlf = CARFAC_OHC_NLF(v, CAR_coeffs); +% zB * nfl is "undamping" delta r: +r = CAR_coeffs.r1_coeffs + zB .* nlf; +zA = state.z2_memory; -% zB and zA are "extra damping", and multiply zr (compressed theta): -r = r1 - CAR_coeffs.zr_coeffs .* (zA + zB); % now reduce state by r and rotate with the fixed cos/sin coeffs: z1 = r .* (CAR_coeffs.a0_coeffs .* state.z1_memory - ... @@ -40,9 +46,6 @@ z2 = r .* (CAR_coeffs.c0_coeffs .* state.z1_memory + ... CAR_coeffs.a0_coeffs .* state.z2_memory); -% update the nonlinear function of "velocity", into zA: -zA = CARFAC_OHC_NLF(state.z2_memory - z2, CAR_coeffs); - zY = CAR_coeffs.h_coeffs .* z2; % partial output % Ripple input-output path, instead of parallel, to avoid delay... @@ -57,7 +60,7 @@ end % put new state back in place of old -% (z1 and z2 are genuine temps; the others can update by reference in C) +% (z1 is a genuine temp; the others can update by reference in C) state.z1_memory = z1; state.z2_memory = z2; state.zA_memory = zA; @@ -65,3 +68,6 @@ state.zY_memory = zY; state.g_memory = g; +car_out = zY; + +
--- a/matlab/bmm/carfac/CARFAC_Close_AGC_Loop.m Sat May 12 04:31:59 2012 +0000 +++ b/matlab/bmm/carfac/CARFAC_Close_AGC_Loop.m Thu May 24 22:26:56 2012 +0000 @@ -24,12 +24,13 @@ decim1 = CF.AGC_params.decimation(1); for ear = 1:CF.n_ears - extra_damping = CF.ears(ear).AGC_state.AGC_memory(:, 1); % stage 1 result + undamping = 1 - 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.ears(ear).CAR_coeffs, extra_damping); + new_g = CARFAC_Stage_g(CF.ears(ear).CAR_coeffs, undamping); % set the deltas needed to get to the new damping: CF.ears(ear).CAR_state.dzB_memory = ... - (extra_damping - CF.ears(ear).CAR_state.zB_memory) / decim1; + (CF.ears(ear).CAR_coeffs.zr_coeffs .* undamping - ... + 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
--- a/matlab/bmm/carfac/CARFAC_Design.m Sat May 12 04:31:59 2012 +0000 +++ b/matlab/bmm/carfac/CARFAC_Design.m Thu May 24 22:26:56 2012 +0000 @@ -52,11 +52,11 @@ if nargin < 3 CF_CAR_params = struct( ... - 'velocity_scale', 0.2, ... % for the "cubic" velocity nonlinearity + 'velocity_scale', 0.05, ... % for the velocity nonlinearity 'v_offset', 0.04, ... % 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 + 'max_zeta', 0.35, ... % maximum 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 @@ -71,10 +71,9 @@ 'n_stages', 4, ... 'time_constants', [1, 4, 16, 64]*0.002, ... 'AGC_stage_gain', 2, ... % gain from each stage to next slower stage - 'decimation', [4, 2, 2, 2], ... % how often to update the AGC states + '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 @@ -83,7 +82,8 @@ one_cap = 0; % bool; 0 for new two-cap hack just_hwr = 0; % book; 0 for normal/fancy IHC; 1 for HWR if just_hwr - CF_IHC_params = struct('just_hwr', 1); % just a simple HWR + CF_IHC_params = struct('just_hwr', 1, ... % just a simple HWR + 'ac_corner_Hz', 20); else if one_cap CF_IHC_params = struct( ... @@ -91,7 +91,8 @@ 'one_cap', one_cap, ... % bool; 0 for new two-cap hack 'tau_lpf', 0.000080, ... % 80 microseconds smoothing twice 'tau_out', 0.0005, ... % depletion tau is pretty fast - 'tau_in', 0.010 ); % recovery tau is slower + 'tau_in', 0.010, ... % recovery tau is slower + 'ac_corner_Hz', 20); else CF_IHC_params = struct( ... 'just_hwr', just_hwr, ... % not just a simple HWR @@ -100,7 +101,8 @@ 'tau1_out', 0.010, ... % depletion tau is pretty fast 'tau1_in', 0.020, ... % recovery tau is slower 'tau2_out', 0.0025, ... % depletion tau is pretty fast - 'tau2_in', 0.005 ); % recovery tau is slower + 'tau2_in', 0.005, ... % recovery tau is slower + 'ac_corner_Hz', 20); end end end @@ -164,8 +166,7 @@ 'n_ch', n_ch, ... 'velocity_scale', CAR_params.velocity_scale, ... 'v_offset', CAR_params.v_offset, ... - 'v2_corner', CAR_params.v2_corner, ... - 'v_damp_max', CAR_params.v_damp_max ... + 'v2_corner', CAR_params.v2_corner ... ); % don't really need these zero arrays, but it's a clue to what fields @@ -194,18 +195,19 @@ % Compress theta to give somewhat higher Q at highest thetas: ff = CAR_params.high_f_damping_compression; % 0 to 1; typ. 0.5 x = theta/pi; + zr_coeffs = pi * (x - ff * x.^3); % when ff is 0, this is just theta, % and when ff is 1 it goes to zero at theta = pi. -CAR_coeffs.zr_coeffs = zr_coeffs; % how r relates to zeta +max_zeta = CAR_params.max_zeta; +CAR_coeffs.r1_coeffs = (1 - zr_coeffs .* max_zeta); % "r1" for the max-damping condition min_zeta = CAR_params.min_zeta; -% increase the min damping where channels are spaced out more: - -min_zeta = min_zeta + 0.25*(ERB_Hz(pole_freqs, ... +% Increase the min damping where channels are spaced out more, by pulling +% 25% of the way toward ERB_Hz/pole_freqs (close to 0.1 at high f) +min_zetas = min_zeta + 0.25*(ERB_Hz(pole_freqs, ... CAR_params.ERB_break_freq, CAR_params.ERB_Q) ./ pole_freqs - min_zeta); -r1 = (1 - zr_coeffs .* min_zeta); % "1" for the min-damping condition - -CAR_coeffs.r1_coeffs = r1; +CAR_coeffs.zr_coeffs = zr_coeffs .* ... + (max_zeta - min_zetas); % how r relates to undamping % undamped coupled-form coefficients: CAR_coeffs.a0_coeffs = a0; @@ -216,10 +218,10 @@ CAR_coeffs.h_coeffs = h; % for unity gain at min damping, radius r; only used in CARFAC_Init: -extra_damping = zeros(size(r1)); +relative_undamping = ones(n_ch, 1); % max undamping to start % this function needs to take CAR_coeffs even if we haven't finished % constucting it by putting in the g0_coeffs: -CAR_coeffs.g0_coeffs = CARFAC_Stage_g(CAR_coeffs, extra_damping); +CAR_coeffs.g0_coeffs = CARFAC_Stage_g(CAR_coeffs, relative_undamping); %% the AGC design coeffs: @@ -310,14 +312,8 @@ AGC_coeffs.AGC_gain = total_DC_gain; -% adjust the detect_scale by the total DC gain of the AGC filters: -AGC_coeffs.detect_scale = AGC_params.detect_scale / total_DC_gain; - -% % print some results -AGC_coeffs -AGC_spatial_FIR = AGC_coeffs.AGC_spatial_FIR -AGC_spatial_iterations = AGC_coeffs.AGC_spatial_iterations -AGC_spatial_n_taps = AGC_coeffs.AGC_spatial_n_taps +% adjust the detect_scale to be the reciprocal DC gain of the AGC filters: +AGC_coeffs.detect_scale = 1 / total_DC_gain; %% @@ -355,7 +351,7 @@ 'just_hwr', 1); else if IHC_params.one_cap - ro = 1 / CARFAC_Detect(2); % output resistance + ro = 1 / CARFAC_Detect(10); % output resistance at a very high level c = IHC_params.tau_out / ro; ri = IHC_params.tau_in / c; % to get steady-state average, double ro for 50% duty cycle @@ -381,7 +377,7 @@ 'lpf2_state', 0, ... 'ihc_accum', 0); else - ro = 1 / CARFAC_Detect(2); % output resistance + ro = 1 / CARFAC_Detect(10); % output resistance at a very high level c2 = IHC_params.tau2_out / ro; r2 = IHC_params.tau2_in / c2; c1 = IHC_params.tau1_out / r2; @@ -415,6 +411,8 @@ 'ihc_accum', 0); end end +% one more late addition that applies to all cases: +IHC_coeffs.ac_coeff = 2 * pi * IHC_params.ac_corner_Hz / fs; %% % default design result, running this function with no args, should look @@ -422,12 +420,15 @@ % % % CF = CARFAC_Design -% CF.CAR_params -% CF.AGC_params -% CF.CAR_coeffs -% CF.AGC_coeffs -% CF.IHC_coeffs -% CF = +% CAR_params = CF.CAR_params +% AGC_params = CF.AGC_params +% IHC_params = CF.IHC_params +% CAR_coeffs = CF.ears(1).CAR_coeffs +% AGC_coeffs = CF.ears(1).AGC_coeffs +% AGC_spatial_FIR = AGC_coeffs.AGC_spatial_FIR +% IHC_coeffs = CF.ears(1).IHC_coeffs + +% CF = % fs: 22050 % max_channels_per_octave: 12.2709 % CAR_params: [1x1 struct] @@ -435,16 +436,14 @@ % IHC_params: [1x1 struct] % n_ch: 71 % pole_freqs: [71x1 double] -% CAR_coeffs: [1x1 struct] -% AGC_coeffs: [1x1 struct] -% IHC_coeffs: [1x1 struct] -% n_ears: 0 -% ans = -% velocity_scale: 0.2000 -% v_offset: 0.0100 +% ears: [1x1 struct] +% n_ears: 1 +% CAR_params = +% velocity_scale: 0.0500 +% v_offset: 0.0400 % v2_corner: 0.2000 -% v_damp_max: 0.0100 % min_zeta: 0.1000 +% max_zeta: 0.3500 % first_pole_theta: 2.6704 % zero_ratio: 1.4142 % high_f_damping_compression: 0.5000 @@ -452,28 +451,35 @@ % min_pole_Hz: 30 % ERB_break_freq: 165.3000 % ERB_Q: 9.2645 -% ans = +% AGC_params = % n_stages: 4 % time_constants: [0.0020 0.0080 0.0320 0.1280] % AGC_stage_gain: 2 % decimation: [8 2 2 2] % AGC1_scales: [1 1.4000 2 2.8000] % AGC2_scales: [1.6000 2.2500 3.2000 4.5000] -% detect_scale: 0.2500 % AGC_mix_coeff: 0.5000 -% ans = +% IHC_params = +% just_hwr: 0 +% one_cap: 0 +% tau_lpf: 8.0000e-05 +% tau1_out: 0.0100 +% tau1_in: 0.0200 +% tau2_out: 0.0025 +% tau2_in: 0.0050 +% ac_corner_Hz: 20 +% CAR_coeffs = % n_ch: 71 -% velocity_scale: 0.2000 -% v_offset: 0.0100 +% velocity_scale: 0.0500 +% v_offset: 0.0400 % v2_corner: 0.2000 -% v_damp_max: 0.0100 % r1_coeffs: [71x1 double] % a0_coeffs: [71x1 double] % c0_coeffs: [71x1 double] % h_coeffs: [71x1 double] % g0_coeffs: [71x1 double] % zr_coeffs: [71x1 double] -% ans = +% AGC_coeffs = % n_ch: 71 % n_AGC_stages: 4 % AGC_stage_gain: 2 @@ -486,17 +492,25 @@ % AGC_spatial_n_taps: [3 3 3 3] % AGC_mix_coeffs: [0 0.0454 0.0227 0.0113] % AGC_gain: 15 -% detect_scale: 0.0167 -% ans = +% detect_scale: 0.0667 +% AGC_spatial_FIR = +% 0.2744 0.2829 0.2972 0.2999 +% 0.3423 0.3571 0.3512 0.3616 +% 0.3832 0.3600 0.3516 0.3385 +% IHC_coeffs = % n_ch: 71 % just_hwr: 0 % lpf_coeff: 0.4327 % out1_rate: 0.0045 % in1_rate: 0.0023 -% out2_rate: 0.0267 +% out2_rate: 0.0199 % in2_rate: 0.0091 % one_cap: 0 -% output_gain: 17.9162 -% rest_output: 0.5240 -% rest_cap2: 0.7421 -% rest_cap1: 0.8281 +% output_gain: 12.1185 +% rest_output: 0.3791 +% rest_cap2: 0.7938 +% rest_cap1: 0.8625 +% ac_coeff: 0.0057 + + +
--- a/matlab/bmm/carfac/CARFAC_Design_Doc.txt Sat May 12 04:31:59 2012 +0000 +++ b/matlab/bmm/carfac/CARFAC_Design_Doc.txt Thu May 24 22:26:56 2012 +0000 @@ -1,6 +1,6 @@ CARFAC Design Doc by "Richard F. Lyon" <dicklyon@google.com> - +updated 24 May 2012 The CAR-FAC (cascade of asymmetric resonators with fast-acting compression) is a cochlear model implemented as an efficient sound @@ -25,11 +25,10 @@ The three main subsystems of the EAR are the cascade of asymmetric resonators (CAR), the inner hair cell (IHC), and the automatic gain -control (AGC). These are not intended to work independently, so may -not have corresponding classes to combine all their aspects (in the -Matlab so far, they don't). Rather, each part has three classes -associated with it, and the CARFAC stores instances of all of these as -members: +control (AGC). These are not intended to work independently, but +each part has three groups of data associated with it. The CARFAC +stores instances of the "params" that drive the design, and the +"coeffs" and "state" are stored per ear: CAR_params, CAR_coeffs, CAR_state IHC_params, IHC_coeffs, IHC_state @@ -44,10 +43,9 @@ model on samples or segments of sound waveforms, such as the state variables of the digital filters. -At construction ("design") time, params are provided, and coeffs are -created. The created CARFAC stores the params that it was designed -from, and the coeffs that will be used at run time; there is no state -yet: +At construction ("design") time, params are provided, and ears with coeffs +are created. The created CARFAC stores the params that it was designed +from; there is no state yet: CF = CARFAC_Design(CAR_params, IHC_params, AGC_params) @@ -63,19 +61,22 @@ not earlier at design time; it is not in params since it doesn't affect coefficient design). -Multi-ear designs always share the same coeffs, but need separate state. -The only place the ears interact is in the AGC. The AGC_state is -one object that holds the state of all the ears, so they can be -concurrently updated. For the CAR and IHC, though, the state object -represents a single ear's state, and the CARFAC stores arrays (vectors) -of state objects for the different ears. The functions that update the -CAR and IHC states are then simple single-ear functions. +Multi-ear designs usually have the same coeffs across several ears, but +always need separate state. +The coeffs are kept separate per ear in case someone wants to +modify one or both to simulate asymmetric hearing loss or such. + +The only place the ears interact is in the AGC. The function that +closes the AGC loop can "mix" their states, making an inter-ear +coupling. Other than that, the functions that update the CAR and IHC +and AGC states are simple single-ear functions (methods of the ear +class?). Data size and performance: The coeffs and states are several kilobytes each, since they store a -handful (5 to 10) of floating-point values (at 4 or 8 bytes each) for +handful (10 or so) of floating-point values (at 4 or 8 bytes each) for each channel (typically 60 to 100 channels); that 240 to 800 bytes per coefficient and per state variable. That's the entire data memory footprint; most of it is accessed at every sample time (hopefully it @@ -102,15 +103,11 @@ length of 1 sample if results are needed with very low latency. Internally, CARFAC_Run updates each part of the state, one sample at a -time. First the CAR and IHC are updated ("stepped") for all ears: +time. First the CAR, IHC, and AGC are updated ("stepped") for all ears: [car_out, CAR_state] = CARFAC_CAR_Step(sample, CAR_coeffs, CAR_state) [ihc_out, IHC_state] = CARFAC_IHC_Step(car_out, IHC_coeffs, IHC_state) - -Then the AGC is updated, for all ears at once (note the plural -"ihc_outs", representing the collection of n_ears): - - [AGC_state, updated] = CARFAC_AGC_Step(AGC_coeffs, ihc_outs, AGC_state) + [AGC_state, updated] = CARFAC_AGC_Step(ihc_out, AGC_coeffs, AGC_state) The AGC filter mostly runs at a lower sample rate (by a factor of 8 by default). Usually it just accumulates its input and returns quickly. The
--- a/matlab/bmm/carfac/CARFAC_IHC_Step.m Sat May 12 04:31:59 2012 +0000 +++ b/matlab/bmm/carfac/CARFAC_IHC_Step.m Thu May 24 22:26:56 2012 +0000 @@ -23,14 +23,15 @@ % One sample-time update of inner-hair-cell (IHC) model, including the % detection nonlinearity and one or two capacitor state variables. -just_hwr = coeffs.just_hwr; +% AC couple the filters_out, with 20 Hz corner +ac_diff = filters_out - state.ac_coupler; +state.ac_coupler = state.ac_coupler + coeffs.ac_coeff * ac_diff; -if just_hwr - ihc_out = min(2, max(0, filters_out)); % limit it for stability - state.ihc_accum = state.ihc_accum + ihc_out; +if coeffs.just_hwr + ihc_out = min(2, max(0, ac_diff)); % limit it for stability else - conductance = CARFAC_Detect(filters_out); % detect with HWR or so - + conductance = CARFAC_Detect(ac_diff); % rectifying nonlinearity + if coeffs.one_cap; ihc_out = conductance .* state.cap_voltage; state.cap_voltage = state.cap_voltage - ihc_out .* coeffs.out_rate + ... @@ -54,5 +55,7 @@ state.lpf2_state = state.lpf2_state + coeffs.lpf_coeff * ... (state.lpf1_state - state.lpf2_state); ihc_out = state.lpf2_state - coeffs.rest_output; - state.ihc_accum = state.ihc_accum + ihc_out; % for where decimated output is useful end + +state.ihc_accum = state.ihc_accum + ihc_out; % for where decimated output is useful +
--- a/matlab/bmm/carfac/CARFAC_Init.m Sat May 12 04:31:59 2012 +0000 +++ b/matlab/bmm/carfac/CARFAC_Init.m Thu May 24 22:26:56 2012 +0000 @@ -67,7 +67,8 @@ 'ihc_accum', zeros(n_ch, 1), ... 'cap_voltage', coeffs.rest_cap * ones(n_ch, 1), ... 'lpf1_state', coeffs.rest_output * ones(n_ch, 1), ... - 'lpf2_state', coeffs.rest_output * ones(n_ch, 1) ... + 'lpf2_state', coeffs.rest_output * ones(n_ch, 1), ... + 'ac_coupler', zeros(n_ch, 1) ... ); else state = struct( ... @@ -75,7 +76,8 @@ 'cap1_voltage', coeffs.rest_cap1 * ones(n_ch, 1), ... 'cap2_voltage', coeffs.rest_cap2* ones(n_ch, 1), ... 'lpf1_state', coeffs.rest_output * ones(n_ch, 1), ... - 'lpf2_state', coeffs.rest_output * ones(n_ch, 1) ... + 'lpf2_state', coeffs.rest_output * ones(n_ch, 1), ... + 'ac_coupler', zeros(n_ch, 1) ... ); end end
--- a/matlab/bmm/carfac/CARFAC_OHC_NLF.m Sat May 12 04:31:59 2012 +0000 +++ b/matlab/bmm/carfac/CARFAC_OHC_NLF.m Thu May 24 22:26:56 2012 +0000 @@ -1,7 +1,28 @@ +% Copyright 2012, Google, Inc. +% Author: Richard F. Lyon +% +% This Matlab file is part of an implementation of Lyon's cochlear model: +% "Cascade of Asymmetric Resonators with Fast-Acting Compression" +% to supplement Lyon's upcoming book "Human and Machine Hearing" +% +% Licensed under the Apache License, Version 2.0 (the "License"); +% you may not use this file except in compliance with the License. +% You may obtain a copy of the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, +% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +% See the License for the specific language governing permissions and +% limitations under the License. + function nlf = CARFAC_OHC_NLF(velocities, CAR_coeffs) +% function nlf = CARFAC_OHC_NLF(velocities, CAR_coeffs) +% start with a quadratic nonlinear function, and limit it via a +% rational function; make the result go to zero a high +% absolute velocities, so it will do nothing there. -nlf = ((velocities .* CAR_coeffs.velocity_scale) + ... +qnlf = ((velocities .* CAR_coeffs.velocity_scale) + ... CAR_coeffs.v_offset) .^ 2; -% soft saturation to make it more like an "essential" nonlinearity: -nlf = CAR_coeffs.v_damp_max * nlf ./ (CAR_coeffs.v2_corner + nlf); - +nlf = 1 - qnlf ./ (CAR_coeffs.v2_corner + qnlf);
--- a/matlab/bmm/carfac/CARFAC_Run.m Sat May 12 04:31:59 2012 +0000 +++ b/matlab/bmm/carfac/CARFAC_Run.m Thu May 24 22:26:56 2012 +0000 @@ -72,7 +72,7 @@ naps = zeros(n_samp, n_ch, n_ears); -seglen = 256; +seglen = 441; % anything should work; this is 20 ms at default fs n_segs = ceil(n_samp / seglen); if nargout > 1
--- a/matlab/bmm/carfac/CARFAC_Run_Linear.m Sat May 12 04:31:59 2012 +0000 +++ b/matlab/bmm/carfac/CARFAC_Run_Linear.m Thu May 24 22:26:56 2012 +0000 @@ -17,8 +17,8 @@ % See the License for the specific language governing permissions and % limitations under the License. -function [naps, CF] = CARFAC_Run_Linear(CF, input_waves, extra_damping) -% function [naps, CF] = CARFAC_Run_Linear(CF, input_waves, extra_damping) +function [naps, CF] = CARFAC_Run_Linear(CF, input_waves, relative_undamping) +% function [naps, CF] = CARFAC_Run_Linear(CF, input_waves, relative_undamping) % % This function runs the CARFAC; that is, filters a 1 or more channel % sound input to make one or more neural activity patterns (naps); @@ -26,16 +26,17 @@ % linear (not detected) output. % only saving one of these, really: -saved_v_damp_max = CF.ears(1).CAR_coeffs.v_damp_max; +velocity_scale = CF.ears(1).CAR_coeffs.velocity_scale; for ear = 1:CF.n_ears - CF.ears(ear).CAR_coeffs.v_damp_max = 0.00; % make it linear for now + % make it effectively linear for now + CF.ears(ear).CAR_coeffs.velocity_scale = 0; end [n_samp, n_ears] = size(input_waves); n_ch = CF.n_ch; if nargin < 3 - extra_damping = 0; + relative_undamping = 1; % default to min-damping condition end if n_ears ~= CF.n_ears @@ -43,11 +44,11 @@ end for ear = 1:CF.n_ears + coeffs = CF.ears(ear).CAR_coeffs; % Set the state of damping, and prevent interpolation from there: - CF.ears(ear).CAR_state.zB_memory(:) = extra_damping; % interpolator state + CF.ears(ear).CAR_state.zB_memory(:) = coeffs.zr_coeffs .* relative_undamping; % 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.g_memory = CARFAC_Stage_g(coeffs, relative_undamping); CF.ears(ear).CAR_state.dg_memory(:) = 0; % interpolator slope end @@ -64,6 +65,6 @@ end for ear = 1:CF.n_ears - CF.ears(ear).CAR_coeffs.v_damp_max = saved_v_damp_max; + CF.ears(ear).CAR_coeffs.velocity_scale = velocity_scale; end
--- a/matlab/bmm/carfac/CARFAC_Run_Segment.m Sat May 12 04:31:59 2012 +0000 +++ b/matlab/bmm/carfac/CARFAC_Run_Segment.m Thu May 24 22:26:56 2012 +0000 @@ -87,7 +87,7 @@ % run the AGC update step, decimating internally, [CF.ears(ear).AGC_state, updated] = CARFAC_AGC_Step( ... - CF.ears(ear).AGC_coeffs, ihc_out, CF.ears(ear).AGC_state); + ihc_out, CF.ears(ear).AGC_coeffs, CF.ears(ear).AGC_state); % save some output data: naps(k, :, ear) = ihc_out; % output to neural activity pattern
--- a/matlab/bmm/carfac/CARFAC_Stage_g.m Sat May 12 04:31:59 2012 +0000 +++ b/matlab/bmm/carfac/CARFAC_Stage_g.m Thu May 24 22:26:56 2012 +0000 @@ -17,14 +17,14 @@ % See the License for the specific language governing permissions and % limitations under the License. -function g = CARFAC_Stage_g(CAR_coeffs, extra_damping) -% function g = CARFAC_Stage_g(CAR_coeffs, extra_damping) +function g = CARFAC_Stage_g(CAR_coeffs, relative_undamping) +% function g = CARFAC_Stage_g(CAR_coeffs, relative_undamping) % Return the stage gain g needed to get unity gain at DC -r1 = CAR_coeffs.r1_coeffs; % not zero damping, but min damping +r1 = CAR_coeffs.r1_coeffs; % at max damping a0 = CAR_coeffs.a0_coeffs; c0 = CAR_coeffs.c0_coeffs; h = CAR_coeffs.h_coeffs; zr = CAR_coeffs.zr_coeffs; -r = r1 - zr.*extra_damping; +r = r1 + zr .* relative_undamping; g = (1 - 2*r.*a0 + r.^2) ./ (1 - 2*r.*a0 + h.*r.*c0 + r.^2);
--- a/matlab/bmm/carfac/CARFAC_Transfer_Functions.m Sat May 12 04:31:59 2012 +0000 +++ b/matlab/bmm/carfac/CARFAC_Transfer_Functions.m Thu May 24 22:26:56 2012 +0000 @@ -50,7 +50,7 @@ % Now multiply gains from input to output places; use logs? log_gains = log(gains); - cum_log_gains = cumsum(log_gains); % accum across cascaded stages + cum_log_gains = cumsum(log_gains); % accum across cascaded stages % And figure out which cascade products we want: n_ch = CF.n_ch; @@ -95,6 +95,7 @@ gains = (numerators * zz) ./ (denominators * zz); + function [stage_numerators, stage_denominators] = ... CARFAC_Rational_Functions(CF, ear) % function [stage_z_numerators, stage_z_denominators] = ... @@ -107,23 +108,23 @@ n_ch = CF.n_ch; coeffs = CF.ears(ear).CAR_coeffs; -min_zeta = CF.CAR_params.min_zeta; a0 = coeffs.a0_coeffs; c0 = coeffs.c0_coeffs; zr = coeffs.zr_coeffs; % get r, adapted if we have state: -r = coeffs.r1_coeffs; +r1 = coeffs.r1_coeffs; % max-damping condition if isfield(CF.ears(ear), 'CAR_state') state = CF.ears(ear).CAR_state; - zB = state.zB_memory; % current extra damping - r = r - zr .* zB; + zB = state.zB_memory; % current delta-r from undamping + r = r1 + zB; else - zB = 0; + zB = 0; % HIGH-level linear condition by default end -g = CARFAC_Stage_g(coeffs, zB); +relative_undamping = zB ./ zr; +g = CARFAC_Stage_g(coeffs, relative_undamping); a = a0 .* r; c = c0 .* r; r2 = r .* r;
--- a/matlab/bmm/carfac/CARFAC_hacking.m Sat May 12 04:31:59 2012 +0000 +++ b/matlab/bmm/carfac/CARFAC_hacking.m Thu May 24 22:26:56 2012 +0000 @@ -22,7 +22,10 @@ clear variables %% + use_plan_file = 1; +dB_list = -60:20:40 + if use_plan_file file_signal = wavread('plan.wav'); @@ -30,12 +33,10 @@ file_signal = file_signal(10000+(1:10000)); % trim for a faster test else - flist = [1000]; - alist = [1]; - flist = 1000; - alist = 1; + flist = 1400 + (1:4)*200; + alist = [1, 1, 1, 1]; sine_signal = 0; - times = (0:19999)' / 22050; + times = (0:9999)' / 22050; for fno = 1:length(flist) sine_signal = sine_signal + alist(fno)*sin(flist(fno)*2*pi*times); end @@ -43,16 +44,7 @@ file_signal = 1.0 * (sine_signal .* (times/max(times)).^growth_power); end -% repeat with negated signal to compare responses: -% file_signal = [file_signal; -file_signal]; - % make a long test signal by repeating at different levels: -do_distortion_figs = 0; % use 1 for distortion figure hack.... -if do_distortion_figs - dB_list = -40:20:0 -else - dB_list = -80:20:60 -end % dB = dB_list(1); % test_signal = 10^(dB/20)* file_signal(1:4000) % lead-in []; test_signal = []; @@ -65,7 +57,7 @@ agc_plot_fig_num = 6; -for n_ears = 1 % 1:2 +for n_ears = 1:2 CF_struct = CARFAC_Design(n_ears); % default design @@ -82,11 +74,13 @@ % nap = deskew(nap); % deskew doesn't make much difference % dB_BM = 10/log(10) * log(filter(1, [1, -0.995], BM(:, 20:50, :).^2)); - dB_BM = 10/log(10) * log(filter(1, [1, -0.995], BM(:, :, :).^2)); + sm_BM = filter(1, [1, -0.995], BM(:, :, :).^2); % only ear 1: - MultiScaleSmooth(dB_BM(5000:200:end, :, 1), 1); + smoothed = sm_BM(100:100:end, :, 1); + MultiScaleSmooth(10/log(10) * log(smoothed), 1); + % Display results for 1 or 2 ears: for ear = 1:n_ears smooth_nap = nap_decim(:, :, ear); @@ -105,52 +99,6 @@ CF_struct.ears(1).AGC_state min_max_decim = [min(nap_decim(:)), max(nap_decim(:))] - %% - if do_distortion_figs - channels = [38, 39, 40]; - times = 0000 + (3200:3599); - smoothed_ohc = ohc; - epsi = 0.4; - % smoothed_ohc = filter(epsi, [1, -(1-epsi)], smoothed_ohc); - % smoothed_ohc = filter(epsi, [1, -(1-epsi)], smoothed_ohc); - - figure(101); hold off - plot(smoothed_ohc(times, channels)) - hold on - plot(smoothed_ohc(times, channels(2)), 'k-', 'LineWidth', 1.5) - title('OHC') - - figure(105); hold off - plot(agc(times, channels)) - hold on - plot(agc(times, channels(2)), 'k-', 'LineWidth', 1.5) - title('AGC') - - figure(103); hold off - plot(BM(times, channels)) - hold on - plot(BM(times, channels(2)), 'k-', 'LineWidth', 1.5) - title('BM') - - extra_damping = smoothed_ohc + agc; - figure(102); hold off - plot(extra_damping(times, channels)) - hold on - plot(extra_damping(times, channels(2)), 'k-', 'LineWidth', 1.5) - title('extra damping') - - distortion = -(extra_damping - smooth1d(extra_damping, 10)) .* BM; - distortion = filter(epsi, [1, -(1-epsi)], distortion); - distortion = filter(epsi, [1, -(1-epsi)], distortion); - % distortion = filter(epsi, [1, -(1-epsi)], distortion); - figure(104); hold off - plot(distortion(times, channels)) - hold on - plot(distortion(times, channels(2)), 'k-', 'LineWidth', 1.5) - title('distortion') - - end - %% end % Expected result: Figure 3 looks like figure 2, a tiny bit darker.
--- a/matlab/bmm/carfac/MultiScaleSmooth.m Sat May 12 04:31:59 2012 +0000 +++ b/matlab/bmm/carfac/MultiScaleSmooth.m Thu May 24 22:26:56 2012 +0000 @@ -29,8 +29,6 @@ % Until we decide what we want, we'll just plot things, one plot per scale. fig_offset1 = 10; -fig_offset2 = 30; -fig_offset3 = 50; if nargin < 2 n_scales = 20; @@ -53,9 +51,6 @@ figure(scale_no + fig_offset1) imagesc(squeeze(smoothed(:,:,1))') - figure(scale_no + fig_offset2) - plot(squeeze(mean(smoothed, 2))); - drawnow pause(1)