On this page:
6.1 Frequency analysis and C code generation

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)

image

> (plot-filter svf)

image

> (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);

    }

}