6 Examples
6.1 Frequency analysis and C code generation
A typical use case is to define a filter, plot its transfer function, and when satisfied, generate some C code.
The filter can be defined in a separate module file or a submodule form exporting an identifier referring to the abstract program. This program can then be passed to an analysis or code generation function such as ai-spectrum or ai-array-c below. The former can be used in conjunction with Racket’s plot facility. The latter produces a C syntax file containing a C function, structure definitions for input, output and state, and preprocessor macros that abstract meta data to facilitate integration in a C host framework.
> (module test rai/stream (provide svf integrator) (define (integrator (s) (x)) (let ((s (+ s x))) (values s s))) (define (svf (s1 s2) (in)) (let* ((f 0.1) (q 0.3) (s2 (+ s2 (* f s1))) (s1 (- s1 (* f (+ (* q s1) s2 in))))) (values s1 s2 s2))))
> (require 'test)
> (require rai/ai-freq)
> (require plot)
> (define (plot-filter f) (parameterize ((plot-x-transform log-transform) (plot-y-transform log-transform) (plot-x-ticks (log-ticks)) (plot-y-ticks (log-ticks))) (plot (function (compose magnitude (ai-spectrum f)) 0.0001 0.5))))
> (plot-filter integrator) > (plot-filter svf) > (require rai/ai-array-c)
> (display (ai-array-c svf #:nsi 1))
struct proc_si {
int r5;
float r7;
float r8;
};
#define proc_si_r5 0
#define proc_si_r7 0
#define proc_si_r8 0
#define proc_for_si(m) \
m(r5, 0, 1) \
m(r7, 0, 1) \
m(r8, 0, 1) \
struct proc_so {
int r6;
float r15;
float r10;
};
#define proc_so_r6 0
#define proc_so_r15 0
#define proc_so_r10 0
#define proc_for_so(m) \
m(r6, 0, 1) \
m(r15, 0, 1) \
m(r10, 0, 1) \
struct proc_in {
float * restrict in;
};
#define proc_in_in 0
#define proc_for_in(m) \
m(in, 0, 1) \
struct proc_param {
};
#define proc_for_param(m) \
struct proc_out {
float * restrict r16;
};
#define proc_out_r16 0
#define proc_for_out(m) \
m(r16, 0, 1) \
struct proc_store {
float r2[1];
};
#define proc_store_r2 1
#define proc_for_store(m) \
m(r2, 1, 1, 1) \
#define proc_for_control(m) \
void proc_loop (
struct proc_si * restrict state,
struct proc_in * restrict in,
struct proc_param * restrict param,
struct proc_out * restrict out,
struct proc_store * restrict store,
int t_endx) {
struct proc_si * restrict si = (struct proc_si *)(&state[(0)&1]);
struct proc_so * restrict so = (struct proc_so *)(&state[(1)&1]);
for (int t = 0; t < t_endx; t ++) {
struct proc_si * restrict si = (struct proc_si *)(&state[(t^0)&1]);
struct proc_so * restrict so = (struct proc_so *)(&state[(t^1)&1]);
/*?*/ float r0 = p_copy(t);
/*?*/ float r1 = p_copy(t_endx);
/*?*/ float r3 = p_copy(1.0);
/*?*/ float r4 = p_sub(r3, 1.0);
so->r6 = p_sub(si->r5, 1.0);
float r9 = p_mul(0.1, si->r7);
so->r10 = p_add(si->r8, r9);
float r11 = p_mul(0.3, si->r7);
float r12 = p_add(so->r10, in->in[t]);
float r13 = p_add(r11, r12);
float r14 = p_mul(0.1, r13);
so->r15 = p_sub(si->r7, r14);
out->r16[t] = p_copy(so->r10);
}
}