1 /*
2  * This file is part of libsidplayfp, a SID player engine.
3  *
4  *  Copyright (C) 2014-2015 Leandro Nini
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20 
21 #include "UnitTest++/UnitTest++.h"
22 #include "UnitTest++/TestReporter.h"
23 
24 #include <limits>
25 
26 #include "../src/builders/residfp-builder/residfp/Spline.h"
27 #include "../src/builders/residfp-builder/residfp/Spline.cpp"
28 
29 using namespace UnitTest;
30 using namespace reSIDfp;
31 
32 const unsigned int OPAMP_SIZE = 33;
33 
34 const Spline::Point opamp_voltage[OPAMP_SIZE] =
35 {
36   {  0.81, 10.31 },  // Approximate start of actual range
37   {  2.40, 10.31 },
38   {  2.60, 10.30 },
39   {  2.70, 10.29 },
40   {  2.80, 10.26 },
41   {  2.90, 10.17 },
42   {  3.00, 10.04 },
43   {  3.10,  9.83 },
44   {  3.20,  9.58 },
45   {  3.30,  9.32 },
46   {  3.50,  8.69 },
47   {  3.70,  8.00 },
48   {  4.00,  6.89 },
49   {  4.40,  5.21 },
50   {  4.54,  4.54 },  // Working point (vi = vo)
51   {  4.60,  4.19 },
52   {  4.80,  3.00 },
53   {  4.90,  2.30 },  // Change of curvature
54   {  4.95,  2.03 },
55   {  5.00,  1.88 },
56   {  5.05,  1.77 },
57   {  5.10,  1.69 },
58   {  5.20,  1.58 },
59   {  5.40,  1.44 },
60   {  5.60,  1.33 },
61   {  5.80,  1.26 },
62   {  6.00,  1.21 },
63   {  6.40,  1.12 },
64   {  7.00,  1.02 },
65   {  7.50,  0.97 },
66   {  8.50,  0.89 },
67   { 10.00,  0.81 },
68   { 10.31,  0.81 },  // Approximate end of actual range
69 };
70 
SUITE(Spline)71 SUITE(Spline)
72 {
73 
74 TEST(TestMonotonicity)
75 {
76     Spline s(opamp_voltage, OPAMP_SIZE);
77 
78     double old = std::numeric_limits<double>::max();
79     for (double x = 0.0; x < 12.0; x+=0.01)
80     {
81         Spline::Point out = s.evaluate(x);
82 
83         CHECK(out.x <= old);
84 
85         old = out.x;
86     }
87 }
88 
89 TEST(TestPoints)
90 {
91     Spline s(opamp_voltage, OPAMP_SIZE);
92 
93     for (int i = 0; i < OPAMP_SIZE; i++)
94     {
95         Spline::Point out = s.evaluate(opamp_voltage[i].x);
96 
97         CHECK_EQUAL(opamp_voltage[i].y, out.x);
98     }
99 }
100 
101 TEST(TestInterpolateOutsideBounds)
102 {
103     const Spline::Point values[5] = {
104         { 10, 15 },
105         { 15, 20 },
106         { 20, 30 },
107         { 25, 40 },
108         { 30, 45 },
109     };
110 
111     Spline s(values, 5);
112 
113     Spline::Point out;
114 
115     out = s.evaluate(5);
116     CHECK_CLOSE(6.66667, out.x, 0.00001);
117 
118     out = s.evaluate(40);
119     CHECK_CLOSE(75.0, out.x, 0.00001);
120 }
121 
122 }
123