annotate carfac/agc_coeffs.cc @ 632:c692afd86cc9

Fixed the C++ license as previously discussed
author flatmax
date Thu, 23 May 2013 23:00:29 +0000
parents 6a13139d4b71
children
rev   line source
alexbrandmeyer@626 1 //
alexbrandmeyer@626 2 // agc_coeffs.cc
alexbrandmeyer@626 3 // CARFAC Open Source C++ Library
alexbrandmeyer@626 4 //
alexbrandmeyer@626 5 // Created by Alex Brandmeyer on 5/18/13.
alexbrandmeyer@626 6 //
alexbrandmeyer@626 7 // This C++ file is part of an implementation of Lyon's cochlear model:
alexbrandmeyer@626 8 // "Cascade of Asymmetric Resonators with Fast-Acting Compression"
alexbrandmeyer@626 9 // to supplement Lyon's upcoming book "Human and Machine Hearing"
alexbrandmeyer@626 10 //
alexbrandmeyer@626 11 // Licensed under the Apache License, Version 2.0 (the "License");
alexbrandmeyer@626 12 // you may not use this file except in compliance with the License.
alexbrandmeyer@626 13 // You may obtain a copy of the License at
alexbrandmeyer@626 14 //
alexbrandmeyer@626 15 // http://www.apache.org/licenses/LICENSE-2.0
alexbrandmeyer@626 16 //
alexbrandmeyer@626 17 // Unless required by applicable law or agreed to in writing, software
alexbrandmeyer@626 18 // distributed under the License is distributed on an "AS IS" BASIS,
alexbrandmeyer@626 19 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
alexbrandmeyer@626 20 // See the License for the specific language governing permissions and
alexbrandmeyer@626 21 // limitations under the License.
alexbrandmeyer@626 22
ronw@628 23 #include <assert.h>
ronw@628 24
alexbrandmeyer@626 25 #include "agc_coeffs.h"
alexbrandmeyer@626 26
alexbrandmeyer@626 27 void AGCCoeffs::Design(const AGCParams& agc_params, const int stage,
alexbrandmeyer@626 28 const FPType fs, const FPType previous_stage_gain,
alexbrandmeyer@626 29 FPType decim) {
alexbrandmeyer@626 30 n_agc_stages_ = agc_params.n_stages_;
alexbrandmeyer@626 31 agc_stage_gain_ = agc_params.agc_stage_gain_;
alexbrandmeyer@626 32 std::vector<FPType> agc1_scales = agc_params.agc1_scales_;
alexbrandmeyer@626 33 std::vector<FPType> agc2_scales = agc_params.agc2_scales_;
alexbrandmeyer@626 34 std::vector<FPType> time_constants = agc_params.time_constants_;
alexbrandmeyer@626 35 FPType mix_coeff = agc_params.agc_mix_coeff_;
alexbrandmeyer@626 36 decimation_ = agc_params.decimation_[stage];
alexbrandmeyer@626 37 FPType total_dc_gain = previous_stage_gain;
alexbrandmeyer@626 38 // Here we calculate the parameters for the current stage.
alexbrandmeyer@626 39 FPType tau = time_constants[stage];
alexbrandmeyer@626 40 decim_ = decim;
alexbrandmeyer@626 41 decim_ *= decimation_;
alexbrandmeyer@626 42 agc_epsilon_ = 1 - exp((-1 * decim_) / (tau * fs));
alexbrandmeyer@626 43 FPType n_times = tau * (fs / decim_);
alexbrandmeyer@626 44 FPType delay = (agc2_scales[stage] - agc1_scales[stage]) / n_times;
alexbrandmeyer@626 45 FPType spread_sq = (pow(agc1_scales[stage], 2) +
alexbrandmeyer@626 46 pow(agc2_scales[stage], 2)) / n_times;
alexbrandmeyer@626 47 FPType u = 1 + (1 / spread_sq);
alexbrandmeyer@626 48 FPType p = u - sqrt(pow(u, 2) - 1);
alexbrandmeyer@626 49 FPType dp = delay * (1 - (2 * p) + (p * p)) / 2;
alexbrandmeyer@626 50 agc_pole_z1_ = p - dp;
alexbrandmeyer@626 51 agc_pole_z2_ = p + dp;
alexbrandmeyer@626 52 int n_taps = 0;
alexbrandmeyer@626 53 bool fir_ok = false;
alexbrandmeyer@626 54 int n_iterations = 1;
alexbrandmeyer@626 55 // This section initializes the FIR coeffs settings at each stage.
alexbrandmeyer@626 56 agc_spatial_fir_.resize(3);
alexbrandmeyer@626 57 std::vector<FPType> fir(3);
alexbrandmeyer@626 58 while (! fir_ok) {
alexbrandmeyer@626 59 switch (n_taps) {
alexbrandmeyer@626 60 case 0:
alexbrandmeyer@626 61 n_taps = 3;
alexbrandmeyer@626 62 break;
alexbrandmeyer@626 63 case 3:
alexbrandmeyer@626 64 n_taps = 5;
alexbrandmeyer@626 65 break;
alexbrandmeyer@626 66 case 5:
ronw@628 67 n_iterations++;
ronw@628 68 assert(n_iterations < 16 &&
ronw@628 69 "Too many iterations needed in AGC spatial smoothing.");
alexbrandmeyer@626 70 break;
alexbrandmeyer@626 71 default:
ronw@628 72 assert(true && "Bad n_taps; should be 3 or 5.");
alexbrandmeyer@626 73 break;
alexbrandmeyer@626 74 }
alexbrandmeyer@626 75 // The smoothing function is a space-domain smoothing, but it considered
alexbrandmeyer@626 76 // here by analogy to time-domain smoothing, which is why its potential
alexbrandmeyer@626 77 // off-centeredness is called a delay. Since it's a smoothing filter, it
alexbrandmeyer@626 78 // is also analogous to a discrete probability distribution (a p.m.f.),
alexbrandmeyer@626 79 // with mean corresponding to delay and variance corresponding to squared
alexbrandmeyer@626 80 // spatial spread (in samples, or channels, and the square thereof,
alexbrandmeyer@626 81 // respecitively). Here we design a filter implementation's coefficient
alexbrandmeyer@626 82 // via the method of moment matching, so we get the intended delay and
alexbrandmeyer@626 83 // spread, and don't worry too much about the shape of the distribution,
alexbrandmeyer@626 84 // which will be some kind of blob not too far from Gaussian if we run
alexbrandmeyer@626 85 // several FIR iterations.
alexbrandmeyer@626 86 FPType delay_variance = spread_sq / n_iterations;
alexbrandmeyer@626 87 FPType mean_delay = delay / n_iterations;
alexbrandmeyer@626 88 FPType a, b;
alexbrandmeyer@626 89 switch (n_taps) {
alexbrandmeyer@626 90 case 3:
alexbrandmeyer@626 91 a = (delay_variance + (mean_delay*mean_delay) - mean_delay) / 2.0;
alexbrandmeyer@626 92 b = (delay_variance + (mean_delay*mean_delay) + mean_delay) / 2.0;
alexbrandmeyer@626 93 fir[0] = a;
alexbrandmeyer@626 94 fir[1] = 1 - a - b;
alexbrandmeyer@626 95 fir[2] = b;
alexbrandmeyer@626 96 fir_ok = fir[1] >= 0.2 ? true : false;
alexbrandmeyer@626 97 break;
alexbrandmeyer@626 98 case 5:
alexbrandmeyer@626 99 a = (((delay_variance + (mean_delay*mean_delay)) * 2.0/5.0) -
alexbrandmeyer@626 100 (mean_delay * 2.0/3.0)) / 2.0;
alexbrandmeyer@626 101 b = (((delay_variance + (mean_delay*mean_delay)) * 2.0/5.0) +
alexbrandmeyer@626 102 (mean_delay * 2.0/3.0)) / 2.0;
alexbrandmeyer@626 103 fir[0] = a / 2.0;
alexbrandmeyer@626 104 fir[1] = 1 - a - b;
alexbrandmeyer@626 105 fir[2] = b / 2.0;
alexbrandmeyer@626 106 fir_ok = fir[1] >= 0.1 ? true : false;
alexbrandmeyer@626 107 break;
alexbrandmeyer@626 108 default:
ronw@630 109 assert(true && "Bad n_taps; should be 3 or 5.");
ronw@630 110 break;
alexbrandmeyer@626 111 }
alexbrandmeyer@626 112 }
alexbrandmeyer@626 113 // Once we have the FIR design for this stage we can assign it to the
alexbrandmeyer@626 114 // appropriate data members.
alexbrandmeyer@626 115 agc_spatial_iterations_ = n_iterations;
alexbrandmeyer@626 116 agc_spatial_n_taps_ = n_taps;
alexbrandmeyer@626 117 agc_spatial_fir_[0] = fir[0];
alexbrandmeyer@626 118 agc_spatial_fir_[1] = fir[1];
alexbrandmeyer@626 119 agc_spatial_fir_[2] = fir[2];
alexbrandmeyer@626 120 total_dc_gain += pow(agc_stage_gain_, stage);
alexbrandmeyer@626 121 agc_mix_coeffs_ = stage == 0 ? 0 : mix_coeff / (tau * (fs /decim_));
alexbrandmeyer@626 122 agc_gain_ = total_dc_gain;
alexbrandmeyer@626 123 detect_scale_ = 1 / total_dc_gain;
ronw@628 124 }