Mercurial > ~darius > hgwebdir.cgi > modulator
comparison 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 |
comparison
equal
deleted
inserted
replaced
13:032acb7fbc04 | 14:388074ff9474 |
---|---|
1 /* Project: Q-Number (Q16.16, signed) library | |
2 * Author: Richard James Howe | |
3 * License: The Unlicense | |
4 * Email: howe.r.j.89@gmail.com | |
5 * Repo: <https://github.com/q> */ | |
6 | |
7 #ifndef Q_H | |
8 #define Q_H | |
9 | |
10 #ifdef __cplusplus | |
11 extern "C" { | |
12 #endif | |
13 | |
14 #include <stdint.h> | |
15 #include <stddef.h> | |
16 | |
17 #define QMAX_ID (32) | |
18 #define QMAX_ERROR (256) | |
19 | |
20 #define QBITS (12) | |
21 #define QMASK ((1ULL << QBITS) - 1ULL) | |
22 #define QHIGH (1ULL << (QBITS - 1ULL)) | |
23 | |
24 #define QMK(QHIGH, LOW, SF) ((ld_t)((((lu_t)QHIGH) << QBITS) | (QMASK & ((((lu_t)LOW) << QBITS) >> (SF))))) | |
25 #define QINT(INT) ((q_t)((u_t)(INT) << QBITS)) | |
26 #define QPI (QMK(0x3, 0x243F, 16)) | |
27 | |
28 #ifndef PREPACK | |
29 #define PREPACK | |
30 #endif | |
31 | |
32 #ifndef POSTPACK | |
33 #define POSTPACK | |
34 #endif | |
35 | |
36 #ifndef RESTRICT | |
37 #ifdef __cplusplus | |
38 #define RESTRICT | |
39 #else | |
40 #define RESTRICT restrict | |
41 #endif | |
42 #endif | |
43 | |
44 typedef int32_t q_t; /* Q Fixed Point Number, (Q16.16, Signed) */ | |
45 typedef int64_t ld_t; /* Double width of Q, signed, for internal calculations, not in Q format */ | |
46 typedef int32_t d_t; /* same width as Q, signed, but not in Q format */ | |
47 typedef uint32_t u_t; /* same width as Q, unsigned, but not in Q format */ | |
48 | |
49 typedef PREPACK struct { | |
50 size_t whole, /* number of bits for whole, or integer, part of Q number */ | |
51 fractional; /* number of bits for fractional part of Q number */ | |
52 const q_t zero, /* the constant '0' */ | |
53 bit, /* smallest 'q' number representable */ | |
54 one, /* the constant '1' */ | |
55 pi, /* the constant 'pi' */ | |
56 e, /* the constant 'e' */ | |
57 sqrt2, /* the square root of 2 */ | |
58 sqrt3, /* the square root of 3 */ | |
59 ln2, /* the natural logarithm of 2 */ | |
60 ln10, /* the natural logarithm of 10 */ | |
61 min, /* most negative 'q' number */ | |
62 max; /* most positive 'q' number */ | |
63 const uint32_t version; /* version in X.Y.Z format (Z = lowest 8 bits) */ | |
64 } POSTPACK qinfo_t; | |
65 | |
66 typedef PREPACK struct { | |
67 q_t rc, /* time constant */ | |
68 time, /* time of previous measurement */ | |
69 raw, /* previous raw value */ | |
70 filtered; /* filtered value */ | |
71 } POSTPACK qfilter_t; /* High/Low Pass Filter */ | |
72 | |
73 typedef PREPACK struct { | |
74 q_t d_gain, d_state; /* differentiator; gain, state */ | |
75 q_t i_gain, i_state, i_min, i_max; /* integrator; gain, state, minimum and maximum */ | |
76 q_t p_gain; /* proportional gain */ | |
77 } POSTPACK qpid_t; /* PID Controller <https://en.wikipedia.org/wiki/PID_controller> */ | |
78 | |
79 struct qexpr; | |
80 typedef struct qexpr qexpr_t; | |
81 | |
82 typedef PREPACK struct { | |
83 char *name; | |
84 union { | |
85 q_t (*unary) (q_t a); | |
86 q_t (*binary) (q_t a1, q_t a2); | |
87 } eval; | |
88 union { | |
89 q_t (*unary) (qexpr_t *e, q_t a); | |
90 q_t (*binary) (qexpr_t *e, q_t a1, q_t a2); | |
91 } check; | |
92 int precedence, arity, assocativity, hidden; | |
93 } POSTPACK qoperations_t; /* use in the expression evaluator */ | |
94 | |
95 typedef PREPACK struct { | |
96 char *name; | |
97 q_t value; | |
98 } POSTPACK qvariable_t; /* Variable which can be used with the expression evaluator */ | |
99 | |
100 struct PREPACK qexpr { | |
101 const qoperations_t **ops, *lpar, *rpar, *negate, *minus; | |
102 qvariable_t **vars; | |
103 char id[QMAX_ID]; | |
104 char error_string[QMAX_ERROR]; | |
105 q_t number; | |
106 const qoperations_t *op; | |
107 q_t *numbers; | |
108 size_t ops_count, ops_max; | |
109 size_t numbers_count, numbers_max; | |
110 size_t id_count; | |
111 size_t vars_max; | |
112 int error; | |
113 int initialized; | |
114 } POSTPACK; /* An expression evaluator for the Q library */ | |
115 | |
116 typedef q_t (*qbounds_t)(ld_t s); | |
117 | |
118 q_t qbound_saturate(ld_t s); /* default over/underflow behavior, saturation */ | |
119 q_t qbound_wrap(ld_t s); /* over/underflow behavior, wrap around */ | |
120 | |
121 typedef PREPACK struct { | |
122 qbounds_t bound; /* handles saturation when a number over or underflows */ | |
123 int dp; /* decimal points to print, negative specifies maximum precision */ | |
124 unsigned base; /* base to use for numeric number conversion */ | |
125 } POSTPACK qconf_t; /* Q format configuration options */ | |
126 | |
127 extern const qinfo_t qinfo; /* information about the format and constants */ | |
128 extern qconf_t qconf; /* @warning GLOBAL Q configuration options */ | |
129 | |
130 int qtoi(q_t toi); | |
131 q_t qint(int toq); | |
132 signed char qtoc(const q_t q); | |
133 q_t qchar(signed char c); | |
134 short qtoh(const q_t q); | |
135 q_t qshort(short s); | |
136 long qtol(const q_t q); | |
137 q_t qlong(long l); | |
138 long long qtoll(const q_t q); | |
139 q_t qvlong(long long ll); | |
140 | |
141 q_t qisnegative(q_t a); | |
142 q_t qispositive(q_t a); | |
143 q_t qisinteger(q_t a); | |
144 q_t qisodd(q_t a); | |
145 q_t qiseven(q_t a); | |
146 | |
147 q_t qless(q_t a, q_t b); | |
148 q_t qmore(q_t a, q_t b); | |
149 q_t qeqless(q_t a, q_t b); | |
150 q_t qeqmore(q_t a, q_t b); | |
151 q_t qequal(q_t a, q_t b); | |
152 q_t qunequal(q_t a, q_t b); | |
153 q_t qapproxequal(q_t a, q_t b, q_t epsilon); | |
154 q_t qapproxunequal(q_t a, q_t b, q_t epsilon); | |
155 q_t qwithin(q_t v, q_t b1, q_t b2); | |
156 q_t qwithin_interval(q_t v, q_t expected, q_t allowance); | |
157 | |
158 q_t qnegate(q_t a); | |
159 q_t qmin(q_t a, q_t b); | |
160 q_t qmax(q_t a, q_t b); | |
161 q_t qabs(q_t a); | |
162 q_t qcopysign(q_t a, q_t b); | |
163 q_t qsign(q_t a); | |
164 q_t qsignum(q_t a); | |
165 | |
166 q_t qadd(q_t a, q_t b); | |
167 q_t qsub(q_t a, q_t b); | |
168 q_t qmul(q_t a, q_t b); | |
169 q_t qdiv(q_t a, q_t b); | |
170 q_t qrem(q_t a, q_t b); | |
171 q_t qmod(q_t a, q_t b); | |
172 q_t qfma(q_t a, q_t b, q_t c); | |
173 q_t qsqr(q_t x); | |
174 q_t qexp(q_t e); | |
175 q_t qlog(q_t n); | |
176 q_t qsqrt(q_t x); | |
177 | |
178 q_t qround(q_t q); | |
179 q_t qceil(q_t q); | |
180 q_t qtrunc(q_t q); | |
181 q_t qfloor(q_t q); | |
182 | |
183 q_t qand(q_t a, q_t b); | |
184 q_t qxor(q_t a, q_t b); | |
185 q_t qor(q_t a, q_t b); | |
186 q_t qinvert(q_t a); | |
187 q_t qnot(q_t a); | |
188 q_t qlogical(q_t a); | |
189 | |
190 q_t qlls(q_t a, q_t b); | |
191 q_t qlrs(q_t a, q_t b); | |
192 q_t qals(q_t a, q_t b); | |
193 q_t qars(q_t a, q_t b); | |
194 | |
195 q_t qpow(q_t n, q_t exp); | |
196 | |
197 int qsprint(q_t p, char *s, size_t length); | |
198 int qsprintb(q_t p, char *s, size_t length, u_t base); | |
199 int qsprintbdp(q_t p, char *s, size_t length, u_t base, d_t idp); | |
200 int qnconv(q_t *q, const char *s, size_t length); | |
201 int qnconvb(q_t *q, const char *s, size_t length, d_t base); | |
202 int qconv(q_t *q, const char *s); | |
203 int qconvb(q_t *q, const char * const s, d_t base); | |
204 int qnconvbdp(q_t *q, const char *s, size_t length, d_t base, u_t idp); | |
205 | |
206 void qsincos(q_t theta, q_t *sine, q_t *cosine); | |
207 q_t qsin(q_t theta); | |
208 q_t qcos(q_t theta); | |
209 q_t qtan(q_t theta); | |
210 q_t qcot(q_t theta); | |
211 q_t qhypot(q_t a, q_t b); | |
212 | |
213 q_t qatan(q_t t); | |
214 q_t qatan2(q_t x, q_t y); | |
215 q_t qasin(q_t t); | |
216 q_t qacos(q_t t); | |
217 q_t qsinh(q_t a); | |
218 q_t qcosh(q_t a); | |
219 q_t qtanh(q_t a); | |
220 | |
221 q_t qatanh(q_t t); | |
222 q_t qasinh(q_t t); | |
223 q_t qacosh(q_t t); | |
224 | |
225 void qsincosh(q_t a, q_t *sinh, q_t *cosh); | |
226 | |
227 q_t qcordic_ln(q_t d); /* CORDIC testing only */ | |
228 q_t qcordic_exp(q_t e); /* CORDIC testing only; useless for large values */ | |
229 q_t qcordic_sqrt(q_t a); /* CORDIC testing only; do not use, a <= 2, a >= 0 */ | |
230 q_t qcordic_mul(q_t a, q_t b); /* CORDIC testing only; do not use */ | |
231 q_t qcordic_div(q_t a, q_t b); /* CORDIC testing only; do not use */ | |
232 q_t qcordic_circular_gain(int n); | |
233 q_t qcordic_hyperbolic_gain(int n); | |
234 | |
235 void qpol2rec(q_t magnitude, q_t theta, q_t *i, q_t *j); | |
236 void qrec2pol(q_t i, q_t j, q_t *magnitude, q_t *theta); | |
237 | |
238 q_t qrad2deg(q_t rad); | |
239 q_t qdeg2rad(q_t deg); | |
240 | |
241 d_t dpower(d_t b, unsigned e); | |
242 d_t dlog(d_t n, unsigned base); | |
243 d_t arshift(d_t v, unsigned p); | |
244 int qpack(const q_t *q, char *buffer, size_t length); | |
245 int qunpack(q_t *q, const char *buffer, size_t length); | |
246 | |
247 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 */ | |
248 | |
249 void qfilter_init(qfilter_t *f, q_t time, q_t rc, q_t seed); | |
250 q_t qfilter_low_pass(qfilter_t *f, q_t time, q_t data); | |
251 q_t qfilter_high_pass(qfilter_t *f, q_t time, q_t data); | |
252 q_t qfilter_value(const qfilter_t *f); | |
253 | |
254 q_t qpid_update(qpid_t *pid, const q_t error, const q_t position); | |
255 | |
256 /* A matrix consists of at least four elements, a meta data field, | |
257 * the length of the array (which must be big enough to store | |
258 * row*column, but may be * larger) and a row and a column count | |
259 * in unsigned integer format, and the array elements in Q format. | |
260 * This simplifies storage and declaration of matrices. | |
261 * | |
262 * An example, the 2x3 matrix: | |
263 * | |
264 * [ 1, 2, 3; 4, 5, 6 ] | |
265 * | |
266 * Should be defined as: | |
267 * | |
268 * q_t m[] = { 0, 2*3, 2, 3, QINT(1), QINT(2), QINT(3), QINT(4), QINT(5), QINT(6) }; | |
269 * | |
270 */ | |
271 int qmatrix_apply_unary(q_t *r, const q_t *a, q_t (*func)(q_t)); | |
272 int qmatrix_apply_scalar(q_t *r, const q_t *a, q_t (*func)(q_t, q_t), const q_t c); | |
273 int qmatrix_apply_binary(q_t * RESTRICT r, const q_t *a, const q_t *b, q_t (*func)(q_t, q_t)); | |
274 int qmatrix_sprintb(const q_t *m, char *str, size_t length, unsigned base); | |
275 int qmatrix_resize(q_t *m, const size_t row, const size_t column); | |
276 int qmatrix_copy(q_t *r, const q_t *a); | |
277 size_t qmatrix_string_length(const q_t *m); | |
278 | |
279 q_t qmatrix_trace(const q_t *m); | |
280 q_t qmatrix_determinant(const q_t *m); | |
281 q_t qmatrix_equal(const q_t *a, const q_t *b); | |
282 | |
283 int qmatrix_zero(q_t *r); | |
284 int qmatrix_one(q_t *r); | |
285 int qmatrix_identity(q_t *r); /* turn into identity matrix, r must be square */ | |
286 | |
287 int qmatrix_logical(q_t *r, const q_t *a); | |
288 int qmatrix_not(q_t *r, const q_t *a); | |
289 int qmatrix_signum(q_t *r, const q_t *a); | |
290 int qmatrix_invert(q_t *r, const q_t *a); | |
291 | |
292 int qmatrix_is_valid(const q_t *m); | |
293 int qmatrix_is_square(const q_t *m); | |
294 | |
295 int qmatrix_transpose(q_t * RESTRICT r, const q_t * RESTRICT m); | |
296 int qmatrix_add(q_t * RESTRICT r, const q_t *a, const q_t *b); | |
297 int qmatrix_sub(q_t * RESTRICT r, const q_t *a, const q_t *b); | |
298 int qmatrix_mul(q_t * RESTRICT r, const q_t *a, const q_t *b); | |
299 int qmatrix_and(q_t *r, const q_t *a, const q_t *b); | |
300 int qmatrix_or (q_t *r, const q_t *a, const q_t *b); | |
301 int qmatrix_xor(q_t *r, const q_t *a, const q_t *b); | |
302 | |
303 int qmatrix_scalar_add(q_t *r, const q_t *a, const q_t scalar); | |
304 int qmatrix_scalar_sub(q_t *r, const q_t *a, const q_t scalar); | |
305 int qmatrix_scalar_mul(q_t *r, const q_t *a, const q_t scalar); | |
306 int qmatrix_scalar_div(q_t *r, const q_t *a, const q_t scalar); | |
307 int qmatrix_scalar_mod(q_t *r, const q_t *a, const q_t scalar); | |
308 int qmatrix_scalar_rem(q_t *r, const q_t *a, const q_t scalar); | |
309 int qmatrix_scalar_and(q_t *r, const q_t *a, const q_t scalar); | |
310 int qmatrix_scalar_or (q_t *r, const q_t *a, const q_t scalar); | |
311 int qmatrix_scalar_xor(q_t *r, const q_t *a, const q_t scalar); | |
312 | |
313 /* Expression evaluator */ | |
314 | |
315 int qexpr(qexpr_t *e, const char *expr); | |
316 int qexpr_init(qexpr_t *e); | |
317 int qexpr_error(qexpr_t *e); | |
318 q_t qexpr_result(qexpr_t *e); | |
319 const qoperations_t *qop(const char *op); | |
320 | |
321 /* A better cosine/sine, not in Q format */ | |
322 | |
323 int16_t furman_sin(int16_t x); /* SINE: 1 Furman = 1/65536 of a circle */ | |
324 int16_t furman_cos(int16_t x); /* COSINE: 1 Furman = 1/65536 of a circle */ | |
325 | |
326 #ifdef __cplusplus | |
327 } | |
328 #endif | |
329 #endif |