annotate carfac/carfac_test.cc @ 637:efc5b1b54f63

Sixth revision of Alex Brandmeyer's C++ implementation. Only small changes in response to Lyon's comments from r285. Note: I tried to use a consistent indentation with two spaces, but also preserving parenthetical structure to make reading the longer equations easier. Please advise if this is OK. Additional documentation and tests with non-standard parameter sets will be added in a subsequent revision.
author alexbrandmeyer
date Tue, 28 May 2013 15:54:54 +0000
parents 27f2d9b76075
children d08c02c8e26f
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@636 23 #include <string>
alexbrandmeyer@636 24 #include <fstream>
alexbrandmeyer@636 25 // GoogleTest is now included for running unit tests
alexbrandmeyer@636 26 #include <gtest/gtest.h>
alexbrandmeyer@636 27 #include "carfac.h"
alexbrandmeyer@637 28
alexbrandmeyer@636 29 using std::vector;
alexbrandmeyer@636 30 using std::string;
alexbrandmeyer@636 31 using std::ifstream;
alexbrandmeyer@636 32 using std::ofstream;
alexbrandmeyer@636 33
alexbrandmeyer@637 34 // This is the 'test_data' subdirectory of aimc/carfac that specifies where to
alexbrandmeyer@637 35 // locate the text files produced by 'CARFAC_GenerateTestData.m' for comparing
alexbrandmeyer@637 36 // the ouput of the Matlab version of CARFAC with this C++ version.
alexbrandmeyer@637 37 static const char* kTestSourceDir= "./test_data/";
alexbrandmeyer@636 38 // Here we specify the level to which the output should match (7 decimals).
alexbrandmeyer@637 39 static const float kPrecisionLevel = 1.0e-7;
ronw@630 40
alexbrandmeyer@626 41 // Three helper functions are defined here for loading the test data generated
alexbrandmeyer@626 42 // by the Matlab version of CARFAC.
alexbrandmeyer@626 43 // This loads one-dimensional FloatArrays from single-column text files.
alexbrandmeyer@636 44 void WriteNAPOutput(CARFACOutput output, const string filename, int ear) {
alexbrandmeyer@637 45 string fullfile = kTestSourceDir + filename;
alexbrandmeyer@636 46 ofstream ofile(fullfile.c_str());
alexbrandmeyer@637 47 int32_t n_timepoints = output.nap().size();
alexbrandmeyer@637 48 int channels = output.nap()[0][0].size();
alexbrandmeyer@636 49 if (ofile.is_open()) {
alexbrandmeyer@636 50 for (int32_t i = 0; i < n_timepoints; ++i) {
alexbrandmeyer@636 51 for (int j = 0; j < channels; ++j) {
alexbrandmeyer@637 52 ofile << output.nap()[i][ear](j);
alexbrandmeyer@636 53 if ( j < channels - 1) {
alexbrandmeyer@636 54 ofile << " ";
alexbrandmeyer@636 55 }
alexbrandmeyer@636 56 }
alexbrandmeyer@636 57 ofile << "\n";
alexbrandmeyer@636 58 }
alexbrandmeyer@636 59 }
alexbrandmeyer@636 60 ofile.close();
alexbrandmeyer@636 61 }
alexbrandmeyer@636 62
alexbrandmeyer@637 63 FloatArray LoadTestData(const string filename, const int number_points) {
alexbrandmeyer@637 64 string fullfile = kTestSourceDir + filename;
alexbrandmeyer@636 65 ifstream file(fullfile.c_str());
alexbrandmeyer@626 66 FPType myarray[number_points];
alexbrandmeyer@626 67 FloatArray output(number_points);
alexbrandmeyer@626 68 if (file.is_open()) {
alexbrandmeyer@626 69 for (int i = 0; i < number_points; ++i) {
alexbrandmeyer@626 70 file >> myarray[i];
alexbrandmeyer@626 71 output(i) = myarray[i];
alexbrandmeyer@626 72 }
alexbrandmeyer@626 73 }
alexbrandmeyer@636 74 file.close();
alexbrandmeyer@626 75 return output;
alexbrandmeyer@626 76 }
alexbrandmeyer@626 77
alexbrandmeyer@636 78 // This loads a vector of FloatArrays from multi-column text files.
alexbrandmeyer@636 79 vector<FloatArray> Load2dTestData(const string filename, const int rows,
alexbrandmeyer@626 80 const int columns) {
alexbrandmeyer@637 81 string fullfile = kTestSourceDir + filename;
alexbrandmeyer@636 82 ifstream file(fullfile.c_str());
alexbrandmeyer@626 83 FPType myarray[rows][columns];
alexbrandmeyer@636 84 vector<FloatArray> output;
alexbrandmeyer@626 85 output.resize(rows);
alexbrandmeyer@626 86 for (auto& timepoint : output) {
alexbrandmeyer@626 87 timepoint.resize(columns);
alexbrandmeyer@626 88 }
alexbrandmeyer@626 89 if (file.is_open()) {
alexbrandmeyer@626 90 for (int i = 0; i < rows; ++i) {
alexbrandmeyer@626 91 for (int j = 0; j < columns; ++j) {
alexbrandmeyer@626 92 file >> myarray[i][j];
alexbrandmeyer@626 93 output[i](j) = myarray[i][j];
alexbrandmeyer@626 94 }
alexbrandmeyer@626 95 }
alexbrandmeyer@626 96 }
alexbrandmeyer@636 97 file.close();
alexbrandmeyer@626 98 return output;
alexbrandmeyer@626 99 }
alexbrandmeyer@626 100
alexbrandmeyer@626 101 // This loads two dimensional vectors of audio data using data generated in
alexbrandmeyer@626 102 // Matlab using the wavread() function.
alexbrandmeyer@636 103 vector<vector<float>> Load2dAudioVector(string filename, int timepoints,
alexbrandmeyer@636 104 int channels) {
alexbrandmeyer@637 105 string fullfile = kTestSourceDir + filename;
alexbrandmeyer@636 106 ifstream file(fullfile.c_str());
alexbrandmeyer@636 107 vector<vector<float>> output;
alexbrandmeyer@626 108 output.resize(channels);
alexbrandmeyer@626 109 for (auto& channel : output) {
alexbrandmeyer@626 110 channel.resize(timepoints);
alexbrandmeyer@626 111 }
alexbrandmeyer@626 112 if (file.is_open()) {
alexbrandmeyer@626 113 for (int i = 0; i < timepoints; ++i) {
alexbrandmeyer@626 114 for (int j = 0; j < channels; ++j) {
alexbrandmeyer@626 115 file >> output[j][i];
alexbrandmeyer@626 116 }
alexbrandmeyer@626 117 }
alexbrandmeyer@626 118 }
alexbrandmeyer@636 119 file.close();
alexbrandmeyer@626 120 return output;
alexbrandmeyer@626 121 }
alexbrandmeyer@626 122
alexbrandmeyer@636 123 TEST(CARFACTest, Binaural_Output_test) {
alexbrandmeyer@636 124 int n_timepoints = 882;
alexbrandmeyer@636 125 int n_channels = 71;
alexbrandmeyer@636 126 int n_ears = 2;
alexbrandmeyer@637 127 string filename = "binaural_test_nap1.txt";
alexbrandmeyer@637 128 vector<FloatArray> nap1 = Load2dTestData(filename, n_timepoints, n_channels);
alexbrandmeyer@636 129 filename = "binaural_test_bm1.txt";
alexbrandmeyer@637 130 vector<FloatArray> bm1 = Load2dTestData(filename, n_timepoints, n_channels);
alexbrandmeyer@636 131 filename = "binaural_test_nap2.txt";
alexbrandmeyer@637 132 vector<FloatArray> nap2 = Load2dTestData(filename, n_timepoints, n_channels);
alexbrandmeyer@636 133 filename = "binaural_test_bm2.txt";
alexbrandmeyer@637 134 vector<FloatArray> bm2 = Load2dTestData(filename, n_timepoints, n_channels);
alexbrandmeyer@636 135 filename = "file_signal_binaural_test.txt";
alexbrandmeyer@637 136 vector<vector<float>> sound_data = Load2dAudioVector(filename, n_timepoints,
alexbrandmeyer@637 137 n_ears);
alexbrandmeyer@626 138 CARParams car_params;
alexbrandmeyer@636 139 IHCParams ihc_params;
alexbrandmeyer@636 140 AGCParams agc_params;
alexbrandmeyer@636 141 CARFAC mycf;
alexbrandmeyer@636 142 mycf.Design(n_ears, 22050, car_params, ihc_params,
alexbrandmeyer@636 143 agc_params);
alexbrandmeyer@636 144 CARFACOutput my_output;
alexbrandmeyer@636 145 my_output.Init(n_ears, true, false, true, false, false);
alexbrandmeyer@636 146 mycf.Run(sound_data, &my_output);
alexbrandmeyer@636 147 filename = "cpp_nap_output_1_binaural_test.txt";
alexbrandmeyer@636 148 WriteNAPOutput(my_output, filename, 0);
alexbrandmeyer@636 149 filename = "cpp_nap_output_2_binaural_test.txt";
alexbrandmeyer@636 150 WriteNAPOutput(my_output, filename, 1);
alexbrandmeyer@636 151 int ear = 0;
alexbrandmeyer@636 152 int n_ch = 71;
alexbrandmeyer@636 153 for (int timepoint = 0; timepoint < n_timepoints; ++timepoint) {
alexbrandmeyer@636 154 for (int channel = 0; channel < n_ch; ++channel) {
alexbrandmeyer@637 155 FPType cplusplus = my_output.nap()[timepoint][ear](channel);
alexbrandmeyer@636 156 FPType matlab = nap1[timepoint](channel);
alexbrandmeyer@637 157 ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel);
alexbrandmeyer@637 158 cplusplus = my_output.bm()[timepoint][ear](channel);
alexbrandmeyer@636 159 matlab = bm1[timepoint](channel);
alexbrandmeyer@637 160 ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel);
alexbrandmeyer@636 161 }
alexbrandmeyer@626 162 }
alexbrandmeyer@636 163 ear = 1;
alexbrandmeyer@636 164 for (int timepoint = 0; timepoint < n_timepoints; ++timepoint) {
alexbrandmeyer@636 165 for (int channel = 0; channel < n_ch; ++channel) {
alexbrandmeyer@637 166 FPType cplusplus = my_output.nap()[timepoint][ear](channel);
alexbrandmeyer@636 167 FPType matlab = nap2[timepoint](channel);
alexbrandmeyer@637 168 ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel);
alexbrandmeyer@637 169 cplusplus = my_output.bm()[timepoint][ear](channel);
alexbrandmeyer@636 170 matlab = bm2[timepoint](channel);
alexbrandmeyer@637 171 ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel);
alexbrandmeyer@626 172 }
alexbrandmeyer@626 173 }
alexbrandmeyer@626 174 }
alexbrandmeyer@626 175
alexbrandmeyer@636 176 TEST(CARFACTest, Long_Output_test) {
alexbrandmeyer@636 177 int n_timepoints = 2000;
alexbrandmeyer@636 178 int n_channels = 83;
alexbrandmeyer@636 179 int n_ears = 2;
alexbrandmeyer@636 180 string filename = "long_test_nap1.txt";
alexbrandmeyer@637 181 vector<FloatArray> nap1 = Load2dTestData(filename, n_timepoints, n_channels);
alexbrandmeyer@636 182 filename = "long_test_bm1.txt";
alexbrandmeyer@637 183 vector<FloatArray> bm1 = Load2dTestData(filename, n_timepoints, n_channels);
alexbrandmeyer@636 184 filename = "long_test_nap2.txt";
alexbrandmeyer@637 185 vector<FloatArray> nap2 = Load2dTestData(filename, n_timepoints, n_channels);
alexbrandmeyer@636 186 filename = "long_test_bm2.txt";
alexbrandmeyer@637 187 vector<FloatArray> bm2 = Load2dTestData(filename, n_timepoints, n_channels);
alexbrandmeyer@636 188 filename = "file_signal_long_test.txt";
alexbrandmeyer@637 189 vector<vector<float>> sound_data = Load2dAudioVector(filename, n_timepoints,
alexbrandmeyer@637 190 n_ears);
alexbrandmeyer@626 191 CARParams car_params;
alexbrandmeyer@626 192 IHCParams ihc_params;
alexbrandmeyer@626 193 AGCParams agc_params;
alexbrandmeyer@636 194 CARFAC mycf;
alexbrandmeyer@636 195 mycf.Design(n_ears, 44100, car_params, ihc_params,
alexbrandmeyer@636 196 agc_params);
alexbrandmeyer@636 197 CARFACOutput my_output;
alexbrandmeyer@636 198 my_output.Init(n_ears, true, false, true, false, false);
alexbrandmeyer@636 199 mycf.Run(sound_data, &my_output);
alexbrandmeyer@636 200 filename = "cpp_nap_output_1_long_test.txt";
alexbrandmeyer@636 201 WriteNAPOutput(my_output, filename, 0);
alexbrandmeyer@636 202 filename = "cpp_nap_output_2_long_test.txt";
alexbrandmeyer@636 203 WriteNAPOutput(my_output, filename, 1);
alexbrandmeyer@636 204 int ear = 0;
alexbrandmeyer@636 205 for (int timepoint = 0; timepoint < n_timepoints; ++timepoint) {
alexbrandmeyer@636 206 for (int channel = 0; channel < n_channels; ++channel) {
alexbrandmeyer@637 207 FPType cplusplus = my_output.nap()[timepoint][ear](channel);
alexbrandmeyer@636 208 FPType matlab = nap1[timepoint](channel);
alexbrandmeyer@637 209 ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel);
alexbrandmeyer@637 210 cplusplus = my_output.bm()[timepoint][ear](channel);
alexbrandmeyer@636 211 matlab = bm1[timepoint](channel);
alexbrandmeyer@637 212 ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel);
alexbrandmeyer@636 213 }
alexbrandmeyer@626 214 }
alexbrandmeyer@636 215 ear = 1;
alexbrandmeyer@636 216 for (int timepoint = 0; timepoint < n_timepoints; ++timepoint) {
alexbrandmeyer@636 217 for (int channel = 0; channel < n_channels; ++channel) {
alexbrandmeyer@637 218 FPType cplusplus = my_output.nap()[timepoint][ear](channel);
alexbrandmeyer@636 219 FPType matlab = nap2[timepoint](channel);
alexbrandmeyer@637 220 ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel);
alexbrandmeyer@637 221 cplusplus = my_output.bm()[timepoint][ear](channel);
alexbrandmeyer@636 222 matlab = bm2[timepoint](channel);
alexbrandmeyer@637 223 ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel);
alexbrandmeyer@626 224 }
alexbrandmeyer@626 225 }
alexbrandmeyer@636 226 }