annotate carfac/carfac_test.cc @ 635:0bdd58ee6e92

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