annotate carfac/carfac_test.cc @ 652:aaa4f60ebf9c

Clean up carfac_test.
author ronw@google.com
date Mon, 24 Jun 2013 16:35:21 +0000
parents 1c2a5868f23a
children a1b82b240328
rev   line source
alexbrandmeyer@626 1 //
alexbrandmeyer@626 2 // carfac_test.cc
alexbrandmeyer@626 3 // CARFAC Open Source C++ Library
alexbrandmeyer@626 4 //
alexbrandmeyer@626 5 // Created by Alex Brandmeyer on 5/22/13.
alexbrandmeyer@626 6 //
alexbrandmeyer@626 7 // This C++ file is part of an implementation of Lyon's cochlear model:
alexbrandmeyer@626 8 // "Cascade of Asymmetric Resonators with Fast-Acting Compression"
alexbrandmeyer@626 9 // to supplement Lyon's upcoming book "Human and Machine Hearing"
alexbrandmeyer@626 10 //
alexbrandmeyer@626 11 // Licensed under the Apache License, Version 2.0 (the "License");
alexbrandmeyer@626 12 // you may not use this file except in compliance with the License.
alexbrandmeyer@626 13 // You may obtain a copy of the License at
alexbrandmeyer@626 14 //
alexbrandmeyer@626 15 // http://www.apache.org/licenses/LICENSE-2.0
alexbrandmeyer@626 16 //
alexbrandmeyer@626 17 // Unless required by applicable law or agreed to in writing, software
alexbrandmeyer@626 18 // distributed under the License is distributed on an "AS IS" BASIS,
alexbrandmeyer@626 19 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
alexbrandmeyer@626 20 // See the License for the specific language governing permissions and
alexbrandmeyer@626 21 // limitations under the License.
alexbrandmeyer@626 22
ronw@647 23 #include "carfac.h"
ronw@647 24
ronw@646 25 #include <fstream>
alexbrandmeyer@636 26 #include <string>
alexbrandmeyer@640 27 #include <vector>
ronw@642 28
ronw@642 29 #include "gtest/gtest.h"
alexbrandmeyer@643 30
ronw@646 31 #include "agc.h"
alexbrandmeyer@643 32 #include "car.h"
ronw@647 33 #include "carfac_output.h"
alexbrandmeyer@643 34 #include "common.h"
ronw@646 35 #include "ihc.h"
alexbrandmeyer@637 36
ronw@652 37 using std::deque;
alexbrandmeyer@636 38 using std::ifstream;
alexbrandmeyer@636 39 using std::ofstream;
ronw@646 40 using std::string;
ronw@646 41 using std::vector;
alexbrandmeyer@636 42
ronw@652 43 // Location of the text files produced by 'CARFAC_GenerateTestData.m' for
ronw@652 44 // comparing the ouput of the Matlab implementation with the one used here.
ronw@652 45 static const char* kTestSourceDir = "./test_data/";
ronw@630 46
ronw@652 47 // Writes the CARFAC NAP output to a text file.
ronw@652 48 void WriteNAPOutput(const CARFACOutput& output, const string& filename,
ronw@646 49 int ear) {
alexbrandmeyer@637 50 string fullfile = kTestSourceDir + filename;
alexbrandmeyer@636 51 ofstream ofile(fullfile.c_str());
alexbrandmeyer@643 52 int32_t num_timepoints = output.nap().size();
alexbrandmeyer@637 53 int channels = output.nap()[0][0].size();
alexbrandmeyer@636 54 if (ofile.is_open()) {
alexbrandmeyer@643 55 for (int32_t i = 0; i < num_timepoints; ++i) {
alexbrandmeyer@636 56 for (int j = 0; j < channels; ++j) {
alexbrandmeyer@637 57 ofile << output.nap()[i][ear](j);
ronw@646 58 if (j < channels - 1) {
alexbrandmeyer@636 59 ofile << " ";
alexbrandmeyer@636 60 }
alexbrandmeyer@636 61 }
alexbrandmeyer@636 62 ofile << "\n";
alexbrandmeyer@636 63 }
alexbrandmeyer@636 64 }
alexbrandmeyer@636 65 ofile.close();
alexbrandmeyer@636 66 }
alexbrandmeyer@636 67
ronw@652 68 // Reads a size rows vector of size columns Container objects from a
ronw@652 69 // multi-column text file generated by the Matlab version of CARFAC.
ronw@652 70 template <typename Container = ArrayX, bool ColMajor = true>
ronw@652 71 vector<Container> Load2dTestData(const string& filename, const int rows,
ronw@652 72 const int columns) {
alexbrandmeyer@637 73 string fullfile = kTestSourceDir + filename;
alexbrandmeyer@636 74 ifstream file(fullfile.c_str());
ronw@652 75 vector<Container> output;
ronw@652 76 if (ColMajor) {
ronw@652 77 output.assign(rows, Container(columns));
ronw@652 78 } else {
ronw@652 79 output.assign(columns, Container(rows));
alexbrandmeyer@626 80 }
alexbrandmeyer@626 81 if (file.is_open()) {
alexbrandmeyer@626 82 for (int i = 0; i < rows; ++i) {
alexbrandmeyer@626 83 for (int j = 0; j < columns; ++j) {
ronw@652 84 if (ColMajor) {
ronw@652 85 file >> output[i][j];
ronw@652 86 } else {
ronw@652 87 file >> output[j][i];
ronw@652 88 }
alexbrandmeyer@626 89 }
alexbrandmeyer@626 90 }
alexbrandmeyer@626 91 }
alexbrandmeyer@636 92 file.close();
alexbrandmeyer@626 93 return output;
alexbrandmeyer@626 94 }
alexbrandmeyer@626 95
ronw@652 96 // Reads a two dimensional vector of audio data from a text file
ronw@652 97 // containing the output of the Matlab wavread() function.
alexbrandmeyer@636 98 vector<vector<float>> Load2dAudioVector(string filename, int timepoints,
alexbrandmeyer@636 99 int channels) {
ronw@652 100 return Load2dTestData<vector<float>, false>(filename, timepoints, channels);
ronw@652 101 }
ronw@652 102
ronw@652 103 class CARFACTest : public testing::Test {
ronw@652 104 protected:
ronw@652 105 deque<vector<ArrayX>> LoadTestData(
ronw@652 106 const string& basename, int n_timepoints, int n_ears, int n_ch) const {
ronw@652 107 deque<vector<ArrayX>> test_data(n_timepoints, vector<ArrayX>(n_ears));
ronw@652 108 for (int ear = 0; ear < n_ears; ++ear) {
ronw@652 109 string filename = basename + std::to_string(ear + 1) + ".txt";
ronw@652 110 vector<ArrayX> data = Load2dTestData(filename, n_timepoints, n_ch);
ronw@652 111 for (int i = 0; i < n_timepoints; ++i) {
ronw@652 112 test_data[i][ear] = data[i];
ronw@652 113 }
ronw@652 114 }
ronw@652 115 return test_data;
alexbrandmeyer@626 116 }
ronw@652 117
ronw@652 118 void AssertCARFACOutputNear(const deque<vector<ArrayX>>& expected,
ronw@652 119 const deque<vector<ArrayX>>& actual,
ronw@652 120 int n_timepoints, int n_ears, int n_ch) const {
ronw@652 121 for (int timepoint = 0; timepoint < n_timepoints; ++timepoint) {
ronw@652 122 for (int ear = 0; ear < n_ears; ++ear) {
ronw@652 123 for (int channel = 0; channel < n_ch; ++channel) {
ronw@652 124 const float kPrecisionLevel = 1.0e-7;
ronw@652 125 ASSERT_NEAR(expected[timepoint][ear](channel),
ronw@652 126 actual[timepoint][ear](channel),
ronw@652 127 kPrecisionLevel);
ronw@652 128 }
alexbrandmeyer@626 129 }
alexbrandmeyer@626 130 }
alexbrandmeyer@626 131 }
ronw@652 132
ronw@652 133 CARParams car_params_;
ronw@652 134 IHCParams ihc_params_;
ronw@652 135 AGCParams agc_params_;
ronw@652 136 };
ronw@652 137
ronw@652 138 TEST_F(CARFACTest, BinauralData) {
ronw@652 139 const int n_timepoints = 882;
ronw@652 140 const int n_ears = 2;
ronw@652 141 const int n_ch = 71;
ronw@652 142 vector<vector<float>> sound_data =
ronw@652 143 Load2dAudioVector("file_signal_binaural_test.txt", n_timepoints, n_ears);
ronw@652 144 CARFAC carfac(n_ears, 22050, car_params_, ihc_params_, agc_params_);
ronw@652 145 CARFACOutput output(true, true, false, false);
ronw@652 146 const bool kOpenLoop = false;
ronw@652 147 const int length = sound_data[0].size();
ronw@652 148 carfac.RunSegment(sound_data, 0, length, kOpenLoop, &output);
ronw@652 149
ronw@652 150 // TODO(ronw): Don't unconditionally overwrite files that are
ronw@652 151 // checked in to the repository on every test run.
ronw@652 152 WriteNAPOutput(output, "cpp_nap_output_1_binaural_test.txt", 0);
ronw@652 153 WriteNAPOutput(output, "cpp_nap_output_2_binaural_test.txt", 1);
ronw@652 154
ronw@652 155 deque<vector<ArrayX>> expected_nap =
ronw@652 156 LoadTestData("binaural_test_nap", n_timepoints, n_ears, n_ch);
ronw@652 157 AssertCARFACOutputNear(expected_nap, output.nap(),
ronw@652 158 n_timepoints, n_ears, n_ch);
ronw@652 159 deque<vector<ArrayX>> expected_bm =
ronw@652 160 LoadTestData("binaural_test_bm", n_timepoints, n_ears, n_ch);
ronw@652 161 AssertCARFACOutputNear(expected_bm, output.bm(),
ronw@652 162 n_timepoints, n_ears, n_ch);
alexbrandmeyer@626 163 }
alexbrandmeyer@626 164
ronw@652 165 TEST_F(CARFACTest, LongBinauralData) {
ronw@652 166 const int n_timepoints = 2000;
ronw@652 167 const int n_ears = 2;
ronw@652 168 const int n_ch = 83;
ronw@652 169 vector<vector<float>> sound_data =
ronw@652 170 Load2dAudioVector("file_signal_long_test.txt", n_timepoints, n_ears);
ronw@652 171 CARFAC carfac(n_ears, 44100, car_params_, ihc_params_, agc_params_);
ronw@652 172 CARFACOutput output(true, true, false, false);
ronw@641 173 const bool kOpenLoop = false;
ronw@641 174 const int length = sound_data[0].size();
ronw@652 175 carfac.RunSegment(sound_data, 0, length, kOpenLoop, &output);
ronw@652 176
ronw@652 177 // TODO(ronw): Don't unconditionally overwrite files that are
ronw@652 178 // checked in to the repository on every test run.
ronw@652 179 WriteNAPOutput(output, "cpp_nap_output_1_long_test.txt", 0);
ronw@652 180 WriteNAPOutput(output, "cpp_nap_output_2_long_test.txt", 1);
ronw@652 181
ronw@652 182 deque<vector<ArrayX>> expected_nap =
ronw@652 183 LoadTestData("long_test_nap", n_timepoints, n_ears, n_ch);
ronw@652 184 AssertCARFACOutputNear(expected_nap, output.nap(),
ronw@652 185 n_timepoints, n_ears, n_ch);
ronw@652 186 deque<vector<ArrayX>> expected_bm =
ronw@652 187 LoadTestData("long_test_bm", n_timepoints, n_ears, n_ch);
ronw@652 188 AssertCARFACOutputNear(expected_bm, output.bm(),
ronw@652 189 n_timepoints, n_ears, n_ch);
alexbrandmeyer@626 190 }