alexbrandmeyer@668
|
1 //
|
alexbrandmeyer@668
|
2 // carfac_test.cc
|
alexbrandmeyer@668
|
3 // CARFAC Open Source C++ Library
|
alexbrandmeyer@668
|
4 //
|
alexbrandmeyer@668
|
5 // Created by Alex Brandmeyer on 5/22/13.
|
alexbrandmeyer@668
|
6 //
|
alexbrandmeyer@668
|
7 // This C++ file is part of an implementation of Lyon's cochlear model:
|
alexbrandmeyer@668
|
8 // "Cascade of Asymmetric Resonators with Fast-Acting Compression"
|
alexbrandmeyer@668
|
9 // to supplement Lyon's upcoming book "Human and Machine Hearing"
|
alexbrandmeyer@668
|
10 //
|
alexbrandmeyer@668
|
11 // Licensed under the Apache License, Version 2.0 (the "License");
|
alexbrandmeyer@668
|
12 // you may not use this file except in compliance with the License.
|
alexbrandmeyer@668
|
13 // You may obtain a copy of the License at
|
alexbrandmeyer@668
|
14 //
|
alexbrandmeyer@668
|
15 // http://www.apache.org/licenses/LICENSE-2.0
|
alexbrandmeyer@668
|
16 //
|
alexbrandmeyer@668
|
17 // Unless required by applicable law or agreed to in writing, software
|
alexbrandmeyer@668
|
18 // distributed under the License is distributed on an "AS IS" BASIS,
|
alexbrandmeyer@668
|
19 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
alexbrandmeyer@668
|
20 // See the License for the specific language governing permissions and
|
alexbrandmeyer@668
|
21 // limitations under the License.
|
alexbrandmeyer@668
|
22
|
alexbrandmeyer@678
|
23 #include <string>
|
alexbrandmeyer@678
|
24 #include <fstream>
|
alexbrandmeyer@678
|
25 // GoogleTest is now included for running unit tests
|
alexbrandmeyer@678
|
26 #include <gtest/gtest.h>
|
alexbrandmeyer@678
|
27 #include "carfac.h"
|
alexbrandmeyer@678
|
28 using std::vector;
|
alexbrandmeyer@678
|
29 using std::string;
|
alexbrandmeyer@678
|
30 using std::ifstream;
|
alexbrandmeyer@678
|
31 using std::ofstream;
|
alexbrandmeyer@678
|
32
|
alexbrandmeyer@678
|
33 #define TEST_SRC_DIR "./test_data/"
|
alexbrandmeyer@678
|
34 // Here we specify the level to which the output should match (7 decimals).
|
alexbrandmeyer@678
|
35 #define PRECISION_LEVEL 1.0e-07
|
ronw@672
|
36
|
alexbrandmeyer@668
|
37 // Three helper functions are defined here for loading the test data generated
|
alexbrandmeyer@668
|
38 // by the Matlab version of CARFAC.
|
alexbrandmeyer@668
|
39 // This loads one-dimensional FloatArrays from single-column text files.
|
alexbrandmeyer@678
|
40 void WriteNAPOutput(CARFACOutput output, const string filename, int ear) {
|
alexbrandmeyer@678
|
41 string fullfile = TEST_SRC_DIR + filename;
|
alexbrandmeyer@678
|
42 ofstream ofile(fullfile.c_str());
|
alexbrandmeyer@678
|
43 int32_t n_timepoints = output.nap_.size();
|
alexbrandmeyer@678
|
44 int channels = output.nap_[0][0].size();
|
alexbrandmeyer@678
|
45 if (ofile.is_open()) {
|
alexbrandmeyer@678
|
46 for (int32_t i = 0; i < n_timepoints; ++i) {
|
alexbrandmeyer@678
|
47 for (int j = 0; j < channels; ++j) {
|
alexbrandmeyer@678
|
48 ofile << output.nap(ear, i, j);
|
alexbrandmeyer@678
|
49 if ( j < channels - 1) {
|
alexbrandmeyer@678
|
50 ofile << " ";
|
alexbrandmeyer@678
|
51 }
|
alexbrandmeyer@678
|
52 }
|
alexbrandmeyer@678
|
53 ofile << "\n";
|
alexbrandmeyer@678
|
54 }
|
alexbrandmeyer@678
|
55 }
|
alexbrandmeyer@678
|
56 ofile.close();
|
alexbrandmeyer@678
|
57 }
|
alexbrandmeyer@678
|
58
|
alexbrandmeyer@668
|
59 FloatArray LoadTestData(const std::string filename, const int number_points) {
|
alexbrandmeyer@678
|
60 string fullfile = TEST_SRC_DIR + filename;
|
alexbrandmeyer@678
|
61 ifstream file(fullfile.c_str());
|
alexbrandmeyer@668
|
62 FPType myarray[number_points];
|
alexbrandmeyer@668
|
63 FloatArray output(number_points);
|
alexbrandmeyer@668
|
64 if (file.is_open()) {
|
alexbrandmeyer@668
|
65 for (int i = 0; i < number_points; ++i) {
|
alexbrandmeyer@668
|
66 file >> myarray[i];
|
alexbrandmeyer@668
|
67 output(i) = myarray[i];
|
alexbrandmeyer@668
|
68 }
|
alexbrandmeyer@668
|
69 }
|
alexbrandmeyer@678
|
70 file.close();
|
alexbrandmeyer@668
|
71 return output;
|
alexbrandmeyer@668
|
72 }
|
alexbrandmeyer@668
|
73
|
alexbrandmeyer@678
|
74 // This loads a vector of FloatArrays from multi-column text files.
|
alexbrandmeyer@678
|
75 vector<FloatArray> Load2dTestData(const string filename, const int rows,
|
alexbrandmeyer@668
|
76 const int columns) {
|
alexbrandmeyer@678
|
77 string fullfile = TEST_SRC_DIR + filename;
|
alexbrandmeyer@678
|
78 ifstream file(fullfile.c_str());
|
alexbrandmeyer@668
|
79 FPType myarray[rows][columns];
|
alexbrandmeyer@678
|
80 vector<FloatArray> output;
|
alexbrandmeyer@668
|
81 output.resize(rows);
|
alexbrandmeyer@668
|
82 for (auto& timepoint : output) {
|
alexbrandmeyer@668
|
83 timepoint.resize(columns);
|
alexbrandmeyer@668
|
84 }
|
alexbrandmeyer@668
|
85 if (file.is_open()) {
|
alexbrandmeyer@668
|
86 for (int i = 0; i < rows; ++i) {
|
alexbrandmeyer@668
|
87 for (int j = 0; j < columns; ++j) {
|
alexbrandmeyer@668
|
88 file >> myarray[i][j];
|
alexbrandmeyer@668
|
89 output[i](j) = myarray[i][j];
|
alexbrandmeyer@668
|
90 }
|
alexbrandmeyer@668
|
91 }
|
alexbrandmeyer@668
|
92 }
|
alexbrandmeyer@678
|
93 file.close();
|
alexbrandmeyer@668
|
94 return output;
|
alexbrandmeyer@668
|
95 }
|
alexbrandmeyer@668
|
96
|
alexbrandmeyer@668
|
97 // This loads two dimensional vectors of audio data using data generated in
|
alexbrandmeyer@668
|
98 // Matlab using the wavread() function.
|
alexbrandmeyer@678
|
99 vector<vector<float>> Load2dAudioVector(string filename, int timepoints,
|
alexbrandmeyer@678
|
100 int channels) {
|
alexbrandmeyer@678
|
101 string fullfile = TEST_SRC_DIR + filename;
|
alexbrandmeyer@678
|
102 ifstream file(fullfile.c_str());
|
alexbrandmeyer@678
|
103 vector<vector<float>> output;
|
alexbrandmeyer@668
|
104 output.resize(channels);
|
alexbrandmeyer@668
|
105 for (auto& channel : output) {
|
alexbrandmeyer@668
|
106 channel.resize(timepoints);
|
alexbrandmeyer@668
|
107 }
|
alexbrandmeyer@668
|
108 if (file.is_open()) {
|
alexbrandmeyer@668
|
109 for (int i = 0; i < timepoints; ++i) {
|
alexbrandmeyer@668
|
110 for (int j = 0; j < channels; ++j) {
|
alexbrandmeyer@668
|
111 file >> output[j][i];
|
alexbrandmeyer@668
|
112 }
|
alexbrandmeyer@668
|
113 }
|
alexbrandmeyer@668
|
114 }
|
alexbrandmeyer@678
|
115 file.close();
|
alexbrandmeyer@668
|
116 return output;
|
alexbrandmeyer@668
|
117 }
|
alexbrandmeyer@668
|
118
|
alexbrandmeyer@678
|
119 TEST(CARFACTest, Binaural_Output_test) {
|
alexbrandmeyer@678
|
120 int n_timepoints = 882;
|
alexbrandmeyer@678
|
121 int n_channels = 71;
|
alexbrandmeyer@678
|
122 int n_ears = 2;
|
alexbrandmeyer@678
|
123 std::string filename = "binaural_test_nap1.txt";
|
alexbrandmeyer@678
|
124 std::vector<FloatArray> nap1 = Load2dTestData(filename, n_timepoints,
|
alexbrandmeyer@678
|
125 n_channels);
|
alexbrandmeyer@678
|
126 filename = "binaural_test_bm1.txt";
|
alexbrandmeyer@678
|
127 std::vector<FloatArray> bm1 = Load2dTestData(filename, n_timepoints,
|
alexbrandmeyer@678
|
128 n_channels);
|
alexbrandmeyer@678
|
129 filename = "binaural_test_nap2.txt";
|
alexbrandmeyer@678
|
130 std::vector<FloatArray> nap2 = Load2dTestData(filename, n_timepoints,
|
alexbrandmeyer@678
|
131 n_channels);
|
alexbrandmeyer@678
|
132 filename = "binaural_test_bm2.txt";
|
alexbrandmeyer@678
|
133 std::vector<FloatArray> bm2 = Load2dTestData(filename, n_timepoints,
|
alexbrandmeyer@678
|
134 n_channels);
|
alexbrandmeyer@678
|
135 filename = "file_signal_binaural_test.txt";
|
alexbrandmeyer@678
|
136 std::vector<std::vector<float>> sound_data = Load2dAudioVector(filename,
|
alexbrandmeyer@678
|
137 n_timepoints,
|
alexbrandmeyer@678
|
138 n_ears);
|
alexbrandmeyer@668
|
139 CARParams car_params;
|
alexbrandmeyer@678
|
140 IHCParams ihc_params;
|
alexbrandmeyer@678
|
141 AGCParams agc_params;
|
alexbrandmeyer@678
|
142 CARFAC mycf;
|
alexbrandmeyer@678
|
143 mycf.Design(n_ears, 22050, car_params, ihc_params,
|
alexbrandmeyer@678
|
144 agc_params);
|
alexbrandmeyer@678
|
145 CARFACOutput my_output;
|
alexbrandmeyer@678
|
146 my_output.Init(n_ears, true, false, true, false, false);
|
alexbrandmeyer@678
|
147 mycf.Run(sound_data, &my_output);
|
alexbrandmeyer@678
|
148 filename = "cpp_nap_output_1_binaural_test.txt";
|
alexbrandmeyer@678
|
149 WriteNAPOutput(my_output, filename, 0);
|
alexbrandmeyer@678
|
150 filename = "cpp_nap_output_2_binaural_test.txt";
|
alexbrandmeyer@678
|
151 WriteNAPOutput(my_output, filename, 1);
|
alexbrandmeyer@678
|
152 int ear = 0;
|
alexbrandmeyer@678
|
153 int n_ch = 71;
|
alexbrandmeyer@678
|
154 for (int timepoint = 0; timepoint < n_timepoints; ++timepoint) {
|
alexbrandmeyer@678
|
155 for (int channel = 0; channel < n_ch; ++channel) {
|
alexbrandmeyer@678
|
156 FPType cplusplus = my_output.nap(ear, timepoint, channel);
|
alexbrandmeyer@678
|
157 FPType matlab = nap1[timepoint](channel);
|
alexbrandmeyer@678
|
158 ASSERT_NEAR(cplusplus, matlab, PRECISION_LEVEL);
|
alexbrandmeyer@678
|
159 cplusplus = my_output.bm(ear, timepoint, channel);
|
alexbrandmeyer@678
|
160 matlab = bm1[timepoint](channel);
|
alexbrandmeyer@678
|
161 ASSERT_NEAR(cplusplus, matlab, PRECISION_LEVEL);
|
alexbrandmeyer@678
|
162 }
|
alexbrandmeyer@668
|
163 }
|
alexbrandmeyer@678
|
164 ear = 1;
|
alexbrandmeyer@678
|
165 for (int timepoint = 0; timepoint < n_timepoints; ++timepoint) {
|
alexbrandmeyer@678
|
166 for (int channel = 0; channel < n_ch; ++channel) {
|
alexbrandmeyer@678
|
167 FPType cplusplus = my_output.nap(ear, timepoint, channel);
|
alexbrandmeyer@678
|
168 FPType matlab = nap2[timepoint](channel);
|
alexbrandmeyer@678
|
169 ASSERT_NEAR(cplusplus, matlab, PRECISION_LEVEL);
|
alexbrandmeyer@678
|
170 cplusplus = my_output.bm(ear, timepoint, channel);
|
alexbrandmeyer@678
|
171 matlab = bm2[timepoint](channel);
|
alexbrandmeyer@678
|
172 ASSERT_NEAR(cplusplus, matlab, PRECISION_LEVEL);
|
alexbrandmeyer@668
|
173 }
|
alexbrandmeyer@668
|
174 }
|
alexbrandmeyer@668
|
175 }
|
alexbrandmeyer@668
|
176
|
alexbrandmeyer@678
|
177 TEST(CARFACTest, Long_Output_test) {
|
alexbrandmeyer@678
|
178 int n_timepoints = 2000;
|
alexbrandmeyer@678
|
179 int n_channels = 83;
|
alexbrandmeyer@678
|
180 int n_ears = 2;
|
alexbrandmeyer@678
|
181 string filename = "long_test_nap1.txt";
|
alexbrandmeyer@678
|
182 vector<FloatArray> nap1 = Load2dTestData(filename, n_timepoints,
|
alexbrandmeyer@678
|
183 n_channels);
|
alexbrandmeyer@678
|
184 filename = "long_test_bm1.txt";
|
alexbrandmeyer@678
|
185 vector<FloatArray> bm1 = Load2dTestData(filename, n_timepoints,
|
alexbrandmeyer@678
|
186 n_channels);
|
alexbrandmeyer@678
|
187 filename = "long_test_nap2.txt";
|
alexbrandmeyer@678
|
188 vector<FloatArray> nap2 = Load2dTestData(filename, n_timepoints,
|
alexbrandmeyer@678
|
189 n_channels);
|
alexbrandmeyer@678
|
190 filename = "long_test_bm2.txt";
|
alexbrandmeyer@678
|
191 vector<FloatArray> bm2 = Load2dTestData(filename, n_timepoints,
|
alexbrandmeyer@678
|
192 n_channels);
|
alexbrandmeyer@678
|
193 filename = "file_signal_long_test.txt";
|
alexbrandmeyer@678
|
194 vector<vector<float>> sound_data = Load2dAudioVector(filename,
|
alexbrandmeyer@678
|
195 n_timepoints,
|
alexbrandmeyer@678
|
196 n_ears);
|
alexbrandmeyer@668
|
197 CARParams car_params;
|
alexbrandmeyer@668
|
198 IHCParams ihc_params;
|
alexbrandmeyer@668
|
199 AGCParams agc_params;
|
alexbrandmeyer@678
|
200 CARFAC mycf;
|
alexbrandmeyer@678
|
201 mycf.Design(n_ears, 44100, car_params, ihc_params,
|
alexbrandmeyer@678
|
202 agc_params);
|
alexbrandmeyer@678
|
203 CARFACOutput my_output;
|
alexbrandmeyer@678
|
204 my_output.Init(n_ears, true, false, true, false, false);
|
alexbrandmeyer@678
|
205 mycf.Run(sound_data, &my_output);
|
alexbrandmeyer@678
|
206 filename = "cpp_nap_output_1_long_test.txt";
|
alexbrandmeyer@678
|
207 WriteNAPOutput(my_output, filename, 0);
|
alexbrandmeyer@678
|
208 filename = "cpp_nap_output_2_long_test.txt";
|
alexbrandmeyer@678
|
209 WriteNAPOutput(my_output, filename, 1);
|
alexbrandmeyer@678
|
210 int ear = 0;
|
alexbrandmeyer@678
|
211 for (int timepoint = 0; timepoint < n_timepoints; ++timepoint) {
|
alexbrandmeyer@678
|
212 for (int channel = 0; channel < n_channels; ++channel) {
|
alexbrandmeyer@678
|
213 FPType cplusplus = my_output.nap(ear, timepoint, channel);
|
alexbrandmeyer@678
|
214 FPType matlab = nap1[timepoint](channel);
|
alexbrandmeyer@678
|
215 ASSERT_NEAR(cplusplus, matlab, PRECISION_LEVEL);
|
alexbrandmeyer@678
|
216 cplusplus = my_output.bm(ear, timepoint, channel);
|
alexbrandmeyer@678
|
217 matlab = bm1[timepoint](channel);
|
alexbrandmeyer@678
|
218 ASSERT_NEAR(cplusplus, matlab, PRECISION_LEVEL);
|
alexbrandmeyer@678
|
219 }
|
alexbrandmeyer@668
|
220 }
|
alexbrandmeyer@678
|
221 ear = 1;
|
alexbrandmeyer@678
|
222 for (int timepoint = 0; timepoint < n_timepoints; ++timepoint) {
|
alexbrandmeyer@678
|
223 for (int channel = 0; channel < n_channels; ++channel) {
|
alexbrandmeyer@678
|
224 FPType cplusplus = my_output.nap(ear, timepoint, channel);
|
alexbrandmeyer@678
|
225 FPType matlab = nap2[timepoint](channel);
|
alexbrandmeyer@678
|
226 ASSERT_NEAR(cplusplus, matlab, PRECISION_LEVEL);
|
alexbrandmeyer@678
|
227 cplusplus = my_output.bm(ear, timepoint, channel);
|
alexbrandmeyer@678
|
228 matlab = bm2[timepoint](channel);
|
alexbrandmeyer@678
|
229 ASSERT_NEAR(cplusplus, matlab, PRECISION_LEVEL);
|
alexbrandmeyer@668
|
230 }
|
alexbrandmeyer@668
|
231 }
|
ronw@672
|
232 }
|
alexbrandmeyer@678
|
233
|
alexbrandmeyer@678
|
234 int main(int argc, char **argv) {
|
alexbrandmeyer@678
|
235 // This initializes the GoogleTest unit testing framework.
|
alexbrandmeyer@678
|
236 ::testing::InitGoogleTest(&argc, argv);
|
alexbrandmeyer@678
|
237 // This runs all of the tests that we've defined above.
|
alexbrandmeyer@678
|
238 return RUN_ALL_TESTS();
|
alexbrandmeyer@678
|
239 } |