From patchwork Wed Apr 24 07:44:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 19935 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 91916C3200 for ; Wed, 24 Apr 2024 07:44:36 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6EA5C633ED; Wed, 24 Apr 2024 09:44:35 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="G9FTynnY"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E855E61B14 for ; Wed, 24 Apr 2024 09:44:33 +0200 (CEST) Received: from pyrite.hamster-moth.ts.net (h175-177-049-156.catv02.itscom.jp [175.177.49.156]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id EC7F9B1; Wed, 24 Apr 2024 09:43:40 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1713944622; bh=r8eS9lDyLCVKJ7GtzSqXzFLJ+nXVadwK6EuA6mBSp6I=; h=From:To:Cc:Subject:Date:From; b=G9FTynnYjGew/3xymZHQWdHXWHIIKT+xsjhl2KFTMECsZNCyx6dy2JIKtyAOIcyrm wRzLmzHhdNIM2oeDpNVEfjbxwqLzLMzlMWdVNwHS4KqMI/QRTnWGuN6wTLt1ax3oqQ XEzzSZkfjepmmxI1CAtdm93LJUs0III0zakaHHZc= From: Paul Elder To: libcamera-devel@lists.libcamera.org Cc: Paul Elder Subject: [PATCH v2] libcamera: utils: Add a helper to convert floating-point to fixed-point Date: Wed, 24 Apr 2024 16:44:09 +0900 Message-Id: <20240424074409.1275425-1-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.39.2 MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add helper functions for converting between floating point and fixed point numbers. Also add tests for them. Signed-off-by: Paul Elder --- Changes in v2: - added the reverse conversion function (fixed -> floating) - added tests - make the conversion code cleaner --- include/libcamera/base/utils.h | 37 +++++++++++++++++++++++++ src/libcamera/base/utils.cpp | 20 ++++++++++++++ test/utils.cpp | 49 ++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+) diff --git a/include/libcamera/base/utils.h b/include/libcamera/base/utils.h index 37d9af60..da0767e3 100644 --- a/include/libcamera/base/utils.h +++ b/include/libcamera/base/utils.h @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -369,6 +370,42 @@ decltype(auto) abs_diff(const T &a, const T &b) double strtod(const char *__restrict nptr, char **__restrict endptr); +#ifndef __DOXYGEN__ +template && + std::is_floating_point_v> * = nullptr> +#else +template +#endif +constexpr R floatingToFixedPoint(T number) +{ + static_assert(I + F <= sizeof(R) * 8); + + R maskI = (1 << I) - 1; + R whole = (static_cast(number) & maskI) << F; + + R maskF = (1 << F) - 1; + R frac = static_cast(std::round(number * (1 << F))) & maskF; + + return whole | frac; +} + +#ifndef __DOXYGEN__ +template && + std::is_integral_v> * = nullptr> +#else +template +#endif +constexpr R fixedToFloatingPoint(T number) +{ + static_assert(I + F <= sizeof(T) * 8); + + int coeff = number >> (I + F - 1) ? -1 : 1; + + return coeff * static_cast(number) / static_cast(1 << F); +} + } /* namespace utils */ #ifndef __DOXYGEN__ diff --git a/src/libcamera/base/utils.cpp b/src/libcamera/base/utils.cpp index 3b73b442..ba36026d 100644 --- a/src/libcamera/base/utils.cpp +++ b/src/libcamera/base/utils.cpp @@ -521,6 +521,26 @@ double strtod(const char *__restrict nptr, char **__restrict endptr) #endif } +/** + * \fn R floatingToFixedPoint(T number) + * \brief Convert a floating point number to a fixed-point representation + * \tparam I Bit width of the integer part of the fixed-point + * \tparam F Bit width of the fractional part of the fixed-point + * \tparam R Return type of the fixed-point representation + * \tparam T Input type of the floating point representation + * \return The converted value + */ + +/** + * \fn R fixedToFloatingPoint(T number) + * \brief Convert a fixed-point number to a floating point representation + * \tparam I Bit width of the integer part of the fixed-point + * \tparam F Bit width of the fractional part of the fixed-point + * \tparam R Return type of the floating point representation + * \tparam T Input type of the fixed-point representation + * \return The converted value + */ + } /* namespace utils */ #ifndef __DOXYGEN__ diff --git a/test/utils.cpp b/test/utils.cpp index fc56e14e..f1805207 100644 --- a/test/utils.cpp +++ b/test/utils.cpp @@ -170,6 +170,51 @@ protected: return TestPass; } + template + int testSingleFixedPoint(double input, T expected) + { + T ret = utils::floatingToFixedPoint(input); + if (ret != expected) { + cerr << "Expected " << input << " to convert to " + << expected << ", got " << ret << std::endl; + return TestFail; + } + + /* + * The precision check is fairly arbitrary but is based on what + * the rkisp1 is capable of in the crosstalk module. + */ + double f = utils::fixedToFloatingPoint(ret); + if (std::abs(f - input) > 0.001) { + cerr << "Reverse conversion expected " << ret + << " to convert to " << input + << ", got " << f << std::endl; + return TestFail; + } + + return TestPass; + } + + int testFixedPoint() + { + /* These are the only cases that we know for certain */ + std::map testCases = { + { 7.992, 0x3FF }, + { -8, 0x400 }, + { 0, 0 }, + }; + + int ret; + for (const auto &testCase : testCases) { + ret = testSingleFixedPoint<4, 7, uint16_t>(testCase.first, + testCase.second); + if (ret != TestPass) + return ret; + } + + return TestPass; + } + int run() { /* utils::hex() test. */ @@ -290,6 +335,10 @@ protected: if (testDuration() != TestPass) return TestFail; + /* fixed point conversion test */ + if (testFixedPoint() != TestPass) + return TestFail; + return TestPass; } };