annotate carfac/carfac_test.cc @ 660:499ffd3a50ba

Factor out common test utility functions and clean up carfac_test.
author ronw@google.com
date Mon, 01 Jul 2013 19:02:32 +0000
parents ae172177497d
children 7a0031c321da
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@660 29 #include <Eigen/Core>
ronw@660 30
ronw@642 31 #include "gtest/gtest.h"
alexbrandmeyer@643 32
ronw@646 33 #include "agc.h"
alexbrandmeyer@643 34 #include "car.h"
ronw@647 35 #include "carfac_output.h"
alexbrandmeyer@643 36 #include "common.h"
ronw@646 37 #include "ihc.h"
ronw@660 38 #include "test_util.h"
alexbrandmeyer@637 39
ronw@652 40 using std::deque;
alexbrandmeyer@636 41 using std::ofstream;
ronw@646 42 using std::string;
ronw@646 43 using std::vector;
alexbrandmeyer@636 44
ronw@660 45 // Reads a two dimensional vector of audio data from a text file
ronw@660 46 // containing the output of the Matlab wavread() function.
ronw@660 47 vector<vector<float>> LoadAudio(const string& filename, int timepoints,
ronw@660 48 int num_channels) {
ronw@660 49 return LoadMatrix<vector<float>, false>(filename, timepoints, num_channels);
ronw@660 50 }
ronw@630 51
ronw@652 52 // Writes the CARFAC NAP output to a text file.
ronw@652 53 void WriteNAPOutput(const CARFACOutput& output, const string& filename,
ronw@646 54 int ear) {
ronw@656 55 string fullfile = kTestDataDir + filename;
alexbrandmeyer@636 56 ofstream ofile(fullfile.c_str());
ronw@660 57 const int kPrecision = 9;
ronw@660 58 ofile.precision(kPrecision);
alexbrandmeyer@643 59 int32_t num_timepoints = output.nap().size();
alexbrandmeyer@637 60 int channels = output.nap()[0][0].size();
ronw@660 61 Eigen::IOFormat ioformat(kPrecision, Eigen::DontAlignCols);
alexbrandmeyer@636 62 if (ofile.is_open()) {
alexbrandmeyer@643 63 for (int32_t i = 0; i < num_timepoints; ++i) {
ronw@660 64 ofile << output.nap()[i][ear].transpose().format(ioformat) << std::endl;
alexbrandmeyer@636 65 }
alexbrandmeyer@636 66 }
alexbrandmeyer@636 67 ofile.close();
alexbrandmeyer@636 68 }
alexbrandmeyer@636 69
ronw@652 70 class CARFACTest : public testing::Test {
ronw@652 71 protected:
ronw@654 72 deque<vector<ArrayX>> LoadTestData(const string& basename,
ronw@654 73 int num_samples,
ronw@654 74 int num_ears,
ronw@654 75 int num_channels) const {
ronw@654 76 deque<vector<ArrayX>> test_data(num_samples, vector<ArrayX>(num_ears));
ronw@654 77 for (int ear = 0; ear < num_ears; ++ear) {
ronw@652 78 string filename = basename + std::to_string(ear + 1) + ".txt";
ronw@660 79 vector<ArrayX> data = LoadMatrix(filename, num_samples, num_channels);
ronw@654 80 for (int i = 0; i < num_samples; ++i) {
ronw@652 81 test_data[i][ear] = data[i];
ronw@652 82 }
ronw@652 83 }
ronw@652 84 return test_data;
alexbrandmeyer@626 85 }
ronw@652 86
ronw@652 87 void AssertCARFACOutputNear(const deque<vector<ArrayX>>& expected,
ronw@652 88 const deque<vector<ArrayX>>& actual,
ronw@654 89 int num_samples,
ronw@660 90 int num_ears) const {
ronw@654 91 for (int timepoint = 0; timepoint < num_samples; ++timepoint) {
ronw@654 92 for (int ear = 0; ear < num_ears; ++ear) {
ronw@660 93 const float kPrecisionLevel = 1.0e-7;
ronw@660 94 ASSERT_TRUE(ArraysNear(expected[timepoint][ear],
ronw@660 95 actual[timepoint][ear],
ronw@660 96 kPrecisionLevel));
ronw@652 97 }
alexbrandmeyer@626 98 }
alexbrandmeyer@626 99 }
ronw@652 100
ronw@660 101 void RunCARFACAndCompareWithMatlab(const string& test_name,
ronw@660 102 int num_samples,
ronw@660 103 int num_ears,
ronw@660 104 int num_channels,
ronw@660 105 FPType sample_rate) const {
ronw@660 106 vector<vector<float>> sound_data =
ronw@660 107 LoadAudio(test_name + "-audio.txt", num_samples, num_ears);
ronw@660 108
ronw@660 109 CARParams car_params;
ronw@660 110 IHCParams ihc_params;
ronw@660 111 AGCParams agc_params;
ronw@660 112 CARFAC carfac(num_ears, sample_rate, car_params, ihc_params, agc_params);
ronw@660 113 CARFACOutput output(true, true, false, false);
ronw@660 114 const bool kOpenLoop = false;
ronw@660 115 const int length = sound_data[0].size();
ronw@660 116 carfac.RunSegment(sound_data, 0, length, kOpenLoop, &output);
ronw@660 117
ronw@660 118 // TODO(ronw): Don't unconditionally overwrite files that are
ronw@660 119 // checked in to the repository on every test run.
ronw@660 120 WriteNAPOutput(output, test_name + "-cpp-nap1.txt", 0);
ronw@660 121 WriteNAPOutput(output, test_name + "-cpp-nap2.txt", 1);
ronw@660 122
ronw@660 123 deque<vector<ArrayX>> expected_nap = LoadTestData(
ronw@660 124 test_name + "-matlab-nap", num_samples, num_ears, num_channels);
ronw@660 125 AssertCARFACOutputNear(expected_nap, output.nap(), num_samples, num_ears);
ronw@660 126 deque<vector<ArrayX>> expected_bm = LoadTestData(
ronw@660 127 test_name + "-matlab-bm", num_samples, num_ears, num_channels);
ronw@660 128 AssertCARFACOutputNear(expected_bm, output.bm(), num_samples, num_ears);
ronw@660 129 }
ronw@652 130 };
ronw@652 131
ronw@660 132 TEST_F(CARFACTest, MatchesMatlabOnBinauralData) {
ronw@654 133 const int kNumSamples = 882;
ronw@654 134 const int kNumEars = 2;
ronw@654 135 const int kNumChannels = 71;
ronw@660 136 const FPType kSampleRate = 22050.0;
ronw@660 137 RunCARFACAndCompareWithMatlab(
ronw@660 138 "binaural_test", kNumSamples, kNumEars, kNumChannels, kSampleRate);
alexbrandmeyer@626 139 }
alexbrandmeyer@626 140
ronw@660 141 TEST_F(CARFACTest, MatchesMatlabOnLongBinauralData) {
ronw@654 142 const int kNumSamples = 2000;
ronw@654 143 const int kNumEars = 2;
ronw@654 144 const int kNumChannels = 83;
ronw@660 145 const FPType kSampleRate = 44100.0;
ronw@660 146 RunCARFACAndCompareWithMatlab(
ronw@660 147 "long_test", kNumSamples, kNumEars, kNumChannels, kSampleRate);
alexbrandmeyer@626 148 }