4 * Various functions for baseband sample processing
6 * Copyright (C) 2012 by Benjamin Larsson <benjamin@southpole.se>
7 * Copyright (C) 2015 Tommy Vestermark
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
23 static uint16_t scaled_squares[256];
25 /* precalculate lookup table for envelope detection */
26 static void calc_squares() {
28 for (i = 0; i < 256; i++)
29 scaled_squares[i] = (127 - i) * (127 - i);
32 /** This will give a noisy envelope of OOK/ASK signals
33 * Subtract the bias (-128) and get an envelope estimation
34 * The output will be written in the input buffer
35 * @returns pointer to the input buffer
37 void envelope_detect(const uint8_t *iq_buf, uint16_t *y_buf, uint32_t len) {
39 for (i = 0; i < len; i++) {
40 y_buf[i] = scaled_squares[iq_buf[2 * i ]] + scaled_squares[iq_buf[2 * i + 1]];
45 /** Something that might look like a IIR lowpass filter
47 * [b,a] = butter(1, Wc) # low pass filter with cutoff pi*Wc radians
48 * Q1.15*Q15.0 = Q16.15
50 * Q15.14 + Q15.14 + Q15.14 could possibly overflow to 17.14
51 * but the b coeffs are small so it wont happen
52 * Q15.14>>14 = Q15.0 \o/
55 #define S_CONST (1<<F_SCALE)
56 #define FIX(x) ((int)(x*S_CONST))
58 /// [b,a] = butter(1, 0.01) -> 3x tau (95%) ~100 samples
59 //static int a[FILTER_ORDER + 1] = {FIX(1.00000), FIX(0.96907)};
60 //static int b[FILTER_ORDER + 1] = {FIX(0.015466), FIX(0.015466)};
61 /// [b,a] = butter(1, 0.05) -> 3x tau (95%) ~20 samples
62 static int a[FILTER_ORDER + 1] = {FIX(1.00000), FIX(0.85408)};
63 static int b[FILTER_ORDER + 1] = {FIX(0.07296), FIX(0.07296)};
66 void baseband_low_pass_filter(const uint16_t *x_buf, int16_t *y_buf, uint32_t len, FilterState *state) {
68 // Fixme: Will Segmentation Fault if len < FILTERORDER
70 /* Calculate first sample */
71 y_buf[0] = ((a[1] * state->y[0] >> 1) + (b[0] * x_buf[0] >> 1) + (b[1] * state->x[0] >> 1)) >> (F_SCALE - 1);
72 for (i = 1; i < len; i++) {
73 y_buf[i] = ((a[1] * y_buf[i - 1] >> 1) + (b[0] * x_buf[i] >> 1) + (b[1] * x_buf[i - 1] >> 1)) >> (F_SCALE - 1);
76 /* Save last samples */
77 memcpy(state->x, &x_buf[len - FILTER_ORDER], FILTER_ORDER * sizeof (int16_t));
78 memcpy(state->y, &y_buf[len - FILTER_ORDER], FILTER_ORDER * sizeof (int16_t));
79 //fprintf(stderr, "%d\n", y_buf[0]);
83 /// Integer implementation of atan2() with int16_t normalized output
85 /// Returns arc tangent of y/x across all quadrants in radians
86 /// Reference: http://dspguru.com/dsp/tricks/fixed-point-atan2-with-self-normalization
87 /// @param y: Numerator (imaginary value of complex vector)
88 /// @param x: Denominator (real value of complex vector)
89 /// @return angle in radians (Pi equals INT16_MAX)
90 int16_t atan2_int16(int16_t y, int16_t x) {
91 static const int32_t I_PI_4 = INT16_MAX/4; // M_PI/4
92 static const int32_t I_3_PI_4 = 3*INT16_MAX/4; // 3*M_PI/4
93 const int32_t abs_y = abs(y);
96 if (x >= 0) { // Quadrant I and IV
97 int32_t denom = (abs_y + x);
98 if (denom == 0) denom = 1; // Prevent divide by zero
99 r = ((x - abs_y) << 16) / denom;
101 } else { // Quadrant II and III
102 int32_t denom = (abs_y - x);
103 if (denom == 0) denom = 1; // Prevent divide by zero
104 r = ((x + abs_y) << 16) / denom;
107 angle -= (I_PI_4 * r) >> 16; // Error max 0.07 radians
108 if (y < 0) angle = -angle; // Negate if in III or IV
113 /// [b,a] = butter(1, 0.1) -> 3x tau (95%) ~10 samples
114 //static int alp[2] = {FIX(1.00000), FIX(0.72654)};
115 //static int blp[2] = {FIX(0.13673), FIX(0.13673)};
116 /// [b,a] = butter(1, 0.2) -> 3x tau (95%) ~5 samples
117 static int alp[2] = {FIX(1.00000), FIX(0.50953)};
118 static int blp[2] = {FIX(0.24524), FIX(0.24524)};
120 void baseband_demod_FM(const uint8_t *x_buf, int16_t *y_buf, unsigned num_samples, DemodFM_State *state) {
121 int16_t ar, ai; // New IQ sample: x[n]
122 int16_t br, bi; // Old IQ sample: x[n-1]
123 int32_t pr, pi; // Phase difference vector
124 int16_t angle; // Phase difference angle
125 int16_t xlp, ylp, xlp_old, ylp_old; // Low Pass filter variables
127 // Pre-feed old sample
128 ar = state->br; ai = state->bi;
129 xlp_old = state->xlp; ylp_old = state->ylp;
131 for (unsigned n = 0; n < num_samples; n++) {
137 ai = x_buf[2*n+1]-128;
138 // Calculate phase difference vector: x[n] * conj(x[n-1])
139 pr = ar*br+ai*bi; // May exactly overflow an int16_t (-128*-128 + -128*-128)
141 // xlp = (int16_t)((atan2f(pi, pr) / M_PI) * INT16_MAX); // Floating point implementation
142 xlp = atan2_int16(pi, pr); // Integer implementation
143 // xlp = pi; // Cheat and use only imaginary part (works OK, but is amplitude sensitive)
145 ylp = ((alp[1] * ylp_old >> 1) + (blp[0] * xlp >> 1) + (blp[1] * xlp_old >> 1)) >> (F_SCALE - 1);
146 ylp_old = ylp; xlp_old = xlp;
150 // Store newest sample for next run
151 state->br = ar; state->bi = ai;
152 state->xlp = xlp_old; state->ylp = ylp_old;
156 void baseband_init(void) {
161 static FILE *dumpfile = NULL;
163 void baseband_dumpfile(const uint8_t *buf, uint32_t len) {
164 if (dumpfile == NULL) {
165 dumpfile = fopen("dumpfile.dat", "wb");
168 if (dumpfile == NULL) {
169 fprintf(stderr, "Error: could not open dumpfile.dat\n");
171 fwrite(buf, 1, len, dumpfile);
172 fflush(dumpfile); // Flush as file is not closed cleanly...