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
10 #ifdef __clang__
11 /*
12 * Floating-point contraction merges an operation of the form (a*b + c) from
13 * two operations (fmul, fadd) into a single operation (fmadd). This can change
14 * the value of the resulting LSB, causing problems when the expected value is
15 * some multiple of 0.5f and the rounding functions are used. Disable
16 * contraction for the tests to ensure this doesn't occur.
17 */
18 #pragma STDC FP_CONTRACT OFF
19 #endif
20
21 #include <zephyr/math/interpolation.h>
22
ZTEST(interpolation,test_interpolation_oob)23 ZTEST(interpolation, test_interpolation_oob)
24 {
25 int32_t x_axis[] = {10, 20, 30, 40, 50};
26 int32_t y_axis[] = {20, 22, 24, 28, 36};
27 uint8_t len = ARRAY_SIZE(x_axis);
28
29 zassert_equal(ARRAY_SIZE(x_axis), ARRAY_SIZE(y_axis));
30
31 zassert_equal(y_axis[0], linear_interpolate(x_axis, y_axis, len, INT32_MIN));
32 zassert_equal(y_axis[0], linear_interpolate(x_axis, y_axis, len, -1));
33 zassert_equal(y_axis[0], linear_interpolate(x_axis, y_axis, len, 0));
34 zassert_equal(y_axis[0], linear_interpolate(x_axis, y_axis, len, x_axis[0] - 1));
35
36 zassert_equal(y_axis[4], linear_interpolate(x_axis, y_axis, len, x_axis[4] + 1));
37 zassert_equal(y_axis[4], linear_interpolate(x_axis, y_axis, len, 100));
38 zassert_equal(y_axis[4], linear_interpolate(x_axis, y_axis, len, INT32_MAX));
39 }
40
ZTEST(interpolation,test_interpolation_on_boundary)41 ZTEST(interpolation, test_interpolation_on_boundary)
42 {
43 int32_t x_axis[] = {10, 20, 30, 40, 50};
44 int32_t y_axis[] = {20, 22, 24, 28, 36};
45 uint8_t len = ARRAY_SIZE(x_axis);
46
47 zassert_equal(ARRAY_SIZE(x_axis), ARRAY_SIZE(y_axis));
48
49 /* Looking up x_axis values should return corresponding y_axis */
50 for (int i = 0; i < ARRAY_SIZE(x_axis); i++) {
51 zassert_equal(y_axis[i], linear_interpolate(x_axis, y_axis, len, x_axis[i]));
52 }
53 }
54
ZTEST(interpolation,test_interpolation_rounding)55 ZTEST(interpolation, test_interpolation_rounding)
56 {
57 int32_t y_axis[] = {0, 1, 2};
58 int32_t x_axis[] = {0, 10, 20};
59 uint8_t len = ARRAY_SIZE(x_axis);
60
61 zassert_equal(ARRAY_SIZE(x_axis), ARRAY_SIZE(y_axis));
62
63 /* 0 to 4 -> 0 */
64 for (int i = 0; i < 5; i++) {
65 zassert_equal(0, linear_interpolate(x_axis, y_axis, len, i));
66 }
67 /* 5 to 14 -> 1 */
68 for (int i = 5; i < 15; i++) {
69 zassert_equal(1, linear_interpolate(x_axis, y_axis, len, i));
70 }
71 /* 15 to N -> 2 */
72 for (int i = 15; i <= 20; i++) {
73 zassert_equal(2, linear_interpolate(x_axis, y_axis, len, i));
74 }
75 }
76
ZTEST(interpolation,test_interpolation_simple)77 ZTEST(interpolation, test_interpolation_simple)
78 {
79 int32_t y_axis[] = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
80 int32_t x_axis[] = {2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, 2800, 2900, 3000};
81 uint8_t len = ARRAY_SIZE(x_axis);
82 int32_t expected;
83
84 zassert_equal(ARRAY_SIZE(x_axis), ARRAY_SIZE(y_axis));
85
86 /* y = (x - 2000) / 10 */
87 for (int i = x_axis[0]; i <= x_axis[1]; i++) {
88 expected = round((i - 2000.0) / 10.0);
89 zassert_equal(expected, linear_interpolate(x_axis, y_axis, len, i));
90 }
91 }
92
ZTEST(interpolation,test_interpolation_negative_y)93 ZTEST(interpolation, test_interpolation_negative_y)
94 {
95 int32_t y_axis[] = {-100, -90, -80, -70, -60, -50, -40, -30, -20, -10, 0};
96 int32_t x_axis[] = {2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, 2800, 2900, 3000};
97 uint8_t len = ARRAY_SIZE(x_axis);
98 int32_t expected;
99
100 zassert_equal(ARRAY_SIZE(x_axis), ARRAY_SIZE(y_axis));
101
102 /* y = ((x - 2000) / 10) - 100 */
103 for (int i = x_axis[0]; i <= x_axis[len - 1]; i++) {
104 expected = round((i - 2000.0) / 10.0 - 100.0);
105 zassert_equal(expected, linear_interpolate(x_axis, y_axis, len, i));
106 }
107 }
108
ZTEST(interpolation,test_interpolation_negative_x)109 ZTEST(interpolation, test_interpolation_negative_x)
110 {
111 int32_t y_axis[] = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
112 int32_t x_axis[] = {-3000, -2900, -2800, -2700, -2600, -2500,
113 -2400, -2300, -2200, -2100, -2000};
114 uint8_t len = ARRAY_SIZE(x_axis);
115 int32_t expected;
116
117 zassert_equal(ARRAY_SIZE(x_axis), ARRAY_SIZE(y_axis));
118
119 /* y = ((x + 3000) / 10) */
120 for (int i = x_axis[0]; i <= x_axis[len - 1]; i++) {
121 expected = round((i + 3000.0) / 10.0);
122 zassert_equal(expected, linear_interpolate(x_axis, y_axis, len, i));
123 }
124 }
125
ZTEST(interpolation,test_interpolation_negative_xy)126 ZTEST(interpolation, test_interpolation_negative_xy)
127 {
128 int32_t y_axis[] = {-100, -90, -80, -70, -60, -50, -40, -30, -20, -10, 0};
129 int32_t x_axis[] = {-3000, -2900, -2800, -2700, -2600, -2500,
130 -2400, -2300, -2200, -2100, -2000};
131 uint8_t len = ARRAY_SIZE(x_axis);
132 int32_t expected;
133
134 zassert_equal(ARRAY_SIZE(x_axis), ARRAY_SIZE(y_axis));
135
136 /* y = ((x + 3000) / 10) - 100 */
137 for (int i = x_axis[0]; i <= x_axis[len - 1]; i++) {
138 expected = round((i + 3000.0) / 10.0 - 100.0);
139 zassert_equal(expected, linear_interpolate(x_axis, y_axis, len, i));
140 }
141 }
142
ZTEST(interpolation,test_interpolation_piecewise)143 ZTEST(interpolation, test_interpolation_piecewise)
144 {
145 int32_t y_axis[] = {10, 30, 110, 40, 0};
146 int32_t x_axis[] = {100, 150, 200, 250, 300};
147 uint8_t len = ARRAY_SIZE(x_axis);
148 int32_t expected;
149
150 zassert_equal(ARRAY_SIZE(x_axis), ARRAY_SIZE(y_axis));
151
152 /* First line segment, y = 0.4x - 30 */
153 for (int i = x_axis[0]; i <= x_axis[1]; i++) {
154 expected = round(0.4 * i - 30.0);
155 zassert_equal(expected, linear_interpolate(x_axis, y_axis, len, i));
156 }
157
158 /* Second line segment, y = 1.6x - 210 */
159 for (int i = x_axis[1]; i <= x_axis[2]; i++) {
160 expected = round(1.6 * i - 210.0);
161 zassert_equal(expected, linear_interpolate(x_axis, y_axis, len, i));
162 }
163
164 /* Third line segment, y = 390 - 1.4x */
165 for (int i = x_axis[2]; i <= x_axis[3]; i++) {
166 expected = round(390.0 - 1.4 * i);
167 zassert_equal(expected, linear_interpolate(x_axis, y_axis, len, i));
168 }
169
170 /* Fourth line segment, y = 240 - 0.8x */
171 for (int i = x_axis[3]; i <= x_axis[4]; i++) {
172 expected = round(240.0 - 0.8 * i);
173 zassert_equal(expected, linear_interpolate(x_axis, y_axis, len, i));
174 }
175 }
176
177 ZTEST_SUITE(interpolation, NULL, NULL, NULL, NULL, NULL);
178