annotate C++/CAR.C @ 593:40934f897a56

Fixed certain minor documentation bugs. Added the CAR::designFilters and CAR::stageG methods. These methods design the CAR.coeff coefficients. They have been compared to be the same as the matlab coefficients. An Ear is now contructed with a specific FS or, it uses the default. Added the PsychoAcoustics class to do ERB and Hz conversions. Added the EarTest.C main which allows the construction of an Ear class for testing.
author flatmax
date Wed, 20 Feb 2013 22:30:19 +0000
parents 76c6b3fd0a05
children 2d18671876c8
rev   line source
flatmax@592 1 // Copyright 2013 Matt R. Flax <flatmax\@> All Rights Reserved.
flatmax@593 2 // Author Matt Flax <flatmax@>
flatmax@592 3 //
flatmax@592 4 // This C++ file is part of an implementation of Lyon's cochlear model:
flatmax@592 5 // "Cascade of Asymmetric Resonators with Fast-Acting Compression"
flatmax@592 6 // to supplement Lyon's upcoming book "Human and Machine Hearing"
flatmax@592 7 //
flatmax@592 8 // Licensed under the Apache License, Version 2.0 (the "License");
flatmax@592 9 // you may not use this file except in compliance with the License.
flatmax@592 10 // You may obtain a copy of the License at
flatmax@592 11 //
flatmax@592 12 // http://www.apache.org/licenses/LICENSE-2.0
flatmax@592 13 //
flatmax@592 14 // Unless required by applicable law or agreed to in writing, software
flatmax@592 15 // distributed under the License is distributed on an "AS IS" BASIS,
flatmax@592 16 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
flatmax@592 17 // See the License for the specific language governing permissions and
flatmax@592 18 // limitations under the License.
flatmax@592 19 /**
flatmax@592 20 \author {Matt Flax <flatmax\@>}
flatmax@592 21 \date 2013.02.08
flatmax@592 22 */
flatmax@592 23
flatmax@592 24 #include "CAR.H"
flatmax@592 25
flatmax@592 26 CAR::CAR() {
flatmax@592 27 //ctor
flatmax@592 28 }
flatmax@592 29
flatmax@592 30 CAR::~CAR() {
flatmax@592 31 //dtor
flatmax@592 32 }
flatmax@593 33
flatmax@593 34 void CAR::designFilters(FP_TYPE fs, int n_ch) {
flatmax@593 35 // don't really need these zero arrays, but it's a clue to what fields
flatmax@593 36 // and types are need in ohter language implementations:
flatmax@593 37 coeff.r1_coeffs.resize(n_ch, 1); coeff.r1_coeffs-=coeff.r1_coeffs; // resize and zero
flatmax@593 38 coeff.a0_coeffs.resize(n_ch, 1); coeff.a0_coeffs-=coeff.a0_coeffs;
flatmax@593 39 coeff.c0_coeffs.resize(n_ch, 1); coeff.c0_coeffs-=coeff.c0_coeffs;
flatmax@593 40 coeff.h_coeffs.resize(n_ch, 1); coeff.h_coeffs-=coeff.h_coeffs;
flatmax@593 41 coeff.g0_coeffs.resize(n_ch, 1); coeff.g0_coeffs-=coeff.g0_coeffs;
flatmax@593 42 // zr_coeffs is not zeroed ... perhaps it should be ?
flatmax@593 43
flatmax@593 44 // zero_ratio comes in via h. In book's circuit D, zero_ratio is 1/sqrt(a),
flatmax@593 45 // and that a is here 1 / (1+f) where h = f*c.
flatmax@593 46 // solve for f: 1/zero_ratio^2 = 1 / (1+f)
flatmax@593 47 // zero_ratio^2 = 1+f => f = zero_ratio^2 - 1
flatmax@593 48 FP_TYPE f = pow(param.zero_ratio,2.) - 1.; // nominally 1 for half-octave
flatmax@593 49
flatmax@593 50 // Make pole positions, s and c coeffs, h and g coeffs, etc.,
flatmax@593 51 // which mostly depend on the pole angle theta:
flatmax@593 52 Array<FP_TYPE, Dynamic, 1> theta = pole_freqs * (2. * M_PI / fs);
flatmax@593 53
flatmax@593 54
flatmax@593 55 // undamped coupled-form coefficients:
flatmax@593 56 coeff.c0_coeffs = theta.sin();
flatmax@593 57 coeff.a0_coeffs = theta.cos();
flatmax@593 58
flatmax@593 59 // different possible interpretations for min-damping r:
flatmax@593 60 // r = exp(-theta * CF_CAR_params.min_zeta).
flatmax@593 61 // Compress theta to give somewhat higher Q at highest thetas:
flatmax@593 62 FP_TYPE ff = param.high_f_damping_compression; // 0 to 1 typ. 0.5
flatmax@593 63 Array<FP_TYPE, Dynamic,1> x = theta/M_PI;
flatmax@593 64
flatmax@593 65 coeff.zr_coeffs = M_PI * (x - ff * x.pow(3.)); // when ff is 0, this is just theta,
flatmax@593 66 // and when ff is 1 it goes to zero at theta = pi.
flatmax@593 67 coeff.r1_coeffs = (1. - coeff.zr_coeffs.array() * param.max_zeta); // "r1" for the max-damping condition
flatmax@593 68
flatmax@593 69 // Increase the min damping where channels are spaced out more, by pulling
flatmax@593 70 // 25% of the way toward ERB_Hz/pole_freqs (close to 0.1 at high f)
flatmax@593 71 Array<FP_TYPE, Dynamic, 1> min_zetas = param.min_zeta + 0.25*(PsychoAcoustics::Hz2ERB(pole_freqs, param.ERB_break_freq, param.ERB_Q).array() / pole_freqs - param.min_zeta);
flatmax@593 72 coeff.zr_coeffs = coeff.zr_coeffs.array() * (param.max_zeta - min_zetas); // how r relates to undamping
flatmax@593 73
flatmax@593 74 // the zeros follow via the h_coeffs
flatmax@593 75 coeff.h_coeffs = coeff.c0_coeffs * f;
flatmax@593 76
flatmax@593 77 // for unity gain at min damping, radius r; only used in CARFAC_Init:
flatmax@593 78 Array<FP_TYPE, Dynamic,1> relative_undamping(n_ch, 1);
flatmax@593 79 relative_undamping=(relative_undamping-=relative_undamping).cos();// what is an efficient way to set a matrix to 1. ? As this is in a design phase, I will leave it for now
flatmax@593 80
flatmax@593 81 // this function needs to take CAR_coeffs even if we haven't finished
flatmax@593 82 // constucting it by putting in the g0_coeffs:
flatmax@593 83 coeff.g0_coeffs = stageG(relative_undamping);
flatmax@593 84
flatmax@593 85 }
flatmax@593 86
flatmax@593 87 Array<FP_TYPE, Dynamic, 1> CAR::stageG(Array<FP_TYPE, Dynamic, 1> &relative_undamping) {
flatmax@593 88 // at max damping
flatmax@593 89 Array<FP_TYPE, Dynamic, 1> r = coeff.r1_coeffs.array() + coeff.zr_coeffs.array() * relative_undamping;
flatmax@593 90 return (1. - 2.*r*coeff.a0_coeffs.array() + r.pow(2.)) / (1. - 2.*r*coeff.a0_coeffs.array() + coeff.h_coeffs.array()*r*coeff.c0_coeffs.array() + pow(r,2.));
flatmax@593 91 }