annotate trunk/carfac/carfac_test.cc @ 668:933cf18d9a59

Fourth revision of Alex Brandmeyer's C++ implementation. Fixed more style issues, changed AGC structures to vectors, replaced FloatArray2d with vector<FloatArray>, implemented first tests using GTest to verify coefficients and monaural output against Matlab values (stored in aimc/carfac/test_data/). To run tests, change the path stored in carfac_test.h in TEST_SRC_DIR. Added CARFAC_GenerateTestData to the Matlab branch, fixed stage indexing in CARFAC_Cross_Couple.m to reflect changes in AGCCoeffs and AGCState structs.
author alexbrandmeyer
date Wed, 22 May 2013 21:30:02 +0000
parents
children a9694d0bb55a
rev   line source
alexbrandmeyer@668 1 //
alexbrandmeyer@668 2 // carfac_test.cc
alexbrandmeyer@668 3 // CARFAC Open Source C++ Library
alexbrandmeyer@668 4 //
alexbrandmeyer@668 5 // Created by Alex Brandmeyer on 5/22/13.
alexbrandmeyer@668 6 //
alexbrandmeyer@668 7 // This C++ file is part of an implementation of Lyon's cochlear model:
alexbrandmeyer@668 8 // "Cascade of Asymmetric Resonators with Fast-Acting Compression"
alexbrandmeyer@668 9 // to supplement Lyon's upcoming book "Human and Machine Hearing"
alexbrandmeyer@668 10 //
alexbrandmeyer@668 11 // Licensed under the Apache License, Version 2.0 (the "License");
alexbrandmeyer@668 12 // you may not use this file except in compliance with the License.
alexbrandmeyer@668 13 // You may obtain a copy of the License at
alexbrandmeyer@668 14 //
alexbrandmeyer@668 15 // http://www.apache.org/licenses/LICENSE-2.0
alexbrandmeyer@668 16 //
alexbrandmeyer@668 17 // Unless required by applicable law or agreed to in writing, software
alexbrandmeyer@668 18 // distributed under the License is distributed on an "AS IS" BASIS,
alexbrandmeyer@668 19 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
alexbrandmeyer@668 20 // See the License for the specific language governing permissions and
alexbrandmeyer@668 21 // limitations under the License.
alexbrandmeyer@668 22
alexbrandmeyer@668 23 #include "carfac_test.h"
alexbrandmeyer@668 24 // Three helper functions are defined here for loading the test data generated
alexbrandmeyer@668 25 // by the Matlab version of CARFAC.
alexbrandmeyer@668 26 // This loads one-dimensional FloatArrays from single-column text files.
alexbrandmeyer@668 27 FloatArray LoadTestData(const std::string filename, const int number_points) {
alexbrandmeyer@668 28 std::string fullfile = TEST_SRC_DIR + filename;
alexbrandmeyer@668 29 std::ifstream file(fullfile.c_str());
alexbrandmeyer@668 30 FPType myarray[number_points];
alexbrandmeyer@668 31 FloatArray output(number_points);
alexbrandmeyer@668 32 if (file.is_open()) {
alexbrandmeyer@668 33 for (int i = 0; i < number_points; ++i) {
alexbrandmeyer@668 34 file >> myarray[i];
alexbrandmeyer@668 35 output(i) = myarray[i];
alexbrandmeyer@668 36 }
alexbrandmeyer@668 37 }
alexbrandmeyer@668 38 return output;
alexbrandmeyer@668 39 }
alexbrandmeyer@668 40
alexbrandmeyer@668 41 // This loads two-dimensional FloatArrays from multi-column text files.
alexbrandmeyer@668 42 std::vector<FloatArray> Load2dTestData(const std::string filename, const int rows,
alexbrandmeyer@668 43 const int columns) {
alexbrandmeyer@668 44 std::string fullfile = TEST_SRC_DIR + filename;
alexbrandmeyer@668 45 std::ifstream file(fullfile.c_str());
alexbrandmeyer@668 46 FPType myarray[rows][columns];
alexbrandmeyer@668 47 std::vector<FloatArray> output;
alexbrandmeyer@668 48 output.resize(rows);
alexbrandmeyer@668 49 for (auto& timepoint : output) {
alexbrandmeyer@668 50 timepoint.resize(columns);
alexbrandmeyer@668 51 }
alexbrandmeyer@668 52 if (file.is_open()) {
alexbrandmeyer@668 53 for (int i = 0; i < rows; ++i) {
alexbrandmeyer@668 54 for (int j = 0; j < columns; ++j) {
alexbrandmeyer@668 55 file >> myarray[i][j];
alexbrandmeyer@668 56 output[i](j) = myarray[i][j];
alexbrandmeyer@668 57 }
alexbrandmeyer@668 58 }
alexbrandmeyer@668 59 }
alexbrandmeyer@668 60 return output;
alexbrandmeyer@668 61 }
alexbrandmeyer@668 62
alexbrandmeyer@668 63 // This loads two dimensional vectors of audio data using data generated in
alexbrandmeyer@668 64 // Matlab using the wavread() function.
alexbrandmeyer@668 65 std::vector<std::vector<float>> Load2dAudioVector(std::string filename,
alexbrandmeyer@668 66 int timepoints,
alexbrandmeyer@668 67 int channels) {
alexbrandmeyer@668 68 std::string fullfile = TEST_SRC_DIR + filename;
alexbrandmeyer@668 69 std::ifstream file(fullfile.c_str());
alexbrandmeyer@668 70 std::vector<std::vector<float>> output;
alexbrandmeyer@668 71 output.resize(channels);
alexbrandmeyer@668 72 for (auto& channel : output) {
alexbrandmeyer@668 73 channel.resize(timepoints);
alexbrandmeyer@668 74 }
alexbrandmeyer@668 75 if (file.is_open()) {
alexbrandmeyer@668 76 for (int i = 0; i < timepoints; ++i) {
alexbrandmeyer@668 77 for (int j = 0; j < channels; ++j) {
alexbrandmeyer@668 78 file >> output[j][i];
alexbrandmeyer@668 79 }
alexbrandmeyer@668 80 }
alexbrandmeyer@668 81 }
alexbrandmeyer@668 82 return output;
alexbrandmeyer@668 83 }
alexbrandmeyer@668 84
alexbrandmeyer@668 85 // The first test verifies that the resulting CAR coefficients are the same as
alexbrandmeyer@668 86 // in Matlab when using the default CAR parameter set.
alexbrandmeyer@668 87 TEST(CARFACTest, CARCoeffs_Test){
alexbrandmeyer@668 88 // These initialze the CAR Params and Coeffs objects needed for this test.
alexbrandmeyer@668 89 CARParams car_params;
alexbrandmeyer@668 90 CARCoeffs car_coeffs;
alexbrandmeyer@668 91 FPType fs = 22050.0;
alexbrandmeyer@668 92 // We calculate the pole frequencies and number of channels in the same way
alexbrandmeyer@668 93 // as in the CARFAC 'Design' method.
alexbrandmeyer@668 94 int n_ch = 0;
alexbrandmeyer@668 95 FPType pole_hz = car_params.first_pole_theta_ * fs / (2 * PI);
alexbrandmeyer@668 96 while (pole_hz > car_params.min_pole_hz_) {
alexbrandmeyer@668 97 n_ch++;
alexbrandmeyer@668 98 pole_hz = pole_hz - car_params.erb_per_step_ *
alexbrandmeyer@668 99 ERBHz(pole_hz, car_params.erb_break_freq_, car_params.erb_q_);
alexbrandmeyer@668 100 }
alexbrandmeyer@668 101 FloatArray pole_freqs(n_ch);
alexbrandmeyer@668 102 pole_hz = car_params.first_pole_theta_ * fs / (2 * PI);
alexbrandmeyer@668 103 for (int ch = 0; ch < n_ch; ++ch) {
alexbrandmeyer@668 104 pole_freqs(ch) = pole_hz;
alexbrandmeyer@668 105 pole_hz = pole_hz - car_params.erb_per_step_ *
alexbrandmeyer@668 106 ERBHz(pole_hz, car_params.erb_break_freq_, car_params.erb_q_);
alexbrandmeyer@668 107 }
alexbrandmeyer@668 108 // This initializes the CAR coeffecients object and runs the design method.
alexbrandmeyer@668 109 car_coeffs.Design(car_params, 22050, pole_freqs);
alexbrandmeyer@668 110 // Now we go through each set of coefficients to verify that the values are
alexbrandmeyer@668 111 // the same as in MATLAB.
alexbrandmeyer@668 112 std::string filename;
alexbrandmeyer@668 113 FloatArray output;
alexbrandmeyer@668 114
alexbrandmeyer@668 115 ASSERT_EQ(car_coeffs.v_offset_, 0.04);
alexbrandmeyer@668 116 ASSERT_EQ(car_coeffs.velocity_scale_, 0.1);
alexbrandmeyer@668 117
alexbrandmeyer@668 118 filename = "r1_coeffs.txt";
alexbrandmeyer@668 119 output = LoadTestData(filename, n_ch);
alexbrandmeyer@668 120 for (int i = 0; i < n_ch; ++i) {
alexbrandmeyer@668 121 ASSERT_NEAR(output(i), car_coeffs.r1_coeffs_(i), PRECISION_LEVEL);
alexbrandmeyer@668 122 }
alexbrandmeyer@668 123
alexbrandmeyer@668 124 filename = "a0_coeffs.txt";
alexbrandmeyer@668 125 output = LoadTestData(filename, n_ch);
alexbrandmeyer@668 126 for (int i = 0; i < n_ch; ++i) {
alexbrandmeyer@668 127 ASSERT_NEAR(output(i), car_coeffs.a0_coeffs_(i), PRECISION_LEVEL);
alexbrandmeyer@668 128 }
alexbrandmeyer@668 129
alexbrandmeyer@668 130 filename = "c0_coeffs.txt";
alexbrandmeyer@668 131 output = LoadTestData(filename, n_ch);
alexbrandmeyer@668 132 for (int i = 0; i < n_ch; ++i) {
alexbrandmeyer@668 133 ASSERT_NEAR(output(i), car_coeffs.c0_coeffs_(i), PRECISION_LEVEL);
alexbrandmeyer@668 134 }
alexbrandmeyer@668 135
alexbrandmeyer@668 136 filename = "zr_coeffs.txt";
alexbrandmeyer@668 137 output = LoadTestData(filename, n_ch);
alexbrandmeyer@668 138 for (int i = 0; i < n_ch; ++i) {
alexbrandmeyer@668 139 ASSERT_NEAR(output(i), car_coeffs.zr_coeffs_(i), PRECISION_LEVEL);
alexbrandmeyer@668 140 }
alexbrandmeyer@668 141
alexbrandmeyer@668 142 filename = "h_coeffs.txt";
alexbrandmeyer@668 143 output = LoadTestData(filename, n_ch);
alexbrandmeyer@668 144 for (int i = 0; i < n_ch; ++i) {
alexbrandmeyer@668 145 ASSERT_NEAR(output(i), car_coeffs.h_coeffs_(i), PRECISION_LEVEL);
alexbrandmeyer@668 146 }
alexbrandmeyer@668 147
alexbrandmeyer@668 148 filename = "g0_coeffs.txt";
alexbrandmeyer@668 149 output = LoadTestData(filename, n_ch);
alexbrandmeyer@668 150 for (int i = 0; i < n_ch; ++i) {
alexbrandmeyer@668 151 ASSERT_NEAR(output(i), car_coeffs.g0_coeffs_(i), PRECISION_LEVEL);
alexbrandmeyer@668 152 }
alexbrandmeyer@668 153 }
alexbrandmeyer@668 154
alexbrandmeyer@668 155 // The second test verifies that the IHC coefficient calculations result in the
alexbrandmeyer@668 156 // same set of values as in the Matlab version of the CARFAC.
alexbrandmeyer@668 157 TEST(CARFACTest, IHCCoeffs_Test){
alexbrandmeyer@668 158 IHCParams ihc_params;
alexbrandmeyer@668 159 IHCCoeffs ihc_coeffs;
alexbrandmeyer@668 160 FPType fs = 22050.0;
alexbrandmeyer@668 161 ihc_coeffs.Design(ihc_params, fs);
alexbrandmeyer@668 162
alexbrandmeyer@668 163 std::string filename = "ihc_coeffs.txt";
alexbrandmeyer@668 164 FloatArray output = LoadTestData(filename, 9);
alexbrandmeyer@668 165
alexbrandmeyer@668 166 // The sequence of the individual coefficients is determined using the
alexbrandmeyer@668 167 // CARFAC_GenerateTestData() function in the Matlab version, with all of the
alexbrandmeyer@668 168 // parameters placed in a single output file for convenience.
alexbrandmeyer@668 169 bool just_hwr = output(0);
alexbrandmeyer@668 170 FPType lpf_coeff = output(1);
alexbrandmeyer@668 171 FPType out_rate = output(2);
alexbrandmeyer@668 172 FPType in_rate = output(3);
alexbrandmeyer@668 173 bool one_cap = output(4);
alexbrandmeyer@668 174 FPType output_gain = output(5);
alexbrandmeyer@668 175 FPType rest_output = output(6);
alexbrandmeyer@668 176 FPType rest_cap = output(7);
alexbrandmeyer@668 177 FPType ac_coeff = output(8);
alexbrandmeyer@668 178
alexbrandmeyer@668 179 // Once we have the Matlab values initialized, we can compare them to the
alexbrandmeyer@668 180 // output of the IHCCoeffs 'Design' method.
alexbrandmeyer@668 181 ASSERT_EQ(just_hwr, ihc_coeffs.just_hwr_);
alexbrandmeyer@668 182 ASSERT_NEAR(lpf_coeff, ihc_coeffs.lpf_coeff_, PRECISION_LEVEL);
alexbrandmeyer@668 183 ASSERT_NEAR(out_rate, ihc_coeffs.out1_rate_, PRECISION_LEVEL);
alexbrandmeyer@668 184 ASSERT_NEAR(in_rate, ihc_coeffs.in1_rate_, PRECISION_LEVEL);
alexbrandmeyer@668 185 ASSERT_EQ(one_cap, ihc_coeffs.one_cap_);
alexbrandmeyer@668 186 ASSERT_NEAR(output_gain, ihc_coeffs.output_gain_, PRECISION_LEVEL);
alexbrandmeyer@668 187 ASSERT_NEAR(rest_output, ihc_coeffs.rest_output_, PRECISION_LEVEL);
alexbrandmeyer@668 188 ASSERT_NEAR(rest_cap, ihc_coeffs.rest_cap1_, PRECISION_LEVEL);
alexbrandmeyer@668 189 ASSERT_NEAR(ac_coeff, ihc_coeffs.ac_coeff_, PRECISION_LEVEL);
alexbrandmeyer@668 190 }
alexbrandmeyer@668 191
alexbrandmeyer@668 192
alexbrandmeyer@668 193 TEST(CARFACTest, AGCCoeffs_Test) {
alexbrandmeyer@668 194 AGCParams agc_params;
alexbrandmeyer@668 195 std::vector<AGCCoeffs> agc_coeffs;
alexbrandmeyer@668 196 std::vector<FloatArray> output;
alexbrandmeyer@668 197 output.resize(agc_params.n_stages_);
alexbrandmeyer@668 198 std::string filename = "agc_coeffs_1.txt";
alexbrandmeyer@668 199 output[0] = LoadTestData(filename, 14);
alexbrandmeyer@668 200 filename = "agc_coeffs_2.txt";
alexbrandmeyer@668 201 output[1] = LoadTestData(filename, 14);
alexbrandmeyer@668 202 filename = "agc_coeffs_3.txt";
alexbrandmeyer@668 203 output[2] = LoadTestData(filename, 14);
alexbrandmeyer@668 204 filename = "agc_coeffs_4.txt";
alexbrandmeyer@668 205 output[3] = LoadTestData(filename, 14);
alexbrandmeyer@668 206 agc_coeffs.resize(agc_params.n_stages_);
alexbrandmeyer@668 207 // We initialize the AGC stages in the same was as in Ear::Init.
alexbrandmeyer@668 208 FPType fs = 22050.0;
alexbrandmeyer@668 209 FPType previous_stage_gain = 0.0;
alexbrandmeyer@668 210 FPType decim = 1.0;
alexbrandmeyer@668 211 for (int stage = 0; stage < agc_params.n_stages_; ++stage) {
alexbrandmeyer@668 212 agc_coeffs[stage].Design(agc_params, stage, fs, previous_stage_gain, decim);
alexbrandmeyer@668 213 previous_stage_gain = agc_coeffs[stage].agc_gain_;
alexbrandmeyer@668 214 decim = agc_coeffs[stage].decim_;
alexbrandmeyer@668 215 }
alexbrandmeyer@668 216 // Now we run through the individual coefficients and verify that they're the
alexbrandmeyer@668 217 // same as in Matlab.
alexbrandmeyer@668 218 for (int stage = 0; stage < agc_params.n_stages_; ++stage) {
alexbrandmeyer@668 219 int n_agc_stages = output[stage](1);
alexbrandmeyer@668 220 FPType agc_stage_gain = output[stage](2);
alexbrandmeyer@668 221 int decimation = output[stage](3);
alexbrandmeyer@668 222 FPType agc_epsilon = output[stage](4);
alexbrandmeyer@668 223 FPType agc_polez1 = output[stage](5);
alexbrandmeyer@668 224 FPType agc_polez2 = output[stage](6);
alexbrandmeyer@668 225 int agc_spatial_iterations = output[stage](7);
alexbrandmeyer@668 226 FPType agc_spatial_fir_1 = output[stage](8);
alexbrandmeyer@668 227 FPType agc_spatial_fir_2 = output[stage](9);
alexbrandmeyer@668 228 FPType agc_spatial_fir_3 = output[stage](10);
alexbrandmeyer@668 229 int agc_spatial_n_taps = output[stage](11);
alexbrandmeyer@668 230 FPType agc_mix_coeffs = output[stage](12);
alexbrandmeyer@668 231 FPType detect_scale = output[stage](13);
alexbrandmeyer@668 232
alexbrandmeyer@668 233 ASSERT_EQ(n_agc_stages, agc_coeffs[stage].n_agc_stages_);
alexbrandmeyer@668 234 ASSERT_NEAR(agc_stage_gain, agc_coeffs[stage].agc_stage_gain_,
alexbrandmeyer@668 235 PRECISION_LEVEL);
alexbrandmeyer@668 236 ASSERT_EQ(decimation, agc_coeffs[stage].decimation_);
alexbrandmeyer@668 237 ASSERT_NEAR(agc_epsilon, agc_coeffs[stage].agc_epsilon_, PRECISION_LEVEL);
alexbrandmeyer@668 238 ASSERT_NEAR(agc_polez1, agc_coeffs[stage].agc_pole_z1_, PRECISION_LEVEL);
alexbrandmeyer@668 239 ASSERT_NEAR(agc_polez2, agc_coeffs[stage].agc_pole_z2_, PRECISION_LEVEL);
alexbrandmeyer@668 240 ASSERT_EQ(agc_spatial_iterations,
alexbrandmeyer@668 241 agc_coeffs[stage].agc_spatial_iterations_);
alexbrandmeyer@668 242 ASSERT_NEAR(agc_spatial_fir_1, agc_coeffs[stage].agc_spatial_fir_[0],
alexbrandmeyer@668 243 PRECISION_LEVEL);
alexbrandmeyer@668 244 ASSERT_NEAR(agc_spatial_fir_2, agc_coeffs[stage].agc_spatial_fir_[1],
alexbrandmeyer@668 245 PRECISION_LEVEL);
alexbrandmeyer@668 246 ASSERT_EQ(agc_spatial_n_taps,
alexbrandmeyer@668 247 agc_coeffs[stage].agc_spatial_n_taps_);
alexbrandmeyer@668 248 ASSERT_NEAR(agc_spatial_fir_3, agc_coeffs[stage].agc_spatial_fir_[2],
alexbrandmeyer@668 249 PRECISION_LEVEL);
alexbrandmeyer@668 250 ASSERT_NEAR(agc_mix_coeffs, agc_coeffs[stage].agc_mix_coeffs_,
alexbrandmeyer@668 251 PRECISION_LEVEL);
alexbrandmeyer@668 252
alexbrandmeyer@668 253 // The last stage will have the correct detect_scale_ value on the basis of
alexbrandmeyer@668 254 // the total gain accumlated over the stages.
alexbrandmeyer@668 255 if (stage == agc_params.n_stages_ - 1) {
alexbrandmeyer@668 256 ASSERT_NEAR(detect_scale, agc_coeffs[stage].detect_scale_,
alexbrandmeyer@668 257 PRECISION_LEVEL);
alexbrandmeyer@668 258 }
alexbrandmeyer@668 259 }
alexbrandmeyer@668 260 }
alexbrandmeyer@668 261
alexbrandmeyer@668 262 // This test verifies the output of the C++ code relative to that of the Matlab
alexbrandmeyer@668 263 // version using a single segment (441 samples) of audio from the "plan.wav"
alexbrandmeyer@668 264 // file. The single-channel audio data and different output matrices from Matlab
alexbrandmeyer@668 265 // are stored in text files and then read into 2d Eigen arrays (for now, this
alexbrandmeyer@668 266 // should be changed to a vector of FloatArrays... TODO (alexbrandmeyer)). For
alexbrandmeyer@668 267 // reference, see the CARFAC_GenerateTestData() function in the Matlab branch
alexbrandmeyer@668 268 // of the repository.
alexbrandmeyer@668 269 //
alexbrandmeyer@668 270 // A single Ear object is used along with the code from CARFAC.RunSegment() to
alexbrandmeyer@668 271 // evaluate the output of the CAR and IHC steps on a sample by sample basis
alexbrandmeyer@668 272 // relative to the output read in from Matlab. The test passes with 11 degrees
alexbrandmeyer@668 273 // of precision, with the Matlab data stored using 12 decimals.
alexbrandmeyer@668 274 //
alexbrandmeyer@668 275 // TODO (alexbrandmeyer): A subseqent version of this test will operate directly
alexbrandmeyer@668 276 // on the CARFACOutput structure and will evaluate binaural data.
alexbrandmeyer@668 277 TEST(CARFACTest, Monaural_Output_Test) {
alexbrandmeyer@668 278 std::string filename = "monaural_test_nap.txt";
alexbrandmeyer@668 279 std::vector<FloatArray> nap = Load2dTestData(filename, 441, 71);
alexbrandmeyer@668 280 filename = "monaural_test_bm.txt";
alexbrandmeyer@668 281 std::vector<FloatArray> bm = Load2dTestData(filename, 441, 71);
alexbrandmeyer@668 282 filename = "monaural_test_ohc.txt";
alexbrandmeyer@668 283 std::vector<FloatArray> ohc = Load2dTestData(filename, 441, 71);
alexbrandmeyer@668 284 filename = "monaural_test_agc.txt";
alexbrandmeyer@668 285 std::vector<FloatArray> agc = Load2dTestData(filename, 441, 71);
alexbrandmeyer@668 286 filename = "file_signal_monaural_test.txt";
alexbrandmeyer@668 287 std::vector<std::vector<float>> sound_data = Load2dAudioVector(filename, 441,
alexbrandmeyer@668 288 1);
alexbrandmeyer@668 289 // The number of timepoints is determined from the length of the audio
alexbrandmeyer@668 290 // segment.
alexbrandmeyer@668 291 int32_t n_timepoints = sound_data[0].size();
alexbrandmeyer@668 292
alexbrandmeyer@668 293 CARParams car_params;
alexbrandmeyer@668 294 IHCParams ihc_params;
alexbrandmeyer@668 295 AGCParams agc_params;
alexbrandmeyer@668 296 FPType fs = 22050.0;
alexbrandmeyer@668 297 int n_ch = 0;
alexbrandmeyer@668 298 FPType pole_hz = car_params.first_pole_theta_ * fs / (2 * PI);
alexbrandmeyer@668 299 while (pole_hz > car_params.min_pole_hz_) {
alexbrandmeyer@668 300 n_ch++;
alexbrandmeyer@668 301 pole_hz = pole_hz - car_params.erb_per_step_ *
alexbrandmeyer@668 302 ERBHz(pole_hz, car_params.erb_break_freq_, car_params.erb_q_);
alexbrandmeyer@668 303 }
alexbrandmeyer@668 304 FloatArray pole_freqs(n_ch);
alexbrandmeyer@668 305 pole_hz = car_params.first_pole_theta_ * fs / (2 * PI);
alexbrandmeyer@668 306 for (int ch = 0; ch < n_ch; ++ch) {
alexbrandmeyer@668 307 pole_freqs(ch) = pole_hz;
alexbrandmeyer@668 308 pole_hz = pole_hz - car_params.erb_per_step_ *
alexbrandmeyer@668 309 ERBHz(pole_hz, car_params.erb_break_freq_, car_params.erb_q_);
alexbrandmeyer@668 310 }
alexbrandmeyer@668 311
alexbrandmeyer@668 312 // This initializes the CARFAC object and runs the design method.
alexbrandmeyer@668 313 Ear ear;
alexbrandmeyer@668 314 ear.InitEar(n_ch, fs, pole_freqs, car_params, ihc_params, agc_params);
alexbrandmeyer@668 315
alexbrandmeyer@668 316 CARFACOutput seg_output;
alexbrandmeyer@668 317 seg_output.InitOutput(1, n_ch, n_timepoints);
alexbrandmeyer@668 318
alexbrandmeyer@668 319 // A nested loop structure is used to iterate through the individual samples
alexbrandmeyer@668 320 // for each ear (audio channel).
alexbrandmeyer@668 321 FloatArray car_out(n_ch);
alexbrandmeyer@668 322 FloatArray ihc_out(n_ch);
alexbrandmeyer@668 323 FloatArray matlab_car_out(n_ch);
alexbrandmeyer@668 324 FloatArray matlab_ihc_out(n_ch);
alexbrandmeyer@668 325 bool updated; // This variable is used by the AGC stage.
alexbrandmeyer@668 326 for (int32_t i = 0; i < n_timepoints; ++i) {
alexbrandmeyer@668 327 int j = 0;
alexbrandmeyer@668 328 // First we create a reference to the current Ear object.
alexbrandmeyer@668 329 // This stores the audio sample currently being processed.
alexbrandmeyer@668 330 FPType input = sound_data[j][i];
alexbrandmeyer@668 331 // Now we apply the three stages of the model in sequence to the current
alexbrandmeyer@668 332 // audio sample.
alexbrandmeyer@668 333 ear.CARStep(input, &car_out);
alexbrandmeyer@668 334 matlab_car_out = bm[i];
alexbrandmeyer@668 335 // This step verifies that the ouput of the CAR step is the same at each
alexbrandmeyer@668 336 // timepoint and channel as that of the Matlab version.
alexbrandmeyer@668 337 for (int channel = 0; channel < n_ch; ++channel) {
alexbrandmeyer@668 338 FPType a = matlab_car_out(channel);
alexbrandmeyer@668 339 FPType b = car_out(channel);
alexbrandmeyer@668 340 ASSERT_NEAR(a, b, PRECISION_LEVEL);
alexbrandmeyer@668 341 }
alexbrandmeyer@668 342 ear.IHCStep(car_out, &ihc_out);
alexbrandmeyer@668 343 matlab_ihc_out = nap[i];
alexbrandmeyer@668 344 // This step verifies that the ouput of the IHC step is the same at each
alexbrandmeyer@668 345 // timepoint and channel as that of the Matlab version.
alexbrandmeyer@668 346 for (int channel = 0; channel < n_ch; ++channel) {
alexbrandmeyer@668 347 FPType a = matlab_ihc_out(channel);
alexbrandmeyer@668 348 FPType b = ihc_out(channel);
alexbrandmeyer@668 349 ASSERT_NEAR(a, b, PRECISION_LEVEL);
alexbrandmeyer@668 350 }
alexbrandmeyer@668 351
alexbrandmeyer@668 352 updated = ear.AGCStep(ihc_out);
alexbrandmeyer@668 353 // These lines assign the output of the model for the current sample
alexbrandmeyer@668 354 // to the appropriate data members of the current ear in the output
alexbrandmeyer@668 355 // object.
alexbrandmeyer@668 356 seg_output.StoreNAPOutput(i, j, ihc_out);
alexbrandmeyer@668 357 seg_output.StoreBMOutput(i, j, car_out);
alexbrandmeyer@668 358 seg_output.StoreOHCOutput(i, j, ear.za_memory());
alexbrandmeyer@668 359 seg_output.StoreAGCOutput(i, j, ear.zb_memory());
alexbrandmeyer@668 360 if (updated) {
alexbrandmeyer@668 361 FloatArray undamping = 1 - ear.agc_memory(0);
alexbrandmeyer@668 362 // This updates the target stage gain for the new damping.
alexbrandmeyer@668 363 ear.set_dzb_memory((ear.zr_coeffs() * undamping - ear.zb_memory()) /
alexbrandmeyer@668 364 ear.agc_decimation(0));
alexbrandmeyer@668 365 ear.set_dg_memory((ear.StageGValue(undamping) - ear.g_memory()) /
alexbrandmeyer@668 366 ear.agc_decimation(0));
alexbrandmeyer@668 367 }
alexbrandmeyer@668 368 }
alexbrandmeyer@668 369 }