diff --git a/test/ztest/unit/fast-get/testcase.yaml b/test/ztest/unit/fast-get/testcase.yaml index 458febdd9f09..e3648bfc4e5d 100644 --- a/test/ztest/unit/fast-get/testcase.yaml +++ b/test/ztest/unit/fast-get/testcase.yaml @@ -6,7 +6,7 @@ # generative artificial intelligence solutions. tests: - fast_get.basic_functionality: + sof.unit.fast_get: tags: fast_get memory cache platform_allow: native_sim integration_platforms: diff --git a/test/ztest/unit/list/testcase.yaml b/test/ztest/unit/list/testcase.yaml index 90e8eafebbbe..38b1697f5d2c 100644 --- a/test/ztest/unit/list/testcase.yaml +++ b/test/ztest/unit/list/testcase.yaml @@ -6,7 +6,7 @@ # generative artificial intelligence solutions. tests: - sof.list: + sof.unit.list: platform_allow: native_sim harness: ztest tags: unit diff --git a/test/ztest/unit/math/advanced/functions/CMakeLists.txt b/test/ztest/unit/math/advanced/functions/CMakeLists.txt index 04fc940b916b..20912580d9d3 100644 --- a/test/ztest/unit/math/advanced/functions/CMakeLists.txt +++ b/test/ztest/unit/math/advanced/functions/CMakeLists.txt @@ -29,11 +29,15 @@ target_compile_definitions(app PRIVATE target_sources(app PRIVATE test_scalar_power_ztest.c + test_base2_logarithm_ztest.c + test_exponential_ztest.c ${SOF_ROOT}/src/math/power.c + ${SOF_ROOT}/src/math/base2log.c + ${SOF_ROOT}/src/math/exp_fcn.c + # Note: exp_fcn_hifi.c is conditionally compiled only for Xtensa HiFi platforms. + # TODO: Enable these tests on Xtensa platforms to also test HiFi-optimized code paths. + ${SOF_ROOT}/src/math/exp_fcn_hifi.c ) # Apply SOF relative path definitions for proper compilation sof_append_relative_path_definitions(app) - -# Link math library for advanced math functions -target_link_libraries(app PRIVATE m) diff --git a/test/ztest/unit/math/advanced/functions/test_base2_logarithm_ztest.c b/test/ztest/unit/math/advanced/functions/test_base2_logarithm_ztest.c new file mode 100644 index 000000000000..52d1eb0e6a0b --- /dev/null +++ b/test/ztest/unit/math/advanced/functions/test_base2_logarithm_ztest.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. All rights reserved. +// +// These contents may have been developed with support from one or more Intel-operated +// generative artificial intelligence solutions. +// +// Converted from CMock to Ztest +// +// Original test from sof/test/cmocka/src/math/arithmetic/base2_logarithm.c +// Author: Shriram Shastry + +#include +#include +#include +#include +#include + +/* Test data tables from MATLAB-generated reference */ +#include "log2_tables.h" + +/* 'Error[max] = 0.0000236785999981,THD(-dBc) = -92.5128795787487235' */ +#define CMP_TOLERANCE 0.0000236785691029f + +/* testvector in Q32.0 */ +static const uint32_t uv[100] = { + 1ULL, 43383509ULL, 86767017ULL, 130150525ULL, 173534033ULL, 216917541ULL, + 260301049ULL, 303684557ULL, 347068065ULL, 390451573ULL, 433835081ULL, 477218589ULL, + 520602097ULL, 563985605ULL, 607369113ULL, 650752621ULL, 694136129ULL, 737519638ULL, + 780903146ULL, 824286654ULL, 867670162ULL, 911053670ULL, 954437178ULL, 997820686ULL, + 1041204194ULL, 1084587702ULL, 1127971210ULL, 1171354718ULL, 1214738226ULL, 1258121734ULL, + 1301505242ULL, 1344888750ULL, 1388272258ULL, 1431655766ULL, 1475039274ULL, 1518422782ULL, + 1561806290ULL, 1605189798ULL, 1648573306ULL, 1691956814ULL, 1735340322ULL, 1778723830ULL, + 1822107338ULL, 1865490846ULL, 1908874354ULL, 1952257862ULL, 1995641370ULL, 2039024878ULL, + 2082408386ULL, 2125791894ULL, 2169175403ULL, 2212558911ULL, 2255942419ULL, 2299325927ULL, + 2342709435ULL, 2386092943ULL, 2429476451ULL, 2472859959ULL, 2516243467ULL, 2559626975ULL, + 2603010483ULL, 2646393991ULL, 2689777499ULL, 2733161007ULL, 2776544515ULL, 2819928023ULL, + 2863311531ULL, 2906695039ULL, 2950078547ULL, 2993462055ULL, 3036845563ULL, 3080229071ULL, + 3123612579ULL, 3166996087ULL, 3210379595ULL, 3253763103ULL, 3297146611ULL, 3340530119ULL, + 3383913627ULL, 3427297135ULL, 3470680643ULL, 3514064151ULL, 3557447659ULL, 3600831168ULL, + 3644214676ULL, 3687598184ULL, 3730981692ULL, 3774365200ULL, 3817748708ULL, 3861132216ULL, + 3904515724ULL, 3947899232ULL, 3991282740ULL, 4034666248ULL, 4078049756ULL, 4121433264ULL, + 4164816772ULL, 4208200280ULL, 4251583788ULL, 4294967295ULL}; + +/** + * @brief Test base-2 logarithm function with fixed-point arithmetic + * + * This test validates the base2_logarithm() function against MATLAB-generated + * reference values. It tests 100 uniformly distributed input values across + * the full uint32_t range, checking that the fixed-point logarithm calculation + * stays within acceptable tolerance. + * + * Input values: Q32.0 format (unsigned 32-bit integers) + * Result: Q16.16 fixed-point format + * Reference: MATLAB log2() function results + */ +ZTEST(math_advanced_functions_suite, test_math_arithmetic_base2log_fixed) +{ + uint32_t u[100]; + int i, ret; + + BUILD_ASSERT(ARRAY_SIZE(uv) == ARRAY_SIZE(log2_lookup_table), + "Test vector size must match reference table size"); + + ret = memcpy_s((void *)&u[0], sizeof(u), (void *)&uv[0], 100U * sizeof(uint32_t)); + zassert_equal(ret, 0, "memcpy_s failed with error code %d", ret); + + for (i = 0; i < ARRAY_SIZE(u); i++) { + float y = Q_CONVERT_QTOF(base2_logarithm(u[i]), 0); + float delta = fabsf((float)(log2_lookup_table[i] - (double)y / (1 << 16))); + + zassert_true(delta <= CMP_TOLERANCE, + "base2_logarithm(%u): delta %.16f > tolerance (expected %.16f, got %.16f)", + u[i], (double)delta, log2_lookup_table[i], (double)y / (1 << 16)); + } +} diff --git a/test/ztest/unit/math/advanced/functions/test_exponential_ztest.c b/test/ztest/unit/math/advanced/functions/test_exponential_ztest.c new file mode 100644 index 000000000000..1fd03b6bb5af --- /dev/null +++ b/test/ztest/unit/math/advanced/functions/test_exponential_ztest.c @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2022-2026 Intel Corporation. + * + * These contents may have been developed with support from one or more Intel-operated + * generative artificial intelligence solutions. + * + * Converted from CMock to Ztest + * + * Original test from sof/test/cmocka/src/math/arithmetic/exponential.c + * + * Author: Shriram Shastry + * Seppo Ingalsuo + */ + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(test_exponential, LOG_LEVEL_INF); + +#define ULP_TOLERANCE 1.0 +#define ULP_SCALE 1.9073e-06 /* For exp() output Q13.19, 1 / 2^19 */ +#define NUMTESTSAMPLES 256 + +#define NUMTESTSAMPLES_TEST2 100 +#define ABS_DELTA_TOLERANCE_TEST2 2.0e-6 +#define REL_DELTA_TOLERANCE_TEST2 1000.0 /* rel. error is large with values near zero */ +#define NUMTESTSAMPLES_TEST3 100 +#define ABS_DELTA_TOLERANCE_TEST3 2.0e-6 +#define REL_DELTA_TOLERANCE_TEST3 10.0e-2 +#define SOFM_EXP_FIXED_ARG_MIN -11.5 +#define SOFM_EXP_FIXED_ARG_MAX 7.6245 + +#define NUMTESTSAMPLES_TEST4 100 +#define ABS_DELTA_TOLERANCE_TEST4 2.5e-5 +#define REL_DELTA_TOLERANCE_TEST4 1000.0 /* rel. error is large with values near zero */ + +/** + * Saturates input to 32 bits + * @param x Input value + * @return Saturated output value + */ +static int32_t saturate32(int64_t x) +{ + if (x < INT32_MIN) + return INT32_MIN; + else if (x > INT32_MAX) + return INT32_MAX; + + return x; +} + +/** + * Generates linearly spaced values for a vector with end points and number points in + * desired fractional Q-format for 32 bit integer. If the test values exceed int32_t + * range, the values are saturated to INT32_MIN to INT32_MAX range. + * + * @param a First value of test vector + * @param b Last value of test vector + * @param step_count Number of values in vector + * @param point Calculate n-th point of vector 0 .. step_count - 1 + * @param qformat Number of fractional bits y in Qx.y format + * @param fout Pointer to calculated test vector value, double + * @param iout Pointer to calculated test vector value, int32_t + */ +static void gen_testvector_linspace_int32(double a, double b, int step_count, int point, + int qformat, double *fout, int32_t *iout) +{ + double fstep = (b - a) / (step_count - 1); + double fvalue = a + fstep * point; + int64_t itmp; + + itmp = (int64_t)round(fvalue * (double)(1 << qformat)); + *iout = saturate32(itmp); + *fout = (double)*iout / (1 << qformat); +} + +/** + * Calculate reference exponent value + * @param x Input value + * @param qformat Fractional bits y in Qx.y format + * @return Saturated exponent value to match fractional format + */ +static double ref_exp(double x, int qformat) +{ + double yf; + int64_t yi; + + yf = exp(x); + yi = yf * (1 << qformat); + + if (yi > INT32_MAX) + yi = INT32_MAX; + else if (yi < INT32_MIN) + yi = INT32_MIN; + + yf = (double)yi / (1 << qformat); + return yf; +} + +/** + * Calculates test exponent function and compares result to reference exponent. + * @param ivalue Fractional format input value Q5.27 + * @param iexp_value Fractional format output value Q12.20 + * @param abs_delta_max Calculated absolute error + * @param rel_delta_max Calculated relative error + * @param abs_delta_tolerance Tolerance for absolute error + * @param rel_delta_tolerance Tolerance for relative error + */ +static void test_exp_with_input_value(int32_t ivalue, int32_t *iexp_value, + double *abs_delta_max, double *rel_delta_max, + double abs_delta_tolerance, double rel_delta_tolerance) +{ + double fvalue, fexp_value, ref_exp_value; + double rel_delta, abs_delta; + double eps = 1e-9; + + *iexp_value = sofm_exp_fixed(ivalue); + fvalue = (double)ivalue / (1 << 27); /* Q5.27 */ + fexp_value = (double)*iexp_value / (1 << 20); /* Q12.20 */ + ref_exp_value = ref_exp(fvalue, 20); + abs_delta = fabs(ref_exp_value - fexp_value); + rel_delta = abs_delta / (ref_exp_value + eps); + + if (abs_delta > *abs_delta_max) + *abs_delta_max = abs_delta; + + if (rel_delta > *rel_delta_max) + *rel_delta_max = rel_delta; + + zassert_true(abs_delta <= abs_delta_tolerance, + "sofm_exp_fixed: Absolute error %g exceeds limit %g, input %g output %g", + abs_delta, abs_delta_tolerance, fvalue, fexp_value); + + zassert_true(rel_delta <= rel_delta_tolerance, + "sofm_exp_fixed: Relative error %g exceeds limit %g, input %g output %g", + rel_delta, rel_delta_tolerance, fvalue, fexp_value); +} + +/** + * Reference function for dB to linear conversion + * @param x Input value + * @param qformat Fractional bits y in Qx.y format for saturation + * @return Saturated linear value + */ +static double ref_db2lin(double x, int qformat) +{ + double fref; + int64_t iref; + + fref = pow(10, x / 20); + iref = fref * (1 << qformat); + return (double)saturate32(iref) / (1 << qformat); +} + +/** + * @brief Test sofm_exp_approx() function with ULP error validation + * + * This test validates the sofm_exp_approx() exponential approximation function + * against the C standard library exp() function. It tests 256 linearly spaced + * input values and checks that the ULP (Unit in the Last Place) error stays + * within acceptable tolerance. + * + * Input values: Q28 format, range -8 to 8 + * Result: Q19 format + * Validation: ULP error < 1.0 ULP + */ +ZTEST(math_advanced_functions_suite, test_function_sofm_exp_approx) +{ + int32_t accum; + int i; + double a_i; + double max_ulp = 0; + double ulp; + double a_tmp = -8; + double b_tmp = 8; + int32_t b_i; + + for (i = 0; i < NUMTESTSAMPLES; i++) { + gen_testvector_linspace_int32(a_tmp, b_tmp, NUMTESTSAMPLES, i, 28, &a_i, &b_i); + accum = sofm_exp_approx(b_i); + ulp = fabs(exp(a_i) - (double)accum / (1 << 19)) / ULP_SCALE; + if (ulp > max_ulp) + max_ulp = ulp; + + zassert_true(ulp <= ULP_TOLERANCE, + "sofm_exp_approx: ULP %.16f exceeds tolerance, value=%.16f, exp=%.16f", + ulp, (double)b_i / (1 << 28), (double)accum / (1 << 19)); + } + + LOG_INF("Worst-case ULP: %g ULP_SCALE %g", max_ulp, ULP_SCALE); +} + +/** + * @brief Test sofm_exp_fixed() function with absolute and relative error validation + * + * This test validates the sofm_exp_fixed() fixed-point exponential function + * against a reference implementation. It performs two sub-tests with different + * input ranges and tolerance requirements. + * + * Sub-test 1: Coarse grid across max range + * - Input values: Q27 format, range -16 to 16 + * - Result: Q20 format + * - Tolerances: abs 2.0e-6, rel 1000.0 + * + * Sub-test 2: Fine grid across typical range + * - Input values: Q27 format, range -11.5 to 7.6245 + * - Result: Q20 format + * - Tolerances: abs 2.0e-6, rel 10.0e-2 + */ +ZTEST(math_advanced_functions_suite, test_function_sofm_exp_fixed) +{ + double rel_delta_max, abs_delta_max; + double tmp; + int32_t ivalue, iexp_value; + int i; + + /* Test max int32_t range with coarse grid */ + rel_delta_max = 0; + abs_delta_max = 0; + for (i = 0; i < NUMTESTSAMPLES_TEST2; i++) { + gen_testvector_linspace_int32(-16, 16, NUMTESTSAMPLES_TEST2, i, 27, &tmp, &ivalue); + test_exp_with_input_value(ivalue, &iexp_value, &abs_delta_max, &rel_delta_max, + ABS_DELTA_TOLERANCE_TEST2, REL_DELTA_TOLERANCE_TEST2); + } + + LOG_INF("Absolute max error was %.6e (max range)", abs_delta_max); + LOG_INF("Relative max error was %.6e (max range)", rel_delta_max); + + /* Test max int32_t middle range with fine grid */ + rel_delta_max = 0; + abs_delta_max = 0; + for (i = 0; i < NUMTESTSAMPLES_TEST3; i++) { + gen_testvector_linspace_int32(SOFM_EXP_FIXED_ARG_MIN, SOFM_EXP_FIXED_ARG_MAX, + NUMTESTSAMPLES_TEST3, i, 27, &tmp, &ivalue); + test_exp_with_input_value(ivalue, &iexp_value, &abs_delta_max, &rel_delta_max, + ABS_DELTA_TOLERANCE_TEST3, REL_DELTA_TOLERANCE_TEST3); + } + + LOG_INF("Absolute max error was %.6e (middle)", abs_delta_max); + LOG_INF("Relative max error was %.6e (middle)", rel_delta_max); +} + +/** + * @brief Test sofm_db2lin_fixed() function for dB to linear conversion + * + * This test validates the sofm_db2lin_fixed() function that converts decibel + * values to linear scale using fixed-point arithmetic. It compares against + * a reference implementation using floating-point pow(10, x/20). + * + * Input values: Q24 format, range -128 to 128 dB + * Result: Q20 format + * Tolerances: abs 2.5e-5, rel 1000.0 + */ +ZTEST(math_advanced_functions_suite, test_function_sofm_db2lin_fixed) +{ + double abs_delta, rel_delta, abs_delta_max, rel_delta_max; + double fin, fout, fref; + double eps = 1e-9; + int32_t iin, iout; + int i; + + rel_delta_max = 0; + abs_delta_max = 0; + for (i = 0; i < NUMTESTSAMPLES_TEST4; i++) { + gen_testvector_linspace_int32(-128, 128, NUMTESTSAMPLES_TEST4, i, 24, &fin, &iin); + iout = sofm_db2lin_fixed(iin); + fout = (double)iout / (1 << 20); + fref = ref_db2lin(fin, 20); + abs_delta = fabs(fref - fout); + rel_delta = abs_delta / (fref + eps); + if (abs_delta > abs_delta_max) + abs_delta_max = abs_delta; + + if (rel_delta > rel_delta_max) + rel_delta_max = rel_delta; + + zassert_true(abs_delta <= ABS_DELTA_TOLERANCE_TEST4, + "sofm_db2lin_fixed: Absolute error %g exceeds limit %g, input %g output %g", + abs_delta, ABS_DELTA_TOLERANCE_TEST4, fin, fout); + + zassert_true(rel_delta <= REL_DELTA_TOLERANCE_TEST4, + "sofm_db2lin_fixed: Relative error %g exceeds limit %g, input %g output %g", + rel_delta, REL_DELTA_TOLERANCE_TEST4, fin, fout); + } + + LOG_INF("Absolute max error was %.6e", abs_delta_max); + LOG_INF("Relative max error was %.6e", rel_delta_max); +} diff --git a/test/ztest/unit/math/advanced/functions/testcase.yaml b/test/ztest/unit/math/advanced/functions/testcase.yaml index 6c2dc68751a5..ea5842503aa1 100644 --- a/test/ztest/unit/math/advanced/functions/testcase.yaml +++ b/test/ztest/unit/math/advanced/functions/testcase.yaml @@ -9,8 +9,8 @@ # tests: - math.advanced.functions: - tags: math advanced functions power + sof.unit.math.advanced.functions: + tags: math advanced functions power logarithm base2 exponential exp db2lin platform_allow: native_sim integration_platforms: - native_sim diff --git a/test/ztest/unit/math/basic/arithmetic/testcase.yaml b/test/ztest/unit/math/basic/arithmetic/testcase.yaml index ca2c40938dae..8afd7eca7daa 100644 --- a/test/ztest/unit/math/basic/arithmetic/testcase.yaml +++ b/test/ztest/unit/math/basic/arithmetic/testcase.yaml @@ -9,7 +9,7 @@ # tests: - math.basic.arithmetic: + sof.unit.math.basic.arithmetic: tags: math arithmetic numbers platform_allow: native_sim integration_platforms: diff --git a/test/ztest/unit/math/basic/complex/testcase.yaml b/test/ztest/unit/math/basic/complex/testcase.yaml index 196cdd00bc84..729fbd762b58 100644 --- a/test/ztest/unit/math/basic/complex/testcase.yaml +++ b/test/ztest/unit/math/basic/complex/testcase.yaml @@ -16,6 +16,6 @@ common: arch_exclude: xtensa # Test is for host builds only tests: - sof.unit.math.complex: + sof.unit.math.basic.complex: platform_allow: - native_sim diff --git a/test/ztest/unit/math/basic/trigonometry/testcase.yaml b/test/ztest/unit/math/basic/trigonometry/testcase.yaml index 037fbcaac456..90bb941c4a22 100644 --- a/test/ztest/unit/math/basic/trigonometry/testcase.yaml +++ b/test/ztest/unit/math/basic/trigonometry/testcase.yaml @@ -19,6 +19,6 @@ common: arch_exclude: xtensa # Test is for host builds only tests: - sof.unit.math.trigonometry: + sof.unit.math.basic.trigonometry: platform_allow: - native_sim diff --git a/test/ztest/unit/objpool/testcase.yaml b/test/ztest/unit/objpool/testcase.yaml index dc137a22adc4..5558c1f50a6b 100644 --- a/test/ztest/unit/objpool/testcase.yaml +++ b/test/ztest/unit/objpool/testcase.yaml @@ -5,7 +5,7 @@ # Object pool allocator unit tests for Ztest framework tests: - sof.objpool: + sof.unit.objpool: tags: unit platform_allow: native_sim integration_platforms: