alexbrandmeyer@609
|
1 //
|
alexbrandmeyer@609
|
2 // agc_coeffs.cc
|
alexbrandmeyer@609
|
3 // CARFAC Open Source C++ Library
|
alexbrandmeyer@609
|
4 //
|
alexbrandmeyer@609
|
5 // Created by Alex Brandmeyer on 5/10/13.
|
alexbrandmeyer@609
|
6 //
|
alexbrandmeyer@609
|
7 // This C++ file is part of an implementation of Lyon's cochlear model:
|
alexbrandmeyer@609
|
8 // "Cascade of Asymmetric Resonators with Fast-Acting Compression"
|
alexbrandmeyer@609
|
9 // to supplement Lyon's upcoming book "Human and Machine Hearing"
|
alexbrandmeyer@609
|
10 //
|
alexbrandmeyer@609
|
11 // Licensed under the Apache License, Version 2.0 (the "License");
|
alexbrandmeyer@609
|
12 // you may not use this file except in compliance with the License.
|
alexbrandmeyer@609
|
13 // You may obtain a copy of the License at
|
alexbrandmeyer@609
|
14 //
|
alexbrandmeyer@609
|
15 // http://www.apache.org/licenses/LICENSE-2.0
|
alexbrandmeyer@609
|
16 //
|
alexbrandmeyer@609
|
17 // Unless required by applicable law or agreed to in writing, software
|
alexbrandmeyer@609
|
18 // distributed under the License is distributed on an "AS IS" BASIS,
|
alexbrandmeyer@609
|
19 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
alexbrandmeyer@609
|
20 // See the License for the specific language governing permissions and
|
alexbrandmeyer@609
|
21 // limitations under the License.
|
alexbrandmeyer@609
|
22
|
alexbrandmeyer@609
|
23 #include "agc_coeffs.h"
|
alexbrandmeyer@609
|
24
|
alexbrandmeyer@609
|
25 //This method has been created for debugging purposes and depends on <iostream>.
|
alexbrandmeyer@609
|
26 //Could possibly be removed in the final version to reduce dependencies.
|
alexbrandmeyer@609
|
27 void AGCCoeffs::OutputCoeffs(){
|
alexbrandmeyer@609
|
28 std::cout << "AGCCoeffs Values" << std::endl;
|
alexbrandmeyer@609
|
29 std::cout << "****************" << std::endl;
|
alexbrandmeyer@609
|
30 std::cout << "n_ch_ = " << n_ch_ << std::endl;
|
alexbrandmeyer@609
|
31 std::cout << "n_agc_stages_ = " << n_agc_stages_ << std::endl;
|
alexbrandmeyer@609
|
32 std::cout << "agc_stage_gain_ = " << agc_stage_gain_ << std::endl;
|
alexbrandmeyer@609
|
33 std::cout << "agc_epsilon_ = " << agc_epsilon_ << std::endl;
|
alexbrandmeyer@609
|
34 std::cout << "decimation_ = " << decimation_ << std::endl;
|
alexbrandmeyer@609
|
35 std::cout << "agc_pole_z1_ = " << agc_pole_z1_ << std::endl;
|
alexbrandmeyer@609
|
36 std::cout << "agc_pole_z2_ = " << agc_pole_z2_ << std::endl;
|
alexbrandmeyer@609
|
37 std::cout << "agc_spatial_iterations_ = " << agc_spatial_iterations_
|
alexbrandmeyer@609
|
38 << std::endl;
|
alexbrandmeyer@609
|
39 std::cout << "agc_spatial_fir_ = " << agc_spatial_fir_ << std::endl;
|
alexbrandmeyer@609
|
40 std::cout << "agc_spatial_n_taps_ = " << agc_spatial_n_taps_ << std::endl;
|
alexbrandmeyer@609
|
41 std::cout << "agc_mix_coeffs_ = " << agc_mix_coeffs_ << std::endl;
|
alexbrandmeyer@609
|
42 std::cout << "agc1_scales_ = " << agc1_scales_ << std::endl;
|
alexbrandmeyer@609
|
43 std::cout << "agc2_scales_ = " << agc2_scales_ << std::endl;
|
alexbrandmeyer@609
|
44 std::cout << "time_constants_ = " << time_constants_
|
alexbrandmeyer@609
|
45 << std::endl << std::endl;
|
alexbrandmeyer@609
|
46 }
|
alexbrandmeyer@609
|
47
|
alexbrandmeyer@609
|
48 void AGCCoeffs::DesignAGC(AGCParams agc_params, long fs, int n_ch){
|
alexbrandmeyer@609
|
49 n_ch_ = n_ch;
|
alexbrandmeyer@609
|
50 n_agc_stages_ = agc_params.n_stages_;
|
alexbrandmeyer@609
|
51 agc_stage_gain_ = agc_params.agc_stage_gain_;
|
alexbrandmeyer@609
|
52 agc1_scales_ = agc_params.agc1_scales_;
|
alexbrandmeyer@609
|
53 agc2_scales_ = agc_params.agc2_scales_;
|
alexbrandmeyer@609
|
54 time_constants_ = agc_params.time_constants_;
|
alexbrandmeyer@609
|
55 agc_epsilon_.resize(n_agc_stages_);
|
alexbrandmeyer@609
|
56 agc_pole_z1_.resize(n_agc_stages_);
|
alexbrandmeyer@609
|
57 agc_pole_z2_.resize(n_agc_stages_);
|
alexbrandmeyer@609
|
58 agc_spatial_iterations_.resize(n_agc_stages_);
|
alexbrandmeyer@609
|
59 agc_spatial_n_taps_.resize(n_agc_stages_);
|
alexbrandmeyer@609
|
60 agc_spatial_fir_.resize(3,n_agc_stages_);
|
alexbrandmeyer@609
|
61 agc_mix_coeffs_.resize(n_agc_stages_);
|
alexbrandmeyer@609
|
62 mix_coeff_ = agc_params.agc_mix_coeff_;
|
alexbrandmeyer@609
|
63 fir_.resize(3);
|
alexbrandmeyer@609
|
64 decim_ = 1;
|
alexbrandmeyer@609
|
65 decimation_ = agc_params.decimation_;
|
alexbrandmeyer@609
|
66 total_dc_gain_ = 0;
|
alexbrandmeyer@609
|
67
|
alexbrandmeyer@609
|
68 for (int stage=0; stage < n_agc_stages_; stage++){
|
alexbrandmeyer@609
|
69 tau_ = time_constants_(stage);
|
alexbrandmeyer@609
|
70 decim_ = decim_ * decimation_(stage);
|
alexbrandmeyer@609
|
71 agc_epsilon_(stage) = 1 - exp((-1 * decim_) / (tau_ * fs));
|
alexbrandmeyer@609
|
72 n_times_ = tau_ * (fs / decim_);
|
alexbrandmeyer@609
|
73 delay_ = (agc2_scales_(stage) - agc1_scales_(stage)) / n_times_;
|
alexbrandmeyer@609
|
74 spread_sq_ = (pow(agc1_scales_(stage),2) + pow(agc2_scales_(stage),2)) /
|
alexbrandmeyer@609
|
75 n_times_;
|
alexbrandmeyer@609
|
76 u_ = 1 + (1 / spread_sq_);
|
alexbrandmeyer@609
|
77 p_ = u_ - sqrt(pow(u_,2) - 1);
|
alexbrandmeyer@609
|
78 dp_ = delay_ * (1 - (2 * p_) + pow(p_,2)) / 2;
|
alexbrandmeyer@609
|
79 pole_z1_ = p_ - dp_;
|
alexbrandmeyer@609
|
80 pole_z2_ = p_ + dp_;
|
alexbrandmeyer@609
|
81 agc_pole_z1_(stage) = pole_z1_;
|
alexbrandmeyer@609
|
82 agc_pole_z2_(stage) = pole_z2_;
|
alexbrandmeyer@609
|
83 n_taps_ = 0;
|
alexbrandmeyer@609
|
84 fir_ok_ = 0;
|
alexbrandmeyer@609
|
85 n_iterations_ = 1;
|
alexbrandmeyer@609
|
86 //initialize FIR coeffs settings
|
alexbrandmeyer@609
|
87 try {
|
alexbrandmeyer@609
|
88 while (! fir_ok_){
|
alexbrandmeyer@609
|
89 switch (n_taps_){
|
alexbrandmeyer@609
|
90 case 0:
|
alexbrandmeyer@609
|
91 n_taps_ = 3;
|
alexbrandmeyer@609
|
92 break;
|
alexbrandmeyer@609
|
93 case 3:
|
alexbrandmeyer@609
|
94 n_taps_ = 5;
|
alexbrandmeyer@609
|
95 break;
|
alexbrandmeyer@609
|
96 case 5:
|
alexbrandmeyer@609
|
97 n_iterations_ ++;
|
alexbrandmeyer@609
|
98 if (n_iterations_ > 16){
|
alexbrandmeyer@609
|
99 throw 10; //too many iterations
|
alexbrandmeyer@609
|
100 }
|
alexbrandmeyer@609
|
101 break;
|
alexbrandmeyer@609
|
102 default:
|
alexbrandmeyer@609
|
103 throw 20; //bad n_taps
|
alexbrandmeyer@609
|
104 }
|
alexbrandmeyer@609
|
105 //Design FIR Coeffs
|
alexbrandmeyer@609
|
106 FPType var = spread_sq_ / n_iterations_;
|
alexbrandmeyer@609
|
107 FPType mn = delay_ / n_iterations_;
|
alexbrandmeyer@609
|
108 switch (n_taps_){
|
alexbrandmeyer@609
|
109 case 3:
|
alexbrandmeyer@609
|
110 a = (var + pow(mn,2) - mn) / 2;
|
alexbrandmeyer@609
|
111 b = (var + pow(mn,2) + mn) / 2;
|
alexbrandmeyer@609
|
112 fir_ << a, 1 - a - b, b;
|
alexbrandmeyer@609
|
113 if (fir_(2) >= 0.2) {
|
alexbrandmeyer@609
|
114 fir_ok_ = true;
|
alexbrandmeyer@609
|
115 } else {
|
alexbrandmeyer@609
|
116 fir_ok_ = false;
|
alexbrandmeyer@609
|
117 }
|
alexbrandmeyer@609
|
118 break;
|
alexbrandmeyer@609
|
119 case 5:
|
alexbrandmeyer@609
|
120 a = (((var + pow(mn,2)) * 2/5) - (mn * 2/3)) / 2;
|
alexbrandmeyer@609
|
121 b = (((var + pow(mn,2)) * 2/5) + (mn * 2/3)) / 2;
|
alexbrandmeyer@609
|
122 fir_ << a/2, 1 - a - b, b/2;
|
alexbrandmeyer@609
|
123 if (fir_(2) >= 0.1) {
|
alexbrandmeyer@609
|
124 fir_ok_ = true;
|
alexbrandmeyer@609
|
125 } else {
|
alexbrandmeyer@609
|
126 fir_ok_ = false;
|
alexbrandmeyer@609
|
127 }
|
alexbrandmeyer@609
|
128 break;
|
alexbrandmeyer@609
|
129 default:
|
alexbrandmeyer@609
|
130 throw 30; //bad n_taps in FIR design
|
alexbrandmeyer@609
|
131 }
|
alexbrandmeyer@609
|
132 }
|
alexbrandmeyer@609
|
133 }
|
alexbrandmeyer@609
|
134 catch (int e) {
|
alexbrandmeyer@609
|
135 switch (e) {
|
alexbrandmeyer@609
|
136 case 10:
|
alexbrandmeyer@609
|
137 std::cout << "ERROR: Too many n_iterations in agc_coeffs.DesignAGC"
|
alexbrandmeyer@609
|
138 << std::endl;
|
alexbrandmeyer@609
|
139 break;
|
alexbrandmeyer@609
|
140 case 20:
|
alexbrandmeyer@609
|
141 std::cout << "ERROR: Bad n_taps in agc_coeffs.DesignAGC" << std::endl;
|
alexbrandmeyer@609
|
142 break;
|
alexbrandmeyer@609
|
143 case 30:
|
alexbrandmeyer@609
|
144 std::cout << "ERROR: Bad n_taps in agc_coeffs.DesignAGC/FIR"
|
alexbrandmeyer@609
|
145 << std::endl;
|
alexbrandmeyer@609
|
146 break;
|
alexbrandmeyer@609
|
147 default:
|
alexbrandmeyer@609
|
148 std::cout << "ERROR: unknown error in agc_coeffs.DesignAGC"
|
alexbrandmeyer@609
|
149 << std::endl;
|
alexbrandmeyer@609
|
150 }
|
alexbrandmeyer@609
|
151 }
|
alexbrandmeyer@609
|
152 //assign output of filter design
|
alexbrandmeyer@609
|
153 agc_spatial_iterations_(stage) = n_iterations_;
|
alexbrandmeyer@609
|
154 agc_spatial_n_taps_(stage) = n_taps_;
|
alexbrandmeyer@609
|
155 agc_spatial_fir_(0,stage) = fir_(0);
|
alexbrandmeyer@609
|
156 agc_spatial_fir_(1,stage) = fir_(1);
|
alexbrandmeyer@609
|
157 agc_spatial_fir_(2,stage) = fir_(2);
|
alexbrandmeyer@609
|
158 total_dc_gain_ = total_dc_gain_ + pow(agc_stage_gain_,(stage));
|
alexbrandmeyer@609
|
159 if (stage == 0) {
|
alexbrandmeyer@609
|
160 agc_mix_coeffs_(stage) = 0;
|
alexbrandmeyer@609
|
161 } else {
|
alexbrandmeyer@609
|
162 agc_mix_coeffs_(stage) = mix_coeff_ / (tau_ * (fs /decim_));
|
alexbrandmeyer@609
|
163 }
|
alexbrandmeyer@609
|
164 }
|
alexbrandmeyer@609
|
165 agc_gain_ = total_dc_gain_;
|
alexbrandmeyer@609
|
166 detect_scale_ = 1 / total_dc_gain_;
|
alexbrandmeyer@609
|
167 }
|