Mercurial > hg > aimc
changeset 694:a43892e7e5ad
Clean up carfac_test.
author | ronw@google.com |
---|---|
date | Mon, 24 Jun 2013 16:35:21 +0000 |
parents | 3d749a008b87 |
children | 2e3672df5698 |
files | trunk/carfac/carfac_test.cc trunk/carfac/common.h |
diffstat | 2 files changed, 106 insertions(+), 149 deletions(-) [+] |
line wrap: on
line diff
--- a/trunk/carfac/carfac_test.cc Tue Jun 18 18:07:02 2013 +0000 +++ b/trunk/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 <typename Container = ArrayX, bool ColMajor = true> +vector<Container> 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<ArrayX> Load2dTestData(const string filename, const int rows, - const int columns) { - string fullfile = kTestSourceDir + filename; - ifstream file(fullfile.c_str()); - FPType myarray[rows][columns]; - vector<ArrayX> output; - output.resize(rows); - for (ArrayX& timepoint : output) { - timepoint.resize(columns); + vector<Container> 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<vector<float>> Load2dAudioVector(string filename, int timepoints, int channels) { - string fullfile = kTestSourceDir + filename; - ifstream file(fullfile.c_str()); - vector<vector<float>> output; - output.resize(channels); - for (auto& channel : output) { - channel.resize(timepoints); + return Load2dTestData<vector<float>, false>(filename, timepoints, channels); +} + +class CARFACTest : public testing::Test { + protected: + deque<vector<ArrayX>> LoadTestData( + const string& basename, int n_timepoints, int n_ears, int n_ch) const { + deque<vector<ArrayX>> test_data(n_timepoints, vector<ArrayX>(n_ears)); + for (int ear = 0; ear < n_ears; ++ear) { + string filename = basename + std::to_string(ear + 1) + ".txt"; + vector<ArrayX> 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<vector<ArrayX>>& expected, + const deque<vector<ArrayX>>& 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<vector<float>> 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<vector<ArrayX>> expected_nap = + LoadTestData("binaural_test_nap", n_timepoints, n_ears, n_ch); + AssertCARFACOutputNear(expected_nap, output.nap(), + n_timepoints, n_ears, n_ch); + deque<vector<ArrayX>> 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<ArrayX> nap1 = Load2dTestData(filename, num_timepoints, num_channels); - filename = "binaural_test_bm1.txt"; - vector<ArrayX> bm1 = Load2dTestData(filename, num_timepoints, num_channels); - filename = "binaural_test_nap2.txt"; - vector<ArrayX> nap2 = Load2dTestData(filename, num_timepoints, num_channels); - filename = "binaural_test_bm2.txt"; - vector<ArrayX> bm2 = Load2dTestData(filename, num_timepoints, num_channels); - filename = "file_signal_binaural_test.txt"; - vector<vector<float>> 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<vector<float>> 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<vector<ArrayX>> expected_nap = + LoadTestData("long_test_nap", n_timepoints, n_ears, n_ch); + AssertCARFACOutputNear(expected_nap, output.nap(), + n_timepoints, n_ears, n_ch); + deque<vector<ArrayX>> 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<ArrayX> nap1 = Load2dTestData(filename, num_timepoints, num_channels); - filename = "long_test_bm1.txt"; - vector<ArrayX> bm1 = Load2dTestData(filename, num_timepoints, num_channels); - filename = "long_test_nap2.txt"; - vector<ArrayX> nap2 = Load2dTestData(filename, num_timepoints, num_channels); - filename = "long_test_bm2.txt"; - vector<ArrayX> bm2 = Load2dTestData(filename, num_timepoints, num_channels); - filename = "file_signal_long_test.txt"; - vector<vector<float>> 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); - } - } -}
--- a/trunk/carfac/common.h Tue Jun 18 18:07:02 2013 +0000 +++ b/trunk/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<FPType, Eigen::Dynamic, 1> ArrayX;