ronw@642: // Copyright 2013, Google, Inc. ronw@642: // Author: Ron Weiss ronw@642: // ronw@642: // This C++ file is part of an implementation of Lyon's cochlear model: ronw@642: // "Cascade of Asymmetric Resonators with Fast-Acting Compression" ronw@642: // to supplement Lyon's upcoming book "Human and Machine Hearing" ronw@642: // ronw@642: // Licensed under the Apache License, Version 2.0 (the "License"); ronw@642: // you may not use this file except in compliance with the License. ronw@642: // You may obtain a copy of the License at ronw@642: // ronw@642: // http://www.apache.org/licenses/LICENSE-2.0 ronw@642: // ronw@642: // Unless required by applicable law or agreed to in writing, software ronw@642: // distributed under the License is distributed on an "AS IS" BASIS, ronw@642: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ronw@642: // See the License for the specific language governing permissions and ronw@642: // limitations under the License. ronw@642: ronw@642: #include "sai.h" ronw@642: ronw@642: #include ronw@642: #include ronw@642: ronw@642: #include "gtest/gtest.h" ronw@642: ronw@642: using testing::Values; ronw@642: using std::vector; ronw@642: alexbrandmeyer@643: vector CreateZeroSegment(int n_ch, int length) { alexbrandmeyer@643: vector segment; ronw@642: for (int i = 0; i < length; ++i) { alexbrandmeyer@643: segment.push_back(ArrayX::Zero(n_ch)); ronw@642: } ronw@642: return segment; ronw@642: } ronw@642: alexbrandmeyer@643: bool HasPeakAt(const ArrayXX& frame, int index) { ronw@642: if (index == 0) { ronw@642: return frame(index) > frame(index + 1); ronw@642: } else if (index == frame.size() - 1) { ronw@642: return frame(index) > frame(index - 1); ronw@642: } ronw@642: return frame(index) > frame(index + 1) && frame(index) > frame(index - 1); ronw@642: } ronw@642: ronw@642: class SAIPeriodicInputTest ronw@642: : public testing::TestWithParam> { ronw@642: protected: ronw@642: void SetUp() { ronw@642: period_ = std::tr1::get<0>(GetParam()); ronw@642: phase_ = std::tr1::get<1>(GetParam()); ronw@642: } ronw@642: ronw@642: int period_; ronw@642: int phase_; ronw@642: }; ronw@642: ronw@642: TEST_P(SAIPeriodicInputTest, SingleChannelPulseTrain) { alexbrandmeyer@643: vector segment = CreateZeroSegment(1, 38); ronw@642: for (int i = phase_; i < segment.size(); i += period_) { ronw@642: segment[i](0) = 1; ronw@642: } ronw@642: ronw@642: SAIParams sai_params; ronw@642: sai_params.window_width = segment.size(); ronw@642: sai_params.n_ch = 1; ronw@642: sai_params.width = 15; ronw@642: // Half of the SAI should come from the future. ronw@642: // sai_params.future_lags = sai_params.width / 2; ronw@642: sai_params.future_lags = 0; ronw@642: sai_params.n_window_pos = 2; ronw@642: ronw@642: SAI sai(sai_params); alexbrandmeyer@643: ArrayXX sai_frame; ronw@642: sai.RunSegment(segment, &sai_frame); ronw@642: ronw@642: // The output should have peaks at the same positions, regardless of ronw@642: // input phase. ronw@642: for (int i = sai_frame.size() - 1; i >= 0 ; i -= period_) { ronw@642: EXPECT_TRUE(HasPeakAt(sai_frame, i)); ronw@642: } ronw@642: ronw@642: for (int i = 0; i < segment.size(); ++i) { ronw@642: std::cout << segment[i](0) << " "; ronw@642: } ronw@642: std::cout << "\n"; ronw@642: for (int i = 0; i < sai_frame.size(); ++i) { ronw@642: std::cout << sai_frame(i) << " "; ronw@642: } ronw@642: std::cout << "\n"; ronw@642: } ronw@642: INSTANTIATE_TEST_CASE_P(PeriodicInputVariations, SAIPeriodicInputTest, ronw@642: testing::Combine(Values(25, 10, 5, 2), // periods. ronw@642: Values(0, 3))); // phases.