alexbrandmeyer@626: // alexbrandmeyer@626: // carfac_test.cc alexbrandmeyer@626: // CARFAC Open Source C++ Library alexbrandmeyer@626: // alexbrandmeyer@626: // Created by Alex Brandmeyer on 5/22/13. alexbrandmeyer@626: // alexbrandmeyer@626: // This C++ file is part of an implementation of Lyon's cochlear model: alexbrandmeyer@626: // "Cascade of Asymmetric Resonators with Fast-Acting Compression" alexbrandmeyer@626: // to supplement Lyon's upcoming book "Human and Machine Hearing" alexbrandmeyer@626: // alexbrandmeyer@626: // Licensed under the Apache License, Version 2.0 (the "License"); alexbrandmeyer@626: // you may not use this file except in compliance with the License. alexbrandmeyer@626: // You may obtain a copy of the License at alexbrandmeyer@626: // alexbrandmeyer@626: // http://www.apache.org/licenses/LICENSE-2.0 alexbrandmeyer@626: // alexbrandmeyer@626: // Unless required by applicable law or agreed to in writing, software alexbrandmeyer@626: // distributed under the License is distributed on an "AS IS" BASIS, alexbrandmeyer@626: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. alexbrandmeyer@626: // See the License for the specific language governing permissions and alexbrandmeyer@626: // limitations under the License. alexbrandmeyer@626: alexbrandmeyer@636: #include alexbrandmeyer@636: #include alexbrandmeyer@640: #include alexbrandmeyer@636: #include alexbrandmeyer@640: #include "car_params.h" alexbrandmeyer@640: #include "ihc_params.h" alexbrandmeyer@640: #include "agc_params.h" alexbrandmeyer@636: #include "carfac.h" alexbrandmeyer@637: alexbrandmeyer@636: using std::vector; alexbrandmeyer@636: using std::string; alexbrandmeyer@636: using std::ifstream; alexbrandmeyer@636: using std::ofstream; alexbrandmeyer@636: alexbrandmeyer@637: // This is the 'test_data' subdirectory of aimc/carfac that specifies where to alexbrandmeyer@637: // locate the text files produced by 'CARFAC_GenerateTestData.m' for comparing alexbrandmeyer@637: // the ouput of the Matlab version of CARFAC with this C++ version. alexbrandmeyer@637: static const char* kTestSourceDir= "./test_data/"; alexbrandmeyer@636: // Here we specify the level to which the output should match (7 decimals). alexbrandmeyer@637: static const float kPrecisionLevel = 1.0e-7; ronw@630: alexbrandmeyer@626: // Three helper functions are defined here for loading the test data generated alexbrandmeyer@626: // by the Matlab version of CARFAC. alexbrandmeyer@626: // This loads one-dimensional FloatArrays from single-column text files. alexbrandmeyer@636: void WriteNAPOutput(CARFACOutput output, const string filename, int ear) { alexbrandmeyer@637: string fullfile = kTestSourceDir + filename; alexbrandmeyer@636: ofstream ofile(fullfile.c_str()); alexbrandmeyer@637: int32_t n_timepoints = output.nap().size(); alexbrandmeyer@637: int channels = output.nap()[0][0].size(); alexbrandmeyer@636: if (ofile.is_open()) { alexbrandmeyer@636: for (int32_t i = 0; i < n_timepoints; ++i) { alexbrandmeyer@636: for (int j = 0; j < channels; ++j) { alexbrandmeyer@637: ofile << output.nap()[i][ear](j); alexbrandmeyer@636: if ( j < channels - 1) { alexbrandmeyer@636: ofile << " "; alexbrandmeyer@636: } alexbrandmeyer@636: } alexbrandmeyer@636: ofile << "\n"; alexbrandmeyer@636: } alexbrandmeyer@636: } alexbrandmeyer@636: ofile.close(); alexbrandmeyer@636: } alexbrandmeyer@636: alexbrandmeyer@637: FloatArray LoadTestData(const string filename, const int number_points) { alexbrandmeyer@637: string fullfile = kTestSourceDir + filename; alexbrandmeyer@636: ifstream file(fullfile.c_str()); alexbrandmeyer@626: FPType myarray[number_points]; alexbrandmeyer@626: FloatArray output(number_points); alexbrandmeyer@626: if (file.is_open()) { alexbrandmeyer@626: for (int i = 0; i < number_points; ++i) { alexbrandmeyer@626: file >> myarray[i]; alexbrandmeyer@626: output(i) = myarray[i]; alexbrandmeyer@626: } alexbrandmeyer@626: } alexbrandmeyer@636: file.close(); alexbrandmeyer@626: return output; alexbrandmeyer@626: } alexbrandmeyer@626: alexbrandmeyer@636: // This loads a vector of FloatArrays from multi-column text files. alexbrandmeyer@636: vector Load2dTestData(const string filename, const int rows, alexbrandmeyer@626: const int columns) { alexbrandmeyer@637: string fullfile = kTestSourceDir + filename; alexbrandmeyer@636: ifstream file(fullfile.c_str()); alexbrandmeyer@626: FPType myarray[rows][columns]; alexbrandmeyer@636: vector output; alexbrandmeyer@626: output.resize(rows); alexbrandmeyer@626: for (auto& timepoint : output) { alexbrandmeyer@626: timepoint.resize(columns); alexbrandmeyer@626: } alexbrandmeyer@626: if (file.is_open()) { alexbrandmeyer@626: for (int i = 0; i < rows; ++i) { alexbrandmeyer@626: for (int j = 0; j < columns; ++j) { alexbrandmeyer@626: file >> myarray[i][j]; alexbrandmeyer@626: output[i](j) = myarray[i][j]; alexbrandmeyer@626: } alexbrandmeyer@626: } alexbrandmeyer@626: } alexbrandmeyer@636: file.close(); alexbrandmeyer@626: return output; alexbrandmeyer@626: } alexbrandmeyer@626: alexbrandmeyer@626: // This loads two dimensional vectors of audio data using data generated in alexbrandmeyer@626: // Matlab using the wavread() function. alexbrandmeyer@636: vector> Load2dAudioVector(string filename, int timepoints, alexbrandmeyer@636: int channels) { alexbrandmeyer@637: string fullfile = kTestSourceDir + filename; alexbrandmeyer@636: ifstream file(fullfile.c_str()); alexbrandmeyer@636: vector> output; alexbrandmeyer@626: output.resize(channels); alexbrandmeyer@626: for (auto& channel : output) { alexbrandmeyer@626: channel.resize(timepoints); alexbrandmeyer@626: } alexbrandmeyer@626: if (file.is_open()) { alexbrandmeyer@626: for (int i = 0; i < timepoints; ++i) { alexbrandmeyer@626: for (int j = 0; j < channels; ++j) { alexbrandmeyer@626: file >> output[j][i]; alexbrandmeyer@626: } alexbrandmeyer@626: } alexbrandmeyer@626: } alexbrandmeyer@636: file.close(); alexbrandmeyer@626: return output; alexbrandmeyer@626: } alexbrandmeyer@626: alexbrandmeyer@636: TEST(CARFACTest, Binaural_Output_test) { alexbrandmeyer@636: int n_timepoints = 882; alexbrandmeyer@636: int n_channels = 71; alexbrandmeyer@636: int n_ears = 2; alexbrandmeyer@637: string filename = "binaural_test_nap1.txt"; alexbrandmeyer@637: vector nap1 = Load2dTestData(filename, n_timepoints, n_channels); alexbrandmeyer@636: filename = "binaural_test_bm1.txt"; alexbrandmeyer@637: vector bm1 = Load2dTestData(filename, n_timepoints, n_channels); alexbrandmeyer@636: filename = "binaural_test_nap2.txt"; alexbrandmeyer@637: vector nap2 = Load2dTestData(filename, n_timepoints, n_channels); alexbrandmeyer@636: filename = "binaural_test_bm2.txt"; alexbrandmeyer@637: vector bm2 = Load2dTestData(filename, n_timepoints, n_channels); alexbrandmeyer@636: filename = "file_signal_binaural_test.txt"; alexbrandmeyer@637: vector> sound_data = Load2dAudioVector(filename, n_timepoints, alexbrandmeyer@637: n_ears); alexbrandmeyer@626: CARParams car_params; alexbrandmeyer@636: IHCParams ihc_params; alexbrandmeyer@636: AGCParams agc_params; alexbrandmeyer@636: CARFAC mycf; alexbrandmeyer@636: mycf.Design(n_ears, 22050, car_params, ihc_params, alexbrandmeyer@636: agc_params); alexbrandmeyer@636: CARFACOutput my_output; alexbrandmeyer@636: my_output.Init(n_ears, true, false, true, false, false); ronw@641: const bool kOpenLoop = false; ronw@641: const int length = sound_data[0].size(); ronw@641: mycf.RunSegment(sound_data, 0, length, kOpenLoop, &my_output); alexbrandmeyer@636: filename = "cpp_nap_output_1_binaural_test.txt"; alexbrandmeyer@636: WriteNAPOutput(my_output, filename, 0); alexbrandmeyer@636: filename = "cpp_nap_output_2_binaural_test.txt"; alexbrandmeyer@636: WriteNAPOutput(my_output, filename, 1); alexbrandmeyer@636: int ear = 0; alexbrandmeyer@636: int n_ch = 71; alexbrandmeyer@636: for (int timepoint = 0; timepoint < n_timepoints; ++timepoint) { alexbrandmeyer@636: for (int channel = 0; channel < n_ch; ++channel) { alexbrandmeyer@637: FPType cplusplus = my_output.nap()[timepoint][ear](channel); alexbrandmeyer@636: FPType matlab = nap1[timepoint](channel); alexbrandmeyer@637: ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel); alexbrandmeyer@637: cplusplus = my_output.bm()[timepoint][ear](channel); alexbrandmeyer@636: matlab = bm1[timepoint](channel); alexbrandmeyer@637: ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel); alexbrandmeyer@636: } alexbrandmeyer@626: } alexbrandmeyer@636: ear = 1; alexbrandmeyer@636: for (int timepoint = 0; timepoint < n_timepoints; ++timepoint) { alexbrandmeyer@636: for (int channel = 0; channel < n_ch; ++channel) { alexbrandmeyer@637: FPType cplusplus = my_output.nap()[timepoint][ear](channel); alexbrandmeyer@636: FPType matlab = nap2[timepoint](channel); alexbrandmeyer@637: ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel); alexbrandmeyer@637: cplusplus = my_output.bm()[timepoint][ear](channel); alexbrandmeyer@636: matlab = bm2[timepoint](channel); alexbrandmeyer@637: ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel); alexbrandmeyer@626: } alexbrandmeyer@626: } alexbrandmeyer@626: } alexbrandmeyer@626: alexbrandmeyer@636: TEST(CARFACTest, Long_Output_test) { alexbrandmeyer@636: int n_timepoints = 2000; alexbrandmeyer@636: int n_channels = 83; alexbrandmeyer@636: int n_ears = 2; alexbrandmeyer@636: string filename = "long_test_nap1.txt"; alexbrandmeyer@637: vector nap1 = Load2dTestData(filename, n_timepoints, n_channels); alexbrandmeyer@636: filename = "long_test_bm1.txt"; alexbrandmeyer@637: vector bm1 = Load2dTestData(filename, n_timepoints, n_channels); alexbrandmeyer@636: filename = "long_test_nap2.txt"; alexbrandmeyer@637: vector nap2 = Load2dTestData(filename, n_timepoints, n_channels); alexbrandmeyer@636: filename = "long_test_bm2.txt"; alexbrandmeyer@637: vector bm2 = Load2dTestData(filename, n_timepoints, n_channels); alexbrandmeyer@636: filename = "file_signal_long_test.txt"; alexbrandmeyer@637: vector> sound_data = Load2dAudioVector(filename, n_timepoints, alexbrandmeyer@637: n_ears); alexbrandmeyer@626: CARParams car_params; alexbrandmeyer@626: IHCParams ihc_params; alexbrandmeyer@626: AGCParams agc_params; alexbrandmeyer@636: CARFAC mycf; alexbrandmeyer@636: mycf.Design(n_ears, 44100, car_params, ihc_params, alexbrandmeyer@636: agc_params); alexbrandmeyer@636: CARFACOutput my_output; alexbrandmeyer@636: my_output.Init(n_ears, true, false, true, false, false); ronw@641: const bool kOpenLoop = false; ronw@641: const int length = sound_data[0].size(); ronw@641: mycf.RunSegment(sound_data, 0, length, kOpenLoop, &my_output); alexbrandmeyer@636: filename = "cpp_nap_output_1_long_test.txt"; alexbrandmeyer@636: WriteNAPOutput(my_output, filename, 0); alexbrandmeyer@636: filename = "cpp_nap_output_2_long_test.txt"; alexbrandmeyer@636: WriteNAPOutput(my_output, filename, 1); alexbrandmeyer@636: int ear = 0; alexbrandmeyer@636: for (int timepoint = 0; timepoint < n_timepoints; ++timepoint) { alexbrandmeyer@636: for (int channel = 0; channel < n_channels; ++channel) { alexbrandmeyer@637: FPType cplusplus = my_output.nap()[timepoint][ear](channel); alexbrandmeyer@636: FPType matlab = nap1[timepoint](channel); alexbrandmeyer@637: ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel); alexbrandmeyer@637: cplusplus = my_output.bm()[timepoint][ear](channel); alexbrandmeyer@636: matlab = bm1[timepoint](channel); alexbrandmeyer@637: ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel); alexbrandmeyer@636: } alexbrandmeyer@626: } alexbrandmeyer@636: ear = 1; alexbrandmeyer@636: for (int timepoint = 0; timepoint < n_timepoints; ++timepoint) { alexbrandmeyer@636: for (int channel = 0; channel < n_channels; ++channel) { alexbrandmeyer@637: FPType cplusplus = my_output.nap()[timepoint][ear](channel); alexbrandmeyer@636: FPType matlab = nap2[timepoint](channel); alexbrandmeyer@637: ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel); alexbrandmeyer@637: cplusplus = my_output.bm()[timepoint][ear](channel); alexbrandmeyer@636: matlab = bm2[timepoint](channel); alexbrandmeyer@637: ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel); alexbrandmeyer@626: } alexbrandmeyer@626: } ronw@641: }