|
| 1 | +/* Copyright (c) 2024 tinyVision.ai Inc. |
| 2 | + * SPDX-License-Identifier: Apache-2.0 |
| 3 | + */ |
| 4 | + |
| 5 | +#ifndef INCLUDE_ZEPHYR_DSP_MACROS_H_ |
| 6 | +#define INCLUDE_ZEPHYR_DSP_MACROS_H_ |
| 7 | + |
| 8 | +#include <stdint.h> |
| 9 | + |
| 10 | +#include <zephyr/dsp/types.h> |
| 11 | +#include <zephyr/sys/util.h> |
| 12 | + |
| 13 | +/** |
| 14 | + * @brief Definition of the minimum and maximum values of the internal representation |
| 15 | + * |
| 16 | + * @note The value represented is always between -1.0 and 1.0 for any storage size. |
| 17 | + * Scaling variables imported before using them in fixed-points is required. |
| 18 | + * |
| 19 | + * @{ |
| 20 | + */ |
| 21 | + |
| 22 | +/** Minimum internal value for Q.7. */ |
| 23 | +#define MINq7 INT8_MIN |
| 24 | + |
| 25 | +/** Minimum internal value for Q.15. */ |
| 26 | +#define MINq15 INT16_MIN |
| 27 | + |
| 28 | +/** Minimum internal value for Q.31. */ |
| 29 | +#define MINq31 INT32_MIN |
| 30 | + |
| 31 | +/** Maximum internal value for Q.7. */ |
| 32 | +#define MAXq7 INT8_MAX |
| 33 | + |
| 34 | +/** Maximum internal value for Q.15. */ |
| 35 | +#define MAXq15 INT16_MAX |
| 36 | + |
| 37 | +/** Maximum internal value for Q.31. */ |
| 38 | +#define MAXq31 INT32_MAX |
| 39 | + |
| 40 | +/* @} |
| 41 | + */ |
| 42 | + |
| 43 | +/** |
| 44 | + * @brief Clamp a fixed-point value to -1.0 to 1.0. |
| 45 | + * |
| 46 | + * @note Useful for internal use, or when breaking the abstraction barrier. |
| 47 | + * |
| 48 | + * @{ |
| 49 | + */ |
| 50 | + |
| 51 | +/** Enforce the a Q.7 fixed-point to be between -1.0 and 1.0 */ |
| 52 | +#define CLAMPq7(q7) ((q7_t)CLAMP((q7), MINq7, MAXq7)) |
| 53 | + |
| 54 | +/** Enforce the a Q.15 fixed-point to be between -1.0 and 1.0 */ |
| 55 | +#define CLAMPq15(q15) ((q15_t)CLAMP((q15), MINq15, MAXq15)) |
| 56 | + |
| 57 | +/** Enforce the a Q.31 fixed-point to be between -1.0 and 1.0 */ |
| 58 | +#define CLAMPq31(q31) ((q31_t)CLAMP((q31), MINq31, MAXq31)) |
| 59 | + |
| 60 | +/* @} |
| 61 | + */ |
| 62 | + |
| 63 | +/** |
| 64 | + * @brief Construct a fixed-point number out of a floating point number. |
| 65 | + * |
| 66 | + * The input float can be an expression or a single number. |
| 67 | + * If it is below -1.0 or above 1.0, it is adjusted to fit the -1.0 to 1.0 range. |
| 68 | + * |
| 69 | + * @example "Q15(-1.0) // Minimum value" |
| 70 | + * @example "Q31(1.0) // Maximum value" |
| 71 | + * @example "Q15(1.3) // Will become 1.0" |
| 72 | + * @example "Q7(f - 1.0)" |
| 73 | + * @example "Q15(2.0 / 3.1415)" |
| 74 | + * |
| 75 | + * @param f Floating-point number to convert into a fixed-point number. |
| 76 | + * |
| 77 | + * @{ |
| 78 | + */ |
| 79 | + |
| 80 | +/** Construct a Q.7 fixed-point: 1 bit for the sign, 7 bits of fractional part */ |
| 81 | +#define Q7f(f) CLAMPq7((f) * (1ll << 7)) |
| 82 | + |
| 83 | +/** Construct a Q.15 fixed-point: 1 bit for the sign, 15 bits of fractional part */ |
| 84 | +#define Q15f(f) CLAMPq15((f) * (1ll << 15)) |
| 85 | + |
| 86 | +/** Construct a Q.31 fixed-point: 1 bit for the sign, 31 bits of fractional part */ |
| 87 | +#define Q31f(f) CLAMPq31((f) * (1ll << 31)) |
| 88 | + |
| 89 | +/* @} |
| 90 | + */ |
| 91 | + |
| 92 | +/** |
| 93 | + * @brief Construct a fixed-point out of an integer and a scale. |
| 94 | + * |
| 95 | + * This permits to work with numbers above the -1.0 to 1.0 range: |
| 96 | + * The minimum and maximum possible value of the input number are specified. |
| 97 | + * The input number is then scaled so that the minimum value becomes -1.0 and |
| 98 | + * maximum value becomes 1.0. |
| 99 | + * Once the computation is done in fixed piotn, it is popssible to get an |
| 100 | + * unscaled value with @ref INTq7, @ref INtq15 and @rev INTq31. |
| 101 | + * |
| 102 | + * @example "Q15i(temperature, -20, 200)" |
| 103 | + * @example "Q15i(angle, 0, 360)" |
| 104 | + * @example "Q15i(voltage, V_MIN, V_MAX)" |
| 105 | + * |
| 106 | + * @param i Input number to convert to a fixed-point representation |
| 107 | + * @param min Minimum value that @p i can take. |
| 108 | + * The same minimum value is used to convert the numbers back. |
| 109 | + * @param max Maximum value that @p i can take. |
| 110 | + * The same maximum value is used to convert the numbers back. |
| 111 | + * |
| 112 | + * @{ |
| 113 | + */ |
| 114 | + |
| 115 | +/** Build a Q.7 number by scaling @p i range from [min, max] (at most [ , ]) to [-1.0, 1.0] */ |
| 116 | +#define Q7i(i, min, max) CLAMPq7(SCALE((i), (min), (max), MINq7, MAXq7)) |
| 117 | + |
| 118 | +/** Build a Q.15 number by scaling @p i range from [min, max] to [-1.0, 1.0] */ |
| 119 | +#define Q15i(i, min, max) CLAMPq15(SCALE((i), (min), (max), MINq15, MAXq15)) |
| 120 | + |
| 121 | +/** Build a Q.31 number by scaling @p i range from [min, max] to [-1.0, 1.0] */ |
| 122 | +#define Q31i(i, min, max) CLAMPq31(SCALE((i), (min), (max), MINq31, MAXq31)) |
| 123 | + |
| 124 | +/* @} |
| 125 | + */ |
| 126 | + |
| 127 | +/** |
| 128 | + * @brief Convert fixed-points from one size to another |
| 129 | + * |
| 130 | + * This permits to increase or decrease the precision by switching between |
| 131 | + * smaller and larger representation. |
| 132 | + * The values represented does not change except due to loss of precision. |
| 133 | + * The minimum value remains -1.0 and maximum value remains 1.0. |
| 134 | + * Only the internal representation is scaled. |
| 135 | + * |
| 136 | + * @{ |
| 137 | + */ |
| 138 | + |
| 139 | +/** Build a Q.7 number out of a Q.15 number, losing 8 bits of precision */ |
| 140 | +#define Q7q15(q15) (q7_t)((q15) / (1 << 8)) |
| 141 | + |
| 142 | +/** Build a Q.7 number out of a Q.31 number, losing 24 bits of precision */ |
| 143 | +#define Q7q31(q31) (q7_t)((q31) / (1 << 24)) |
| 144 | + |
| 145 | +/** Build a Q.15 number out of a Q.7 number, gaining 8 bits of precision */ |
| 146 | +#define Q15q7(q7) CLAMPq15((q15_t)(q7) * (1 << 8)) |
| 147 | + |
| 148 | +/** Build a Q.15 number out of a Q.31 number, losing 16 bits of precision */ |
| 149 | +#define Q15q31(q31) (q15_t)((q31) / (1 << 16)) |
| 150 | + |
| 151 | +/** Build a Q.31 number out of a Q.7 number, gaining 24 bits of precision */ |
| 152 | +#define Q31q7(q7) CLAMPq31((q31_t)(q7) * (1 << 24)) |
| 153 | + |
| 154 | +/** Build a Q.31 number out of a Q.15 number, gaining 16 bits of precision */ |
| 155 | +#define Q31q15(q15) CLAMPq31((q31_t)(q15) * (1 << 16)) |
| 156 | + |
| 157 | +/* @} |
| 158 | + */ |
| 159 | + |
| 160 | +/** |
| 161 | + * @brief Convert a fixed-point number back to an natural representation. |
| 162 | + * |
| 163 | + * This permits to extract a result value out of a fixed-point number, |
| 164 | + * to reverse the effect of @ref Q7i, @ref Q15i and @ref Q31i. |
| 165 | + * |
| 166 | + * @param i The fixed-point number to convert to a natural number. |
| 167 | + * @param min The minimum value specified to create the fixed-point. |
| 168 | + * @param max The maximum value specified to create the fixed-point. |
| 169 | + * |
| 170 | + * @{ |
| 171 | + */ |
| 172 | + |
| 173 | +/** Convert a Q.7 fixed-point number to a natural integer */ |
| 174 | +#define INTq7(i, min, max) SCALE((i), MINq7, MAXq7, (min), (max)) |
| 175 | + |
| 176 | +/** Convert a Q.15 fixed-point number to a natural integer */ |
| 177 | +#define INTq15(i, min, max) SCALE((i), MINq15, MAXq15, (min), (max)) |
| 178 | + |
| 179 | +/** Convert a Q.31 fixed-point number to a natural integer */ |
| 180 | +#define INTq31(i, min, max) SCALE((i), MINq31, MAXq31, (min), (max)) |
| 181 | + |
| 182 | +/* @} |
| 183 | + */ |
| 184 | + |
| 185 | +/** |
| 186 | + * @brief Add two fixed-point numbers together. |
| 187 | + * |
| 188 | + * Saturation logic is applied, so number out of ranges will be converted |
| 189 | + * to the minimum -1.0 or maximum 1.0 value instead of overflowing. |
| 190 | + * |
| 191 | + * @note If two fixed-point numbers are to be subtracted into a larger type |
| 192 | + * such as Q.7 + Q.7 = Q.15, the C operator @c + can be used instead. |
| 193 | + * |
| 194 | + * @param a First number to add. |
| 195 | + * @param b Second number to add. |
| 196 | + * |
| 197 | + * @{ |
| 198 | + */ |
| 199 | + |
| 200 | +/** Sum two Q.7 numbers and produce a Q.7 result */ |
| 201 | +#define ADDq7(a, b) CLAMPq7((int16_t)(a) + (int16_t)(b)) |
| 202 | + |
| 203 | +/** Sum two Q.15 numbers and produce a Q.15 result */ |
| 204 | +#define ADDq15(a, b) CLAMPq15((int32_t)(a) + (int32_t)(b)) |
| 205 | + |
| 206 | +/** Sum two Q.31 numbers and produce a Q.31 result */ |
| 207 | +#define ADDq31(a, b) CLAMPq31((int64_t)(a) + (int64_t)(b)) |
| 208 | + |
| 209 | +/* @} |
| 210 | + */ |
| 211 | + |
| 212 | +/** |
| 213 | + * @brief Subtract a fixed-point number to another. |
| 214 | + * |
| 215 | + * Saturation logic is applied, so number out of ranges will be converted |
| 216 | + * to the minimum 1.0 or maximum -1.0 value instead of overflowing. |
| 217 | + * |
| 218 | + * @note If two fixed-point numbers are to be subtracted into a larger type |
| 219 | + * such as Q.7 - Q.7 = Q.15, the C operator @c - can be used instead. |
| 220 | + * |
| 221 | + * @param a First number to add. |
| 222 | + * @param a Second number to add. |
| 223 | + * |
| 224 | + * @{ |
| 225 | + */ |
| 226 | + |
| 227 | +/** Subtract two Q.7 numbers and produce a Q.7 result */ |
| 228 | +#define SUBq7(a, b) CLAMPq7((int16_t)(a) - (int16_t)(b)) |
| 229 | + |
| 230 | +/** Subtract two Q.15 numbers and produce a Q.15 result */ |
| 231 | +#define SUBq15(a, b) CLAMPq15((int32_t)(a) - (int32_t)(b)) |
| 232 | + |
| 233 | +/** Subtract two Q.31 numbers and produce a Q.31 result */ |
| 234 | +#define SUBq31(a, b) CLAMPq31((int64_t)(a) - (int64_t)(b)) |
| 235 | + |
| 236 | +/* @} |
| 237 | + */ |
| 238 | + |
| 239 | +/** |
| 240 | + * @brief Multiply two fixed-point numbers together. |
| 241 | + * |
| 242 | + * Saturation logic is applied, so number out of range will be converted |
| 243 | + * to handle the edge case Q#f(-1.0) * Q#f(-1.0) = Q#f(1.0) |
| 244 | + * |
| 245 | + * @note This implementation does not perform rounding. |
| 246 | + * |
| 247 | + * @param a First number to add. |
| 248 | + * @param b Second number to add. |
| 249 | + * |
| 250 | + * @{ |
| 251 | + */ |
| 252 | + |
| 253 | +/** Multiply two Q.7 numbers and produce a Q.7 result */ |
| 254 | +#define MULq7(a, b) CLAMPq7(((int16_t)(a) * (int16_t)(b)) / (1 << 7)) |
| 255 | + |
| 256 | +/** Multiply two Q.15 numbers and produce a Q.15 result */ |
| 257 | +#define MULq15(a, b) CLAMPq15(((int32_t)(a) * (int32_t)(b)) / (1 << 15)) |
| 258 | + |
| 259 | +/** Multiply two Q.31 numbers and produce a Q.31 result */ |
| 260 | +#define MULq31(a, b) CLAMPq31(((int64_t)(a) * (int64_t)(b)) / (1 << 31)) |
| 261 | + |
| 262 | +/* @} |
| 263 | + */ |
| 264 | + |
| 265 | +/** |
| 266 | + * @brief Divide two fixed-point numbers together. |
| 267 | + * |
| 268 | + * Saturation logic is applied, so number out of ranges will be converted |
| 269 | + * to the minimum -1.0 or maximum 1.0 value instead of overflowing. |
| 270 | + * |
| 271 | + * @note This implementation does not perform rounding. |
| 272 | + * |
| 273 | + * @param a Numerator of the division. |
| 274 | + * @param b Denominator of the division. |
| 275 | + * |
| 276 | + * @{ |
| 277 | + */ |
| 278 | + |
| 279 | +/** Divide a Q.7 number and produce a Q.7 result */ |
| 280 | +#define DIVq7(a, b) CLAMPq7((a) * (1 << 7) / (b)) |
| 281 | + |
| 282 | +/** Divide a Q.15 number and produce a Q.15 result */ |
| 283 | +#define DIVq15(a, b) CLAMPq15((a) * (1 << 15) / (b)) |
| 284 | + |
| 285 | +/** Divide a Q.31 number and produce a Q.31 result */ |
| 286 | +#define DIVq31(a, b) CLAMPq31((a) * (1 << 31) / (b)) |
| 287 | + |
| 288 | +/* @} |
| 289 | + */ |
| 290 | + |
| 291 | +/** |
| 292 | + * @brief Apply the opposite value of the fixed-point number. |
| 293 | + * |
| 294 | + * Saturation logic is applied, as the most negative number could |
| 295 | + * overflow internally if converted to positive. |
| 296 | + * |
| 297 | + * @param a Number to get the opposite value for |
| 298 | + * |
| 299 | + * @{ |
| 300 | + */ |
| 301 | + |
| 302 | +/** Get the negation of a Q.7 number and produce a Q.7 result */ |
| 303 | +#define NEGq7(a) (q7_t)((a) == MINq7 ? MAXq7 : -(a)) |
| 304 | + |
| 305 | +/** Get the negation of a Q.15 number and produce a Q.15 result */ |
| 306 | +#define NEGq15(a) (q15_t)((a) == MINq15 ? MAXq15 : -(a)) |
| 307 | + |
| 308 | +/** Get the negation of a Q.15 number and produce a Q.15 result */ |
| 309 | +#define NEGq31(a) (q31_t)((a) == MINq31 ? MAXq31 : -(a)) |
| 310 | + |
| 311 | +/* @} |
| 312 | + */ |
| 313 | + |
| 314 | +/** |
| 315 | + * @brief Get the absolute value of a fixed-point number. |
| 316 | + * |
| 317 | + * Saturation logic is applied, as the most negative number overflows if |
| 318 | + * converted to positive. |
| 319 | + * |
| 320 | + * @param a Number to get the absolute value for. |
| 321 | + * |
| 322 | + * @{ |
| 323 | + */ |
| 324 | + |
| 325 | +/** Get the absolute value of a Q.7 number and produce a Q.7 result */ |
| 326 | +#define ABSq7(a) (q7_t)((a) < 0 ? NEGq7(a) : (a)) |
| 327 | + |
| 328 | +/** Get the absolute value of a Q.15 number and produce a Q.15 result */ |
| 329 | +#define ABSq15(a) (q15_t)((a) < 0 ? NEGq15(a) : (a)) |
| 330 | + |
| 331 | +/** Get the absolute value of a Q.31 number and produce a Q.31 result */ |
| 332 | +#define ABSq31(a) (q31_t)((a) < 0 ? NEGq31(a) : (a)) |
| 333 | + |
| 334 | +/* @} |
| 335 | + */ |
| 336 | + |
| 337 | +#endif /* INCLUDE_ZEPHYR_DSP_MACROS_H_ */ |
0 commit comments