annotate matlab/bmm/carfac/CARFAC_Transfer_Functions.m @ 465:38c62222f0cc

Add CARFAC_Transfer_Functions.m
author dicklyon@google.com
date Wed, 07 Mar 2012 23:10:44 +0000
parents
children 8d9538f64176
rev   line source
dicklyon@465 1 function [complex_transfns_freqs, ...
dicklyon@465 2 stage_numerators, stage_denominators] = ...
dicklyon@465 3 CARFAC_Transfer_Functions(CF, freqs, to_channels, from_channels)
dicklyon@465 4 % function [complex_transfns_freqs, ...
dicklyon@465 5 % stage_z_numerators, stage_z_denominators] = ...
dicklyon@465 6 % CARFAC_Transfer_Functions(CF, freqs, to_channels, from_channels)
dicklyon@465 7 % Return transfer functions as polynomials in z (nums & denoms);
dicklyon@465 8 % And evaluate them at freqs if it's given, to selected output,
dicklyon@465 9 % optionally from selected starting points (from 0, input, by default).
dicklyon@465 10 % complex_transfns_freqs has a row of complex gains per to_channel.
dicklyon@465 11
dicklyon@465 12 % always start with the rational functions, whether we want to return
dicklyon@465 13 % them or not:
dicklyon@465 14 [stage_numerators, stage_denominators] = CARFAC_Rational_Functions(CF);
dicklyon@465 15
dicklyon@465 16 if nargin >= 2
dicklyon@465 17 % Evaluate at the provided list of frequencies.
dicklyon@465 18 if ~isrow(freqs)
dicklyon@465 19 if iscolumn(freqs)
dicklyon@465 20 freqs = freqs';
dicklyon@465 21 else
dicklyon@465 22 error('Bad freqs_row in CARFAC_Transfer_Functions');
dicklyon@465 23 end
dicklyon@465 24 end
dicklyon@465 25 if any(freqs < 0)
dicklyon@465 26 error('Negatives in freqs_row in CARFAC_Transfer_Functions');
dicklyon@465 27 end
dicklyon@465 28 z_row = exp((i * 2 * pi / CF.fs) * freqs); % z = exp(sT)
dicklyon@465 29 gains = Rational_Eval(stage_numerators, stage_denominators, z_row);
dicklyon@465 30
dicklyon@465 31 % Now multiply gains from input to output places; use logs?
dicklyon@465 32 log_gains = log(gains);
dicklyon@465 33 cum_log_gains = cumsum(log_gains);
dicklyon@465 34
dicklyon@465 35 % And figure out which cascade products we want:
dicklyon@465 36 n_ch = CF.n_ch;
dicklyon@465 37 if nargin < 3
dicklyon@465 38 to_channels = 1:n_ch;
dicklyon@465 39 end
dicklyon@465 40 if isempty(to_channels) || any(to_channels < 1 | to_channels > n_ch)
dicklyon@465 41 error('Bad to_channels in CARFAC_Transfer_Functions');
dicklyon@465 42 end
dicklyon@465 43 if nargin < 4 || isempty(from_channels)
dicklyon@465 44 from_channels = 0; % tranfuns from input, called channel 0.
dicklyon@465 45 end
dicklyon@465 46 if length(from_channels) == 1
dicklyon@465 47 from_channels = from_channels * ones(length(to_channels));
dicklyon@465 48 end
dicklyon@465 49 % Default to cum gain of 1 (log is 0), from input channel 0:
dicklyon@465 50 from_cum = zeros(length(to_channels), length(z_row));
dicklyon@465 51 not_input = from_channels > 0;
dicklyon@465 52 from_cum(not_input, :) = cum_log_gains(from_channels(not_input), :);
dicklyon@465 53 log_transfns = cum_log_gains(to_channels, :) - from_cum;
dicklyon@465 54 complex_transfns_freqs = exp(log_transfns);
dicklyon@465 55 else
dicklyon@465 56 % If no freqs are provided, do nothing but return the stage info above:
dicklyon@465 57 complex_transfns_freqs = [];
dicklyon@465 58 end
dicklyon@465 59
dicklyon@465 60
dicklyon@465 61
dicklyon@465 62 function gains = Rational_Eval(numerators, denominators, z_row)
dicklyon@465 63 % function gains = Rational_Eval(numerators, denominators, z_row)
dicklyon@465 64 % Evaluate rational function at row of z values.
dicklyon@465 65
dicklyon@465 66 zz = [z_row .* z_row; z_row; ones(size(z_row))];
dicklyon@465 67 % dot product of each poly row with each [z2; z; 1] col:
dicklyon@465 68 gains = (numerators * zz) ./ (denominators * zz);
dicklyon@465 69
dicklyon@465 70
dicklyon@465 71 function [stage_numerators, stage_denominators] = ...
dicklyon@465 72 CARFAC_Rational_Functions(CF, chans)
dicklyon@465 73 % function [stage_z_numerators, stage_z_denominators] = ...
dicklyon@465 74 % CARFAC_Rational_Functions(CF, chans)
dicklyon@465 75 % Return transfer functions of all stages as rational functions.
dicklyon@465 76
dicklyon@465 77 if nargin < 2
dicklyon@465 78 n_ch = CF.n_ch;
dicklyon@465 79 chans = 1:n_ch;
dicklyon@465 80 else
dicklyon@465 81 n_ch = length(chans);
dicklyon@465 82 end
dicklyon@465 83 coeffs = CF.filter_coeffs;
dicklyon@465 84 r = coeffs.r_coeffs(chans);
dicklyon@465 85 a = coeffs.a_coeffs(chans) .* r;
dicklyon@465 86 c = coeffs.c_coeffs(chans) .* r;
dicklyon@465 87 r2 = r .* r;
dicklyon@465 88 h = coeffs.h_coeffs(chans);
dicklyon@465 89 g = coeffs.g_coeffs(chans);
dicklyon@465 90 stage_denominators = [ones(n_ch, 1), -2 * a, r2];
dicklyon@465 91 stage_numerators = [g .* ones(n_ch, 1), g .* (-2 * a + h .* c), g .* r2];
dicklyon@465 92
dicklyon@465 93
dicklyon@465 94 %% example
dicklyon@465 95 % CF = CARFAC_Design
dicklyon@465 96 % f = (0:100).^2; % frequencies to 10 kHz, unequally spaced
dicklyon@465 97 % to_ch = 10:10:96; % selected output channels
dicklyon@465 98 % from_ch = to_ch - 10; % test the inclusion of 0 in from list
dicklyon@465 99 % tf = CARFAC_Transfer_Functions(CF, f, to_ch, from_ch);
dicklyon@465 100 % figure
dicklyon@465 101 % plot(f, 20*log(abs(tf)')/log(10)); % dB vs lin. freq for 10 taps
dicklyon@465 102