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
|
alexbrandmeyer@636
|
23 #include <string>
|
alexbrandmeyer@636
|
24 #include <fstream>
|
alexbrandmeyer@636
|
25 // GoogleTest is now included for running unit tests
|
alexbrandmeyer@636
|
26 #include <gtest/gtest.h>
|
alexbrandmeyer@636
|
27 #include "carfac.h"
|
alexbrandmeyer@637
|
28
|
alexbrandmeyer@636
|
29 using std::vector;
|
alexbrandmeyer@636
|
30 using std::string;
|
alexbrandmeyer@636
|
31 using std::ifstream;
|
alexbrandmeyer@636
|
32 using std::ofstream;
|
alexbrandmeyer@636
|
33
|
alexbrandmeyer@637
|
34 // This is the 'test_data' subdirectory of aimc/carfac that specifies where to
|
alexbrandmeyer@637
|
35 // locate the text files produced by 'CARFAC_GenerateTestData.m' for comparing
|
alexbrandmeyer@637
|
36 // the ouput of the Matlab version of CARFAC with this C++ version.
|
alexbrandmeyer@637
|
37 static const char* kTestSourceDir= "./test_data/";
|
alexbrandmeyer@636
|
38 // Here we specify the level to which the output should match (7 decimals).
|
alexbrandmeyer@637
|
39 static const float kPrecisionLevel = 1.0e-7;
|
ronw@630
|
40
|
alexbrandmeyer@626
|
41 // Three helper functions are defined here for loading the test data generated
|
alexbrandmeyer@626
|
42 // by the Matlab version of CARFAC.
|
alexbrandmeyer@626
|
43 // This loads one-dimensional FloatArrays from single-column text files.
|
alexbrandmeyer@636
|
44 void WriteNAPOutput(CARFACOutput output, const string filename, int ear) {
|
alexbrandmeyer@637
|
45 string fullfile = kTestSourceDir + filename;
|
alexbrandmeyer@636
|
46 ofstream ofile(fullfile.c_str());
|
alexbrandmeyer@637
|
47 int32_t n_timepoints = output.nap().size();
|
alexbrandmeyer@637
|
48 int channels = output.nap()[0][0].size();
|
alexbrandmeyer@636
|
49 if (ofile.is_open()) {
|
alexbrandmeyer@636
|
50 for (int32_t i = 0; i < n_timepoints; ++i) {
|
alexbrandmeyer@636
|
51 for (int j = 0; j < channels; ++j) {
|
alexbrandmeyer@637
|
52 ofile << output.nap()[i][ear](j);
|
alexbrandmeyer@636
|
53 if ( j < channels - 1) {
|
alexbrandmeyer@636
|
54 ofile << " ";
|
alexbrandmeyer@636
|
55 }
|
alexbrandmeyer@636
|
56 }
|
alexbrandmeyer@636
|
57 ofile << "\n";
|
alexbrandmeyer@636
|
58 }
|
alexbrandmeyer@636
|
59 }
|
alexbrandmeyer@636
|
60 ofile.close();
|
alexbrandmeyer@636
|
61 }
|
alexbrandmeyer@636
|
62
|
alexbrandmeyer@637
|
63 FloatArray LoadTestData(const string filename, const int number_points) {
|
alexbrandmeyer@637
|
64 string fullfile = kTestSourceDir + filename;
|
alexbrandmeyer@636
|
65 ifstream file(fullfile.c_str());
|
alexbrandmeyer@626
|
66 FPType myarray[number_points];
|
alexbrandmeyer@626
|
67 FloatArray output(number_points);
|
alexbrandmeyer@626
|
68 if (file.is_open()) {
|
alexbrandmeyer@626
|
69 for (int i = 0; i < number_points; ++i) {
|
alexbrandmeyer@626
|
70 file >> myarray[i];
|
alexbrandmeyer@626
|
71 output(i) = myarray[i];
|
alexbrandmeyer@626
|
72 }
|
alexbrandmeyer@626
|
73 }
|
alexbrandmeyer@636
|
74 file.close();
|
alexbrandmeyer@626
|
75 return output;
|
alexbrandmeyer@626
|
76 }
|
alexbrandmeyer@626
|
77
|
alexbrandmeyer@636
|
78 // This loads a vector of FloatArrays from multi-column text files.
|
alexbrandmeyer@636
|
79 vector<FloatArray> Load2dTestData(const string filename, const int rows,
|
alexbrandmeyer@626
|
80 const int columns) {
|
alexbrandmeyer@637
|
81 string fullfile = kTestSourceDir + filename;
|
alexbrandmeyer@636
|
82 ifstream file(fullfile.c_str());
|
alexbrandmeyer@626
|
83 FPType myarray[rows][columns];
|
alexbrandmeyer@636
|
84 vector<FloatArray> output;
|
alexbrandmeyer@626
|
85 output.resize(rows);
|
alexbrandmeyer@626
|
86 for (auto& timepoint : output) {
|
alexbrandmeyer@626
|
87 timepoint.resize(columns);
|
alexbrandmeyer@626
|
88 }
|
alexbrandmeyer@626
|
89 if (file.is_open()) {
|
alexbrandmeyer@626
|
90 for (int i = 0; i < rows; ++i) {
|
alexbrandmeyer@626
|
91 for (int j = 0; j < columns; ++j) {
|
alexbrandmeyer@626
|
92 file >> myarray[i][j];
|
alexbrandmeyer@626
|
93 output[i](j) = myarray[i][j];
|
alexbrandmeyer@626
|
94 }
|
alexbrandmeyer@626
|
95 }
|
alexbrandmeyer@626
|
96 }
|
alexbrandmeyer@636
|
97 file.close();
|
alexbrandmeyer@626
|
98 return output;
|
alexbrandmeyer@626
|
99 }
|
alexbrandmeyer@626
|
100
|
alexbrandmeyer@626
|
101 // This loads two dimensional vectors of audio data using data generated in
|
alexbrandmeyer@626
|
102 // Matlab using the wavread() function.
|
alexbrandmeyer@636
|
103 vector<vector<float>> Load2dAudioVector(string filename, int timepoints,
|
alexbrandmeyer@636
|
104 int channels) {
|
alexbrandmeyer@637
|
105 string fullfile = kTestSourceDir + filename;
|
alexbrandmeyer@636
|
106 ifstream file(fullfile.c_str());
|
alexbrandmeyer@636
|
107 vector<vector<float>> output;
|
alexbrandmeyer@626
|
108 output.resize(channels);
|
alexbrandmeyer@626
|
109 for (auto& channel : output) {
|
alexbrandmeyer@626
|
110 channel.resize(timepoints);
|
alexbrandmeyer@626
|
111 }
|
alexbrandmeyer@626
|
112 if (file.is_open()) {
|
alexbrandmeyer@626
|
113 for (int i = 0; i < timepoints; ++i) {
|
alexbrandmeyer@626
|
114 for (int j = 0; j < channels; ++j) {
|
alexbrandmeyer@626
|
115 file >> output[j][i];
|
alexbrandmeyer@626
|
116 }
|
alexbrandmeyer@626
|
117 }
|
alexbrandmeyer@626
|
118 }
|
alexbrandmeyer@636
|
119 file.close();
|
alexbrandmeyer@626
|
120 return output;
|
alexbrandmeyer@626
|
121 }
|
alexbrandmeyer@626
|
122
|
alexbrandmeyer@636
|
123 TEST(CARFACTest, Binaural_Output_test) {
|
alexbrandmeyer@636
|
124 int n_timepoints = 882;
|
alexbrandmeyer@636
|
125 int n_channels = 71;
|
alexbrandmeyer@636
|
126 int n_ears = 2;
|
alexbrandmeyer@637
|
127 string filename = "binaural_test_nap1.txt";
|
alexbrandmeyer@637
|
128 vector<FloatArray> nap1 = Load2dTestData(filename, n_timepoints, n_channels);
|
alexbrandmeyer@636
|
129 filename = "binaural_test_bm1.txt";
|
alexbrandmeyer@637
|
130 vector<FloatArray> bm1 = Load2dTestData(filename, n_timepoints, n_channels);
|
alexbrandmeyer@636
|
131 filename = "binaural_test_nap2.txt";
|
alexbrandmeyer@637
|
132 vector<FloatArray> nap2 = Load2dTestData(filename, n_timepoints, n_channels);
|
alexbrandmeyer@636
|
133 filename = "binaural_test_bm2.txt";
|
alexbrandmeyer@637
|
134 vector<FloatArray> bm2 = Load2dTestData(filename, n_timepoints, n_channels);
|
alexbrandmeyer@636
|
135 filename = "file_signal_binaural_test.txt";
|
alexbrandmeyer@637
|
136 vector<vector<float>> sound_data = Load2dAudioVector(filename, n_timepoints,
|
alexbrandmeyer@637
|
137 n_ears);
|
alexbrandmeyer@626
|
138 CARParams car_params;
|
alexbrandmeyer@636
|
139 IHCParams ihc_params;
|
alexbrandmeyer@636
|
140 AGCParams agc_params;
|
alexbrandmeyer@636
|
141 CARFAC mycf;
|
alexbrandmeyer@636
|
142 mycf.Design(n_ears, 22050, car_params, ihc_params,
|
alexbrandmeyer@636
|
143 agc_params);
|
alexbrandmeyer@636
|
144 CARFACOutput my_output;
|
alexbrandmeyer@636
|
145 my_output.Init(n_ears, true, false, true, false, false);
|
alexbrandmeyer@636
|
146 mycf.Run(sound_data, &my_output);
|
alexbrandmeyer@636
|
147 filename = "cpp_nap_output_1_binaural_test.txt";
|
alexbrandmeyer@636
|
148 WriteNAPOutput(my_output, filename, 0);
|
alexbrandmeyer@636
|
149 filename = "cpp_nap_output_2_binaural_test.txt";
|
alexbrandmeyer@636
|
150 WriteNAPOutput(my_output, filename, 1);
|
alexbrandmeyer@636
|
151 int ear = 0;
|
alexbrandmeyer@636
|
152 int n_ch = 71;
|
alexbrandmeyer@636
|
153 for (int timepoint = 0; timepoint < n_timepoints; ++timepoint) {
|
alexbrandmeyer@636
|
154 for (int channel = 0; channel < n_ch; ++channel) {
|
alexbrandmeyer@637
|
155 FPType cplusplus = my_output.nap()[timepoint][ear](channel);
|
alexbrandmeyer@636
|
156 FPType matlab = nap1[timepoint](channel);
|
alexbrandmeyer@637
|
157 ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel);
|
alexbrandmeyer@637
|
158 cplusplus = my_output.bm()[timepoint][ear](channel);
|
alexbrandmeyer@636
|
159 matlab = bm1[timepoint](channel);
|
alexbrandmeyer@637
|
160 ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel);
|
alexbrandmeyer@636
|
161 }
|
alexbrandmeyer@626
|
162 }
|
alexbrandmeyer@636
|
163 ear = 1;
|
alexbrandmeyer@636
|
164 for (int timepoint = 0; timepoint < n_timepoints; ++timepoint) {
|
alexbrandmeyer@636
|
165 for (int channel = 0; channel < n_ch; ++channel) {
|
alexbrandmeyer@637
|
166 FPType cplusplus = my_output.nap()[timepoint][ear](channel);
|
alexbrandmeyer@636
|
167 FPType matlab = nap2[timepoint](channel);
|
alexbrandmeyer@637
|
168 ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel);
|
alexbrandmeyer@637
|
169 cplusplus = my_output.bm()[timepoint][ear](channel);
|
alexbrandmeyer@636
|
170 matlab = bm2[timepoint](channel);
|
alexbrandmeyer@637
|
171 ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel);
|
alexbrandmeyer@626
|
172 }
|
alexbrandmeyer@626
|
173 }
|
alexbrandmeyer@626
|
174 }
|
alexbrandmeyer@626
|
175
|
alexbrandmeyer@636
|
176 TEST(CARFACTest, Long_Output_test) {
|
alexbrandmeyer@636
|
177 int n_timepoints = 2000;
|
alexbrandmeyer@636
|
178 int n_channels = 83;
|
alexbrandmeyer@636
|
179 int n_ears = 2;
|
alexbrandmeyer@636
|
180 string filename = "long_test_nap1.txt";
|
alexbrandmeyer@637
|
181 vector<FloatArray> nap1 = Load2dTestData(filename, n_timepoints, n_channels);
|
alexbrandmeyer@636
|
182 filename = "long_test_bm1.txt";
|
alexbrandmeyer@637
|
183 vector<FloatArray> bm1 = Load2dTestData(filename, n_timepoints, n_channels);
|
alexbrandmeyer@636
|
184 filename = "long_test_nap2.txt";
|
alexbrandmeyer@637
|
185 vector<FloatArray> nap2 = Load2dTestData(filename, n_timepoints, n_channels);
|
alexbrandmeyer@636
|
186 filename = "long_test_bm2.txt";
|
alexbrandmeyer@637
|
187 vector<FloatArray> bm2 = Load2dTestData(filename, n_timepoints, n_channels);
|
alexbrandmeyer@636
|
188 filename = "file_signal_long_test.txt";
|
alexbrandmeyer@637
|
189 vector<vector<float>> sound_data = Load2dAudioVector(filename, n_timepoints,
|
alexbrandmeyer@637
|
190 n_ears);
|
alexbrandmeyer@626
|
191 CARParams car_params;
|
alexbrandmeyer@626
|
192 IHCParams ihc_params;
|
alexbrandmeyer@626
|
193 AGCParams agc_params;
|
alexbrandmeyer@636
|
194 CARFAC mycf;
|
alexbrandmeyer@636
|
195 mycf.Design(n_ears, 44100, car_params, ihc_params,
|
alexbrandmeyer@636
|
196 agc_params);
|
alexbrandmeyer@636
|
197 CARFACOutput my_output;
|
alexbrandmeyer@636
|
198 my_output.Init(n_ears, true, false, true, false, false);
|
alexbrandmeyer@636
|
199 mycf.Run(sound_data, &my_output);
|
alexbrandmeyer@636
|
200 filename = "cpp_nap_output_1_long_test.txt";
|
alexbrandmeyer@636
|
201 WriteNAPOutput(my_output, filename, 0);
|
alexbrandmeyer@636
|
202 filename = "cpp_nap_output_2_long_test.txt";
|
alexbrandmeyer@636
|
203 WriteNAPOutput(my_output, filename, 1);
|
alexbrandmeyer@636
|
204 int ear = 0;
|
alexbrandmeyer@636
|
205 for (int timepoint = 0; timepoint < n_timepoints; ++timepoint) {
|
alexbrandmeyer@636
|
206 for (int channel = 0; channel < n_channels; ++channel) {
|
alexbrandmeyer@637
|
207 FPType cplusplus = my_output.nap()[timepoint][ear](channel);
|
alexbrandmeyer@636
|
208 FPType matlab = nap1[timepoint](channel);
|
alexbrandmeyer@637
|
209 ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel);
|
alexbrandmeyer@637
|
210 cplusplus = my_output.bm()[timepoint][ear](channel);
|
alexbrandmeyer@636
|
211 matlab = bm1[timepoint](channel);
|
alexbrandmeyer@637
|
212 ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel);
|
alexbrandmeyer@636
|
213 }
|
alexbrandmeyer@626
|
214 }
|
alexbrandmeyer@636
|
215 ear = 1;
|
alexbrandmeyer@636
|
216 for (int timepoint = 0; timepoint < n_timepoints; ++timepoint) {
|
alexbrandmeyer@636
|
217 for (int channel = 0; channel < n_channels; ++channel) {
|
alexbrandmeyer@637
|
218 FPType cplusplus = my_output.nap()[timepoint][ear](channel);
|
alexbrandmeyer@636
|
219 FPType matlab = nap2[timepoint](channel);
|
alexbrandmeyer@637
|
220 ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel);
|
alexbrandmeyer@637
|
221 cplusplus = my_output.bm()[timepoint][ear](channel);
|
alexbrandmeyer@636
|
222 matlab = bm2[timepoint](channel);
|
alexbrandmeyer@637
|
223 ASSERT_NEAR(cplusplus, matlab, kPrecisionLevel);
|
alexbrandmeyer@626
|
224 }
|
alexbrandmeyer@626
|
225 }
|
alexbrandmeyer@636
|
226 } |