Revision: 301
Author:
ro...@google.com
Date: Mon Jun 24 09:35:21 2013
Log: Clean up carfac_test.
http://code.google.com/p/aimc/source/detail?r=301
Modified:
/trunk/carfac/carfac_test.cc
/trunk/carfac/common.h
=======================================
--- /trunk/carfac/carfac_test.cc Tue Jun 11 14:41:53 2013
+++ /trunk/carfac/carfac_test.cc Mon Jun 24 09:35:21 2013
@@ -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;
-}
-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);
+ 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();
- 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_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, 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);
+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_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);
- }
- }
+ 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);
}
=======================================
--- /trunk/carfac/common.h Tue Jun 11 14:32:50 2013
+++ /trunk/carfac/common.h Mon Jun 24 09:35:21 2013
@@ -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;