annotate trunk/matlab/bmm/carfac/CARFAC_Transfer_Functions.m @ 534:95a11cca4619

Add CARFAC_Design_Doc.txt, CARFAC_Run_Segment.m, and some renames; rename various variables to be more parallel; clean up init code and such.
author dicklyon@google.com
date Fri, 16 Mar 2012 04:19:24 +0000
parents 55c46c01e522
children 3dff17554c6d
rev   line source
dicklyon@527 1 % Copyright 2012, Google, Inc.
dicklyon@527 2 % Author: Richard F. Lyon
dicklyon@527 3 %
dicklyon@527 4 % This Matlab file is part of an implementation of Lyon's cochlear model:
dicklyon@527 5 % "Cascade of Asymmetric Resonators with Fast-Acting Compression"
dicklyon@527 6 % to supplement Lyon's upcoming book "Human and Machine Hearing"
dicklyon@527 7 %
dicklyon@527 8 % Licensed under the Apache License, Version 2.0 (the "License");
dicklyon@527 9 % you may not use this file except in compliance with the License.
dicklyon@527 10 % You may obtain a copy of the License at
dicklyon@527 11 %
dicklyon@527 12 % http://www.apache.org/licenses/LICENSE-2.0
dicklyon@527 13 %
dicklyon@527 14 % Unless required by applicable law or agreed to in writing, software
dicklyon@527 15 % distributed under the License is distributed on an "AS IS" BASIS,
dicklyon@527 16 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
dicklyon@527 17 % See the License for the specific language governing permissions and
dicklyon@527 18 % limitations under the License.
dicklyon@527 19
dicklyon@526 20 function [complex_transfns_freqs, ...
dicklyon@533 21 stage_numerators, stage_denominators, group_delays] = ...
dicklyon@533 22 CARFAC_Transfer_Functions(CF, freqs, to_channels, from_channels)
dicklyon@526 23 % function [complex_transfns_freqs, ...
dicklyon@533 24 % stage_numerators, stage_denominators, group_delays] = ...
dicklyon@533 25 % CARFAC_Transfer_Functions(CF, freqs, to_channels, from_channels)
dicklyon@533 26 %
dicklyon@526 27 % Return transfer functions as polynomials in z (nums & denoms);
dicklyon@526 28 % And evaluate them at freqs if it's given, to selected output,
dicklyon@526 29 % optionally from selected starting points (from 0, input, by default).
dicklyon@526 30 % complex_transfns_freqs has a row of complex gains per to_channel.
dicklyon@526 31
dicklyon@526 32 % always start with the rational functions, whether we want to return
dicklyon@526 33 % them or not:
dicklyon@526 34 [stage_numerators, stage_denominators] = CARFAC_Rational_Functions(CF);
dicklyon@526 35
dicklyon@526 36 if nargin >= 2
dicklyon@526 37 % Evaluate at the provided list of frequencies.
dicklyon@526 38 if ~isrow(freqs)
dicklyon@526 39 if iscolumn(freqs)
dicklyon@526 40 freqs = freqs';
dicklyon@526 41 else
dicklyon@526 42 error('Bad freqs_row in CARFAC_Transfer_Functions');
dicklyon@526 43 end
dicklyon@526 44 end
dicklyon@526 45 if any(freqs < 0)
dicklyon@526 46 error('Negatives in freqs_row in CARFAC_Transfer_Functions');
dicklyon@526 47 end
dicklyon@526 48 z_row = exp((i * 2 * pi / CF.fs) * freqs); % z = exp(sT)
dicklyon@526 49 gains = Rational_Eval(stage_numerators, stage_denominators, z_row);
dicklyon@526 50
dicklyon@526 51 % Now multiply gains from input to output places; use logs?
dicklyon@526 52 log_gains = log(gains);
dicklyon@533 53 cum_log_gains = cumsum(log_gains); % accum across cascaded stages
dicklyon@526 54
dicklyon@526 55 % And figure out which cascade products we want:
dicklyon@526 56 n_ch = CF.n_ch;
dicklyon@526 57 if nargin < 3
dicklyon@526 58 to_channels = 1:n_ch;
dicklyon@526 59 end
dicklyon@526 60 if isempty(to_channels) || any(to_channels < 1 | to_channels > n_ch)
dicklyon@526 61 error('Bad to_channels in CARFAC_Transfer_Functions');
dicklyon@526 62 end
dicklyon@526 63 if nargin < 4 || isempty(from_channels)
dicklyon@526 64 from_channels = 0; % tranfuns from input, called channel 0.
dicklyon@526 65 end
dicklyon@526 66 if length(from_channels) == 1
dicklyon@528 67 from_channels = from_channels * ones(1,length(to_channels));
dicklyon@526 68 end
dicklyon@526 69 % Default to cum gain of 1 (log is 0), from input channel 0:
dicklyon@526 70 from_cum = zeros(length(to_channels), length(z_row));
dicklyon@526 71 not_input = from_channels > 0;
dicklyon@526 72 from_cum(not_input, :) = cum_log_gains(from_channels(not_input), :);
dicklyon@526 73 log_transfns = cum_log_gains(to_channels, :) - from_cum;
dicklyon@526 74 complex_transfns_freqs = exp(log_transfns);
dicklyon@533 75
dicklyon@533 76 if nargout >= 4
dicklyon@533 77 phases = imag(log_gains); % no wrapping problem on single stages
dicklyon@533 78 cum_phases = cumsum(phases); % so no wrapping here either
dicklyon@533 79 group_delays = -diff(cum_phases')'; % diff across frequencies
dicklyon@533 80 group_delays = group_delays ./ (2*pi*repmat(diff(freqs), n_ch, 1));
dicklyon@533 81 end
dicklyon@526 82 else
dicklyon@526 83 % If no freqs are provided, do nothing but return the stage info above:
dicklyon@526 84 complex_transfns_freqs = [];
dicklyon@526 85 end
dicklyon@526 86
dicklyon@526 87
dicklyon@526 88
dicklyon@526 89 function gains = Rational_Eval(numerators, denominators, z_row)
dicklyon@526 90 % function gains = Rational_Eval(numerators, denominators, z_row)
dicklyon@526 91 % Evaluate rational function at row of z values.
dicklyon@526 92
dicklyon@526 93 zz = [z_row .* z_row; z_row; ones(size(z_row))];
dicklyon@526 94 % dot product of each poly row with each [z2; z; 1] col:
dicklyon@526 95 gains = (numerators * zz) ./ (denominators * zz);
dicklyon@526 96
dicklyon@526 97
dicklyon@526 98 function [stage_numerators, stage_denominators] = ...
dicklyon@528 99 CARFAC_Rational_Functions(CF)
dicklyon@526 100 % function [stage_z_numerators, stage_z_denominators] = ...
dicklyon@526 101 % CARFAC_Rational_Functions(CF, chans)
dicklyon@526 102 % Return transfer functions of all stages as rational functions.
dicklyon@526 103
dicklyon@528 104 n_ch = CF.n_ch;
dicklyon@534 105 coeffs = CF.CAR_coeffs;
dicklyon@534 106 min_zeta = CF.CAR_params.min_zeta;
dicklyon@528 107
dicklyon@530 108 a0 = coeffs.a0_coeffs;
dicklyon@530 109 c0 = coeffs.c0_coeffs;
dicklyon@530 110 zr = coeffs.zr_coeffs;
dicklyon@528 111
dicklyon@528 112 % get r, adapted if we have state:
dicklyon@530 113 r = coeffs.r1_coeffs;
dicklyon@534 114 if isfield(CF, 'CAR_state')
dicklyon@534 115 state = CF.CAR_state;
dicklyon@528 116 zB = state.zB_memory; % current extra damping
dicklyon@530 117 r = r - zr .* zB;
dicklyon@526 118 else
dicklyon@528 119 zB = 0;
dicklyon@526 120 end
dicklyon@528 121
dicklyon@530 122 g = CARFAC_Stage_g(coeffs, zB);
dicklyon@528 123 a = a0 .* r;
dicklyon@528 124 c = c0 .* r;
dicklyon@526 125 r2 = r .* r;
dicklyon@528 126 h = coeffs.h_coeffs;
dicklyon@528 127
dicklyon@526 128 stage_denominators = [ones(n_ch, 1), -2 * a, r2];
dicklyon@526 129 stage_numerators = [g .* ones(n_ch, 1), g .* (-2 * a + h .* c), g .* r2];
dicklyon@526 130
dicklyon@526 131
dicklyon@526 132 %% example
dicklyon@526 133 % CF = CARFAC_Design
dicklyon@526 134 % f = (0:100).^2; % frequencies to 10 kHz, unequally spaced
dicklyon@526 135 % to_ch = 10:10:96; % selected output channels
dicklyon@526 136 % from_ch = to_ch - 10; % test the inclusion of 0 in from list
dicklyon@526 137 % tf = CARFAC_Transfer_Functions(CF, f, to_ch, from_ch);
dicklyon@526 138 % figure
dicklyon@526 139 % plot(f, 20*log(abs(tf)')/log(10)); % dB vs lin. freq for 10 taps
dicklyon@526 140