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