1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
/*
tdec.c
David Rowe
Jan 2017
Trivial non filtered decimator for high ration sample rate conversion.
build: gcc tdec.c -o tdec -Wall -O2
*/
#include <assert.h>
#include <getopt.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#define SIGNED_16BIT 0
#define SIGNED_8BIT 1
#define UNSIGNED_8BIT 2
void freq_shift_complex_buf(short buf[], int n, int lo_i[], int lo_q[]);
void display_help(void) {
fprintf(stderr, "\nusage: tdec inputRawFile OutputRawFile DecimationRatio [-c]\n");
fprintf(stderr, "\nUse - for stdin/stdout\n\n");
fprintf(stderr, "-c complex signed 16 bit input and output\n");
fprintf(stderr, "-d complex signed 8 bit input (e.g. HackRF), complex signed 16 bit output\n");
fprintf(stderr, "-e complex unsigned 8 bit input (e.g. RTL-SDR), complex signed 16 bit output\n");
fprintf(stderr, "-f -Fs/4 freq shift\n\n");
}
int main(int argc, char *argv[]) {
FILE *fin, *fout;
short dec;
int lo_i[3], lo_q[3];
if (argc < 3) {
display_help();
exit(1);
}
if (strcmp(argv[1], "-") == 0)
fin = stdin;
else
fin = fopen(argv[1], "rb");
assert(fin != NULL);
if (strcmp(argv[2], "-") == 0)
fout = stdout;
else
fout = fopen(argv[2], "wb");
assert(fout != NULL);
dec = atoi(argv[3]);
int channels = 1;
int freq_shift = 0;
lo_i[0] = -1; lo_i[1] = 0;
lo_q[0] = 0; lo_q[1] = -1;
int opt;
int format = SIGNED_16BIT;
while ((opt = getopt(argc, argv, "cdef")) != -1) {
switch (opt) {
case 'c': channels = 2; break;
case 'd': channels = 2; format = SIGNED_8BIT; break;
case 'e': channels = 2; format = UNSIGNED_8BIT; break;
case 'f': freq_shift = 1; break;
default:
display_help();
exit(1);
}
}
if (format == SIGNED_16BIT) {
short buf[dec*channels];
while(fread(buf, sizeof(short)*channels, dec, fin) == dec) {
if (freq_shift)
freq_shift_complex_buf(buf, dec*channels, lo_i, lo_q);
fwrite(buf, sizeof(short), channels, fout);
}
}
else {
uint8_t inbuf[dec*channels];
short outbuf[dec*channels];
short sam, i;
while(fread(inbuf, sizeof(uint8_t)*channels, dec, fin) == dec) {
for (i=0; i<dec*channels; i++) {
assert((format == SIGNED_8BIT) || (format == UNSIGNED_8BIT));
if (format == SIGNED_8BIT) {
sam = (short)inbuf[i];
sam <<= 8;
} else {
sam = (short)inbuf[i] - 127;
sam <<= 8;
}
outbuf[i] = sam;
}
if (freq_shift)
freq_shift_complex_buf(outbuf, dec*channels, lo_i, lo_q);
fwrite(outbuf, sizeof(short), channels, fout);
}
}
fclose(fout);
fclose(fin);
return 0;
}
void freq_shift_complex_buf(short buf[], int n, int lo_i[], int lo_q[]) {
int i;
for (i=0; i<n; i+=2) {
/* update local osc recursion */
lo_i[2] = -lo_i[0]; lo_q[2] = -lo_q[0];
/* freq shift down input samples */
int a = buf[i];
int b = buf[i+1];
int c = lo_i[2];
int d = -lo_q[2]; /* conj LO as down shift */
buf[i] = a*c - b*d;
buf[i+1] = b*c + a*d;
//fprintf(stderr, "% d % d % 5d % 5d\n", lo_i[2], lo_q[2], buf[i], buf[i+1]);
/* update LO memory */
lo_i[0] = lo_i[1]; lo_i[1] = lo_i[2];
lo_q[0] = lo_q[1]; lo_q[1] = lo_q[2];
}
}
|