Mercurial > ~darius > hgwebdir.cgi > modulator
diff q/q.h @ 14:388074ff9474
Add fixed point code
author | Daniel O'Connor <darius@dons.net.au> |
---|---|
date | Tue, 25 Feb 2025 13:28:29 +1030 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/q/q.h Tue Feb 25 13:28:29 2025 +1030 @@ -0,0 +1,329 @@ +/* Project: Q-Number (Q16.16, signed) library + * Author: Richard James Howe + * License: The Unlicense + * Email: howe.r.j.89@gmail.com + * Repo: <https://github.com/q> */ + +#ifndef Q_H +#define Q_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include <stddef.h> + +#define QMAX_ID (32) +#define QMAX_ERROR (256) + +#define QBITS (12) +#define QMASK ((1ULL << QBITS) - 1ULL) +#define QHIGH (1ULL << (QBITS - 1ULL)) + +#define QMK(QHIGH, LOW, SF) ((ld_t)((((lu_t)QHIGH) << QBITS) | (QMASK & ((((lu_t)LOW) << QBITS) >> (SF))))) +#define QINT(INT) ((q_t)((u_t)(INT) << QBITS)) +#define QPI (QMK(0x3, 0x243F, 16)) + +#ifndef PREPACK +#define PREPACK +#endif + +#ifndef POSTPACK +#define POSTPACK +#endif + +#ifndef RESTRICT +#ifdef __cplusplus +#define RESTRICT +#else +#define RESTRICT restrict +#endif +#endif + +typedef int32_t q_t; /* Q Fixed Point Number, (Q16.16, Signed) */ +typedef int64_t ld_t; /* Double width of Q, signed, for internal calculations, not in Q format */ +typedef int32_t d_t; /* same width as Q, signed, but not in Q format */ +typedef uint32_t u_t; /* same width as Q, unsigned, but not in Q format */ + +typedef PREPACK struct { + size_t whole, /* number of bits for whole, or integer, part of Q number */ + fractional; /* number of bits for fractional part of Q number */ + const q_t zero, /* the constant '0' */ + bit, /* smallest 'q' number representable */ + one, /* the constant '1' */ + pi, /* the constant 'pi' */ + e, /* the constant 'e' */ + sqrt2, /* the square root of 2 */ + sqrt3, /* the square root of 3 */ + ln2, /* the natural logarithm of 2 */ + ln10, /* the natural logarithm of 10 */ + min, /* most negative 'q' number */ + max; /* most positive 'q' number */ + const uint32_t version; /* version in X.Y.Z format (Z = lowest 8 bits) */ +} POSTPACK qinfo_t; + +typedef PREPACK struct { + q_t rc, /* time constant */ + time, /* time of previous measurement */ + raw, /* previous raw value */ + filtered; /* filtered value */ +} POSTPACK qfilter_t; /* High/Low Pass Filter */ + +typedef PREPACK struct { + q_t d_gain, d_state; /* differentiator; gain, state */ + q_t i_gain, i_state, i_min, i_max; /* integrator; gain, state, minimum and maximum */ + q_t p_gain; /* proportional gain */ +} POSTPACK qpid_t; /* PID Controller <https://en.wikipedia.org/wiki/PID_controller> */ + +struct qexpr; +typedef struct qexpr qexpr_t; + +typedef PREPACK struct { + char *name; + union { + q_t (*unary) (q_t a); + q_t (*binary) (q_t a1, q_t a2); + } eval; + union { + q_t (*unary) (qexpr_t *e, q_t a); + q_t (*binary) (qexpr_t *e, q_t a1, q_t a2); + } check; + int precedence, arity, assocativity, hidden; +} POSTPACK qoperations_t; /* use in the expression evaluator */ + +typedef PREPACK struct { + char *name; + q_t value; +} POSTPACK qvariable_t; /* Variable which can be used with the expression evaluator */ + +struct PREPACK qexpr { + const qoperations_t **ops, *lpar, *rpar, *negate, *minus; + qvariable_t **vars; + char id[QMAX_ID]; + char error_string[QMAX_ERROR]; + q_t number; + const qoperations_t *op; + q_t *numbers; + size_t ops_count, ops_max; + size_t numbers_count, numbers_max; + size_t id_count; + size_t vars_max; + int error; + int initialized; +} POSTPACK; /* An expression evaluator for the Q library */ + +typedef q_t (*qbounds_t)(ld_t s); + +q_t qbound_saturate(ld_t s); /* default over/underflow behavior, saturation */ +q_t qbound_wrap(ld_t s); /* over/underflow behavior, wrap around */ + +typedef PREPACK struct { + qbounds_t bound; /* handles saturation when a number over or underflows */ + int dp; /* decimal points to print, negative specifies maximum precision */ + unsigned base; /* base to use for numeric number conversion */ +} POSTPACK qconf_t; /* Q format configuration options */ + +extern const qinfo_t qinfo; /* information about the format and constants */ +extern qconf_t qconf; /* @warning GLOBAL Q configuration options */ + +int qtoi(q_t toi); +q_t qint(int toq); +signed char qtoc(const q_t q); +q_t qchar(signed char c); +short qtoh(const q_t q); +q_t qshort(short s); +long qtol(const q_t q); +q_t qlong(long l); +long long qtoll(const q_t q); +q_t qvlong(long long ll); + +q_t qisnegative(q_t a); +q_t qispositive(q_t a); +q_t qisinteger(q_t a); +q_t qisodd(q_t a); +q_t qiseven(q_t a); + +q_t qless(q_t a, q_t b); +q_t qmore(q_t a, q_t b); +q_t qeqless(q_t a, q_t b); +q_t qeqmore(q_t a, q_t b); +q_t qequal(q_t a, q_t b); +q_t qunequal(q_t a, q_t b); +q_t qapproxequal(q_t a, q_t b, q_t epsilon); +q_t qapproxunequal(q_t a, q_t b, q_t epsilon); +q_t qwithin(q_t v, q_t b1, q_t b2); +q_t qwithin_interval(q_t v, q_t expected, q_t allowance); + +q_t qnegate(q_t a); +q_t qmin(q_t a, q_t b); +q_t qmax(q_t a, q_t b); +q_t qabs(q_t a); +q_t qcopysign(q_t a, q_t b); +q_t qsign(q_t a); +q_t qsignum(q_t a); + +q_t qadd(q_t a, q_t b); +q_t qsub(q_t a, q_t b); +q_t qmul(q_t a, q_t b); +q_t qdiv(q_t a, q_t b); +q_t qrem(q_t a, q_t b); +q_t qmod(q_t a, q_t b); +q_t qfma(q_t a, q_t b, q_t c); +q_t qsqr(q_t x); +q_t qexp(q_t e); +q_t qlog(q_t n); +q_t qsqrt(q_t x); + +q_t qround(q_t q); +q_t qceil(q_t q); +q_t qtrunc(q_t q); +q_t qfloor(q_t q); + +q_t qand(q_t a, q_t b); +q_t qxor(q_t a, q_t b); +q_t qor(q_t a, q_t b); +q_t qinvert(q_t a); +q_t qnot(q_t a); +q_t qlogical(q_t a); + +q_t qlls(q_t a, q_t b); +q_t qlrs(q_t a, q_t b); +q_t qals(q_t a, q_t b); +q_t qars(q_t a, q_t b); + +q_t qpow(q_t n, q_t exp); + +int qsprint(q_t p, char *s, size_t length); +int qsprintb(q_t p, char *s, size_t length, u_t base); +int qsprintbdp(q_t p, char *s, size_t length, u_t base, d_t idp); +int qnconv(q_t *q, const char *s, size_t length); +int qnconvb(q_t *q, const char *s, size_t length, d_t base); +int qconv(q_t *q, const char *s); +int qconvb(q_t *q, const char * const s, d_t base); +int qnconvbdp(q_t *q, const char *s, size_t length, d_t base, u_t idp); + +void qsincos(q_t theta, q_t *sine, q_t *cosine); +q_t qsin(q_t theta); +q_t qcos(q_t theta); +q_t qtan(q_t theta); +q_t qcot(q_t theta); +q_t qhypot(q_t a, q_t b); + +q_t qatan(q_t t); +q_t qatan2(q_t x, q_t y); +q_t qasin(q_t t); +q_t qacos(q_t t); +q_t qsinh(q_t a); +q_t qcosh(q_t a); +q_t qtanh(q_t a); + +q_t qatanh(q_t t); +q_t qasinh(q_t t); +q_t qacosh(q_t t); + +void qsincosh(q_t a, q_t *sinh, q_t *cosh); + +q_t qcordic_ln(q_t d); /* CORDIC testing only */ +q_t qcordic_exp(q_t e); /* CORDIC testing only; useless for large values */ +q_t qcordic_sqrt(q_t a); /* CORDIC testing only; do not use, a <= 2, a >= 0 */ +q_t qcordic_mul(q_t a, q_t b); /* CORDIC testing only; do not use */ +q_t qcordic_div(q_t a, q_t b); /* CORDIC testing only; do not use */ +q_t qcordic_circular_gain(int n); +q_t qcordic_hyperbolic_gain(int n); + +void qpol2rec(q_t magnitude, q_t theta, q_t *i, q_t *j); +void qrec2pol(q_t i, q_t j, q_t *magnitude, q_t *theta); + +q_t qrad2deg(q_t rad); +q_t qdeg2rad(q_t deg); + +d_t dpower(d_t b, unsigned e); +d_t dlog(d_t n, unsigned base); +d_t arshift(d_t v, unsigned p); +int qpack(const q_t *q, char *buffer, size_t length); +int qunpack(q_t *q, const char *buffer, size_t length); + +q_t qsimpson(q_t (*f)(q_t), q_t x1, q_t x2, unsigned n); /* numerical integrator of f, between x1, x2, for n steps */ + +void qfilter_init(qfilter_t *f, q_t time, q_t rc, q_t seed); +q_t qfilter_low_pass(qfilter_t *f, q_t time, q_t data); +q_t qfilter_high_pass(qfilter_t *f, q_t time, q_t data); +q_t qfilter_value(const qfilter_t *f); + +q_t qpid_update(qpid_t *pid, const q_t error, const q_t position); + +/* A matrix consists of at least four elements, a meta data field, + * the length of the array (which must be big enough to store + * row*column, but may be * larger) and a row and a column count + * in unsigned integer format, and the array elements in Q format. + * This simplifies storage and declaration of matrices. + * + * An example, the 2x3 matrix: + * + * [ 1, 2, 3; 4, 5, 6 ] + * + * Should be defined as: + * + * q_t m[] = { 0, 2*3, 2, 3, QINT(1), QINT(2), QINT(3), QINT(4), QINT(5), QINT(6) }; + * + */ +int qmatrix_apply_unary(q_t *r, const q_t *a, q_t (*func)(q_t)); +int qmatrix_apply_scalar(q_t *r, const q_t *a, q_t (*func)(q_t, q_t), const q_t c); +int qmatrix_apply_binary(q_t * RESTRICT r, const q_t *a, const q_t *b, q_t (*func)(q_t, q_t)); +int qmatrix_sprintb(const q_t *m, char *str, size_t length, unsigned base); +int qmatrix_resize(q_t *m, const size_t row, const size_t column); +int qmatrix_copy(q_t *r, const q_t *a); +size_t qmatrix_string_length(const q_t *m); + +q_t qmatrix_trace(const q_t *m); +q_t qmatrix_determinant(const q_t *m); +q_t qmatrix_equal(const q_t *a, const q_t *b); + +int qmatrix_zero(q_t *r); +int qmatrix_one(q_t *r); +int qmatrix_identity(q_t *r); /* turn into identity matrix, r must be square */ + +int qmatrix_logical(q_t *r, const q_t *a); +int qmatrix_not(q_t *r, const q_t *a); +int qmatrix_signum(q_t *r, const q_t *a); +int qmatrix_invert(q_t *r, const q_t *a); + +int qmatrix_is_valid(const q_t *m); +int qmatrix_is_square(const q_t *m); + +int qmatrix_transpose(q_t * RESTRICT r, const q_t * RESTRICT m); +int qmatrix_add(q_t * RESTRICT r, const q_t *a, const q_t *b); +int qmatrix_sub(q_t * RESTRICT r, const q_t *a, const q_t *b); +int qmatrix_mul(q_t * RESTRICT r, const q_t *a, const q_t *b); +int qmatrix_and(q_t *r, const q_t *a, const q_t *b); +int qmatrix_or (q_t *r, const q_t *a, const q_t *b); +int qmatrix_xor(q_t *r, const q_t *a, const q_t *b); + +int qmatrix_scalar_add(q_t *r, const q_t *a, const q_t scalar); +int qmatrix_scalar_sub(q_t *r, const q_t *a, const q_t scalar); +int qmatrix_scalar_mul(q_t *r, const q_t *a, const q_t scalar); +int qmatrix_scalar_div(q_t *r, const q_t *a, const q_t scalar); +int qmatrix_scalar_mod(q_t *r, const q_t *a, const q_t scalar); +int qmatrix_scalar_rem(q_t *r, const q_t *a, const q_t scalar); +int qmatrix_scalar_and(q_t *r, const q_t *a, const q_t scalar); +int qmatrix_scalar_or (q_t *r, const q_t *a, const q_t scalar); +int qmatrix_scalar_xor(q_t *r, const q_t *a, const q_t scalar); + +/* Expression evaluator */ + +int qexpr(qexpr_t *e, const char *expr); +int qexpr_init(qexpr_t *e); +int qexpr_error(qexpr_t *e); +q_t qexpr_result(qexpr_t *e); +const qoperations_t *qop(const char *op); + +/* A better cosine/sine, not in Q format */ + +int16_t furman_sin(int16_t x); /* SINE: 1 Furman = 1/65536 of a circle */ +int16_t furman_cos(int16_t x); /* COSINE: 1 Furman = 1/65536 of a circle */ + +#ifdef __cplusplus +} +#endif +#endif