# HG changeset patch # User ronw@google.com # Date 1372091721 0 # Node ID aaa4f60ebf9c21113f5685b28bd6ea03cfdf8d80 # Parent f868244e32e8393ac5fe92a00c3f4397812f2222 Clean up carfac_test. diff -r f868244e32e8 -r aaa4f60ebf9c carfac/carfac_test.cc --- a/carfac/carfac_test.cc Tue Jun 18 18:07:02 2013 +0000 +++ b/carfac/carfac_test.cc Mon Jun 24 16:35:21 2013 +0000 @@ -34,22 +34,18 @@ #include "common.h" #include "ihc.h" +using std::deque; using std::ifstream; using std::ofstream; using std::string; using std::vector; -// This is the 'test_data' subdirectory of aimc/carfac that specifies where to -// locate the text files produced by 'CARFAC_GenerateTestData.m' for comparing -// the ouput of the Matlab version of CARFAC with this C++ version. -static const char* kTestSourceDir= "./test_data/"; -// Here we specify the level to which the output should match (2 decimals). -static const float kPrecisionLevel = 1.0e-2; +// Location of the text files produced by 'CARFAC_GenerateTestData.m' for +// comparing the ouput of the Matlab implementation with the one used here. +static const char* kTestSourceDir = "./test_data/"; -// Three helper functions are defined here for loading the test data generated -// by the Matlab version of CARFAC. -// This loads one-dimensional ArrayXs from single-column text files. -void WriteNAPOutput(const CARFACOutput& output, const string filename, +// Writes the CARFAC NAP output to a text file. +void WriteNAPOutput(const CARFACOutput& output, const string& filename, int ear) { string fullfile = kTestSourceDir + filename; ofstream ofile(fullfile.c_str()); @@ -69,37 +65,27 @@ ofile.close(); } -ArrayX LoadTestData(const string filename, const int number_points) { +// Reads a size rows vector of size columns Container objects from a +// multi-column text file generated by the Matlab version of CARFAC. +template +vector Load2dTestData(const string& filename, const int rows, + const int columns) { string fullfile = kTestSourceDir + filename; ifstream file(fullfile.c_str()); - FPType myarray[number_points]; - ArrayX output(number_points); - if (file.is_open()) { - for (int i = 0; i < number_points; ++i) { - file >> myarray[i]; - output(i) = myarray[i]; - } - } - file.close(); - return output; -} - -// This loads a vector of ArrayXs from multi-column text files. -vector Load2dTestData(const string filename, const int rows, - const int columns) { - string fullfile = kTestSourceDir + filename; - ifstream file(fullfile.c_str()); - FPType myarray[rows][columns]; - vector output; - output.resize(rows); - for (ArrayX& timepoint : output) { - timepoint.resize(columns); + vector output; + if (ColMajor) { + output.assign(rows, Container(columns)); + } else { + output.assign(columns, Container(rows)); } if (file.is_open()) { for (int i = 0; i < rows; ++i) { for (int j = 0; j < columns; ++j) { - file >> myarray[i][j]; - output[i](j) = myarray[i][j]; + if (ColMajor) { + file >> output[i][j]; + } else { + file >> output[j][i]; + } } } } @@ -107,127 +93,98 @@ return output; } -// This loads two dimensional vectors of audio data using data generated in -// Matlab using the wavread() function. +// Reads a two dimensional vector of audio data from a text file +// containing the output of the Matlab wavread() function. vector> Load2dAudioVector(string filename, int timepoints, int channels) { - string fullfile = kTestSourceDir + filename; - ifstream file(fullfile.c_str()); - vector> output; - output.resize(channels); - for (auto& channel : output) { - channel.resize(timepoints); + return Load2dTestData, false>(filename, timepoints, channels); +} + +class CARFACTest : public testing::Test { + protected: + deque> LoadTestData( + const string& basename, int n_timepoints, int n_ears, int n_ch) const { + deque> test_data(n_timepoints, vector(n_ears)); + for (int ear = 0; ear < n_ears; ++ear) { + string filename = basename + std::to_string(ear + 1) + ".txt"; + vector data = Load2dTestData(filename, n_timepoints, n_ch); + for (int i = 0; i < n_timepoints; ++i) { + test_data[i][ear] = data[i]; + } + } + return test_data; } - if (file.is_open()) { - for (int i = 0; i < timepoints; ++i) { - for (int j = 0; j < channels; ++j) { - file >> output[j][i]; + + void AssertCARFACOutputNear(const deque>& expected, + const deque>& actual, + int n_timepoints, int n_ears, int n_ch) const { + for (int timepoint = 0; timepoint < n_timepoints; ++timepoint) { + for (int ear = 0; ear < n_ears; ++ear) { + for (int channel = 0; channel < n_ch; ++channel) { + const float kPrecisionLevel = 1.0e-7; + ASSERT_NEAR(expected[timepoint][ear](channel), + actual[timepoint][ear](channel), + kPrecisionLevel); + } } } } - file.close(); - return output; + + CARParams car_params_; + IHCParams ihc_params_; + AGCParams agc_params_; +}; + +TEST_F(CARFACTest, BinauralData) { + const int n_timepoints = 882; + const int n_ears = 2; + const int n_ch = 71; + vector> sound_data = + Load2dAudioVector("file_signal_binaural_test.txt", n_timepoints, n_ears); + CARFAC carfac(n_ears, 22050, car_params_, ihc_params_, agc_params_); + CARFACOutput output(true, true, false, false); + const bool kOpenLoop = false; + const int length = sound_data[0].size(); + carfac.RunSegment(sound_data, 0, length, kOpenLoop, &output); + + // TODO(ronw): Don't unconditionally overwrite files that are + // checked in to the repository on every test run. + WriteNAPOutput(output, "cpp_nap_output_1_binaural_test.txt", 0); + WriteNAPOutput(output, "cpp_nap_output_2_binaural_test.txt", 1); + + deque> expected_nap = + LoadTestData("binaural_test_nap", n_timepoints, n_ears, n_ch); + AssertCARFACOutputNear(expected_nap, output.nap(), + n_timepoints, n_ears, n_ch); + deque> expected_bm = + LoadTestData("binaural_test_bm", n_timepoints, n_ears, n_ch); + AssertCARFACOutputNear(expected_bm, output.bm(), + n_timepoints, n_ears, n_ch); } -TEST(CARFACTest, Binaural_Output_test) { - int num_timepoints = 882; - int num_channels = 71; - int num_ears = 2; - string filename = "binaural_test_nap1.txt"; - vector nap1 = Load2dTestData(filename, num_timepoints, num_channels); - filename = "binaural_test_bm1.txt"; - vector bm1 = Load2dTestData(filename, num_timepoints, num_channels); - filename = "binaural_test_nap2.txt"; - vector nap2 = Load2dTestData(filename, num_timepoints, num_channels); - filename = "binaural_test_bm2.txt"; - vector bm2 = Load2dTestData(filename, num_timepoints, num_channels); - filename = "file_signal_binaural_test.txt"; - vector> sound_data = Load2dAudioVector(filename, num_timepoints, - num_ears); - CARParams car_params; - IHCParams ihc_params; - AGCParams agc_params; - CARFAC mycf(num_ears, 22050, car_params, ihc_params, agc_params); - CARFACOutput my_output(true, true, false, false); +TEST_F(CARFACTest, LongBinauralData) { + const int n_timepoints = 2000; + const int n_ears = 2; + const int n_ch = 83; + vector> sound_data = + Load2dAudioVector("file_signal_long_test.txt", n_timepoints, n_ears); + CARFAC carfac(n_ears, 44100, car_params_, ihc_params_, agc_params_); + CARFACOutput output(true, true, false, false); const bool kOpenLoop = false; const int length = sound_data[0].size(); - mycf.RunSegment(sound_data, 0, length, kOpenLoop, &my_output); - filename = "cpp_nap_output_1_binaural_test.txt"; - WriteNAPOutput(my_output, filename, 0); - filename = "cpp_nap_output_2_binaural_test.txt"; - WriteNAPOutput(my_output, filename, 1); - int ear = 0; - int n_ch = 71; - for (int timepoint = 0; timepoint < num_timepoints; ++timepoint) { - for (int channel = 0; channel < n_ch; ++channel) { - FPType cplusplus = my_output.nap()[timepoint][ear](channel); - FPType matlab = nap1[timepoint](channel); - ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel); - cplusplus = my_output.bm()[timepoint][ear](channel); - matlab = bm1[timepoint](channel); - ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel); - } - } - ear = 1; - for (int timepoint = 0; timepoint < num_timepoints; ++timepoint) { - for (int channel = 0; channel < n_ch; ++channel) { - FPType cplusplus = my_output.nap()[timepoint][ear](channel); - FPType matlab = nap2[timepoint](channel); - ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel); - cplusplus = my_output.bm()[timepoint][ear](channel); - matlab = bm2[timepoint](channel); - ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel); - } - } + carfac.RunSegment(sound_data, 0, length, kOpenLoop, &output); + + // TODO(ronw): Don't unconditionally overwrite files that are + // checked in to the repository on every test run. + WriteNAPOutput(output, "cpp_nap_output_1_long_test.txt", 0); + WriteNAPOutput(output, "cpp_nap_output_2_long_test.txt", 1); + + deque> expected_nap = + LoadTestData("long_test_nap", n_timepoints, n_ears, n_ch); + AssertCARFACOutputNear(expected_nap, output.nap(), + n_timepoints, n_ears, n_ch); + deque> expected_bm = + LoadTestData("long_test_bm", n_timepoints, n_ears, n_ch); + AssertCARFACOutputNear(expected_bm, output.bm(), + n_timepoints, n_ears, n_ch); } - -TEST(CARFACTest, Long_Output_test) { - int num_timepoints = 2000; - int num_channels = 83; - int num_ears = 2; - string filename = "long_test_nap1.txt"; - vector nap1 = Load2dTestData(filename, num_timepoints, num_channels); - filename = "long_test_bm1.txt"; - vector bm1 = Load2dTestData(filename, num_timepoints, num_channels); - filename = "long_test_nap2.txt"; - vector nap2 = Load2dTestData(filename, num_timepoints, num_channels); - filename = "long_test_bm2.txt"; - vector bm2 = Load2dTestData(filename, num_timepoints, num_channels); - filename = "file_signal_long_test.txt"; - vector> sound_data = Load2dAudioVector(filename, num_timepoints, - num_ears); - CARParams car_params; - IHCParams ihc_params; - AGCParams agc_params; - CARFAC mycf(num_ears, 44100, car_params, ihc_params, agc_params); - CARFACOutput my_output(true, true, false, false); - const bool kOpenLoop = false; - const int length = sound_data[0].size(); - mycf.RunSegment(sound_data, 0, length, kOpenLoop, &my_output); - filename = "cpp_nap_output_1_long_test.txt"; - WriteNAPOutput(my_output, filename, 0); - filename = "cpp_nap_output_2_long_test.txt"; - WriteNAPOutput(my_output, filename, 1); - int ear = 0; - for (int timepoint = 0; timepoint < num_timepoints; ++timepoint) { - for (int channel = 0; channel < num_channels; ++channel) { - FPType cplusplus = my_output.nap()[timepoint][ear](channel); - FPType matlab = nap1[timepoint](channel); - ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel); - cplusplus = my_output.bm()[timepoint][ear](channel); - matlab = bm1[timepoint](channel); - ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel); - } - } - ear = 1; - for (int timepoint = 0; timepoint < num_timepoints; ++timepoint) { - for (int channel = 0; channel < num_channels; ++channel) { - FPType cplusplus = my_output.nap()[timepoint][ear](channel); - FPType matlab = nap2[timepoint](channel); - ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel); - cplusplus = my_output.bm()[timepoint][ear](channel); - matlab = bm2[timepoint](channel); - ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel); - } - } -} diff -r f868244e32e8 -r aaa4f60ebf9c carfac/common.h --- a/carfac/common.h Tue Jun 18 18:07:02 2013 +0000 +++ b/carfac/common.h Mon Jun 24 16:35:21 2013 +0000 @@ -30,7 +30,7 @@ // The 'FPType' typedef is used to enable easy switching in precision level. // It's currently set to double for during the unit testing phase of the // project. -typedef float FPType; +typedef double FPType; // A typedef is used to define a one-dimensional Eigen array with the same // precision level as FPType. typedef Eigen::Array ArrayX;