1 /*
2  * Copyright (c) 2024 Embeint Inc
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #include <math.h>
7 
8 #include <zephyr/ztest.h>
9 #include <zephyr/math/interpolation.h>
10 
ZTEST(interpolation,test_interpolation_oob)11 ZTEST(interpolation, test_interpolation_oob)
12 {
13 	int32_t x_axis[] = {10, 20, 30, 40, 50};
14 	int32_t y_axis[] = {20, 22, 24, 28, 36};
15 	uint8_t len = ARRAY_SIZE(x_axis);
16 
17 	zassert_equal(ARRAY_SIZE(x_axis), ARRAY_SIZE(y_axis));
18 
19 	zassert_equal(y_axis[0], linear_interpolate(x_axis, y_axis, len, INT32_MIN));
20 	zassert_equal(y_axis[0], linear_interpolate(x_axis, y_axis, len, -1));
21 	zassert_equal(y_axis[0], linear_interpolate(x_axis, y_axis, len, 0));
22 	zassert_equal(y_axis[0], linear_interpolate(x_axis, y_axis, len, x_axis[0] - 1));
23 
24 	zassert_equal(y_axis[4], linear_interpolate(x_axis, y_axis, len, x_axis[4] + 1));
25 	zassert_equal(y_axis[4], linear_interpolate(x_axis, y_axis, len, 100));
26 	zassert_equal(y_axis[4], linear_interpolate(x_axis, y_axis, len, INT32_MAX));
27 }
28 
ZTEST(interpolation,test_interpolation_on_boundary)29 ZTEST(interpolation, test_interpolation_on_boundary)
30 {
31 	int32_t x_axis[] = {10, 20, 30, 40, 50};
32 	int32_t y_axis[] = {20, 22, 24, 28, 36};
33 	uint8_t len = ARRAY_SIZE(x_axis);
34 
35 	zassert_equal(ARRAY_SIZE(x_axis), ARRAY_SIZE(y_axis));
36 
37 	/* Looking up x_axis values should return corresponding y_axis */
38 	for (int i = 0; i < ARRAY_SIZE(x_axis); i++) {
39 		zassert_equal(y_axis[i], linear_interpolate(x_axis, y_axis, len, x_axis[i]));
40 	}
41 }
42 
ZTEST(interpolation,test_interpolation_rounding)43 ZTEST(interpolation, test_interpolation_rounding)
44 {
45 	int32_t y_axis[] = {0, 1, 2};
46 	int32_t x_axis[] = {0, 10, 20};
47 	uint8_t len = ARRAY_SIZE(x_axis);
48 
49 	zassert_equal(ARRAY_SIZE(x_axis), ARRAY_SIZE(y_axis));
50 
51 	/* 0 to 4 -> 0 */
52 	for (int i = 0; i < 5; i++) {
53 		zassert_equal(0, linear_interpolate(x_axis, y_axis, len, i));
54 	}
55 	/* 5 to 14 -> 1 */
56 	for (int i = 5; i < 15; i++) {
57 		zassert_equal(1, linear_interpolate(x_axis, y_axis, len, i));
58 	}
59 	/* 15 to N -> 2 */
60 	for (int i = 15; i <= 20; i++) {
61 		zassert_equal(2, linear_interpolate(x_axis, y_axis, len, i));
62 	}
63 }
64 
ZTEST(interpolation,test_interpolation_simple)65 ZTEST(interpolation, test_interpolation_simple)
66 {
67 	int32_t y_axis[] = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
68 	int32_t x_axis[] = {2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, 2800, 2900, 3000};
69 	uint8_t len = ARRAY_SIZE(x_axis);
70 	int32_t expected;
71 
72 	zassert_equal(ARRAY_SIZE(x_axis), ARRAY_SIZE(y_axis));
73 
74 	/* y = (x - 2000) / 10 */
75 	for (int i = x_axis[0]; i <= x_axis[1]; i++) {
76 		expected = round((i - 2000.0) / 10.0);
77 		zassert_equal(expected, linear_interpolate(x_axis, y_axis, len, i));
78 	}
79 }
80 
ZTEST(interpolation,test_interpolation_negative_y)81 ZTEST(interpolation, test_interpolation_negative_y)
82 {
83 	int32_t y_axis[] = {-100, -90, -80, -70, -60, -50, -40, -30, -20, -10, 0};
84 	int32_t x_axis[] = {2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, 2800, 2900, 3000};
85 	uint8_t len = ARRAY_SIZE(x_axis);
86 	int32_t expected;
87 
88 	zassert_equal(ARRAY_SIZE(x_axis), ARRAY_SIZE(y_axis));
89 
90 	/* y = ((x - 2000) / 10) - 100 */
91 	for (int i = x_axis[0]; i <= x_axis[len - 1]; i++) {
92 		expected = round((i - 2000.0) / 10.0 - 100.0);
93 		zassert_equal(expected, linear_interpolate(x_axis, y_axis, len, i));
94 	}
95 }
96 
ZTEST(interpolation,test_interpolation_negative_x)97 ZTEST(interpolation, test_interpolation_negative_x)
98 {
99 	int32_t y_axis[] = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
100 	int32_t x_axis[] = {-3000, -2900, -2800, -2700, -2600, -2500,
101 			    -2400, -2300, -2200, -2100, -2000};
102 	uint8_t len = ARRAY_SIZE(x_axis);
103 	int32_t expected;
104 
105 	zassert_equal(ARRAY_SIZE(x_axis), ARRAY_SIZE(y_axis));
106 
107 	/* y = ((x + 3000) / 10) */
108 	for (int i = x_axis[0]; i <= x_axis[len - 1]; i++) {
109 		expected = round((i + 3000.0) / 10.0);
110 		zassert_equal(expected, linear_interpolate(x_axis, y_axis, len, i));
111 	}
112 }
113 
ZTEST(interpolation,test_interpolation_negative_xy)114 ZTEST(interpolation, test_interpolation_negative_xy)
115 {
116 	int32_t y_axis[] = {-100, -90, -80, -70, -60, -50, -40, -30, -20, -10, 0};
117 	int32_t x_axis[] = {-3000, -2900, -2800, -2700, -2600, -2500,
118 			    -2400, -2300, -2200, -2100, -2000};
119 	uint8_t len = ARRAY_SIZE(x_axis);
120 	int32_t expected;
121 
122 	zassert_equal(ARRAY_SIZE(x_axis), ARRAY_SIZE(y_axis));
123 
124 	/* y = ((x + 3000) / 10) - 100 */
125 	for (int i = x_axis[0]; i <= x_axis[len - 1]; i++) {
126 		expected = round((i + 3000.0) / 10.0 - 100.0);
127 		zassert_equal(expected, linear_interpolate(x_axis, y_axis, len, i));
128 	}
129 }
130 
ZTEST(interpolation,test_interpolation_piecewise)131 ZTEST(interpolation, test_interpolation_piecewise)
132 {
133 	int32_t y_axis[] = {10, 30, 110, 40, 0};
134 	int32_t x_axis[] = {100, 150, 200, 250, 300};
135 	uint8_t len = ARRAY_SIZE(x_axis);
136 	int32_t expected;
137 
138 	zassert_equal(ARRAY_SIZE(x_axis), ARRAY_SIZE(y_axis));
139 
140 	/* First line segment, y = 0.4x - 30 */
141 	for (int i = x_axis[0]; i <= x_axis[1]; i++) {
142 		expected = round(0.4 * i - 30.0);
143 		zassert_equal(expected, linear_interpolate(x_axis, y_axis, len, i));
144 	}
145 
146 	/* Second line segment, y = 1.6x - 210 */
147 	for (int i = x_axis[1]; i <= x_axis[2]; i++) {
148 		expected = round(1.6 * i - 210.0);
149 		zassert_equal(expected, linear_interpolate(x_axis, y_axis, len, i));
150 	}
151 
152 	/* Third line segment, y = 390 - 1.4x */
153 	for (int i = x_axis[2]; i <= x_axis[3]; i++) {
154 		expected = round(390.0 - 1.4 * i);
155 		zassert_equal(expected, linear_interpolate(x_axis, y_axis, len, i));
156 	}
157 
158 	/* Fourth line segment, y = 240 - 0.8x */
159 	for (int i = x_axis[3]; i <= x_axis[4]; i++) {
160 		expected = round(240.0 - 0.8 * i);
161 		zassert_equal(expected, linear_interpolate(x_axis, y_axis, len, i));
162 	}
163 }
164 
165 ZTEST_SUITE(interpolation, NULL, NULL, NULL, NULL, NULL);
166