blob: 134576c19a34371e4b1172b733d91d5104fdd5a9 [file] [log] [blame]
kurtis.heimerlce317332011-11-26 03:18:39 +00001/*
2 * Radio device interface with sample rate conversion
3 * Written by Thomas Tsou <ttsou@vt.edu>
4 *
5 * Copyright 2011 Free Software Foundation, Inc.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 * See the COPYING file in the main directory for details.
20 */
21
22#include <radioInterface.h>
23#include <Logger.h>
24
25/* New chunk sizes for resampled rate */
26#ifdef INCHUNK
27 #undef INCHUNK
28#endif
29#ifdef OUTCHUNK
30 #undef OUTCHUNK
31#endif
32
33/* Resampling parameters */
34#define INRATE 65 * SAMPSPERSYM
35#define INHISTORY INRATE * 2
36#define INCHUNK INRATE * 9
37
38#define OUTRATE 96 * SAMPSPERSYM
39#define OUTHISTORY OUTRATE * 2
40#define OUTCHUNK OUTRATE * 9
41
42/* Resampler low pass filters */
43signalVector *tx_lpf = 0;
44signalVector *rx_lpf = 0;
45
46/* Resampler history */
47signalVector *tx_hist = 0;
48signalVector *rx_hist = 0;
49
50/* Resampler input buffer */
51signalVector *tx_vec = 0;
52signalVector *rx_vec = 0;
53
54/* High rate (device facing) buffers */
55short tx_buf[INCHUNK * 2 * 2];
56short rx_buf[OUTCHUNK * 2 * 2];
57
58/*
59 * Utilities and Conversions
60 *
61 * Manipulate signal vectors dynamically for two reasons. For one,
62 * it's simpler. And two, it doesn't make any reasonable difference
63 * relative to the high overhead generated by the resampling.
64 */
65
66/* Concatenate signal vectors. Deallocate input vectors. */
67signalVector *concat(signalVector *a, signalVector *b)
68{
69 signalVector *vec = new signalVector(*a, *b);
70 delete a;
71 delete b;
72
73 return vec;
74}
75
76/* Segment a signal vector. Deallocate the input vector. */
77signalVector *segment(signalVector *a, int indx, int sz)
78{
79 signalVector *vec = new signalVector(sz);
80 a->segmentCopyTo(*vec, indx, sz);
81 delete a;
82
83 return vec;
84}
85
86/* Create a new signal vector from a short array. */
87signalVector *short_to_sigvec(short *smpls, size_t sz)
88{
89 int i;
90 signalVector *vec = new signalVector(sz);
91 signalVector::iterator itr = vec->begin();
92
93 for (i = 0; i < sz; i++) {
94 *itr++ = Complex<float>(smpls[2 * i + 0], smpls[2 * i + 1]);
95 }
96
97 return vec;
98}
99
100/* Convert and deallocate a signal vector into a short array. */
101int sigvec_to_short(signalVector *vec, short *smpls)
102{
103 int i;
104 signalVector::iterator itr = vec->begin();
105
106 for (i = 0; i < vec->size(); i++) {
107 smpls[2 * i + 0] = itr->real();
108 smpls[2 * i + 1] = itr->imag();
109 itr++;
110 }
111 delete vec;
112
113 return i;
114}
115
116/* Create a new signal vector from a float array. */
117signalVector *float_to_sigvec(float *smpls, int sz)
118{
119 int i;
120 signalVector *vec = new signalVector(sz);
121 signalVector::iterator itr = vec->begin();
122
123 for (i = 0; i < sz; i++) {
124 *itr++ = Complex<float>(smpls[2 * i + 0], smpls[2 * i + 1]);
125 }
126
127 return vec;
128}
129
130/* Convert and deallocate a signal vector into a float array. */
131int sigvec_to_float(signalVector *vec, float *smpls)
132{
133 int i;
134 signalVector::iterator itr = vec->begin();
135
136 for (i = 0; i < vec->size(); i++) {
137 smpls[2 * i + 0] = itr->real();
138 smpls[2 * i + 1] = itr->imag();
139 itr++;
140 }
141 delete vec;
142
143 return i;
144}
145
146/* Initialize resampling signal vectors */
147void init_resampler(signalVector **lpf,
148 signalVector **buf,
149 signalVector **hist,
150 int tx)
151{
152 int P, Q, taps, hist_len;
153 float cutoff_freq;
154
155 if (tx) {
156 LOG(INFO) << "Initializing Tx resampler";
157 P = OUTRATE;
158 Q = INRATE;
159 taps = 651;
160 hist_len = INHISTORY;
161 } else {
162 LOG(INFO) << "Initializing Rx resampler";
163 P = INRATE;
164 Q = OUTRATE;
165 taps = 961;
166 hist_len = OUTHISTORY;
167 }
168
169 if (!*lpf) {
170 cutoff_freq = (P < Q) ? (1.0/(float) Q) : (1.0/(float) P);
171 *lpf = createLPF(cutoff_freq, taps, P);
172 }
173
174 if (!*buf) {
175 *buf = new signalVector();
176 }
177
178 if (!*hist);
179 *hist = new signalVector(hist_len);
180}
181
182/* Resample a signal vector
183 *
184 * The input vector is deallocated and the pointer returned with a vector
185 * of any unconverted samples.
186 */
187signalVector *resmpl_sigvec(signalVector *hist, signalVector **vec,
188 signalVector *lpf, double in_rate,
189 double out_rate, int chunk_sz)
190{
191 signalVector *resamp_vec;
192 int num_chunks = (*vec)->size() / chunk_sz;
193
194 /* Truncate to a chunk multiple */
195 signalVector trunc_vec(num_chunks * chunk_sz);
196 (*vec)->segmentCopyTo(trunc_vec, 0, num_chunks * chunk_sz);
197
198 /* Update sample buffer with remainder */
199 *vec = segment(*vec, trunc_vec.size(), (*vec)->size() - trunc_vec.size());
200
201 /* Add history and resample */
202 signalVector input_vec(*hist, trunc_vec);
203 resamp_vec = polyphaseResampleVector(input_vec, in_rate,
204 out_rate, lpf);
205
206 /* Update history */
207 trunc_vec.segmentCopyTo(*hist, trunc_vec.size() - hist->size(),
208 hist->size());
209 return resamp_vec;
210}
211
212/* Wrapper for receive-side integer-to-float array resampling */
213 int rx_resmpl_int_flt(float *smpls_out, short *smpls_in, int num_smpls)
214{
215 int num_resmpld, num_chunks;
216 signalVector *convert_vec, *resamp_vec, *trunc_vec;
217
218 if (!rx_lpf || !rx_vec || !rx_hist)
219 init_resampler(&rx_lpf, &rx_vec, &rx_hist, false);
220
221 /* Convert and add samples to the receive buffer */
222 convert_vec = short_to_sigvec(smpls_in, num_smpls);
223 rx_vec = concat(rx_vec, convert_vec);
224
225 num_chunks = rx_vec->size() / OUTCHUNK;
226 if (num_chunks < 1)
227 return 0;
228
229 /* Resample */
230 resamp_vec = resmpl_sigvec(rx_hist, &rx_vec, rx_lpf,
231 INRATE, OUTRATE, OUTCHUNK);
232 /* Truncate */
233 trunc_vec = segment(resamp_vec, INHISTORY,
234 resamp_vec->size() - INHISTORY);
235 /* Convert */
236 num_resmpld = sigvec_to_float(trunc_vec, smpls_out);
237
238 return num_resmpld;
239}
240
241/* Wrapper for transmit-side float-to-int array resampling */
242int tx_resmpl_flt_int(short *smpls_out, float *smpls_in, int num_smpls)
243{
244 int num_resmpl, num_chunks;
245 signalVector *convert_vec, *resamp_vec;
246
247 if (!tx_lpf || !tx_vec || !tx_hist)
248 init_resampler(&tx_lpf, &tx_vec, &tx_hist, true);
249
250 /* Convert and add samples to the transmit buffer */
251 convert_vec = float_to_sigvec(smpls_in, num_smpls);
252 tx_vec = concat(tx_vec, convert_vec);
253
254 num_chunks = tx_vec->size() / INCHUNK;
255 if (num_chunks < 1)
256 return 0;
257
258 /* Resample and convert to an integer array */
259 resamp_vec = resmpl_sigvec(tx_hist, &tx_vec, tx_lpf,
260 OUTRATE, INRATE, INCHUNK);
261 num_resmpl = sigvec_to_short(resamp_vec, smpls_out);
262
263 return num_resmpl;
264}
265
266/* Receive a timestamped chunk from the device */
267void RadioInterface::pullBuffer()
268{
269 int num_cv, num_rd;
270 bool local_underrun;
271
272 /* Read samples. Fail if we don't get what we want. */
273 num_rd = mRadio->readSamples(rx_buf, OUTCHUNK, &overrun,
274 readTimestamp, &local_underrun);
275
276 LOG(DEEPDEBUG) << "Rx read " << num_rd << " samples from device";
277 assert(num_rd == OUTCHUNK);
278
279 underrun |= local_underrun;
280 readTimestamp += (TIMESTAMP) num_rd;
281
282 /* Convert and resample */
283 num_cv = rx_resmpl_int_flt(rcvBuffer + 2 * rcvCursor,
284 rx_buf, num_rd);
285
286 LOG(DEEPDEBUG) << "Rx read " << num_cv << " samples from resampler";
287
288 rcvCursor += num_cv;
289}
290
291/* Send a timestamped chunk to the device */
292void RadioInterface::pushBuffer()
293{
294 int num_cv, num_wr;
295
296 if (sendCursor < INCHUNK)
297 return;
298
299 LOG(DEEPDEBUG) << "Tx wrote " << sendCursor << " samples to resampler";
300
301 /* Resample and convert */
302 num_cv = tx_resmpl_flt_int(tx_buf, sendBuffer, sendCursor);
303 assert(num_cv > sendCursor);
304
305 /* Write samples. Fail if we don't get what we want. */
306 num_wr = mRadio->writeSamples(tx_buf + OUTHISTORY * 2,
307 num_cv - OUTHISTORY,
308 &underrun,
309 writeTimestamp);
310
311 LOG(DEEPDEBUG) << "Tx wrote " << num_wr << " samples to device";
312 assert(num_wr == num_wr);
313
314 writeTimestamp += (TIMESTAMP) num_wr;
315 sendCursor = 0;
316}