summaryrefslogtreecommitdiffstats
path: root/baseline/source/fmref/fmref.c
diff options
context:
space:
mode:
Diffstat (limited to 'baseline/source/fmref/fmref.c')
-rw-r--r--baseline/source/fmref/fmref.c283
1 files changed, 283 insertions, 0 deletions
diff --git a/baseline/source/fmref/fmref.c b/baseline/source/fmref/fmref.c
new file mode 100644
index 0000000..6be1436
--- /dev/null
+++ b/baseline/source/fmref/fmref.c
@@ -0,0 +1,283 @@
1/*
2* fmref.c: C reference implementation of FM Radio
3* David Maze <dmaze@cag.lcs.mit.edu>
4* $Id: fmref.c,v 1.2 2010-10-04 21:21:26 garus Exp $
5*/
6
7
8#include "../extra.h"
9#include "wcclibm.h"
10#ifndef M_PI
11#define M_PI 3.1415926535897932384626433832795
12#endif
13
14// Defines
15#define SAMPLING_RATE 250000000
16#define CUTOFF_FREQUENCY 108000000
17#define NUM_TAPS 64
18#define MAX_AMPLITUDE 27000.0
19#define BANDWIDTH 10000
20#define DECIMATION 4
21/* Must be at least NUM_TAPS+1: */
22#define IN_BUFFER_LEN 200
23#define EQUALIZER_BANDS 10
24
25
26// Type declarations
27typedef struct FloatBuffer
28{
29 float buff[IN_BUFFER_LEN];
30 int rpos, rlen;
31}
32FloatBuffer;
33/* Low pass filter: */
34typedef struct LPFData
35{
36 float coeff[NUM_TAPS];
37 float freq;
38 int taps, decimation;
39}
40LPFData;
41typedef struct EqualizerData
42{
43 LPFData lpf[EQUALIZER_BANDS + 1];
44 FloatBuffer fb[EQUALIZER_BANDS + 1];
45 float gain[EQUALIZER_BANDS];
46}
47EqualizerData;
48
49// Global vars
50float fmref_lpf_coeff[NUM_TAPS];
51float fmref_eq_cutoffs[EQUALIZER_BANDS + 1] =
52 { 55.000004f, 77.78174f, 110.00001f, 155.56354f, 220.00002f, 311.12695f,
53 440.00003f, 622.25415f, 880.00006f, 1244.5078f, 1760.0001f };
54static int fmref_numiters = 2;
55
56// Forward declarations
57void fmref_fb_compact(FloatBuffer *fb);
58int fmref_fb_ensure_writable(FloatBuffer *fb, int amount);
59void fmref_get_floats(FloatBuffer *fb);
60void fmref_init_lpf_data(LPFData *data, float freq, int taps, int decimation);
61void fmref_run_lpf(FloatBuffer *fbin, FloatBuffer *fbout, LPFData *data);
62void fmref_run_demod(FloatBuffer *fbin, FloatBuffer *fbout);
63void fmref_init_equalizer(EqualizerData *data);
64void fmref_run_equalizer(FloatBuffer *fbin, FloatBuffer *fbout, EqualizerData *data);
65void fmref_main(void);
66
67void fmref_init(void)
68{
69 // dummy init function
70}
71
72int fmref_return(void)
73{
74 // dummy return value
75 return 0;
76}
77
78int main(int argc, char **argv){
79
80 SET_UP
81 for(jobsComplete=-1; jobsComplete<maxJobs; jobsComplete++){
82 START_LOOP
83 fmref_init();
84 fmref_main();
85 STOP_LOOP
86 }
87 WRITE_TO_FILE
88 return fmref_return();
89}
90
91FloatBuffer fmref_fb1, fmref_fb2, fmref_fb3, fmref_fb4;
92LPFData fmref_lpf_data;
93
94void fmref_main(void)
95{
96 int i;
97 EqualizerData eq_data;
98
99 fmref_fb1.rpos = fmref_fb1.rlen = 0;
100 fmref_fb2.rpos = fmref_fb2.rlen = 0;
101 fmref_fb3.rpos = fmref_fb3.rlen = 0;
102 fmref_fb4.rpos = fmref_fb4.rlen = 0;
103
104 fmref_init_lpf_data(&fmref_lpf_data, CUTOFF_FREQUENCY, NUM_TAPS, DECIMATION);
105 fmref_init_equalizer(&eq_data);
106
107 /* Startup: */
108 fmref_get_floats(&fmref_fb1);
109 /* LPF needs at least NUM_TAPS+1 inputs; fmref_get_floats is fine. */
110 fmref_run_lpf(&fmref_fb1, &fmref_fb2, &fmref_lpf_data);
111 /* run_demod needs 1 input, OK here. */
112 /* run_equalizer needs 51 inputs (same reason as for LPF). This means
113 * running the pipeline up to demod 50 times in advance: */
114 _Pragma( "loopbound min 64 max 64" )
115 for (i = 0; i < 64; i++) {
116 if (fmref_fb1.rlen - fmref_fb1.rpos < NUM_TAPS + 1)
117 fmref_get_floats(&fmref_fb1);
118 fmref_run_lpf(&fmref_fb1, &fmref_fb2, &fmref_lpf_data);
119 fmref_run_demod(&fmref_fb2, &fmref_fb3);
120 }
121
122 /* Main loop: */
123 _Pragma( "loopbound min 2 max 2" )
124 while (fmref_numiters-- > 0) {
125 /* The low-pass filter will need NUM_TAPS+1 items; read them if we
126 * need to. */
127 if (fmref_fb1.rlen - fmref_fb1.rpos < NUM_TAPS + 1)
128 fmref_get_floats(&fmref_fb1);
129 fmref_run_lpf(&fmref_fb1, &fmref_fb2, &fmref_lpf_data);
130 fmref_run_demod(&fmref_fb2, &fmref_fb3);
131 fmref_run_equalizer(&fmref_fb3, &fmref_fb4, &eq_data);
132
133 }
134}
135
136void fmref_fb_compact(FloatBuffer *fb)
137{
138
139 int i;
140 char *source;
141 char *target;
142 target = (char*)(fb->buff);
143 source = (char*)(fb->buff + fb->rpos);
144 _Pragma( "loopbound min 0 max 60" )
145 for (i = 0; i < fb->rlen - fb->rpos; i++) {
146 target[i] = source[i];
147 }
148 fb->rlen -= fb->rpos;
149 fb->rpos = 0;
150}
151
152int fmref_fb_ensure_writable(FloatBuffer *fb, int amount)
153{
154 int available = IN_BUFFER_LEN - fb->rlen;
155 if (available >= amount)
156 return 1;
157
158 /* Nope, not enough room, move current contents back to the beginning. */
159 fmref_fb_compact(fb);
160
161 available = IN_BUFFER_LEN - fb->rlen;
162 if (available >= amount)
163 return 1;
164
165 return 0;
166}
167
168void fmref_get_floats(FloatBuffer *fb)
169{
170 static int x = 0;
171 fmref_fb_compact(fb);
172
173 /* Fill the remaining space in fb with 1.0. */
174 _Pragma( "loopbound min 200 max 200" )
175 while (fb->rlen < IN_BUFFER_LEN) {
176 fb->buff[fb->rlen++] = (float)x;
177 x++;
178 }
179}
180
181void fmref_init_lpf_data(LPFData *data, float freq, int taps, int decimation)
182{
183 /* Assume that CUTOFF_FREQUENCY is non-zero. See comments in
184 * StreamIt LowPassFilter.java for origin. */
185 float w = 2 * M_PI * freq / SAMPLING_RATE;
186 int i;
187 float m = taps - 1.0f;
188
189 data->freq = freq;
190 data->taps = taps;
191 data->decimation = decimation;
192
193 _Pragma( "loopbound min 64 max 64" )
194 for (i = 0; i < taps; i++) {
195 if (i - m / 2 == 0.0f)
196 data->coeff[i] = w / M_PI;
197 else
198 data->coeff[i] = sin(w * (i - m / 2)) / M_PI / (i - m / 2) *
199 (0.54f - 0.46f * cos(2 * M_PI * i / m));
200 }
201}
202
203void fmref_run_lpf(FloatBuffer *fbin, FloatBuffer *fbout, LPFData *data)
204{
205 float sum = 0.0f;
206 int i = 0;
207
208 _Pragma( "loopbound min 64 max 64" )
209 for (i = 0; i < data->taps; i++) {
210 sum += fbin->buff[fbin->rpos + i] * data->coeff[i];
211 }
212
213 fbin->rpos += data->decimation + 1;
214
215 /* Check that there's room in the output buffer; move data if necessary. */
216 fmref_fb_ensure_writable(fbout, 1);
217 fbout->buff[fbout->rlen++] = sum;
218}
219
220void fmref_run_demod(FloatBuffer *fbin, FloatBuffer *fbout)
221{
222 float temp, gain;
223 gain = MAX_AMPLITUDE * SAMPLING_RATE / (BANDWIDTH * M_PI);
224 temp = fbin->buff[fbin->rpos] * fbin->buff[fbin->rpos + 1];
225 temp = gain * atan(temp);
226 fbin->rpos++;
227 fmref_fb_ensure_writable(fbout, 1);
228 fbout->buff[fbout->rlen++] = temp;
229}
230
231void fmref_init_equalizer(EqualizerData *data)
232{
233 int i;
234
235 /* Equalizer structure: there are ten band-pass filters, with
236 * cutoffs as shown below. The outputs of these filters get added
237 * together. Each band-pass filter is LPF(high)-LPF(low). */
238 _Pragma( "loopbound min 11 max 11" )
239 for (i = 0; i < EQUALIZER_BANDS + 1; i++)
240 fmref_init_lpf_data(&data->lpf[i], fmref_eq_cutoffs[i], 64, 0);
241
242 /* Also initialize member buffers. */
243 _Pragma( "loopbound min 11 max 11" )
244 for (i = 0; i < EQUALIZER_BANDS + 1; i++)
245 data->fb[i].rpos = data->fb[i].rlen = 0;
246
247 _Pragma( "loopbound min 10 max 10" )
248 for (i = 0; i < EQUALIZER_BANDS; i++) {
249 // the gain amplifies the middle bands the most
250 float val = (((float)i) - (((float)(EQUALIZER_BANDS - 1)) / 2.0f)) / 5.0f;
251 data->gain[i] = val > 0 ? 2.0f - val : 2.0f + val;
252 }
253}
254
255void fmref_run_equalizer(FloatBuffer *fbin, FloatBuffer *fbout, EqualizerData *data)
256{
257 int i, rpos;
258 float lpf_out[EQUALIZER_BANDS + 1];
259 float sum = 0.0;
260
261 /* Save the input read location; we can reuse the same input data on all
262 * of the LPFs. */
263 rpos = fbin->rpos;
264
265 /* Run the child filters. */
266 _Pragma( "loopbound min 11 max 11" )
267 for (i = 0; i < EQUALIZER_BANDS + 1; i++) {
268 fbin->rpos = rpos;
269 fmref_run_lpf(fbin, &data->fb[i], &data->lpf[i]);
270 lpf_out[i] = data->fb[i].buff[data->fb[i].rpos++];
271 }
272
273 /* Now process the results of the filters. Remember that each band is
274 * output(hi)-output(lo). */
275 _Pragma( "loopbound min 10 max 10" )
276 for (i = 0; i < EQUALIZER_BANDS; i++)
277 sum += (lpf_out[i + 1] - lpf_out[i]) * data->gain[i];
278
279 /* Write that result. */
280 fmref_fb_ensure_writable(fbout, 1);
281 fbout->buff[fbout->rlen++] = sum;
282}
283