Mercurial > ~darius > hgwebdir.cgi > modulator
view q/q.h @ 30:92fdf2ef995d default tip
Use 32 bit rather than 16 bit ints for loop vars.
No risk of overflow and is actually faster.
author | Daniel O'Connor <darius@dons.net.au> |
---|---|
date | Thu, 27 Feb 2025 15:24:17 +1030 |
parents | 388074ff9474 |
children |
line wrap: on
line source
/* 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