annotate trunk/carfac/carfac_test.cc @ 684:49af9a8d5a53

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