Mercurial > hg > aimc
diff carfac/agc_coeffs.cc @ 609:aefe2ca0674f
First version of a C++ implementation by Alex Brandmeyer
author | alexbrandmeyer |
---|---|
date | Mon, 13 May 2013 22:51:15 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/carfac/agc_coeffs.cc Mon May 13 22:51:15 2013 +0000 @@ -0,0 +1,167 @@ +// +// agc_coeffs.cc +// CARFAC Open Source C++ Library +// +// Created by Alex Brandmeyer on 5/10/13. +// +// This C++ 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. + +#include "agc_coeffs.h" + +//This method has been created for debugging purposes and depends on <iostream>. +//Could possibly be removed in the final version to reduce dependencies. +void AGCCoeffs::OutputCoeffs(){ + std::cout << "AGCCoeffs Values" << std::endl; + std::cout << "****************" << std::endl; + std::cout << "n_ch_ = " << n_ch_ << std::endl; + std::cout << "n_agc_stages_ = " << n_agc_stages_ << std::endl; + std::cout << "agc_stage_gain_ = " << agc_stage_gain_ << std::endl; + std::cout << "agc_epsilon_ = " << agc_epsilon_ << std::endl; + std::cout << "decimation_ = " << decimation_ << std::endl; + std::cout << "agc_pole_z1_ = " << agc_pole_z1_ << std::endl; + std::cout << "agc_pole_z2_ = " << agc_pole_z2_ << std::endl; + std::cout << "agc_spatial_iterations_ = " << agc_spatial_iterations_ + << std::endl; + std::cout << "agc_spatial_fir_ = " << agc_spatial_fir_ << std::endl; + std::cout << "agc_spatial_n_taps_ = " << agc_spatial_n_taps_ << std::endl; + std::cout << "agc_mix_coeffs_ = " << agc_mix_coeffs_ << std::endl; + std::cout << "agc1_scales_ = " << agc1_scales_ << std::endl; + std::cout << "agc2_scales_ = " << agc2_scales_ << std::endl; + std::cout << "time_constants_ = " << time_constants_ + << std::endl << std::endl; +} + +void AGCCoeffs::DesignAGC(AGCParams agc_params, long fs, int n_ch){ + n_ch_ = n_ch; + n_agc_stages_ = agc_params.n_stages_; + agc_stage_gain_ = agc_params.agc_stage_gain_; + agc1_scales_ = agc_params.agc1_scales_; + agc2_scales_ = agc_params.agc2_scales_; + time_constants_ = agc_params.time_constants_; + agc_epsilon_.resize(n_agc_stages_); + agc_pole_z1_.resize(n_agc_stages_); + agc_pole_z2_.resize(n_agc_stages_); + agc_spatial_iterations_.resize(n_agc_stages_); + agc_spatial_n_taps_.resize(n_agc_stages_); + agc_spatial_fir_.resize(3,n_agc_stages_); + agc_mix_coeffs_.resize(n_agc_stages_); + mix_coeff_ = agc_params.agc_mix_coeff_; + fir_.resize(3); + decim_ = 1; + decimation_ = agc_params.decimation_; + total_dc_gain_ = 0; + + for (int stage=0; stage < n_agc_stages_; stage++){ + tau_ = time_constants_(stage); + decim_ = decim_ * decimation_(stage); + agc_epsilon_(stage) = 1 - exp((-1 * decim_) / (tau_ * fs)); + n_times_ = tau_ * (fs / decim_); + delay_ = (agc2_scales_(stage) - agc1_scales_(stage)) / n_times_; + spread_sq_ = (pow(agc1_scales_(stage),2) + pow(agc2_scales_(stage),2)) / + n_times_; + u_ = 1 + (1 / spread_sq_); + p_ = u_ - sqrt(pow(u_,2) - 1); + dp_ = delay_ * (1 - (2 * p_) + pow(p_,2)) / 2; + pole_z1_ = p_ - dp_; + pole_z2_ = p_ + dp_; + agc_pole_z1_(stage) = pole_z1_; + agc_pole_z2_(stage) = pole_z2_; + n_taps_ = 0; + fir_ok_ = 0; + n_iterations_ = 1; + //initialize FIR coeffs settings + try { + while (! fir_ok_){ + switch (n_taps_){ + case 0: + n_taps_ = 3; + break; + case 3: + n_taps_ = 5; + break; + case 5: + n_iterations_ ++; + if (n_iterations_ > 16){ + throw 10; //too many iterations + } + break; + default: + throw 20; //bad n_taps + } + //Design FIR Coeffs + FPType var = spread_sq_ / n_iterations_; + FPType mn = delay_ / n_iterations_; + switch (n_taps_){ + case 3: + a = (var + pow(mn,2) - mn) / 2; + b = (var + pow(mn,2) + mn) / 2; + fir_ << a, 1 - a - b, b; + if (fir_(2) >= 0.2) { + fir_ok_ = true; + } else { + fir_ok_ = false; + } + break; + case 5: + a = (((var + pow(mn,2)) * 2/5) - (mn * 2/3)) / 2; + b = (((var + pow(mn,2)) * 2/5) + (mn * 2/3)) / 2; + fir_ << a/2, 1 - a - b, b/2; + if (fir_(2) >= 0.1) { + fir_ok_ = true; + } else { + fir_ok_ = false; + } + break; + default: + throw 30; //bad n_taps in FIR design + } + } + } + catch (int e) { + switch (e) { + case 10: + std::cout << "ERROR: Too many n_iterations in agc_coeffs.DesignAGC" + << std::endl; + break; + case 20: + std::cout << "ERROR: Bad n_taps in agc_coeffs.DesignAGC" << std::endl; + break; + case 30: + std::cout << "ERROR: Bad n_taps in agc_coeffs.DesignAGC/FIR" + << std::endl; + break; + default: + std::cout << "ERROR: unknown error in agc_coeffs.DesignAGC" + << std::endl; + } + } + //assign output of filter design + agc_spatial_iterations_(stage) = n_iterations_; + agc_spatial_n_taps_(stage) = n_taps_; + agc_spatial_fir_(0,stage) = fir_(0); + agc_spatial_fir_(1,stage) = fir_(1); + agc_spatial_fir_(2,stage) = fir_(2); + total_dc_gain_ = total_dc_gain_ + pow(agc_stage_gain_,(stage)); + if (stage == 0) { + agc_mix_coeffs_(stage) = 0; + } else { + agc_mix_coeffs_(stage) = mix_coeff_ / (tau_ * (fs /decim_)); + } + } + agc_gain_ = total_dc_gain_; + detect_scale_ = 1 / total_dc_gain_; +}