view carfac/carfac_test.cc @ 647:749b5aed61f6

More #include cleanups.
author ronw@google.com
date Tue, 11 Jun 2013 21:32:50 +0000
parents e76951e4da20
children 1c2a5868f23a
line wrap: on
line source
//
//  carfac_test.cc
//  CARFAC Open Source C++ Library
//
//  Created by Alex Brandmeyer on 5/22/13.
//
// This C++ file is part of an implementation of Lyon's cochlear model:
// "Cascade of Asymmetric Resonators with Fast-Acting Compression"
// to supplement Lyon's upcoming book "Human and Machine Hearing"
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "carfac.h"

#include <fstream>
#include <string>
#include <vector>

#include "gtest/gtest.h"

#include "agc.h"
#include "car.h"
#include "carfac_output.h"
#include "common.h"
#include "ihc.h"

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;

// 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,
                    int ear) {
  string fullfile = kTestSourceDir + filename;
  ofstream ofile(fullfile.c_str());
  int32_t num_timepoints = output.nap().size();
  int channels = output.nap()[0][0].size();
  if (ofile.is_open()) {
    for (int32_t i = 0; i < num_timepoints; ++i) {
      for (int j = 0; j < channels; ++j) {
        ofile << output.nap()[i][ear](j);
        if (j < channels - 1) {
          ofile << " ";
        }
      }
      ofile << "\n";
    }
  }
  ofile.close();
}

ArrayX LoadTestData(const string filename, const int number_points) {
  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 (auto& timepoint : output) {
    timepoint.resize(columns);
  }
  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];
      }
    }
  }
  file.close();
  return output;
}

// This loads two dimensional vectors of audio data using data generated in
// Matlab using the 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);
  }
  if (file.is_open()) {
    for (int i = 0; i < timepoints; ++i) {
      for (int j = 0; j < channels; ++j) {
        file >> output[j][i];
      }
    }
  }
  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);
  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);
    }
  }
}

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);
  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);
    }
  }
}