From ec37c6583cf653db0a1ce14d909ee3382df4c4a2 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Wed, 4 May 2016 23:46:23 +0200 Subject: [PATCH 001/111] Added BPSK31 varicode decoding. --- csdr.c | 46 ++++++++-- libcsdr.c | 246 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ libcsdr.h | 2 + 3 files changed, 286 insertions(+), 8 deletions(-) diff --git a/csdr.c b/csdr.c index 52de1ab..6a0c42a 100644 --- a/csdr.c +++ b/csdr.c @@ -163,6 +163,8 @@ int clone_(int bufsize_param) } } +#define FREAD_U8 fread (input_buffer, sizeof(unsigned char), the_bufsize, stdin) +#define FWRITE_U8 fwrite (output_buffer, sizeof(unsigned char), the_bufsize, stdout) #define FREAD_R fread (input_buffer, sizeof(float), the_bufsize, stdin) #define FREAD_C fread (input_buffer, sizeof(float)*2, the_bufsize, stdin) #define FWRITE_R fwrite (output_buffer, sizeof(float), the_bufsize, stdout) @@ -352,7 +354,7 @@ int main(int argc, char *argv[]) char** fifo_buffers = (char**)malloc(sizeof(char*)*fifo_num_buffers); for(int i=0;i + { .code = 0b1010101111, .bitcount=10, .ascii=0x3f }, //? + { .code = 0b1010111101, .bitcount=10, .ascii=0x40 }, //@ + { .code = 0b1111101, .bitcount=7, .ascii=0x41 }, //A + { .code = 0b11101011, .bitcount=8, .ascii=0x42 }, //B + { .code = 0b10101101, .bitcount=8, .ascii=0x43 }, //C + { .code = 0b10110101, .bitcount=8, .ascii=0x44 }, //D + { .code = 0b1110111, .bitcount=7, .ascii=0x45 }, //E + { .code = 0b11011011, .bitcount=8, .ascii=0x46 }, //F + { .code = 0b11111101, .bitcount=8, .ascii=0x47 }, //G + { .code = 0b101010101, .bitcount=9, .ascii=0x48 }, //H + { .code = 0b1111111, .bitcount=7, .ascii=0x49 }, //I + { .code = 0b111111101, .bitcount=9, .ascii=0x4a }, //J + { .code = 0b101111101, .bitcount=9, .ascii=0x4b }, //K + { .code = 0b11010111, .bitcount=8, .ascii=0x4c }, //L + { .code = 0b10111011, .bitcount=8, .ascii=0x4d }, //M + { .code = 0b11011101, .bitcount=8, .ascii=0x4e }, //N + { .code = 0b10101011, .bitcount=8, .ascii=0x4f }, //O + { .code = 0b11010101, .bitcount=8, .ascii=0x50 }, //P + { .code = 0b111011101, .bitcount=9, .ascii=0x51 }, //Q + { .code = 0b10101111, .bitcount=8, .ascii=0x52 }, //R + { .code = 0b1101111, .bitcount=7, .ascii=0x53 }, //S + { .code = 0b1101101, .bitcount=7, .ascii=0x54 }, //T + { .code = 0b101010111, .bitcount=9, .ascii=0x55 }, //U + { .code = 0b110110101, .bitcount=9, .ascii=0x56 }, //V + { .code = 0b101011101, .bitcount=9, .ascii=0x57 }, //W + { .code = 0b101110101, .bitcount=9, .ascii=0x58 }, //X + { .code = 0b101111011, .bitcount=9, .ascii=0x59 }, //Y + { .code = 0b1010101101, .bitcount=10, .ascii=0x5a }, //Z + { .code = 0b111110111, .bitcount=9, .ascii=0x5b }, //[ + { .code = 0b111101111, .bitcount=9, .ascii=0x5c }, //\ + { .code = 0b111111011, .bitcount=9, .ascii=0x5d }, //] + { .code = 0b1010111111, .bitcount=10, .ascii=0x5e }, //^ + { .code = 0b101101101, .bitcount=9, .ascii=0x5f }, //_ + { .code = 0b1011011111, .bitcount=10, .ascii=0x60 }, //` + { .code = 0b1011, .bitcount=4, .ascii=0x61 }, //a + { .code = 0b1011111, .bitcount=7, .ascii=0x62 }, //b + { .code = 0b101111, .bitcount=6, .ascii=0x63 }, //c + { .code = 0b101101, .bitcount=6, .ascii=0x64 }, //d + { .code = 0b11, .bitcount=2, .ascii=0x65 }, //e + { .code = 0b111101, .bitcount=6, .ascii=0x66 }, //f + { .code = 0b1011011, .bitcount=7, .ascii=0x67 }, //g + { .code = 0b101011, .bitcount=6, .ascii=0x68 }, //h + { .code = 0b1101, .bitcount=4, .ascii=0x69 }, //i + { .code = 0b111101011, .bitcount=9, .ascii=0x6a }, //j + { .code = 0b10111111, .bitcount=8, .ascii=0x6b }, //k + { .code = 0b11011, .bitcount=5, .ascii=0x6c }, //l + { .code = 0b111011, .bitcount=6, .ascii=0x6d }, //m + { .code = 0b1111, .bitcount=4, .ascii=0x6e }, //n + { .code = 0b111, .bitcount=3, .ascii=0x6f }, //o + { .code = 0b111111, .bitcount=6, .ascii=0x70 }, //p + { .code = 0b110111111, .bitcount=9, .ascii=0x71 }, //q + { .code = 0b10101, .bitcount=5, .ascii=0x72 }, //r + { .code = 0b10111, .bitcount=5, .ascii=0x73 }, //s + { .code = 0b101, .bitcount=3, .ascii=0x74 }, //t + { .code = 0b110111, .bitcount=6, .ascii=0x75 }, //u + { .code = 0b1111011, .bitcount=7, .ascii=0x76 }, //v + { .code = 0b1101011, .bitcount=7, .ascii=0x77 }, //w + { .code = 0b11011111, .bitcount=8, .ascii=0x78 }, //x + { .code = 0b1011101, .bitcount=7, .ascii=0x79 }, //y + { .code = 0b111010101, .bitcount=9, .ascii=0x7a }, //z + { .code = 0b1010110111, .bitcount=10, .ascii=0x7b }, //{ + { .code = 0b110111011, .bitcount=9, .ascii=0x7c }, //| + { .code = 0b1010110101, .bitcount=10, .ascii=0x7d }, //} + { .code = 0b1011010111, .bitcount=10, .ascii=0x7e }, //~ + { .code = 0b1110110101, .bitcount=10, .ascii=0x7f }, //DEL +}; + +const int n_psk31_varicode_items = sizeof(psk31_varicode_items) / sizeof(psk31_varicode_item_t); + +unsigned long long psk31_varicode_masklen_helper[] = +{ + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000001, + 0b0000000000000000000000000000000000000000000000000000000000000011, + 0b0000000000000000000000000000000000000000000000000000000000000111, + 0b0000000000000000000000000000000000000000000000000000000000001111, + 0b0000000000000000000000000000000000000000000000000000000000011111, + 0b0000000000000000000000000000000000000000000000000000000000111111, + 0b0000000000000000000000000000000000000000000000000000000001111111, + 0b0000000000000000000000000000000000000000000000000000000011111111, + 0b0000000000000000000000000000000000000000000000000000000111111111, + 0b0000000000000000000000000000000000000000000000000000001111111111, + 0b0000000000000000000000000000000000000000000000000000011111111111, + 0b0000000000000000000000000000000000000000000000000000111111111111, + 0b0000000000000000000000000000000000000000000000000001111111111111, + 0b0000000000000000000000000000000000000000000000000011111111111111, + 0b0000000000000000000000000000000000000000000000000111111111111111, + 0b0000000000000000000000000000000000000000000000001111111111111111, + 0b0000000000000000000000000000000000000000000000011111111111111111, + 0b0000000000000000000000000000000000000000000000111111111111111111, + 0b0000000000000000000000000000000000000000000001111111111111111111, + 0b0000000000000000000000000000000000000000000011111111111111111111, + 0b0000000000000000000000000000000000000000000111111111111111111111, + 0b0000000000000000000000000000000000000000001111111111111111111111, + 0b0000000000000000000000000000000000000000011111111111111111111111, + 0b0000000000000000000000000000000000000000111111111111111111111111, + 0b0000000000000000000000000000000000000001111111111111111111111111, + 0b0000000000000000000000000000000000000011111111111111111111111111, + 0b0000000000000000000000000000000000000111111111111111111111111111, + 0b0000000000000000000000000000000000001111111111111111111111111111, + 0b0000000000000000000000000000000000011111111111111111111111111111, + 0b0000000000000000000000000000000000111111111111111111111111111111, + 0b0000000000000000000000000000000001111111111111111111111111111111, + 0b0000000000000000000000000000000011111111111111111111111111111111, + 0b0000000000000000000000000000000111111111111111111111111111111111, + 0b0000000000000000000000000000001111111111111111111111111111111111, + 0b0000000000000000000000000000011111111111111111111111111111111111, + 0b0000000000000000000000000000111111111111111111111111111111111111, + 0b0000000000000000000000000001111111111111111111111111111111111111, + 0b0000000000000000000000000011111111111111111111111111111111111111, + 0b0000000000000000000000000111111111111111111111111111111111111111, + 0b0000000000000000000000001111111111111111111111111111111111111111, + 0b0000000000000000000000011111111111111111111111111111111111111111, + 0b0000000000000000000000111111111111111111111111111111111111111111, + 0b0000000000000000000001111111111111111111111111111111111111111111, + 0b0000000000000000000011111111111111111111111111111111111111111111, + 0b0000000000000000000111111111111111111111111111111111111111111111, + 0b0000000000000000001111111111111111111111111111111111111111111111, + 0b0000000000000000011111111111111111111111111111111111111111111111, + 0b0000000000000000111111111111111111111111111111111111111111111111, + 0b0000000000000001111111111111111111111111111111111111111111111111, + 0b0000000000000011111111111111111111111111111111111111111111111111, + 0b0000000000000111111111111111111111111111111111111111111111111111, + 0b0000000000001111111111111111111111111111111111111111111111111111, + 0b0000000000011111111111111111111111111111111111111111111111111111, + 0b0000000000111111111111111111111111111111111111111111111111111111, + 0b0000000001111111111111111111111111111111111111111111111111111111, + 0b0000000011111111111111111111111111111111111111111111111111111111, + 0b0000000111111111111111111111111111111111111111111111111111111111, + 0b0000001111111111111111111111111111111111111111111111111111111111, + 0b0000011111111111111111111111111111111111111111111111111111111111, + 0b0000111111111111111111111111111111111111111111111111111111111111, + 0b0001111111111111111111111111111111111111111111111111111111111111, + 0b0011111111111111111111111111111111111111111111111111111111111111, + 0b0111111111111111111111111111111111111111111111111111111111111111 +}; + +char psk31_varicode_push(unsigned long long* status_shr, unsigned char symbol) +{ + *status_shr=((*status_shr)<<1)|(!!symbol); //shift new bit in shift register + //fprintf(stderr,"*status_shr = %llx\n", *status_shr); + if((*status_shr)&0xFFF==0) return 0; + for(int i=0;i>>>>>>>> %d %x %c\n", i, psk31_varicode_items[i].ascii, psk31_varicode_items[i].ascii);*/ return psk31_varicode_items[i].ascii; } + + } + return 0; +} + + + +/* + +*/ + + + + + /* _____ _ _ | __ \ | | (_) diff --git a/libcsdr.h b/libcsdr.h index 8bcbc2a..419c064 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -178,3 +178,5 @@ void convert_f_i16(float* input, short* output, int input_size); void convert_i16_f(short* input, float* output, int input_size); int is_nan(float f); + +char psk31_varicode_push(unsigned long long* status_shr, unsigned char symbol); From 7c36a0ffcebf526b8a6393a3aef64d0982662653 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Thu, 5 May 2016 23:59:44 +0200 Subject: [PATCH 002/111] Fixed usage --- csdr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/csdr.c b/csdr.c index 6a0c42a..d0a7652 100644 --- a/csdr.c +++ b/csdr.c @@ -108,11 +108,13 @@ char usage[]= " convert_f_samperf \n" " fmmod_fc\n" " fixed_amplitude_cc \n" -" monos2stereo_s16\n" +" mono2stereo_s16\n" " setbuf \n" " fft_exchange_sides_ff \n" " squelch_and_smeter_cc --fifo --outfifo \n" " fifo \n" +" bpsk31_varicode2ascii_sy_u8\n" +" invert_sy_sy\n" " \n" ; From 380bfded2cb5fecff14672bc3bf9657e35079dad Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 8 May 2016 09:33:40 +0200 Subject: [PATCH 003/111] First concept of serial_line_decoder_f_u8. --- csdr.c | 101 ++++++++++++++++++++++++++++-- libcsdr.c | 182 +++++++++++++++++++++++++++++++++++++++++++++++++----- libcsdr.h | 60 +++++++++++++++++- 3 files changed, 321 insertions(+), 22 deletions(-) diff --git a/csdr.c b/csdr.c index d0a7652..6e5b470 100644 --- a/csdr.c +++ b/csdr.c @@ -113,8 +113,11 @@ char usage[]= " fft_exchange_sides_ff \n" " squelch_and_smeter_cc --fifo --outfifo \n" " fifo \n" -" bpsk31_varicode2ascii_sy_u8\n" +" bpsk31_line_decoder_sy_u8\n" " invert_sy_sy\n" +" rtty_line_decoder_sy_u8\n" +" rtty_baudot2ascii_u8_u8\n" +" serial_line_decoder_sy_u8\n" " \n" ; @@ -1836,7 +1839,7 @@ int main(int argc, char *argv[]) } } - if(!strcmp(argv[1],"bpsk31_varicode2ascii_sy_u8")) //not tested + if(!strcmp(argv[1],"bpsk31_line_decoder_sy_u8")) { unsigned long long status_shr = 0; unsigned char output; @@ -1844,14 +1847,14 @@ int main(int argc, char *argv[]) unsigned char i=0; for(;;) { - if((output=psk31_varicode_push(&status_shr, getchar()))) { putchar(output); fflush(stdout); } + if((output=psk31_varicode_decoder_push(&status_shr, getchar()))) { putchar(output); fflush(stdout); } if(i++) continue; //do the following at every 256th execution of the loop body: FEOF_CHECK; TRY_YIELD; } } - if(!strcmp(argv[1],"invert_sy_sy")) //not tested + if(!strcmp(argv[1],"invert_sy_sy")) { if(!sendbufsize(initialize_buffers())) return -2; unsigned char i=0; @@ -1864,11 +1867,97 @@ int main(int argc, char *argv[]) } } + if(!strcmp(argv[1],"rtty_line_decoder_sy_u8")) + { + static rtty_baudot_decoder_t status_baudot; //created on .bss -> initialized to 0 + unsigned char output; + if(!sendbufsize(initialize_buffers())) return -2; + unsigned char i=0; + for(;;) + { + if((output=rtty_baudot_decoder_push(&status_baudot, getchar()))) { putchar(output); fflush(stdout); } + if(i++) continue; //do the following at every 256th execution of the loop body: + FEOF_CHECK; + TRY_YIELD; + } + } + + if(!strcmp(argv[1],"rtty_baudot2ascii_u8_u8")) + { + unsigned char fig_mode = 0; + unsigned char output; + if(!sendbufsize(initialize_buffers())) return -2; + unsigned char i=0; + for(;;) + { + if((output=rtty_baudot_decoder_lookup(&fig_mode, getchar()))) { putchar(output); fflush(stdout); } + if(i++) continue; //do the following at every 256th execution of the loop body: + FEOF_CHECK; + TRY_YIELD; + } + } + + if(!strcmp(argv[1],"binary_slicer_f_u8")) + { + if(!sendbufsize(initialize_buffers())) return -2; + for(;;) + { + FEOF_CHECK; + if(!FREAD_R) break; + binary_slicer_f_u8(input_buffer, (unsigned char*)output_buffer, the_bufsize); + FWRITE_U8; + TRY_YIELD; + } + return 0; + } + + if(!strcmp(argv[1],"serial_line_decoder_f_u8")) + { + bigbufs=1; + + serial_line_t serial; + + if(argc<=2) return badsyntax("need required parameter (samples_per_bits)"); + sscanf(argv[2],"%f",&serial.samples_per_bits); + if(serial.samples_per_bits<1) return badsyntax("samples_per_bits should be at least 1."); + if(serial.samples_per_bits<5) fprintf(stderr, "serial_line_decoder_sy_u8: warning: this algorithm does not work well if samples_per_bits is too low. It should be at least 5.\n"); + serial.actual_samples_per_bits = serial.samples_per_bits; + + serial.databits=8; + if(argc>3) sscanf(argv[3],"%d",&serial.databits); + if(serial.databits>8 || serial.databits<1) return badsyntax("databits should be between 1 and 8."); + + serial.stopbits=1; + if(argc>4) sscanf(argv[4],"%f",&serial.stopbits); + if(serial.stopbits<1) return badsyntax("stopbits should be equal or above 1."); + + serial.samples_per_bits_max_deviation_rate=0.001; + serial.samples_per_bits_loop_gain=0.05; + serial.input_used=0; + + if(!sendbufsize(initialize_buffers())) return -2; + + for(;;) + { + FEOF_CHECK; + if(serial.input_used) + { + memmove(input_buffer, input_buffer+serial.input_used, the_bufsize-serial.input_used); + fread(input_buffer+(the_bufsize-serial.input_used), sizeof(unsigned char), serial.input_used, stdin); + } + else fread(input_buffer, sizeof(unsigned char), the_bufsize, stdin); //should happen only on the first run + serial_line_decoder_f_u8(&serial,input_buffer, (unsigned char*)output_buffer, the_bufsize); + if(serial.input_used==0) { fprintf(stderr, "serial_line_decoder_sy_u8: error: serial_line_decoder() stuck.\n"); return -3; } + fwrite(output_buffer, sizeof(unsigned char), serial.output_size, stdout); + TRY_YIELD; + } + } + if(!strcmp(argv[1],"none")) { return 0; } - return badsyntax("function name given in argument 1 does not exist. Possible causes:\n- You mistyped the commandline.\n- You need to update csdr to a newer version (if available)."); - + fprintf(stderr, "csdr: function name \"%s\" given in argument 1 does not exist. Possible causes:\n- You mistyped the commandline.\n- You need to update csdr to a newer version (if available).", argv[1]); + return -1; } diff --git a/libcsdr.c b/libcsdr.c index 5dd38c7..dc8351c 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -960,14 +960,6 @@ void logpower_cf(complexf* input, float* output, int size, float add_db) |___/ */ - -typedef struct psk31_varicode_item_s -{ - unsigned long long code; - int bitcount; - unsigned char ascii; -} psk31_varicode_item_t; - psk31_varicode_item_t psk31_varicode_items[] = { { .code = 0b1010101011, .bitcount=10, .ascii=0x00 }, //NUL, null @@ -980,10 +972,10 @@ psk31_varicode_item_t psk31_varicode_items[] = { .code = 0b1011111101, .bitcount=10, .ascii=0x07 }, //BEL, bell { .code = 0b1011111111, .bitcount=10, .ascii=0x08 }, //BS, backspace { .code = 0b11101111, .bitcount=8, .ascii=0x09 }, //TAB, horizontal tab - { .code = 0b11101, .bitcount=5, .ascii=0x0a }, //LF, NL line feed, new line + { .code = 0b11101, .bitcount=5, .ascii=0x0a }, //LF, NL line feed, new line { .code = 0b1101101111, .bitcount=10, .ascii=0x0b }, //VT, vertical tab { .code = 0b1011011101, .bitcount=10, .ascii=0x0c }, //FF, NP form feed, new page - { .code = 0b11111, .bitcount=5, .ascii=0x0d }, //CR, carriage return (overwrite) + { .code = 0b11111, .bitcount=5, .ascii=0x0d }, //CR, carriage return (overwrite) { .code = 0b1101110101, .bitcount=10, .ascii=0x0e }, //SO, shift out { .code = 0b1110101011, .bitcount=10, .ascii=0x0f }, //SI, shift in { .code = 0b1011110111, .bitcount=10, .ascii=0x10 }, //DLE, data link escape @@ -1100,8 +1092,6 @@ psk31_varicode_item_t psk31_varicode_items[] = { .code = 0b1110110101, .bitcount=10, .ascii=0x7f }, //DEL }; -const int n_psk31_varicode_items = sizeof(psk31_varicode_items) / sizeof(psk31_varicode_item_t); - unsigned long long psk31_varicode_masklen_helper[] = { 0b0000000000000000000000000000000000000000000000000000000000000000, @@ -1170,7 +1160,9 @@ unsigned long long psk31_varicode_masklen_helper[] = 0b0111111111111111111111111111111111111111111111111111111111111111 }; -char psk31_varicode_push(unsigned long long* status_shr, unsigned char symbol) +const int n_psk31_varicode_items = sizeof(psk31_varicode_items) / sizeof(psk31_varicode_item_t); + +char psk31_varicode_decoder_push(unsigned long long* status_shr, unsigned char symbol) { *status_shr=((*status_shr)<<1)|(!!symbol); //shift new bit in shift register //fprintf(stderr,"*status_shr = %llx\n", *status_shr); @@ -1185,15 +1177,175 @@ char psk31_varicode_push(unsigned long long* status_shr, unsigned char symbol) return 0; } +rtty_baudot_item_t rtty_baudot_items[] = +{ + { .code = 0b00000, .ascii_letter=0, .ascii_figure=0 }, + { .code = 0b10000, .ascii_letter='E', .ascii_figure='3' }, + { .code = 0b01000, .ascii_letter='\n', .ascii_figure='\n' }, + { .code = 0b11000, .ascii_letter='A', .ascii_figure='-' }, + { .code = 0b00100, .ascii_letter=' ', .ascii_figure=' ' }, + { .code = 0b10100, .ascii_letter='S', .ascii_figure='\'' }, + { .code = 0b01100, .ascii_letter='I', .ascii_figure='8' }, + { .code = 0b11100, .ascii_letter='U', .ascii_figure='7' }, + { .code = 0b00010, .ascii_letter='\r', .ascii_figure='\r' }, + { .code = 0b10010, .ascii_letter='D', .ascii_figure='#' }, + { .code = 0b01010, .ascii_letter='R', .ascii_figure='4' }, + { .code = 0b11010, .ascii_letter='J', .ascii_figure='\a' }, + { .code = 0b00110, .ascii_letter='N', .ascii_figure=',' }, + { .code = 0b10110, .ascii_letter='F', .ascii_figure='@' }, + { .code = 0b01110, .ascii_letter='C', .ascii_figure=':' }, + { .code = 0b11110, .ascii_letter='K', .ascii_figure='(' }, + { .code = 0b00001, .ascii_letter='T', .ascii_figure='5' }, + { .code = 0b10001, .ascii_letter='Z', .ascii_figure='+' }, + { .code = 0b01001, .ascii_letter='L', .ascii_figure=')' }, + { .code = 0b11001, .ascii_letter='W', .ascii_figure='2' }, + { .code = 0b00101, .ascii_letter='H', .ascii_figure='$' }, + { .code = 0b10101, .ascii_letter='Y', .ascii_figure='6' }, + { .code = 0b01101, .ascii_letter='P', .ascii_figure='0' }, + { .code = 0b11101, .ascii_letter='Q', .ascii_figure='1' }, + { .code = 0b00011, .ascii_letter='O', .ascii_figure='9' }, + { .code = 0b10011, .ascii_letter='B', .ascii_figure='?' }, + { .code = 0b01011, .ascii_letter='G', .ascii_figure='*' }, + { .code = 0b00111, .ascii_letter='M', .ascii_figure='.' }, + { .code = 0b10111, .ascii_letter='X', .ascii_figure='/' }, + { .code = 0b01111, .ascii_letter='V', .ascii_figure='=' } +}; +const int n_rtty_baudot_items = sizeof(rtty_baudot_items) / sizeof(rtty_baudot_item_t); -/* +char rtty_baudot_decoder_lookup(unsigned char* fig_mode, unsigned char c) +{ + if(c==RTTY_FIGURE_MODE_SELECT_CODE) { *fig_mode=1; return 0; } + if(c==RTTY_LETTER_MODE_SELECT_CODE) { *fig_mode=0; return 0; } + for(int i=0;istate) + { + case RTTY_BAUDOT_WAITING_STOP_PULSE: + if(symbol==1) { s->state = RTTY_BAUDOT_WAITING_START_PULSE; if(s->character_received) return rtty_baudot_decoder_lookup(&s->fig_mode, s->shr&31); } + //If the character data is followed by a stop pulse, then we go on to wait for the next character. + else s->character_received = 0; + //The character should be followed by a stop pulse. If the stop pulse is missing, that is certainly an error. + //In that case, we remove forget the character we just received. + break; + case RTTY_BAUDOT_WAITING_START_PULSE: + s->character_received = 0; + if(symbol==0) { s->state = RTTY_BAUDOT_RECEIVING_DATA; s->shr = s->bit_cntr = 0; } + //Any number of high bits can come after each other, until interrupted with a low bit (start pulse) to indicate + //the beginning of a new character. If we get this start pulse, we go on to wait for the characters. We also + //clear the variables used for counting (bit_cntr) and storing (shr) the data bits. + break; + case RTTY_BAUDOT_RECEIVING_DATA: + s->shr = (s->shr<<1)|(!!symbol); + //We store 5 bits into our shift register + if(s->bit_cntr++==4) { s->state = RTTY_BAUDOT_WAITING_STOP_PULSE; s->character_received = 1; } + //If this is the 5th bit stored, then we wait for the stop pulse. + break; + default: break; + } + return 0; +} +void serial_line_decoder_f_u8(serial_line_t* s, float* input, unsigned char* output, int input_size) +{ + s->output_size = 0; + s->input_used = 0; + int oi=0; + short* output_s = (short*)output; + unsigned* output_u = (unsigned*)output; + for(;;) + { + //we find the start bit (first negative edge on the line) + int startbit_start = -1; + int i; + for(i=1;i 0) { startbit_start=i; break; } + if(startbit_start == -1) { s->input_used += i; fprintf(stderr,"sld:nstartbit\n"); return; } + fprintf(stderr,"sld:startbit_found at %d\n", startbit_start); + //We estimate where the stop bit edge can be, and search for it. + int stopbit_end = -1; + float all_bits = 1 + s->databits + s->stopbits; + float stopbit_end_estimate = startbit_start + s->samples_per_bits * all_bits; + float stopbit_end_search_start = stopbit_end_estimate - s->actual_samples_per_bits * 0.4; + float stopbit_end_search_end = stopbit_end_estimate + s->actual_samples_per_bits * 0.4; + if(stopbit_end_search_end>=input_size) return; + fprintf(stderr,"sld:all_bits = %f\n", all_bits); + fprintf(stderr,"sld:actual_samples_per_bits = %f\n", s->actual_samples_per_bits); + fprintf(stderr,"sld:stopbit_end_search_start = %f\n", stopbit_end_search_start); + fprintf(stderr,"sld:stopbit_end_search_end = %f\n", stopbit_end_search_end); + //If it is too far and we reached the end of the buffer, then we return failed. + //The caller can rearrange the buffer so that the whole character fits into it. + if(stopbit_end_search_end>=input_size) + for(i=stopbit_end_search_start+1;i 0) { stopbit_end=i; break; } + if(stopbit_end == -1) + { + s->input_used += i+1; + if(s->input_used >= input_size) + { + s->input_used = input_size; + fprintf(stderr,"sld:nstopbit input_used out %d\n", s->input_used); + return; + } + input += s->input_used; + input_size -= s->input_used; + fprintf(stderr,"sld:nstopbit remain = %d\n", input_size); continue; + } + fprintf(stderr,"sld:stopbit_end = %d\n", stopbit_end); + //If we have the position of the stop bit, we calculate the actual_samples_per_bits: + float calculated_samples_per_bits = (stopbit_end - startbit_start) / all_bits; + float error_samples_per_bits = s->actual_samples_per_bits - calculated_samples_per_bits; + s->actual_samples_per_bits = s->actual_samples_per_bits - s->samples_per_bits_loop_gain * error_samples_per_bits; + s->actual_samples_per_bits = MIN_M(s->actual_samples_per_bits, (1+s->samples_per_bits_max_deviation_rate) * s->samples_per_bits); + s->actual_samples_per_bits = MAX_M(s->actual_samples_per_bits, (1-s->samples_per_bits_max_deviation_rate) * s->samples_per_bits); + fprintf(stderr,"sld:calculated_samples_per_bits = %f\n", calculated_samples_per_bits); + fprintf(stderr,"sld:error_samples_per_bits = %f\n", error_samples_per_bits); + + fprintf(stderr, "actual_samples_per_bits = %f\n", s->actual_samples_per_bits); + + //Now we have an actual_samples_per_bits, we do the actual sampling + int di; //databit counter + unsigned shr = 0; + for(di=0; di < s->databits; di++) + { + int databit_start = startbit_start + di * s->actual_samples_per_bits; + int databit_end = startbit_start + (di+1) * s->actual_samples_per_bits; + float databit_acc = 0; + for(i=databit_start;i0); + } + + //optionally we could check if the stopbit is correct + + //we write the output sample + if(s->databits <= 8) output[oi++] = shr; + else if(s->databits <= 16) output_s[oi] = shr; + else output_u[oi++] = shr; + + int samples_used_up_now = MIN_M(stopbit_end + s->actual_samples_per_bits, input_size); + s->input_used += samples_used_up_now; + input += samples_used_up_now; + input_size -= samples_used_up_now; + } + s->output_size = oi; + fprintf(stderr, "so: %d\n", s->output_size); +} + +void binary_slicer_f_u8(float* input, unsigned char* output, int input_size) +{ + for(int i=0;i 0; +} /* _____ _ _ diff --git a/libcsdr.h b/libcsdr.h index 419c064..90adaab 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #define MIN_M(x,y) (((x)>(y))?(y):(x)) +#define MAX_M(x,y) (((x)<(y))?(y):(x)) /* _____ _ @@ -179,4 +180,61 @@ void convert_i16_f(short* input, float* output, int input_size); int is_nan(float f); -char psk31_varicode_push(unsigned long long* status_shr, unsigned char symbol); +//digital demod + +typedef struct rtty_baudot_item_s +{ + unsigned long long code; + unsigned char ascii_letter; + unsigned char ascii_figure; +} rtty_baudot_item_t; + +typedef enum rtty_baudot_decoder_state_e +{ + RTTY_BAUDOT_WAITING_STOP_PULSE = 0, + RTTY_BAUDOT_WAITING_START_PULSE, + RTTY_BAUDOT_RECEIVING_DATA +} rtty_baudot_decoder_state_t; + +typedef struct rtty_baudot_decoder_s +{ + unsigned char fig_mode; + unsigned char character_received; + unsigned short shr; + unsigned char bit_cntr; + rtty_baudot_decoder_state_t state; +} rtty_baudot_decoder_t; + +#define RTTY_FIGURE_MODE_SELECT_CODE 0b11011 +#define RTTY_LETTER_MODE_SELECT_CODE 0b11111 + +char rtty_baudot_decoder_lookup(unsigned char* fig_mode, unsigned char c); +char rtty_baudot_decoder_push(rtty_baudot_decoder_t* s, unsigned char symbol); + +//PSK31 + +typedef struct psk31_varicode_item_s +{ + unsigned long long code; + int bitcount; + unsigned char ascii; +} psk31_varicode_item_t; + +char psk31_varicode_decoder_push(unsigned long long* status_shr, unsigned char symbol); + +//Serial + +typedef struct serial_line_s +{ + float samples_per_bits; + float actual_samples_per_bits; + int databits; //including parity + float stopbits; + int output_size; + int input_used; + float samples_per_bits_max_deviation_rate; + float samples_per_bits_loop_gain; +} serial_line_t; + +void serial_line_decoder_f_u8(serial_line_t* s, float* input, unsigned char* output, int input_size); +void binary_slicer_f_u8(float* input, unsigned char* output, int input_size); From d79807a67c32e2b86e83ba14b92dc4d2b995b8a4 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 8 May 2016 12:38:09 +0200 Subject: [PATCH 004/111] Now we have a working serial_line_decoder_f_u8. --- csdr.c | 15 +++++---- libcsdr.c | 95 ++++++++++++++++++++++++------------------------------- libcsdr.h | 4 +-- 3 files changed, 51 insertions(+), 63 deletions(-) diff --git a/csdr.c b/csdr.c index 6e5b470..50e8e82 100644 --- a/csdr.c +++ b/csdr.c @@ -1921,7 +1921,6 @@ int main(int argc, char *argv[]) sscanf(argv[2],"%f",&serial.samples_per_bits); if(serial.samples_per_bits<1) return badsyntax("samples_per_bits should be at least 1."); if(serial.samples_per_bits<5) fprintf(stderr, "serial_line_decoder_sy_u8: warning: this algorithm does not work well if samples_per_bits is too low. It should be at least 5.\n"); - serial.actual_samples_per_bits = serial.samples_per_bits; serial.databits=8; if(argc>3) sscanf(argv[3],"%d",&serial.databits); @@ -1931,8 +1930,7 @@ int main(int argc, char *argv[]) if(argc>4) sscanf(argv[4],"%f",&serial.stopbits); if(serial.stopbits<1) return badsyntax("stopbits should be equal or above 1."); - serial.samples_per_bits_max_deviation_rate=0.001; - serial.samples_per_bits_loop_gain=0.05; + serial.bit_sampling_width_ratio = 0.4; serial.input_used=0; if(!sendbufsize(initialize_buffers())) return -2; @@ -1942,13 +1940,16 @@ int main(int argc, char *argv[]) FEOF_CHECK; if(serial.input_used) { - memmove(input_buffer, input_buffer+serial.input_used, the_bufsize-serial.input_used); - fread(input_buffer+(the_bufsize-serial.input_used), sizeof(unsigned char), serial.input_used, stdin); + memmove(input_buffer, input_buffer+serial.input_used, sizeof(float)*(the_bufsize-serial.input_used)); + fread(input_buffer+(the_bufsize-serial.input_used), sizeof(float), serial.input_used, stdin); } - else fread(input_buffer, sizeof(unsigned char), the_bufsize, stdin); //should happen only on the first run + else fread(input_buffer, sizeof(float), the_bufsize, stdin); //should happen only on the first run serial_line_decoder_f_u8(&serial,input_buffer, (unsigned char*)output_buffer, the_bufsize); - if(serial.input_used==0) { fprintf(stderr, "serial_line_decoder_sy_u8: error: serial_line_decoder() stuck.\n"); return -3; } + //printf("now in | "); + if(serial.input_used==0) { fprintf(stderr, "serial_line_decoder_sy_u8: error: serial_line_decoder_f_u8() got stuck.\n"); return -3; } + //printf("now out %d | ", serial.output_size); fwrite(output_buffer, sizeof(unsigned char), serial.output_size, stdout); + fflush(stdout); TRY_YIELD; } } diff --git a/libcsdr.c b/libcsdr.c index dc8351c..3126440 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1256,11 +1256,19 @@ char rtty_baudot_decoder_push(rtty_baudot_decoder_t* s, unsigned char symbol) return 0; } +#define DEBUG_SERIAL_LINE_DECODER 0 + +//What has not been checked: +// behaviour on 1.5 stop bits +// check all exit conditions + void serial_line_decoder_f_u8(serial_line_t* s, float* input, unsigned char* output, int input_size) { + static int abs_samples_helper = 0; + abs_samples_helper += s->input_used; + int iabs_samples_helper = abs_samples_helper; s->output_size = 0; s->input_used = 0; - int oi=0; short* output_s = (short*)output; unsigned* output_u = (unsigned*)output; for(;;) @@ -1270,76 +1278,57 @@ void serial_line_decoder_f_u8(serial_line_t* s, float* input, unsigned char* out int i; for(i=1;i 0) { startbit_start=i; break; } - if(startbit_start == -1) { s->input_used += i; fprintf(stderr,"sld:nstartbit\n"); return; } - fprintf(stderr,"sld:startbit_found at %d\n", startbit_start); - //We estimate where the stop bit edge can be, and search for it. - int stopbit_end = -1; - float all_bits = 1 + s->databits + s->stopbits; - float stopbit_end_estimate = startbit_start + s->samples_per_bits * all_bits; - float stopbit_end_search_start = stopbit_end_estimate - s->actual_samples_per_bits * 0.4; - float stopbit_end_search_end = stopbit_end_estimate + s->actual_samples_per_bits * 0.4; - if(stopbit_end_search_end>=input_size) return; - fprintf(stderr,"sld:all_bits = %f\n", all_bits); - fprintf(stderr,"sld:actual_samples_per_bits = %f\n", s->actual_samples_per_bits); - fprintf(stderr,"sld:stopbit_end_search_start = %f\n", stopbit_end_search_start); - fprintf(stderr,"sld:stopbit_end_search_end = %f\n", stopbit_end_search_end); + if(startbit_start == -1) { s->input_used += i; DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:startbit_not_found (+%d)\n", s->input_used); return; } + DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:startbit_found at %d (%d)\n", startbit_start, iabs_samples_helper + startbit_start); - //If it is too far and we reached the end of the buffer, then we return failed. + //If the stop bit would be too far so that we reached the end of the buffer, then we return failed. //The caller can rearrange the buffer so that the whole character fits into it. - if(stopbit_end_search_end>=input_size) - for(i=stopbit_end_search_start+1;i 0) { stopbit_end=i; break; } - if(stopbit_end == -1) - { - s->input_used += i+1; - if(s->input_used >= input_size) - { - s->input_used = input_size; - fprintf(stderr,"sld:nstopbit input_used out %d\n", s->input_used); - return; - } - input += s->input_used; - input_size -= s->input_used; - fprintf(stderr,"sld:nstopbit remain = %d\n", input_size); continue; - } - fprintf(stderr,"sld:stopbit_end = %d\n", stopbit_end); + float all_bits = 1 + s->databits + s->stopbits; + DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:all_bits = %f\n", all_bits); + if(startbit_start + s->samples_per_bits * all_bits >= input_size) { s->input_used += MAX_M(0,startbit_start-2); DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:return_stopbit_too_far (+%d)\n", s->input_used); return; } - //If we have the position of the stop bit, we calculate the actual_samples_per_bits: - float calculated_samples_per_bits = (stopbit_end - startbit_start) / all_bits; - float error_samples_per_bits = s->actual_samples_per_bits - calculated_samples_per_bits; - s->actual_samples_per_bits = s->actual_samples_per_bits - s->samples_per_bits_loop_gain * error_samples_per_bits; - s->actual_samples_per_bits = MIN_M(s->actual_samples_per_bits, (1+s->samples_per_bits_max_deviation_rate) * s->samples_per_bits); - s->actual_samples_per_bits = MAX_M(s->actual_samples_per_bits, (1-s->samples_per_bits_max_deviation_rate) * s->samples_per_bits); - fprintf(stderr,"sld:calculated_samples_per_bits = %f\n", calculated_samples_per_bits); - fprintf(stderr,"sld:error_samples_per_bits = %f\n", error_samples_per_bits); - - fprintf(stderr, "actual_samples_per_bits = %f\n", s->actual_samples_per_bits); - - //Now we have an actual_samples_per_bits, we do the actual sampling + //We do the actual sampling. int di; //databit counter unsigned shr = 0; for(di=0; di < s->databits; di++) { - int databit_start = startbit_start + di * s->actual_samples_per_bits; - int databit_end = startbit_start + (di+1) * s->actual_samples_per_bits; + int databit_start = startbit_start + (1+di+(0.5*(1-s->bit_sampling_width_ratio))) * s->samples_per_bits; + int databit_end = startbit_start + (1+di+(0.5*(1+s->bit_sampling_width_ratio))) * s->samples_per_bits; + DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:databit_start = %d (%d)\n", databit_start, iabs_samples_helper+databit_start); + DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:databit_end = %d (%d)\n", databit_end, iabs_samples_helper+databit_end); float databit_acc = 0; - for(i=databit_start;i0)); shr=(shr<<1)|!!(databit_acc>0); } + DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:shr = 0x%x, %d\n", shr, shr); - //optionally we could check if the stopbit is correct + //We check if the stopbit is correct. + int stopbit_start = startbit_start + (1+s->databits) * s->samples_per_bits + (s->stopbits * 0.5 * (1-s->bit_sampling_width_ratio)) * s->samples_per_bits; + int stopbit_end = startbit_start + (1+s->databits) * s->samples_per_bits + (s->stopbits * 0.5 * (1+s->bit_sampling_width_ratio)) * s->samples_per_bits; + DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:stopbit_start = %d (%d)\n", stopbit_start, iabs_samples_helper+stopbit_start); + DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:stopbit_end = %d (%d)\n", stopbit_end, iabs_samples_helper+stopbit_end); + float stopbit_acc = 0; + for(i=stopbit_start;iinput_used += MIN_M(startbit_start + 1, input_size); DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:return_stopbit_faulty (+%d)\n", s->input_used); return; } + DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:stopbit_found\n"); //we write the output sample - if(s->databits <= 8) output[oi++] = shr; - else if(s->databits <= 16) output_s[oi] = shr; - else output_u[oi++] = shr; + if(s->databits <= 8) output[s->output_size] = shr; + else if(s->databits <= 16) output_s[s->output_size] = shr; + else output_u[s->output_size] = shr; + s->output_size++; - int samples_used_up_now = MIN_M(stopbit_end + s->actual_samples_per_bits, input_size); + int samples_used_up_now = MIN_M(startbit_start + all_bits * s->samples_per_bits, input_size); s->input_used += samples_used_up_now; input += samples_used_up_now; input_size -= samples_used_up_now; + iabs_samples_helper += samples_used_up_now; + if(!input_size) { DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:return_no_more_input (+%d)\n", s->input_used); return; } } - s->output_size = oi; - fprintf(stderr, "so: %d\n", s->output_size); + DEBUG_SERIAL_LINE_DECODER && fprintf(stderr, "sld: >> output_size = %d (+%d)\n", s->output_size, s->input_used); } void binary_slicer_f_u8(float* input, unsigned char* output, int input_size) diff --git a/libcsdr.h b/libcsdr.h index 90adaab..b1b116d 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -227,13 +227,11 @@ char psk31_varicode_decoder_push(unsigned long long* status_shr, unsigned char s typedef struct serial_line_s { float samples_per_bits; - float actual_samples_per_bits; int databits; //including parity float stopbits; int output_size; int input_used; - float samples_per_bits_max_deviation_rate; - float samples_per_bits_loop_gain; + float bit_sampling_width_ratio; } serial_line_t; void serial_line_decoder_f_u8(serial_line_t* s, float* input, unsigned char* output, int input_size); From a89d174ec598b8b77ffb6445645bf85a5671c80f Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Mon, 9 May 2016 12:59:08 +0200 Subject: [PATCH 005/111] Added pll_cc --- csdr.c | 39 ++++++++++++++++++++++++++++++++++ libcsdr.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ libcsdr.h | 27 ++++++++++++++++++++++++ 3 files changed, 128 insertions(+) diff --git a/csdr.c b/csdr.c index 50e8e82..17d5b64 100644 --- a/csdr.c +++ b/csdr.c @@ -1954,6 +1954,45 @@ int main(int argc, char *argv[]) } } + if(!strcmp(argv[1],"pll_cc")) + { + pll_t pll; + + if(argc<=2) return badsyntax("need required parameter (pll_type)"); + sscanf(argv[2],"%d",(int*)&pll.pll_type); + //if(serial.samples_per_bits<1) return badsyntax("samples_per_bits should be at least 1."); + //if(serial.samples_per_bits<5) fprintf(stderr, "serial_line_decoder_sy_u8: warning: this algorithm does not work well if samples_per_bits is too low. It should be at least 5.\n"); + if(pll.pll_type == PLL_1ST_ORDER_IIR_LOOP_FILTER) + { + float alpha = 0.01; + if(argc>3) sscanf(argv[3],"%f",&alpha); + pll_cc_init_1st_order_IIR(&pll, alpha); + } + else if(pll.pll_type == PLL_2ND_ORDER_IIR_LOOP_FILTER) + { + float bandwidth = 0.1, gain = 1000, damping_factor = 0.707; + if(argc>3) sscanf(argv[3],"%f",&bandwidth); + if(argc>4) sscanf(argv[4],"%f",&gain); + if(argc>5) sscanf(argv[5],"%f",&damping_factor); + pll_cc_init_2nd_order_IIR(&pll, bandwidth, gain, damping_factor); + fprintf(stderr, "%f %f %f | a: %f %f %f | b: %f %f %f\n", bandwidth, gain, damping_factor, + pll.filter_taps_a[0], pll.filter_taps_a[1], pll.filter_taps_a[2], pll.filter_taps_b[0], pll.filter_taps_b[1], pll.filter_taps_b[2]); + } + else return badsyntax("invalid pll_type. Valid values are:\n\t1: PLL_1ST_ORDER_IIR_LOOP_FILTER\n\t2: PLL_2ND_ORDER_IIR_LOOP_FILTER"); + + if(!sendbufsize(initialize_buffers())) return -2; + + for(;;) + { + FEOF_CHECK; + FREAD_C; + //pll_cc(&pll, (complexf*)input_buffer, NULL, (complexf*)output_buffer, the_bufsize); + pll_cc(&pll, (complexf*)input_buffer, output_buffer, NULL, the_bufsize); + fwrite(output_buffer, sizeof(float), the_bufsize, stdout); + TRY_YIELD; + } + } + if(!strcmp(argv[1],"none")) { return 0; diff --git a/libcsdr.c b/libcsdr.c index 3126440..2bfbd93 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1336,6 +1336,68 @@ void binary_slicer_f_u8(float* input, unsigned char* output, int input_size) for(int i=0;i 0; } +void pll_cc_init_2nd_order_IIR(pll_t* p, float bandwidth, float gain, float dampling_factor) +{ + p->filter_taps_a[0] = 1; + p->filter_taps_a[1] = -2; + p->filter_taps_a[2] = 1; + float tau1 = gain / (bandwidth*bandwidth); + float tau2 = (2*dampling_factor) / bandwidth; + p->filter_taps_b[0] = 4*(gain/tau1)*(1+tau2/2); + p->filter_taps_b[1] = 8*(gain/tau1); + p->filter_taps_b[2] = 4*(gain/tau1)*(1-tau2/2); + p->last_filter_outputs[0]=p->last_filter_outputs[1]=p->last_filter_inputs[0]=p->last_filter_inputs[1]=0; + p->dphase=p->output_phase=0; +} + +void pll_cc_init_1st_order_IIR(pll_t* p, float alpha) +{ + p->alpha = alpha; + p->dphase=p->output_phase=0; +} + + +void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_vco, int input_size) +{ + for(int i=0;ioutput_phase += p->dphase; + while(p->output_phase>PI) p->output_phase-=2*PI; + while(p->output_phase<-PI) p->output_phase+=2*PI; + if(output_vco) //we don't output anything if it is a NULL pointer + { + iof(output_vco,i) = cos(p->output_phase); + qof(output_vco,i) = sin(p->output_phase); + } + + float input_phase = atan2(iof(input,i),qof(input,i)); + float new_dphase = input_phase - p->output_phase; //arg(input[i]/abs(input[i]) * conj(current_output_vco[i])) + + + if(p->pll_type == PLL_2ND_ORDER_IIR_LOOP_FILTER) + { + p->dphase = 0 //... + + new_dphase * p->filter_taps_b[0] + + p->last_filter_inputs[1] * p->filter_taps_b[1] + + p->last_filter_inputs[0] * p->filter_taps_b[2] + - p->last_filter_outputs[1] * p->filter_taps_a[1] + - p->last_filter_outputs[0] * p->filter_taps_a[2]; + //dphase /= filter_taps_a[0]; //The filter taps are already normalized, a[0]==1 always, so it is not necessary. + + p->last_filter_outputs[0]=p->last_filter_outputs[1]; + p->last_filter_outputs[1]=p->dphase; + p->last_filter_inputs[0]=p->last_filter_inputs[1]; + p->last_filter_inputs[1]=new_dphase; + } + else if(p->pll_type == PLL_1ST_ORDER_IIR_LOOP_FILTER) + { + p->dphase = p->dphase * (1-p->alpha) + new_dphase * p->alpha; + } + else return; + if(output_dphase) output_dphase[i] = p->dphase; + } +} + /* _____ _ _ | __ \ | | (_) diff --git a/libcsdr.h b/libcsdr.h index b1b116d..ff89568 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -236,3 +236,30 @@ typedef struct serial_line_s void serial_line_decoder_f_u8(serial_line_t* s, float* input, unsigned char* output, int input_size); void binary_slicer_f_u8(float* input, unsigned char* output, int input_size); + + +typedef enum pll_type_e +{ + PLL_1ST_ORDER_IIR_LOOP_FILTER=1, + PLL_2ND_ORDER_IIR_LOOP_FILTER=2 +} pll_type_t; + +typedef struct pll_s +{ + pll_type_t pll_type; + //common: + float output_phase; + float dphase; + float frequency; + //2nd order IIR: + float last_filter_outputs[2]; + float last_filter_inputs[2]; + float filter_taps_a[3]; + float filter_taps_b[3]; + //1st order IIR: + float alpha; +} pll_t; + +void pll_cc_init_2nd_order_IIR(pll_t* p, float bandwidth, float gain, float dampling_factor); +void pll_cc_init_1st_order_IIR(pll_t* p, float alpha); +void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_vco, int input_size); From 4ecc84eefd3816380b70b190ead86daa6d3bdf50 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Mon, 9 May 2016 13:58:45 +0200 Subject: [PATCH 006/111] Got PLL working with the 1st order IIR loop filter. --- csdr.c | 7 +++++-- libcsdr.c | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/csdr.c b/csdr.c index 17d5b64..bde553e 100644 --- a/csdr.c +++ b/csdr.c @@ -1987,8 +1987,11 @@ int main(int argc, char *argv[]) FEOF_CHECK; FREAD_C; //pll_cc(&pll, (complexf*)input_buffer, NULL, (complexf*)output_buffer, the_bufsize); - pll_cc(&pll, (complexf*)input_buffer, output_buffer, NULL, the_bufsize); - fwrite(output_buffer, sizeof(float), the_bufsize, stdout); + //fprintf(stderr, "| i"); + //pll_cc(&pll, (complexf*)input_buffer, output_buffer, NULL, the_bufsize); + pll_cc(&pll, (complexf*)input_buffer, NULL, (complexf*)output_buffer, the_bufsize); + fwrite(output_buffer, sizeof(complexf), the_bufsize, stdout); + //fprintf(stderr, "| o"); TRY_YIELD; } } diff --git a/libcsdr.c b/libcsdr.c index 2bfbd93..4406e67 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1372,7 +1372,8 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_vc float input_phase = atan2(iof(input,i),qof(input,i)); float new_dphase = input_phase - p->output_phase; //arg(input[i]/abs(input[i]) * conj(current_output_vco[i])) - + while(new_dphase>PI) new_dphase-=2*PI; + while(new_dphase<-PI) new_dphase+=2*PI; if(p->pll_type == PLL_2ND_ORDER_IIR_LOOP_FILTER) { @@ -1395,6 +1396,7 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_vc } else return; if(output_dphase) output_dphase[i] = p->dphase; + //if(output_dphase) output_dphase[i] = new_dphase/3.15; } } From 20a2cdc73c9ec09728c0fcbb74b6201c7597be88 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Mon, 9 May 2016 14:02:24 +0200 Subject: [PATCH 007/111] Got the VCO output inverted (and the signal as well), so now the output and the input are actually in phase. --- libcsdr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libcsdr.c b/libcsdr.c index 4406e67..ca43c40 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1366,8 +1366,8 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_vc while(p->output_phase<-PI) p->output_phase+=2*PI; if(output_vco) //we don't output anything if it is a NULL pointer { - iof(output_vco,i) = cos(p->output_phase); - qof(output_vco,i) = sin(p->output_phase); + iof(output_vco,i) = sin(p->output_phase); + qof(output_vco,i) = cos(p->output_phase); } float input_phase = atan2(iof(input,i),qof(input,i)); @@ -1395,7 +1395,7 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_vc p->dphase = p->dphase * (1-p->alpha) + new_dphase * p->alpha; } else return; - if(output_dphase) output_dphase[i] = p->dphase; + if(output_dphase) output_dphase[i] = -p->dphase; //if(output_dphase) output_dphase[i] = new_dphase/3.15; } } From 88068ec5178d77dbc6a15c0987a886b044946cf3 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Mon, 9 May 2016 14:06:03 +0200 Subject: [PATCH 008/111] Got the VCO output inverted (and the signal as well), so now the output and the input are actually in phase. --- csdr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/csdr.c b/csdr.c index bde553e..05569c5 100644 --- a/csdr.c +++ b/csdr.c @@ -1987,10 +1987,10 @@ int main(int argc, char *argv[]) FEOF_CHECK; FREAD_C; //pll_cc(&pll, (complexf*)input_buffer, NULL, (complexf*)output_buffer, the_bufsize); - //fprintf(stderr, "| i"); - //pll_cc(&pll, (complexf*)input_buffer, output_buffer, NULL, the_bufsize); - pll_cc(&pll, (complexf*)input_buffer, NULL, (complexf*)output_buffer, the_bufsize); - fwrite(output_buffer, sizeof(complexf), the_bufsize, stdout); + // fprintf(stderr, "| i"); + pll_cc(&pll, (complexf*)input_buffer, output_buffer, NULL, the_bufsize); + //pll_cc(&pll, (complexf*)input_buffer, NULL, (complexf*)output_buffer, the_bufsize); + fwrite(output_buffer, sizeof(float), the_bufsize, stdout); //fprintf(stderr, "| o"); TRY_YIELD; } From 33a8cf048215ae737d2067ec491b00dc2ed39a07 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Tue, 10 May 2016 21:46:33 +0200 Subject: [PATCH 009/111] Several changes related to PLL --- csdr.c | 6 +++--- libcsdr.c | 22 ++++++++++++++++------ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/csdr.c b/csdr.c index 05569c5..eff693f 100644 --- a/csdr.c +++ b/csdr.c @@ -1970,7 +1970,7 @@ int main(int argc, char *argv[]) } else if(pll.pll_type == PLL_2ND_ORDER_IIR_LOOP_FILTER) { - float bandwidth = 0.1, gain = 1000, damping_factor = 0.707; + float bandwidth = 0.01, gain = 1000, damping_factor = 0.707; if(argc>3) sscanf(argv[3],"%f",&bandwidth); if(argc>4) sscanf(argv[4],"%f",&gain); if(argc>5) sscanf(argv[5],"%f",&damping_factor); @@ -1987,11 +1987,11 @@ int main(int argc, char *argv[]) FEOF_CHECK; FREAD_C; //pll_cc(&pll, (complexf*)input_buffer, NULL, (complexf*)output_buffer, the_bufsize); - // fprintf(stderr, "| i"); + fprintf(stderr, "| i"); pll_cc(&pll, (complexf*)input_buffer, output_buffer, NULL, the_bufsize); //pll_cc(&pll, (complexf*)input_buffer, NULL, (complexf*)output_buffer, the_bufsize); fwrite(output_buffer, sizeof(float), the_bufsize, stdout); - //fprintf(stderr, "| o"); + fprintf(stderr, "| o"); TRY_YIELD; } } diff --git a/libcsdr.c b/libcsdr.c index ca43c40..09bd22e 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1338,9 +1338,10 @@ void binary_slicer_f_u8(float* input, unsigned char* output, int input_size) void pll_cc_init_2nd_order_IIR(pll_t* p, float bandwidth, float gain, float dampling_factor) { - p->filter_taps_a[0] = 1; - p->filter_taps_a[1] = -2; - p->filter_taps_a[2] = 1; + float k=0.9; + p->filter_taps_a[0] = k*1; + p->filter_taps_a[1] = k*(-2); + p->filter_taps_a[2] = k*1; float tau1 = gain / (bandwidth*bandwidth); float tau2 = (2*dampling_factor) / bandwidth; p->filter_taps_b[0] = 4*(gain/tau1)*(1+tau2/2); @@ -1348,6 +1349,11 @@ void pll_cc_init_2nd_order_IIR(pll_t* p, float bandwidth, float gain, float damp p->filter_taps_b[2] = 4*(gain/tau1)*(1-tau2/2); p->last_filter_outputs[0]=p->last_filter_outputs[1]=p->last_filter_inputs[0]=p->last_filter_inputs[1]=0; p->dphase=p->output_phase=0; + + p->filter_taps_b[0] = 0.02868000; + p->filter_taps_b[1] = 0.00080000; + p->filter_taps_b[2] = -0.02788000; + // s=tf([0.02868000,0.00080000,-0.02788000],[1 -2 1]); pzmap(s) } void pll_cc_init_1st_order_IIR(pll_t* p, float alpha) @@ -1370,6 +1376,8 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_vc qof(output_vco,i) = cos(p->output_phase); } + //ket komplex szam szorzataval inkabb + float input_phase = atan2(iof(input,i),qof(input,i)); float new_dphase = input_phase - p->output_phase; //arg(input[i]/abs(input[i]) * conj(current_output_vco[i])) while(new_dphase>PI) new_dphase-=2*PI; @@ -1389,14 +1397,16 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_vc p->last_filter_outputs[1]=p->dphase; p->last_filter_inputs[0]=p->last_filter_inputs[1]; p->last_filter_inputs[1]=new_dphase; + while(p->dphase>PI) p->dphase-=2*PI; //ez nem fog kelleni + while(p->dphase<-PI) p->dphase+=2*PI; } else if(p->pll_type == PLL_1ST_ORDER_IIR_LOOP_FILTER) { - p->dphase = p->dphase * (1-p->alpha) + new_dphase * p->alpha; + p->dphase = /*p->dphase * (1-p->alpha) +*/ new_dphase * p->alpha; } else return; - if(output_dphase) output_dphase[i] = -p->dphase; - //if(output_dphase) output_dphase[i] = new_dphase/3.15; + if(output_dphase) output_dphase[i] = -p->dphase/10; + // if(output_dphase) output_dphase[i] = new_dphase/10; } } From c0b4706592866eaf98242ff2c5076239e13224b3 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Tue, 10 May 2016 22:59:14 +0200 Subject: [PATCH 010/111] Fixed 1st order loop filter --- csdr.c | 6 +++--- libcsdr.c | 16 ++++++++++------ libcsdr.h | 2 +- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/csdr.c b/csdr.c index eff693f..f4db898 100644 --- a/csdr.c +++ b/csdr.c @@ -1986,11 +1986,11 @@ int main(int argc, char *argv[]) { FEOF_CHECK; FREAD_C; - //pll_cc(&pll, (complexf*)input_buffer, NULL, (complexf*)output_buffer, the_bufsize); - fprintf(stderr, "| i"); + fprintf(stderr, "| ai"); pll_cc(&pll, (complexf*)input_buffer, output_buffer, NULL, the_bufsize); - //pll_cc(&pll, (complexf*)input_buffer, NULL, (complexf*)output_buffer, the_bufsize); fwrite(output_buffer, sizeof(float), the_bufsize, stdout); + // pll_cc(&pll, (complexf*)input_buffer, NULL, (complexf*)output_buffer, the_bufsize); + // fwrite(output_buffer, sizeof(complexf), the_bufsize, stdout); fprintf(stderr, "| o"); TRY_YIELD; } diff --git a/libcsdr.c b/libcsdr.c index 09bd22e..cdeec63 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1363,17 +1363,17 @@ void pll_cc_init_1st_order_IIR(pll_t* p, float alpha) } -void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_vco, int input_size) +void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nco, int input_size) { for(int i=0;ioutput_phase += p->dphase; while(p->output_phase>PI) p->output_phase-=2*PI; while(p->output_phase<-PI) p->output_phase+=2*PI; - if(output_vco) //we don't output anything if it is a NULL pointer + if(output_nco) //we don't output anything if it is a NULL pointer { - iof(output_vco,i) = sin(p->output_phase); - qof(output_vco,i) = cos(p->output_phase); + iof(output_nco,i) = sin(p->output_phase); + qof(output_nco,i) = cos(p->output_phase); } //ket komplex szam szorzataval inkabb @@ -1397,15 +1397,19 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_vc p->last_filter_outputs[1]=p->dphase; p->last_filter_inputs[0]=p->last_filter_inputs[1]; p->last_filter_inputs[1]=new_dphase; + //static float lasttemp; + //lasttemp = p->beta * + //p->dphase = new_dphase * p->alpha; + while(p->dphase>PI) p->dphase-=2*PI; //ez nem fog kelleni while(p->dphase<-PI) p->dphase+=2*PI; } else if(p->pll_type == PLL_1ST_ORDER_IIR_LOOP_FILTER) { - p->dphase = /*p->dphase * (1-p->alpha) +*/ new_dphase * p->alpha; + p->dphase = new_dphase * p->alpha; } else return; - if(output_dphase) output_dphase[i] = -p->dphase/10; + if(output_dphase) output_dphase[i] = -p->dphase; // if(output_dphase) output_dphase[i] = new_dphase/10; } } diff --git a/libcsdr.h b/libcsdr.h index ff89568..92fd3f9 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -262,4 +262,4 @@ typedef struct pll_s void pll_cc_init_2nd_order_IIR(pll_t* p, float bandwidth, float gain, float dampling_factor); void pll_cc_init_1st_order_IIR(pll_t* p, float alpha); -void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_vco, int input_size); +void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nco, int input_size); From e084341ca2bcea1323d7172aa8896fefdf43cc43 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Wed, 11 May 2016 08:48:31 +0200 Subject: [PATCH 011/111] Working on 2nd order IIR loop filter --- csdr.c | 13 +++++++------ libcsdr.c | 44 ++++++++++++-------------------------------- libcsdr.h | 9 ++------- 3 files changed, 21 insertions(+), 45 deletions(-) diff --git a/csdr.c b/csdr.c index f4db898..e1dc7e1 100644 --- a/csdr.c +++ b/csdr.c @@ -1972,11 +1972,12 @@ int main(int argc, char *argv[]) { float bandwidth = 0.01, gain = 1000, damping_factor = 0.707; if(argc>3) sscanf(argv[3],"%f",&bandwidth); - if(argc>4) sscanf(argv[4],"%f",&gain); - if(argc>5) sscanf(argv[5],"%f",&damping_factor); - pll_cc_init_2nd_order_IIR(&pll, bandwidth, gain, damping_factor); - fprintf(stderr, "%f %f %f | a: %f %f %f | b: %f %f %f\n", bandwidth, gain, damping_factor, - pll.filter_taps_a[0], pll.filter_taps_a[1], pll.filter_taps_a[2], pll.filter_taps_b[0], pll.filter_taps_b[1], pll.filter_taps_b[2]); + if(argc>4) sscanf(argv[4],"%f",&damping_factor); + if(argc>5) sscanf(argv[5],"%f",&ko); + if(argc>6) sscanf(argv[6],"%f",&kd); + pll_cc_init_2nd_order_IIR(&pll, bandwidth, ko, kd, damping_factor); + //fprintf(stderr, "%f %f %f | a: %f %f %f | b: %f %f %f\n", bandwidth, gain, damping_factor, + // pll.filter_taps_a[0], pll.filter_taps_a[1], pll.filter_taps_a[2], pll.filter_taps_b[0], pll.filter_taps_b[1], pll.filter_taps_b[2]); } else return badsyntax("invalid pll_type. Valid values are:\n\t1: PLL_1ST_ORDER_IIR_LOOP_FILTER\n\t2: PLL_2ND_ORDER_IIR_LOOP_FILTER"); @@ -1986,7 +1987,7 @@ int main(int argc, char *argv[]) { FEOF_CHECK; FREAD_C; - fprintf(stderr, "| ai"); + fprintf(stderr, "| i"); pll_cc(&pll, (complexf*)input_buffer, output_buffer, NULL, the_bufsize); fwrite(output_buffer, sizeof(float), the_bufsize, stdout); // pll_cc(&pll, (complexf*)input_buffer, NULL, (complexf*)output_buffer, the_bufsize); diff --git a/libcsdr.c b/libcsdr.c index cdeec63..0bcbb7a 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1336,23 +1336,13 @@ void binary_slicer_f_u8(float* input, unsigned char* output, int input_size) for(int i=0;i 0; } -void pll_cc_init_2nd_order_IIR(pll_t* p, float bandwidth, float gain, float dampling_factor) +void pll_cc_init_2nd_order_IIR(pll_t* p, float bandwidth, float ko, float kd, float float damping_factor) { - float k=0.9; - p->filter_taps_a[0] = k*1; - p->filter_taps_a[1] = k*(-2); - p->filter_taps_a[2] = k*1; - float tau1 = gain / (bandwidth*bandwidth); - float tau2 = (2*dampling_factor) / bandwidth; - p->filter_taps_b[0] = 4*(gain/tau1)*(1+tau2/2); - p->filter_taps_b[1] = 8*(gain/tau1); - p->filter_taps_b[2] = 4*(gain/tau1)*(1-tau2/2); - p->last_filter_outputs[0]=p->last_filter_outputs[1]=p->last_filter_inputs[0]=p->last_filter_inputs[1]=0; - p->dphase=p->output_phase=0; - - p->filter_taps_b[0] = 0.02868000; - p->filter_taps_b[1] = 0.00080000; - p->filter_taps_b[2] = -0.02788000; + float bandwidth_omega 2*M_PI*bandwidth; + p->alpha = (damping_factor*2*bandwidth_omega)/(ko*kd); + float sampling_rate = 1; //the bandwidth is normalized to the sampling rate + p->beta = (bandwidth_omega*bandwidth_omega)/(sampling_rate*ko*kd); + p->dphase = p->output_phase=0; // s=tf([0.02868000,0.00080000,-0.02788000],[1 -2 1]); pzmap(s) } @@ -1376,30 +1366,20 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nc qof(output_nco,i) = cos(p->output_phase); } - //ket komplex szam szorzataval inkabb + //calculating error from phase offset float input_phase = atan2(iof(input,i),qof(input,i)); float new_dphase = input_phase - p->output_phase; //arg(input[i]/abs(input[i]) * conj(current_output_vco[i])) while(new_dphase>PI) new_dphase-=2*PI; while(new_dphase<-PI) new_dphase+=2*PI; + //calculating error from two complex samples + if(p->pll_type == PLL_2ND_ORDER_IIR_LOOP_FILTER) { - p->dphase = 0 //... - + new_dphase * p->filter_taps_b[0] - + p->last_filter_inputs[1] * p->filter_taps_b[1] - + p->last_filter_inputs[0] * p->filter_taps_b[2] - - p->last_filter_outputs[1] * p->filter_taps_a[1] - - p->last_filter_outputs[0] * p->filter_taps_a[2]; - //dphase /= filter_taps_a[0]; //The filter taps are already normalized, a[0]==1 always, so it is not necessary. - - p->last_filter_outputs[0]=p->last_filter_outputs[1]; - p->last_filter_outputs[1]=p->dphase; - p->last_filter_inputs[0]=p->last_filter_inputs[1]; - p->last_filter_inputs[1]=new_dphase; - //static float lasttemp; - //lasttemp = p->beta * - //p->dphase = new_dphase * p->alpha; + static float lasttemp; + p->dphase = new_dphase * p->alpha + lasttemp; + lasttemp += new_dphase * p->beta; while(p->dphase>PI) p->dphase-=2*PI; //ez nem fog kelleni while(p->dphase<-PI) p->dphase+=2*PI; diff --git a/libcsdr.h b/libcsdr.h index 92fd3f9..c40d5a3 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -251,15 +251,10 @@ typedef struct pll_s float output_phase; float dphase; float frequency; - //2nd order IIR: - float last_filter_outputs[2]; - float last_filter_inputs[2]; - float filter_taps_a[3]; - float filter_taps_b[3]; - //1st order IIR: float alpha; + float beta; } pll_t; -void pll_cc_init_2nd_order_IIR(pll_t* p, float bandwidth, float gain, float dampling_factor); +void pll_cc_init_2nd_order_IIR(pll_t* p, float bandwidth, float ko, float kd, float float damping_factor); void pll_cc_init_1st_order_IIR(pll_t* p, float alpha); void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nco, int input_size); From ed35bb96e78121be08451a829516034c7f90929d Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Wed, 11 May 2016 08:59:54 +0200 Subject: [PATCH 012/111] Working on phase detector of the PLL --- libcsdr.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/libcsdr.c b/libcsdr.c index 0bcbb7a..16f95a8 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1360,20 +1360,22 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nc p->output_phase += p->dphase; while(p->output_phase>PI) p->output_phase-=2*PI; while(p->output_phase<-PI) p->output_phase+=2*PI; - if(output_nco) //we don't output anything if it is a NULL pointer - { - iof(output_nco,i) = sin(p->output_phase); - qof(output_nco,i) = cos(p->output_phase); - } + complexf current_nco; + iof(current_nco,i) = sin(p->output_phase); + qof(current_nco,i) = cos(p->output_phase); + if(output_nco) output_nco[i] = current_nco; //we don't output anything if it is a NULL pointer - - //calculating error from phase offset + //accurate phase detector: calculating error from phase offset float input_phase = atan2(iof(input,i),qof(input,i)); - float new_dphase = input_phase - p->output_phase; //arg(input[i]/abs(input[i]) * conj(current_output_vco[i])) + float new_dphase = input_phase - p->output_phase; while(new_dphase>PI) new_dphase-=2*PI; while(new_dphase<-PI) new_dphase+=2*PI; - //calculating error from two complex samples + //modeling analog phase detector: abs(input[i] * conj(current_nco)) + //qof(¤t_nco,0)=-qof(¤t_nco,0); //calculate conjugate + //complexf multiply_result; + //cmult(&multiply_result, &input[i], ¤t_nco); + //float new_dphase = absof(&multiply_result,0); if(p->pll_type == PLL_2ND_ORDER_IIR_LOOP_FILTER) { From b36b01e9cf8f8d47a7acaa57baf0528f1ad96b08 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Wed, 18 May 2016 14:56:05 +0200 Subject: [PATCH 013/111] Current status (PLL modified) --- csdr.c | 10 +++++----- libcsdr.c | 36 ++++++++++++++++++------------------ libcsdr.h | 7 ++++--- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/csdr.c b/csdr.c index e1dc7e1..cb02ef7 100644 --- a/csdr.c +++ b/csdr.c @@ -1970,7 +1970,7 @@ int main(int argc, char *argv[]) } else if(pll.pll_type == PLL_2ND_ORDER_IIR_LOOP_FILTER) { - float bandwidth = 0.01, gain = 1000, damping_factor = 0.707; + float bandwidth = 0.01, ko = 10, kd=100, damping_factor = 0.707; if(argc>3) sscanf(argv[3],"%f",&bandwidth); if(argc>4) sscanf(argv[4],"%f",&damping_factor); if(argc>5) sscanf(argv[5],"%f",&ko); @@ -1988,10 +1988,10 @@ int main(int argc, char *argv[]) FEOF_CHECK; FREAD_C; fprintf(stderr, "| i"); - pll_cc(&pll, (complexf*)input_buffer, output_buffer, NULL, the_bufsize); - fwrite(output_buffer, sizeof(float), the_bufsize, stdout); - // pll_cc(&pll, (complexf*)input_buffer, NULL, (complexf*)output_buffer, the_bufsize); - // fwrite(output_buffer, sizeof(complexf), the_bufsize, stdout); + // pll_cc(&pll, (complexf*)input_buffer, output_buffer, NULL, the_bufsize); + // fwrite(output_buffer, sizeof(float), the_bufsize, stdout); + pll_cc(&pll, (complexf*)input_buffer, NULL, (complexf*)output_buffer, the_bufsize); + fwrite(output_buffer, sizeof(complexf), the_bufsize, stdout); fprintf(stderr, "| o"); TRY_YIELD; } diff --git a/libcsdr.c b/libcsdr.c index 16f95a8..4cb3f57 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1336,13 +1336,13 @@ void binary_slicer_f_u8(float* input, unsigned char* output, int input_size) for(int i=0;i 0; } -void pll_cc_init_2nd_order_IIR(pll_t* p, float bandwidth, float ko, float kd, float float damping_factor) +void pll_cc_init_2nd_order_IIR(pll_t* p, float bandwidth, float ko, float kd, float damping_factor) { - float bandwidth_omega 2*M_PI*bandwidth; - p->alpha = (damping_factor*2*bandwidth_omega)/(ko*kd); + float bandwidth_omega = 2*M_PI*bandwidth; + p->alpha = (damping_factor*2*bandwidth_omega)/(ko*kd); float sampling_rate = 1; //the bandwidth is normalized to the sampling rate p->beta = (bandwidth_omega*bandwidth_omega)/(sampling_rate*ko*kd); - p->dphase = p->output_phase=0; + p->iir_temp = p->dphase = p->output_phase = 0; // s=tf([0.02868000,0.00080000,-0.02788000],[1 -2 1]); pzmap(s) } @@ -1361,27 +1361,27 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nc while(p->output_phase>PI) p->output_phase-=2*PI; while(p->output_phase<-PI) p->output_phase+=2*PI; complexf current_nco; - iof(current_nco,i) = sin(p->output_phase); - qof(current_nco,i) = cos(p->output_phase); + iof(¤t_nco,0) = sin(p->output_phase); + qof(¤t_nco,0) = cos(p->output_phase); if(output_nco) output_nco[i] = current_nco; //we don't output anything if it is a NULL pointer //accurate phase detector: calculating error from phase offset - float input_phase = atan2(iof(input,i),qof(input,i)); - float new_dphase = input_phase - p->output_phase; - while(new_dphase>PI) new_dphase-=2*PI; - while(new_dphase<-PI) new_dphase+=2*PI; + // float input_phase = atan2(iof(input,i),qof(input,i)); + // float new_dphase = input_phase - p->output_phase; + // while(new_dphase>PI) new_dphase-=2*PI; + // while(new_dphase<-PI) new_dphase+=2*PI; //modeling analog phase detector: abs(input[i] * conj(current_nco)) - //qof(¤t_nco,0)=-qof(¤t_nco,0); //calculate conjugate - //complexf multiply_result; - //cmult(&multiply_result, &input[i], ¤t_nco); - //float new_dphase = absof(&multiply_result,0); + qof(¤t_nco,0)=-qof(¤t_nco,0); //calculate conjugate + complexf multiply_result; + cmult(&multiply_result, &input[i], ¤t_nco); + output_nco[i] = multiply_result; + float new_dphase = absof(&multiply_result,0); if(p->pll_type == PLL_2ND_ORDER_IIR_LOOP_FILTER) { - static float lasttemp; - p->dphase = new_dphase * p->alpha + lasttemp; - lasttemp += new_dphase * p->beta; + p->dphase = new_dphase * p->alpha + p->iir_temp; + p->iir_temp += new_dphase * p->beta; while(p->dphase>PI) p->dphase-=2*PI; //ez nem fog kelleni while(p->dphase<-PI) p->dphase+=2*PI; @@ -1392,7 +1392,7 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nc } else return; if(output_dphase) output_dphase[i] = -p->dphase; - // if(output_dphase) output_dphase[i] = new_dphase/10; + if(output_dphase) output_dphase[i] = new_dphase/10; } } diff --git a/libcsdr.h b/libcsdr.h index c40d5a3..b05abb2 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -48,9 +48,9 @@ typedef struct complexf_s { float i; float q; } complexf; //apply to pointers: #define iof(complexf_input_p,i) (*(((float*)complexf_input_p)+2*(i))) #define qof(complexf_input_p,i) (*(((float*)complexf_input_p)+2*(i)+1)) -#define absof(complexf_input_p,i) (sqrt(iof(complexf_input_p,i)*iof(complexf_input_p,i)+qof(complexf_input_p,i)*qof(complexf_input_p,i))) +#define absof(complexf_input_p,i) (sqrt((iof(complexf_input_p,i)*iof(complexf_input_p,i))+(qof(complexf_input_p,i)*qof(complexf_input_p,i)))) #define argof(complexf_input_p,i) (atan2(qof(complexf_input_p,i),iof(complexf_input_p,i))) -#define cmult(cfo, cfi1, cfi2) iof(cfo,0)=iof(cfi1,0)*iof(cfi2,0)-qof(cfi1,0)*qof(cfi2,0);qof(cfo,0)=iof(cfi1,0)*qof(cfi2,0)+iof(cfi2,0)*qof(cfi1,0) +#define cmult(cfo, cfi1, cfi2) {iof(cfo,0)=iof(cfi1,0)*iof(cfi2,0)-qof(cfi1,0)*qof(cfi2,0);qof(cfo,0)=iof(cfi1,0)*qof(cfi2,0)+iof(cfi2,0)*qof(cfi1,0);} //(ai+aq*j)*(bi+bq*j)=ai*bi-aq*bq+(aq*bi+ai*bq)*j #define cmultadd(cfo, cfi1, cfi2) { iof(cfo,0)+=iof(cfi1,0)*iof(cfi2,0)-qof(cfi1,0)*qof(cfi2,0);qof(cfo,0)+=iof(cfi1,0)*qof(cfi2,0)+iof(cfi2,0)*qof(cfi1,0); } #define csetnull(cf) { iof(cf,0)=0.0; qof(cf,0)=0.0; } @@ -253,8 +253,9 @@ typedef struct pll_s float frequency; float alpha; float beta; + float iir_temp; } pll_t; -void pll_cc_init_2nd_order_IIR(pll_t* p, float bandwidth, float ko, float kd, float float damping_factor); +void pll_cc_init_2nd_order_IIR(pll_t* p, float bandwidth, float ko, float kd, float damping_factor); void pll_cc_init_1st_order_IIR(pll_t* p, float alpha); void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nco, int input_size); From 07ca9fd73fe992194c90571a6bc101c8b25babbb Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 22 May 2016 18:27:20 +0200 Subject: [PATCH 014/111] Changes to PLL, renamed bpsk31 line decoder to bpsk31_varicode2ascii_sy_u8 --- csdr.c | 14 +++++++------- libcsdr.c | 25 +++++++++++++------------ 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/csdr.c b/csdr.c index cb02ef7..0412f1b 100644 --- a/csdr.c +++ b/csdr.c @@ -1,4 +1,4 @@ -/* +u/* This software is part of libcsdr, a set of simple DSP routines for Software Defined Radio. @@ -113,7 +113,7 @@ char usage[]= " fft_exchange_sides_ff \n" " squelch_and_smeter_cc --fifo --outfifo \n" " fifo \n" -" bpsk31_line_decoder_sy_u8\n" +" bpsk31_varicode2ascii_sy_u8\n" " invert_sy_sy\n" " rtty_line_decoder_sy_u8\n" " rtty_baudot2ascii_u8_u8\n" @@ -1839,7 +1839,7 @@ int main(int argc, char *argv[]) } } - if(!strcmp(argv[1],"bpsk31_line_decoder_sy_u8")) + if(!strcmp(argv[1],"bpsk31_varicode2ascii_sy_u8")) { unsigned long long status_shr = 0; unsigned char output; @@ -1970,13 +1970,13 @@ int main(int argc, char *argv[]) } else if(pll.pll_type == PLL_2ND_ORDER_IIR_LOOP_FILTER) { - float bandwidth = 0.01, ko = 10, kd=100, damping_factor = 0.707; + float bandwidth = 0.01, ko = 10, kd=0.1, damping_factor = 0.707; if(argc>3) sscanf(argv[3],"%f",&bandwidth); if(argc>4) sscanf(argv[4],"%f",&damping_factor); if(argc>5) sscanf(argv[5],"%f",&ko); if(argc>6) sscanf(argv[6],"%f",&kd); pll_cc_init_2nd_order_IIR(&pll, bandwidth, ko, kd, damping_factor); - //fprintf(stderr, "%f %f %f | a: %f %f %f | b: %f %f %f\n", bandwidth, gain, damping_factor, + fprintf(stderr, "bw=%f damping=%f ko=%f kd=%f alpha=%f beta=%f\n", bandwidth, damping_factor, ko, kd, pll.alpha, pll.beta); // pll.filter_taps_a[0], pll.filter_taps_a[1], pll.filter_taps_a[2], pll.filter_taps_b[0], pll.filter_taps_b[1], pll.filter_taps_b[2]); } else return badsyntax("invalid pll_type. Valid values are:\n\t1: PLL_1ST_ORDER_IIR_LOOP_FILTER\n\t2: PLL_2ND_ORDER_IIR_LOOP_FILTER"); @@ -1987,12 +1987,12 @@ int main(int argc, char *argv[]) { FEOF_CHECK; FREAD_C; - fprintf(stderr, "| i"); + //fprintf(stderr, "| i"); // pll_cc(&pll, (complexf*)input_buffer, output_buffer, NULL, the_bufsize); // fwrite(output_buffer, sizeof(float), the_bufsize, stdout); pll_cc(&pll, (complexf*)input_buffer, NULL, (complexf*)output_buffer, the_bufsize); fwrite(output_buffer, sizeof(complexf), the_bufsize, stdout); - fprintf(stderr, "| o"); + //fprintf(stderr, "| o"); TRY_YIELD; } } diff --git a/libcsdr.c b/libcsdr.c index 4cb3f57..10f62ec 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1338,12 +1338,13 @@ void binary_slicer_f_u8(float* input, unsigned char* output, int input_size) void pll_cc_init_2nd_order_IIR(pll_t* p, float bandwidth, float ko, float kd, float damping_factor) { + //kd: detector gain + //ko: VCO gain float bandwidth_omega = 2*M_PI*bandwidth; p->alpha = (damping_factor*2*bandwidth_omega)/(ko*kd); float sampling_rate = 1; //the bandwidth is normalized to the sampling rate p->beta = (bandwidth_omega*bandwidth_omega)/(sampling_rate*ko*kd); p->iir_temp = p->dphase = p->output_phase = 0; - // s=tf([0.02868000,0.00080000,-0.02788000],[1 -2 1]); pzmap(s) } void pll_cc_init_1st_order_IIR(pll_t* p, float alpha) @@ -1366,17 +1367,17 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nc if(output_nco) output_nco[i] = current_nco; //we don't output anything if it is a NULL pointer //accurate phase detector: calculating error from phase offset - // float input_phase = atan2(iof(input,i),qof(input,i)); - // float new_dphase = input_phase - p->output_phase; - // while(new_dphase>PI) new_dphase-=2*PI; - // while(new_dphase<-PI) new_dphase+=2*PI; + float input_phase = atan2(iof(input,i),qof(input,i)); + float new_dphase = input_phase - p->output_phase; + while(new_dphase>PI) new_dphase-=2*PI; + while(new_dphase<-PI) new_dphase+=2*PI; - //modeling analog phase detector: abs(input[i] * conj(current_nco)) - qof(¤t_nco,0)=-qof(¤t_nco,0); //calculate conjugate - complexf multiply_result; - cmult(&multiply_result, &input[i], ¤t_nco); - output_nco[i] = multiply_result; - float new_dphase = absof(&multiply_result,0); + //modeling analog phase detector, which would be abs(input[i] * current_nco) if we had a real output signal, but what if we have complex signals? + //qof(¤t_nco,0)=-qof(¤t_nco,0); //calculate conjugate + //complexf multiply_result; + //cmult(&multiply_result, &input[i], ¤t_nco); + //output_nco[i] = multiply_result; + //float new_dphase = absof(&multiply_result,0); if(p->pll_type == PLL_2ND_ORDER_IIR_LOOP_FILTER) { @@ -1392,7 +1393,7 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nc } else return; if(output_dphase) output_dphase[i] = -p->dphase; - if(output_dphase) output_dphase[i] = new_dphase/10; + //if(output_dphase) output_dphase[i] = new_dphase/10; } } From 4fbcc3f0a8a582c729ed21533339e03de9ee5589 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 22 May 2016 18:35:26 +0200 Subject: [PATCH 015/111] Renamed loop filters --- csdr.c | 10 +++++----- libcsdr.c | 8 ++++---- libcsdr.h | 8 ++++---- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/csdr.c b/csdr.c index 0412f1b..d3da0c9 100644 --- a/csdr.c +++ b/csdr.c @@ -1962,24 +1962,24 @@ int main(int argc, char *argv[]) sscanf(argv[2],"%d",(int*)&pll.pll_type); //if(serial.samples_per_bits<1) return badsyntax("samples_per_bits should be at least 1."); //if(serial.samples_per_bits<5) fprintf(stderr, "serial_line_decoder_sy_u8: warning: this algorithm does not work well if samples_per_bits is too low. It should be at least 5.\n"); - if(pll.pll_type == PLL_1ST_ORDER_IIR_LOOP_FILTER) + if(pll.pll_type == PLL_P_CONTROLLER) { float alpha = 0.01; if(argc>3) sscanf(argv[3],"%f",&alpha); - pll_cc_init_1st_order_IIR(&pll, alpha); + pll_cc_init_p_controller(&pll, alpha); } - else if(pll.pll_type == PLL_2ND_ORDER_IIR_LOOP_FILTER) + else if(pll.pll_type == PLL_PI_CONTROLLER) { float bandwidth = 0.01, ko = 10, kd=0.1, damping_factor = 0.707; if(argc>3) sscanf(argv[3],"%f",&bandwidth); if(argc>4) sscanf(argv[4],"%f",&damping_factor); if(argc>5) sscanf(argv[5],"%f",&ko); if(argc>6) sscanf(argv[6],"%f",&kd); - pll_cc_init_2nd_order_IIR(&pll, bandwidth, ko, kd, damping_factor); + pll_cc_init_pi_controller(&pll, bandwidth, ko, kd, damping_factor); fprintf(stderr, "bw=%f damping=%f ko=%f kd=%f alpha=%f beta=%f\n", bandwidth, damping_factor, ko, kd, pll.alpha, pll.beta); // pll.filter_taps_a[0], pll.filter_taps_a[1], pll.filter_taps_a[2], pll.filter_taps_b[0], pll.filter_taps_b[1], pll.filter_taps_b[2]); } - else return badsyntax("invalid pll_type. Valid values are:\n\t1: PLL_1ST_ORDER_IIR_LOOP_FILTER\n\t2: PLL_2ND_ORDER_IIR_LOOP_FILTER"); + else return badsyntax("invalid pll_type. Valid values are:\n\t1: PLL_P_CONTROLLER\n\t2: PLL_PI_CONTROLLER"); if(!sendbufsize(initialize_buffers())) return -2; diff --git a/libcsdr.c b/libcsdr.c index 10f62ec..0a908e3 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1336,7 +1336,7 @@ void binary_slicer_f_u8(float* input, unsigned char* output, int input_size) for(int i=0;i 0; } -void pll_cc_init_2nd_order_IIR(pll_t* p, float bandwidth, float ko, float kd, float damping_factor) +void pll_cc_init_pi_controller(pll_t* p, float bandwidth, float ko, float kd, float damping_factor) { //kd: detector gain //ko: VCO gain @@ -1347,7 +1347,7 @@ void pll_cc_init_2nd_order_IIR(pll_t* p, float bandwidth, float ko, float kd, fl p->iir_temp = p->dphase = p->output_phase = 0; } -void pll_cc_init_1st_order_IIR(pll_t* p, float alpha) +void pll_cc_init_p_controller(pll_t* p, float alpha) { p->alpha = alpha; p->dphase=p->output_phase=0; @@ -1379,7 +1379,7 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nc //output_nco[i] = multiply_result; //float new_dphase = absof(&multiply_result,0); - if(p->pll_type == PLL_2ND_ORDER_IIR_LOOP_FILTER) + if(p->pll_type == PLL_PI_CONTROLLER) { p->dphase = new_dphase * p->alpha + p->iir_temp; p->iir_temp += new_dphase * p->beta; @@ -1387,7 +1387,7 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nc while(p->dphase>PI) p->dphase-=2*PI; //ez nem fog kelleni while(p->dphase<-PI) p->dphase+=2*PI; } - else if(p->pll_type == PLL_1ST_ORDER_IIR_LOOP_FILTER) + else if(p->pll_type == PLL_P_CONTROLLER) { p->dphase = new_dphase * p->alpha; } diff --git a/libcsdr.h b/libcsdr.h index b05abb2..4af1c74 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -240,8 +240,8 @@ void binary_slicer_f_u8(float* input, unsigned char* output, int input_size); typedef enum pll_type_e { - PLL_1ST_ORDER_IIR_LOOP_FILTER=1, - PLL_2ND_ORDER_IIR_LOOP_FILTER=2 + PLL_P_CONTROLLER=1, + PLL_PI_CONTROLLER=2 } pll_type_t; typedef struct pll_s @@ -256,6 +256,6 @@ typedef struct pll_s float iir_temp; } pll_t; -void pll_cc_init_2nd_order_IIR(pll_t* p, float bandwidth, float ko, float kd, float damping_factor); -void pll_cc_init_1st_order_IIR(pll_t* p, float alpha); +void pll_cc_init_pi_controller(pll_t* p, float bandwidth, float ko, float kd, float damping_factor); +void pll_cc_init_p_controller(pll_t* p, float alpha); void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nco, int input_size); From c1a42d1efff7815055cdeb141940c87379963b89 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 22 May 2016 18:45:56 +0200 Subject: [PATCH 016/111] Did not build; fixed --- csdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csdr.c b/csdr.c index d3da0c9..048ab06 100644 --- a/csdr.c +++ b/csdr.c @@ -1,4 +1,4 @@ -u/* +/* This software is part of libcsdr, a set of simple DSP routines for Software Defined Radio. From 22ea31d5b121e89c67641436449fc7552a3e0993 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 19 Feb 2017 14:02:10 +0100 Subject: [PATCH 017/111] First modifications for fir_interpolate_cc, from last April --- csdr.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ libcsdr.c | 18 ++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/csdr.c b/csdr.c index 5763f23..31d8ddc 100644 --- a/csdr.c +++ b/csdr.c @@ -848,6 +848,62 @@ int main(int argc, char *argv[]) //fprintf(stderr,"iskip=%d output_size=%d start=%x target=%x skipcount=%x \n",input_skip,output_size,input_buffer, ((complexf*)input_buffer)+(BIG_BUFSIZE-input_skip),(BIG_BUFSIZE-input_skip)); } } + + if(!strcmp(argv[1],"fir_interpolate_cc")) + { + bigbufs=1; + + if(argc<=2) return badsyntax("need required parameter (interpolation factor)"); + + int factor; + sscanf(argv[2],"%d",&factor); + + float transition_bw = 0.05; + if(argc>=4) sscanf(argv[3],"%g",&transition_bw); + + window_t window = WINDOW_DEFAULT; + if(argc>=5) + { + window=firdes_get_window_from_string(argv[4]); + } + else fprintf(stderr,"fir_interpolate_cc: window = %s\n",firdes_get_string_from_window(window)); + + int taps_length=firdes_filter_len(transition_bw); + fprintf(stderr,"fir_interpolate_cc: taps_length = %d\n",taps_length); + + while (env_csdr_fixed_big_bufsize < taps_length*2) env_csdr_fixed_big_bufsize*=2; //temporary fix for buffer size if [transition_bw] is low + //fprintf(stderr, "env_csdr_fixed_big_bufsize = %d\n", env_csdr_fixed_big_bufsize); + + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize/factor); + + + float *taps; + taps=(float*)malloc(taps_length*sizeof(float)); + + firdes_lowpass_f(taps,taps_length,0.5/(float)factor,window); + + int input_skip=0; + int output_size=0; + FREAD_C; + for(;;) + { + FEOF_CHECK; + output_size=fir_interpolate_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, factor, taps, taps_length); + //fprintf(stderr, "os %d\n",output_size); + fwrite(output_buffer, sizeof(complexf), output_size, stdout); + fflush(stdout); + TRY_YIELD; + input_skip=factor*output_size; + memmove((complexf*)input_buffer,((complexf*)input_buffer)+input_skip,(the_bufsize-input_skip)*sizeof(complexf)); //memmove lets the source and destination overlap + fread(((complexf*)input_buffer)+(the_bufsize-input_skip), sizeof(complexf), input_skip, stdin); + //fprintf(stderr,"iskip=%d output_size=%d start=%x target=%x skipcount=%x \n",input_skip,output_size,input_buffer, ((complexf*)input_buffer)+(BIG_BUFSIZE-input_skip),(BIG_BUFSIZE-input_skip)); + } + } + + + + /*if(!strcmp(argv[1],"ejw_test")) { printf("ejqd=["); diff --git a/libcsdr.c b/libcsdr.c index e3b01bf..f5da71c 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -379,6 +379,24 @@ int fir_decimate_cc(complexf *input, complexf *output, int input_size, int decim } */ +int fir_interpolate_cc(complexf *input, complexf *output, int input_size, int interpolation, float *taps, int taps_length) +{ + int oi=0; + for(int i=0; iinput_size) break; + float acci=0; + for(int ti=0; ti Date: Sun, 19 Feb 2017 15:41:33 +0100 Subject: [PATCH 018/111] Almost there at working interpolator --- csdr.c | 17 +++++++++++------ libcsdr.c | 26 +++++++++++++++++--------- libcsdr.h | 1 + 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/csdr.c b/csdr.c index 31d8ddc..c135c61 100644 --- a/csdr.c +++ b/csdr.c @@ -48,6 +48,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ima_adpcm.h" #include #include +#include char usage[]= "csdr - a simple commandline tool for Software Defined Radio receiver DSP.\n\n" @@ -857,9 +858,11 @@ int main(int argc, char *argv[]) int factor; sscanf(argv[2],"%d",&factor); + assert(factor >= 1); float transition_bw = 0.05; if(argc>=4) sscanf(argv[3],"%g",&transition_bw); + assert(transition_bw >= 0 && transition_bw < 1.); window_t window = WINDOW_DEFAULT; if(argc>=5) @@ -870,31 +873,33 @@ int main(int argc, char *argv[]) int taps_length=firdes_filter_len(transition_bw); fprintf(stderr,"fir_interpolate_cc: taps_length = %d\n",taps_length); + assert(taps_length > 0); while (env_csdr_fixed_big_bufsize < taps_length*2) env_csdr_fixed_big_bufsize*=2; //temporary fix for buffer size if [transition_bw] is low //fprintf(stderr, "env_csdr_fixed_big_bufsize = %d\n", env_csdr_fixed_big_bufsize); if(!initialize_buffers()) return -2; - sendbufsize(the_bufsize/factor); - + sendbufsize(the_bufsize*factor); + assert(the_bufsize > 0); float *taps; taps=(float*)malloc(taps_length*sizeof(float)); + assert(taps); firdes_lowpass_f(taps,taps_length,0.5/(float)factor,window); int input_skip=0; int output_size=0; - FREAD_C; + float* interp_output_buffer = (float*)malloc(sizeof(float)*2*the_bufsize*factor); for(;;) { FEOF_CHECK; - output_size=fir_interpolate_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, factor, taps, taps_length); + output_size=fir_interpolate_cc((complexf*)input_buffer, (complexf*)interp_output_buffer, the_bufsize, factor, taps, taps_length); //fprintf(stderr, "os %d\n",output_size); - fwrite(output_buffer, sizeof(complexf), output_size, stdout); + fwrite(interp_output_buffer, sizeof(complexf), output_size, stdout); fflush(stdout); TRY_YIELD; - input_skip=factor*output_size; + input_skip=output_size/factor; memmove((complexf*)input_buffer,((complexf*)input_buffer)+input_skip,(the_bufsize-input_skip)*sizeof(complexf)); //memmove lets the source and destination overlap fread(((complexf*)input_buffer)+(the_bufsize-input_skip), sizeof(complexf), input_skip, stdin); //fprintf(stderr,"iskip=%d output_size=%d start=%x target=%x skipcount=%x \n",input_skip,output_size,input_buffer, ((complexf*)input_buffer)+(BIG_BUFSIZE-input_skip),(BIG_BUFSIZE-input_skip)); diff --git a/libcsdr.c b/libcsdr.c index f5da71c..2e02c8b 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -381,17 +381,25 @@ int fir_decimate_cc(complexf *input, complexf *output, int input_size, int decim int fir_interpolate_cc(complexf *input, complexf *output, int input_size, int interpolation, float *taps, int taps_length) { + //i: input index + //oi: output index + //ti: tap index + //ti: secondary index (inside filter function) + //ip: interpolation phase (0 <= ip < interpolation) int oi=0; - for(int i=0; iinput_size) break; - float acci=0; - for(int ti=0; ti input_size*interpolation) break; + for(int ip=0; ip Date: Sun, 19 Feb 2017 16:06:08 +0100 Subject: [PATCH 019/111] Working interpolator. --- csdr.c | 2 +- libcsdr.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/csdr.c b/csdr.c index c135c61..d297f61 100644 --- a/csdr.c +++ b/csdr.c @@ -860,7 +860,7 @@ int main(int argc, char *argv[]) sscanf(argv[2],"%d",&factor); assert(factor >= 1); - float transition_bw = 0.05; + float transition_bw = 0.01; if(argc>=4) sscanf(argv[3],"%g",&transition_bw); assert(transition_bw >= 0 && transition_bw < 1.); diff --git a/libcsdr.c b/libcsdr.c index 2e02c8b..5483f79 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -394,8 +394,10 @@ int fir_interpolate_cc(complexf *input, complexf *output, int input_size, int in { float acci=0; float accq=0; - for(int ti=ip, si=0; ti Date: Sun, 19 Feb 2017 16:22:49 +0100 Subject: [PATCH 020/111] Added to README and --help as well --- README.md | 7 +- csdr.c | 3 +- grc_tests/test_fir_interpolate_cc.grc | 1212 +++++++++++++++++++++++++ libcsdr.c | 4 +- 4 files changed, 1222 insertions(+), 4 deletions(-) create mode 100644 grc_tests/test_fir_interpolate_cc.grc diff --git a/README.md b/README.md index eb8edfe..72620f0 100644 --- a/README.md +++ b/README.md @@ -287,7 +287,12 @@ Other parameters were explained above at `firdes_lowpass_f`. fir_decimate_cc [transition_bw [window]] It is a decimator that keeps one sample out of `decimation_factor` samples. -To avoid aliasing, it runs a filter on the signal and removes spectral components above `0.5 × nyquist_frequency × decimation_factor`. +To avoid aliasing, it runs a filter on the signal and removes spectral components above `0.5 × nyquist_frequency × decimation_factor` from the input signal. + + fir_interpolate_cc [transition_bw [window]] + +It is an interpolator that generates `interpolation_factor` number of output samples from one input sample. +To avoid aliasing, it runs a filter on the signal and removes spectral components above `0.5 × nyquist_frequency / interpolation_factor` from the output signal. `transition_bw` and `window` are the parameters of the filter. diff --git a/csdr.c b/csdr.c index d297f61..a2beb4a 100644 --- a/csdr.c +++ b/csdr.c @@ -88,6 +88,7 @@ char usage[]= " amdemod_cf\n" " amdemod_estimator_cf\n" " fir_decimate_cc [transition_bw [window]]\n" +" fir_interpolate_cc [transition_bw [window]]\n" " firdes_lowpass_f [window [--octave]]\n" " firdes_bandpass_c [window [--octave]]\n" " agc_ff [hang_time [reference [attack_rate [decay_rate [max_gain [attack_wait [filter_alpha]]]]]]]\n" @@ -860,7 +861,7 @@ int main(int argc, char *argv[]) sscanf(argv[2],"%d",&factor); assert(factor >= 1); - float transition_bw = 0.01; + float transition_bw = 0.05; if(argc>=4) sscanf(argv[3],"%g",&transition_bw); assert(transition_bw >= 0 && transition_bw < 1.); diff --git a/grc_tests/test_fir_interpolate_cc.grc b/grc_tests/test_fir_interpolate_cc.grc new file mode 100644 index 0000000..65eb887 --- /dev/null +++ b/grc_tests/test_fir_interpolate_cc.grc @@ -0,0 +1,1212 @@ + + + + Tue Nov 25 18:16:05 2014 + + options + + author + + + + window_size + 1280, 1024 + + + category + Custom + + + comment + + + + description + + + + _enabled + True + + + _coordinate + (10, 10) + + + _rotation + 0 + + + generate_options + wx_gui + + + id + top_block + + + max_nouts + 0 + + + realtime_scheduling + + + + run_options + prompt + + + run + True + + + thread_safe_setters + + + + title + + + + + variable_slider + + comment + + + + converver + float_converter + + + value + 4e3 + + + _enabled + True + + + _coordinate + (8, 331) + + + _rotation + 0 + + + grid_pos + 2,1,1,1 + + + id + input_freq + + + label + + + + max + samp_rate/2 + + + min + -samp_rate/2 + + + notebook + + + + num_steps + 100 + + + style + wx.SL_HORIZONTAL + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (432, 11) + + + _rotation + 0 + + + id + interpolation + + + value + 2 + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (176, 11) + + + _rotation + 0 + + + id + samp_rate + + + value + 240000 + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (328, 11) + + + _rotation + 0 + + + id + samp_rate_2 + + + value + samp_rate*interpolation + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (536, 11) + + + _rotation + 0 + + + id + transition_bw + + + value + 0.01 + + + + analog_sig_source_x + + amp + 1 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + freq + input_freq + + + _coordinate + (8, 83) + + + _rotation + 0 + + + id + analog_sig_source_x_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + offset + 0 + + + type + complex + + + samp_rate + samp_rate + + + waveform + analog.GR_COS_WAVE + + + + blocks_throttle + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (168, 115) + + + _rotation + 0 + + + id + blocks_throttle_0 + + + ignoretag + True + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + samples_per_second + samp_rate + + + type + complex + + + vlen + 1 + + + + ha5kfu_execproc_xx + + alias + + + + commandline + "csdr fir_interpolate_cc "+str(interpolation)+" "+str(transition_bw) + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (352, 115) + + + _rotation + 0 + + + id + ha5kfu_execproc_xx_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + cc + + + + interp_fir_filter_xxx + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (368, 643) + + + _rotation + 0 + + + id + interp_fir_filter_xxx_0 + + + interp + interpolation + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + samp_delay + 0 + + + taps + firdes.low_pass(1,1,1./(2*interpolation), transition_bw) + + + type + ccc + + + + notebook + + alias + + + + comment + + + + _enabled + True + + + _coordinate + (16, 683) + + + _rotation + 0 + + + grid_pos + 1,2,1,1 + + + id + nb0 + + + labels + ['scope','fft'] + + + notebook + + + + style + wx.NB_TOP + + + + notebook + + alias + + + + comment + + + + _enabled + True + + + _coordinate + (16, 579) + + + _rotation + 0 + + + grid_pos + 1,1,1,1 + + + id + nb1 + + + labels + ['scope','fft'] + + + notebook + + + + style + wx.NB_TOP + + + + notebook + + alias + + + + comment + + + + _enabled + True + + + _coordinate + (16, 475) + + + _rotation + 0 + + + grid_pos + 2,2,1,1 + + + id + nb2 + + + labels + ['scope','fft'] + + + notebook + + + + style + wx.NB_TOP + + + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (640, 235) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_0 + + + notebook + nb0,1 + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate_2 + + + title + Resampled signal (csdr) + + + type + complex + + + win_size + + + + win + None + + + y_divs + 10 + + + y_per_div + 10 + + + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (640, 579) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_0_0 + + + notebook + nb2,1 + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate_2 + + + title + Resampled signal (GNU Radio) + + + type + complex + + + win_size + + + + win + None + + + y_divs + 10 + + + y_per_div + 10 + + + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (360, 355) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_1 + + + notebook + nb1,1 + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate + + + title + Original signal + + + type + complex + + + win_size + + + + win + None + + + y_divs + 10 + + + y_per_div + 10 + + + + wxgui_scopesink2 + + ac_couple + False + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (640, 115) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_scopesink2_0 + + + notebook + nb0,0 + + + num_inputs + 1 + + + samp_rate + samp_rate_2 + + + t_scale + 0 + + + title + Resampled signal (csdr) + + + trig_mode + wxgui.TRIG_MODE_AUTO + + + type + complex + + + v_offset + 0 + + + v_scale + 0 + + + win_size + + + + xy_mode + False + + + y_axis_label + Counts + + + + wxgui_scopesink2 + + ac_couple + False + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (360, 235) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_scopesink2_0_0 + + + notebook + nb1,0 + + + num_inputs + 1 + + + samp_rate + samp_rate + + + t_scale + 0 + + + title + Original signal + + + trig_mode + wxgui.TRIG_MODE_AUTO + + + type + complex + + + v_offset + 0 + + + v_scale + 0 + + + win_size + + + + xy_mode + False + + + y_axis_label + Counts + + + + wxgui_scopesink2 + + ac_couple + False + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (640, 459) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_scopesink2_0_1 + + + notebook + nb2,0 + + + num_inputs + 1 + + + samp_rate + samp_rate_2 + + + t_scale + 0 + + + title + Resampled signal (GNU Radio) + + + trig_mode + wxgui.TRIG_MODE_AUTO + + + type + complex + + + v_offset + 0 + + + v_scale + 0 + + + win_size + + + + xy_mode + False + + + y_axis_label + Counts + + + + analog_sig_source_x_0 + blocks_throttle_0 + 0 + 0 + + + blocks_throttle_0 + ha5kfu_execproc_xx_0 + 0 + 0 + + + blocks_throttle_0 + interp_fir_filter_xxx_0 + 0 + 0 + + + blocks_throttle_0 + wxgui_fftsink2_1 + 0 + 0 + + + blocks_throttle_0 + wxgui_scopesink2_0_0 + 0 + 0 + + + ha5kfu_execproc_xx_0 + wxgui_fftsink2_0 + 0 + 0 + + + ha5kfu_execproc_xx_0 + wxgui_scopesink2_0 + 0 + 0 + + + interp_fir_filter_xxx_0 + wxgui_fftsink2_0_0 + 0 + 0 + + + interp_fir_filter_xxx_0 + wxgui_scopesink2_0_1 + 0 + 0 + + diff --git a/libcsdr.c b/libcsdr.c index 5483f79..04440c5 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -396,8 +396,8 @@ int fir_interpolate_cc(complexf *input, complexf *output, int input_size, int in float accq=0; //int tistart = (interpolation-ip)%interpolation; int tistart = (interpolation-ip); //why does this work? why don't we need the % part? - for(int ti=tistart, si=0; ti Date: Thu, 2 Mar 2017 12:17:31 +0100 Subject: [PATCH 021/111] Added timing_recovery_cc --- csdr.c | 32 ++++++++++++++ libcsdr.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++- libcsdr.h | 22 ++++++++++ 3 files changed, 176 insertions(+), 1 deletion(-) diff --git a/csdr.c b/csdr.c index 7353b85..c227819 100644 --- a/csdr.c +++ b/csdr.c @@ -2348,6 +2348,38 @@ int main(int argc, char *argv[]) fwrite(output_buffer, sizeof(complexf), the_bufsize, stdout); //fprintf(stderr, "| o"); TRY_YIELD; + } + + if(!strcmp(argv[1],"timing_recovery_cc")) // [--add_q] + { + if(argc<=2) return badsyntax("need required parameter (algorithm)"); + timing_recovery_algorithm_t algorithm = timing_recovery_get_algorithm_from_string(argv[2]); + /* if(algorithm == TIMING_RECOVERY_ALGORITHM_DEFAULT) */ + fprintf(stderr,"timing_recovery_cc: algorithm = %s\n",timing_recovery_get_string_from_algorithm(algorithm)); + if(argc<=3) return badsyntax("need required parameter (decimation factor)"); + int decimation; + sscanf(argv[3],"%d",&decimation); + if(decimation<=4 || decimation&3) badsyntax("decimation factor should be a positive integer divisible by 4"); + + int add_q = (argc>=5 && !strcmp(argv[4], "--add_q")); + + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize/decimation); + + timing_recovery_state_t state = timing_recovery_init(algorithm, decimation, add_q); + + FREAD_C; + for(;;) + { + FEOF_CHECK; + timing_recovery((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, &state); + //fprintf(stderr, "os %d\n",state->output_size); + fwrite(output_buffer, sizeof(complexf), state->output_size, stdout); + fflush(stdout); + TRY_YIELD; + memmove((complexf*)input_buffer,((complexf*)input_buffer)+state->input_processed,(the_bufsize-state->input_processed)*sizeof(complexf)); //memmove lets the source and destination overlap + fread(((complexf*)input_buffer)+(the_bufsize-state->input_processed), sizeof(complexf), state->input_processed, stdin); + //fprintf(stderr,"iskip=%d state->output_size=%d start=%x target=%x skipcount=%x \n",state->input_processed,state->output_size,input_buffer, ((complexf*)input_buffer)+(BIG_BUFSIZE-state->input_processed),(BIG_BUFSIZE-state->input_processed)); } } diff --git a/libcsdr.c b/libcsdr.c index 5f0bdb0..e7cc163 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1572,6 +1572,17 @@ void binary_slicer_f_u8(float* input, unsigned char* output, int input_size) for(int i=0;i 0; } +/* + _____ _ _______ _ _ _____ + / ____| (_) ___ |__ __(_) (_) | __ \ + | | __ _ _ __ _ __ _ ___ _ __ ( _ ) | | _ _ __ ___ _ _ __ __ _ | |__) |___ ___ _____ _____ _ __ _ _ + | | / _` | '__| '__| |/ _ \ '__| / _ \/\ | | | | '_ ` _ \| | '_ \ / _` | | _ // _ \/ __/ _ \ \ / / _ \ '__| | | | + | |___| (_| | | | | | | __/ | | (_> < | | | | | | | | | | | | | (_| | | | \ \ __/ (_| (_) \ V / __/ | | |_| | + \_____\__,_|_| |_| |_|\___|_| \___/\/ |_| |_|_| |_| |_|_|_| |_|\__, | |_| \_\___|\___\___/ \_/ \___|_| \__, | + __/ | __/ | + |___/ |___/ +*/ + void pll_cc_init_pi_controller(pll_t* p, float bandwidth, float ko, float kd, float damping_factor) { //kd: detector gain @@ -1620,7 +1631,7 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nc p->dphase = new_dphase * p->alpha + p->iir_temp; p->iir_temp += new_dphase * p->beta; - while(p->dphase>PI) p->dphase-=2*PI; //ez nem fog kelleni + while(p->dphase>PI) p->dphase-=2*PI; //won't need this one while(p->dphase<-PI) p->dphase+=2*PI; } else if(p->pll_type == PLL_P_CONTROLLER) @@ -1633,6 +1644,116 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nc } } +timing_recovery_state_t timing_recovery_init(timing_recovery_algorithm_t algorithm, int decimation_rate, int use_q) +{ + timing_recovery_state_t to_return; + to_return.algorithm = algorithm; + to_return.decimation_rate = decimation_rate; + to_return.use_q = use_q; + return to_return; +} + +int timing_recovery(complexf* input, complexf* output, int input_size, timing_recovery_state_t* state) +{ + //We always assume that the input starts at center of the first symbol cross before the first symbol. + //Last time we consumed that much from the input samples that it is there. + int current_bitstart_index = 0; + int num_samples_bit = state->decimation_rate; + int num_samples_halfbit = state->decimation_rate / 2; + int num_samples_quarterbit = state->decimation_rate / 4; + float error; + int si; + if(state->algorithm == TIMING_RECOVERY_ALGORITHM_GARDNER) + { + for(si=0;;si++) + { + if(current_bitstart_index + num_samples_halfbit * 3 >= input_size) break; + output[si++] = input[current_bitstart_index + num_samples_halfbit]; + error = ( + iof(input, current_bitstart_index + num_samples_halfbit * 3) - iof(input, current_bitstart_index + num_samples_halfbit) + ) * iof(input, current_bitstart_index + num_samples_halfbit * 2); + if(state->use_q) + { + error += ( + qof(input, current_bitstart_index + num_samples_halfbit * 3) - qof(input, current_bitstart_index + num_samples_halfbit) + ) * qof(input, current_bitstart_index + num_samples_halfbit * 2); + error /= 2; + } + current_bitstart_index += num_samples_halfbit * 2 + (error)?((error>0)?1:-1):0; + + } + state->input_processed = current_bitstart_index; + state->output_size = si; + } + else if(state->algorithm == TIMING_RECOVERY_ALGORITHM_EARLYLATE) + { + for(si=0;;si++) + { + if(current_bitstart_index + num_samples_bit >= input_size) break; + output[si++] = input[current_bitstart_index + num_samples_halfbit]; + error = ( + iof(input, current_bitstart_index + num_samples_quarterbit * 3) - iof(input, current_bitstart_index + num_samples_quarterbit) + ); //* iof(input, current_bitstart_index + num_samples_halfbit); //I don't think we need the end of the Nutaq formula + if(state->use_q) + { + error += qof(input, current_bitstart_index + num_samples_quarterbit * 3) - qof(input, current_bitstart_index + num_samples_quarterbit); + error /= 2; + } + //Correction method #1: this version can only move a single sample in any direction + //current_bitstart_index += num_samples_halfbit * 2 + (error)?((error<0)?1:-1):0; + //Correction method #2: this can move in proportional to the error + if(error>2) error=2; + if(error<-2) error=-2; + current_bitstart_index += num_samples_halfbit * 2 + num_samples_halfbit * (-error/2); + } + state->input_processed = current_bitstart_index; + state->output_i = si; + } +} + +#define MTIMINGR_GAS(NAME) \ + if(!strcmp( #NAME , input )) return TIMING_RECOVERY_ALGORITHM_ ## NAME; + +timing_recovery_algorithm_t timing_recovery_get_algorithm_from_string(char* input) +{ + MTIMINGR_GAS(GARDNER); + MTIMINGR_GAS(EARLYLATE); + return TIMING_RECOVERY_ALGORITHM_DEFAULT; +} + +#define MTIMINGR_GSA(NAME) \ + if(algorithm == TIMING_RECOVERY_ALGORITHM_ ## NAME) return #NAME; + +char* timing_recovery_get_string_from_algorithm(timing_recovery_algorithm_t algorithm) +{ + MTIMINGR_GSA(GARDNER); + MTIMINGR_GSA(EARLYLATE); + return "INVALID"; +} + +/* +in struct: + char* debug_string; + char* debug_string_end; + int debug_string_length; + int debug_mode; + int debug_first_n_symbols; +func: +void timing_recovery_write_debug_string +( + int input, + int input_length, + int current_bitstart_index, + int current_output_index, + int current_p1_index, + int current_p2_index, + timing_recovery_state_t* state +) +{ + if(state->debug_string_end==state->debug_string+debug_string_length) return; +}*/ + + /* _____ _ _ | __ \ | | (_) diff --git a/libcsdr.h b/libcsdr.h index 0ae8fbc..8259c37 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -287,3 +287,25 @@ typedef struct pll_s void pll_cc_init_pi_controller(pll_t* p, float bandwidth, float ko, float kd, float damping_factor); void pll_cc_init_p_controller(pll_t* p, float alpha); void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nco, int input_size); + +typedef enum timing_recovery_algorithm_e +{ + TIMING_RECOVERY_ALGORITHM_GARDNER, + TIMING_RECOVERY_ALGORITHM_EARLYLATE +} timing_recovery_algorithm_t; + +#define TIMING_RECOVERY_ALGORITHM_DEFAULT TIMING_RECOVERY_ALGORITHM_GARDNER + +typedef struct timing_recovery_state_s +{ + timing_recovery_algorithm_t algorithm; + int decimation_rate; // = input_rate / output_rate. We should get an input signal that is N times oversampled. + int output_size; + int input_processed; + int use_q; //use both I and Q for calculating the error +} timing_recovery_state_t; + +timing_recovery_state_t timing_recovery_init(timing_recovery_algorithm_t algorithm, int decimation_rate, int use_q); +int timing_recovery(complexf* input, complexf* output, int input_length, timing_recovery_state_t* state); +timing_recovery_algorithm_t timing_recovery_get_algorithm_from_string(char* input); +char* timing_recovery_get_string_from_algorithm(timing_recovery_algorithm_t algorithm); From 2af14b8082f13cee2165205c470fa4e04fff9be6 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Thu, 2 Mar 2017 12:27:53 +0100 Subject: [PATCH 022/111] Made timing_recovery_cc build --- csdr.c | 11 ++++++----- libcsdr.c | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/csdr.c b/csdr.c index c227819..2cf1fd3 100644 --- a/csdr.c +++ b/csdr.c @@ -2348,6 +2348,7 @@ int main(int argc, char *argv[]) fwrite(output_buffer, sizeof(complexf), the_bufsize, stdout); //fprintf(stderr, "| o"); TRY_YIELD; + } } if(!strcmp(argv[1],"timing_recovery_cc")) // [--add_q] @@ -2373,13 +2374,13 @@ int main(int argc, char *argv[]) { FEOF_CHECK; timing_recovery((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, &state); - //fprintf(stderr, "os %d\n",state->output_size); - fwrite(output_buffer, sizeof(complexf), state->output_size, stdout); + //fprintf(stderr, "os %d\n",state.output_size); + fwrite(output_buffer, sizeof(complexf), state.output_size, stdout); fflush(stdout); TRY_YIELD; - memmove((complexf*)input_buffer,((complexf*)input_buffer)+state->input_processed,(the_bufsize-state->input_processed)*sizeof(complexf)); //memmove lets the source and destination overlap - fread(((complexf*)input_buffer)+(the_bufsize-state->input_processed), sizeof(complexf), state->input_processed, stdin); - //fprintf(stderr,"iskip=%d state->output_size=%d start=%x target=%x skipcount=%x \n",state->input_processed,state->output_size,input_buffer, ((complexf*)input_buffer)+(BIG_BUFSIZE-state->input_processed),(BIG_BUFSIZE-state->input_processed)); + memmove((complexf*)input_buffer,((complexf*)input_buffer)+state.input_processed,(the_bufsize-state.input_processed)*sizeof(complexf)); //memmove lets the source and destination overlap + fread(((complexf*)input_buffer)+(the_bufsize-state.input_processed), sizeof(complexf), state.input_processed, stdin); + //fprintf(stderr,"iskip=%d state.output_size=%d start=%x target=%x skipcount=%x \n",state.input_processed,state.output_size,input_buffer, ((complexf*)input_buffer)+(BIG_BUFSIZE-state.input_processed),(BIG_BUFSIZE-state.input_processed)); } } diff --git a/libcsdr.c b/libcsdr.c index e7cc163..c3c9583 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1707,7 +1707,7 @@ int timing_recovery(complexf* input, complexf* output, int input_size, timing_re current_bitstart_index += num_samples_halfbit * 2 + num_samples_halfbit * (-error/2); } state->input_processed = current_bitstart_index; - state->output_i = si; + state->output_size = si; } } From ccf09a1b994d9ddeebdcc7f93ac5107e03b622f2 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Fri, 3 Mar 2017 11:20:49 +0100 Subject: [PATCH 023/111] timing_recovery is timing_recovery_cc --- csdr.c | 2 +- libcsdr.c | 2 +- libcsdr.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/csdr.c b/csdr.c index 2cf1fd3..2eff419 100644 --- a/csdr.c +++ b/csdr.c @@ -2373,7 +2373,7 @@ int main(int argc, char *argv[]) for(;;) { FEOF_CHECK; - timing_recovery((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, &state); + timing_recovery_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, &state); //fprintf(stderr, "os %d\n",state.output_size); fwrite(output_buffer, sizeof(complexf), state.output_size, stdout); fflush(stdout); diff --git a/libcsdr.c b/libcsdr.c index c3c9583..73270c8 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1653,7 +1653,7 @@ timing_recovery_state_t timing_recovery_init(timing_recovery_algorithm_t algorit return to_return; } -int timing_recovery(complexf* input, complexf* output, int input_size, timing_recovery_state_t* state) +void timing_recovery_cc(complexf* input, complexf* output, int input_size, timing_recovery_state_t* state) { //We always assume that the input starts at center of the first symbol cross before the first symbol. //Last time we consumed that much from the input samples that it is there. diff --git a/libcsdr.h b/libcsdr.h index 8259c37..754a4a2 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -306,6 +306,6 @@ typedef struct timing_recovery_state_s } timing_recovery_state_t; timing_recovery_state_t timing_recovery_init(timing_recovery_algorithm_t algorithm, int decimation_rate, int use_q); -int timing_recovery(complexf* input, complexf* output, int input_length, timing_recovery_state_t* state); +void timing_recovery_cc(complexf* input, complexf* output, int input_length, timing_recovery_state_t* state); timing_recovery_algorithm_t timing_recovery_get_algorithm_from_string(char* input); char* timing_recovery_get_string_from_algorithm(timing_recovery_algorithm_t algorithm); From 26c12746eb68c9f3860ff9ada1c1abbfa213f5de Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Fri, 3 Mar 2017 16:21:45 +0100 Subject: [PATCH 024/111] Added octave_complex_c, finished timing_recovery_cc debug, fixed indent --- csdr.c | 51 +++++++++++++++++- libcsdr.c | 156 +++++++++++++++++++++++++++++++----------------------- libcsdr.h | 3 ++ 3 files changed, 143 insertions(+), 67 deletions(-) diff --git a/csdr.c b/csdr.c index 2eff419..40d2271 100644 --- a/csdr.c +++ b/csdr.c @@ -122,6 +122,8 @@ char usage[]= " rtty_line_decoder_sy_u8\n" " rtty_baudot2ascii_u8_u8\n" " serial_line_decoder_sy_u8\n" +" octave_complex_c \n" +" timing_recovery_cc [--add_q]\n" " \n" ; @@ -2364,16 +2366,21 @@ int main(int argc, char *argv[]) int add_q = (argc>=5 && !strcmp(argv[4], "--add_q")); + int debug_n = 0; + if(argc>=7 && !strcmp(argv[5], "--octave")) debug_n = atoi(argv[6]); + if(!initialize_buffers()) return -2; sendbufsize(the_bufsize/decimation); timing_recovery_state_t state = timing_recovery_init(algorithm, decimation, add_q); + int debug_i=0; FREAD_C; for(;;) { FEOF_CHECK; timing_recovery_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, &state); + if(++debug_i%debug_n==0) timing_recovery_trigger_debug(&state, 3); //fprintf(stderr, "os %d\n",state.output_size); fwrite(output_buffer, sizeof(complexf), state.output_size, stdout); fflush(stdout); @@ -2384,10 +2391,52 @@ int main(int argc, char *argv[]) } } + if(!strcmp(argv[1],"octave_complex_c")) + { + if(argc<=2) return badsyntax("need required parameter (samples_to_plot)"); + int samples_to_plot = 0; + sscanf(argv[2], "%d", &samples_to_plot); + if(samples_to_plot<=0) badsyntax("Number of samples to plot should be > 0"); + if(argc<=3) return badsyntax("need required parameter (out_of_n_samples)"); + int out_of_n_samples = 0; + sscanf(argv[3], "%d", &out_of_n_samples); + if(out_of_n_samples0;seek_remain-=samples_to_plot) + { + fread(read_buf, sizeof(complexf), MIN_M(samples_to_plot,seek_remain), stdin); + } + FEOF_CHECK; + TRY_YIELD; + } + } + if(!strcmp(argv[1],"none")) { return 0; } - fprintf(stderr,"csdr: function name given in argument 1 (%s) does not exist. Possible causes:\n- You mistyped the commandline.\n- You need to update csdr to a newer version (if available).", argv[1]); return -1; + if(argv[1][0]=='?') + { + char buffer[100]; + snprintf(buffer, 100-1, "csdr 2>&1 | grep %s", argv[1]+1); + fprintf(stderr, "csdr ?: %s\n", buffer); + system(buffer); + return 0; + } + + fprintf(stderr,"csdr: function name given in argument 1 (%s) does not exist. Possible causes:\n- You mistyped the commandline.\n- You need to update csdr to a newer version (if available).\n", argv[1]); return -1; } diff --git a/libcsdr.c b/libcsdr.c index 73270c8..4c323f9 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -38,6 +38,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "libcsdr.h" #include "predefined.h" #include +#include /* _ _ __ _ _ @@ -276,11 +277,11 @@ shift_unroll_data_t shift_unroll_init(float rate, int size) { myphase += output.phase_increment; while(myphase>PI) myphase-=2*PI; - while(myphase<-PI) myphase+=2*PI; + while(myphase<-PI) myphase+=2*PI; output.dsin[i]=sin(myphase); output.dcos[i]=cos(myphase); } - return output; + return output; } float shift_unroll_cc(complexf *input, complexf* output, int input_size, shift_unroll_data_t* d, float starting_phase) @@ -323,7 +324,7 @@ float shift_addfast_cc(complexf *input, complexf* output, int input_size, shift_ //input_size should be multiple of 4 float cos_start[4], sin_start[4]; float cos_vals[4], sin_vals[4]; - for(int i=0;i<4;i++) + for(int i=0;i<4;i++) { cos_start[i] = cos(starting_phase); sin_start[i] = sin(starting_phase); @@ -343,7 +344,7 @@ float shift_addfast_cc(complexf *input, complexf* output, int input_size, shift_ #define RCOSV "q4" //cos_vals, sin_vals #define RSINV "q5" #define ROUTI "q6" //output_i, output_q - #define ROUTQ "q7" + #define ROUTQ "q7" #define RINPI "q8" //input_i, input_q #define RINPQ "q9" #define R3(x,y,z) x ", " y ", " z "\n\t" @@ -353,7 +354,7 @@ float shift_addfast_cc(complexf *input, complexf* output, int input_size, shift_ " vld1.32 {" RDSIN "}, [%[pdsin]]\n\t" " vld1.32 {" RCOSST "}, [%[cos_start]]\n\t" " vld1.32 {" RSINST "}, [%[sin_start]]\n\t" - "for_addfast: vld2.32 {" RINPI "-" RINPQ "}, [%[pinput]]!\n\t" //load q0 and q1 directly from the memory address stored in pinput, with interleaving (so that we get the I samples in RINPI and the Q samples in RINPQ), also increment the memory address in pinput (hence the "!" mark) + "for_addfast: vld2.32 {" RINPI "-" RINPQ "}, [%[pinput]]!\n\t" //load q0 and q1 directly from the memory address stored in pinput, with interleaving (so that we get the I samples in RINPI and the Q samples in RINPQ), also increment the memory address in pinput (hence the "!" mark) //C version: //cos_vals[j] = cos_start * d->dcos[j] - sin_start * d->dsin[j]; @@ -366,7 +367,7 @@ float shift_addfast_cc(complexf *input, complexf* output, int input_size, shift_ //C version: //iof(output,4*i+j)=cos_vals[j]*iof(input,4*i+j)-sin_vals[j]*qof(input,4*i+j); - //qof(output,4*i+j)=sin_vals[j]*iof(input,4*i+j)+cos_vals[j]*qof(input,4*i+j); + //qof(output,4*i+j)=sin_vals[j]*iof(input,4*i+j)+cos_vals[j]*qof(input,4*i+j); " vmul.f32 " R3(ROUTI, RCOSV, RINPI) //output_i = cos_vals * input_i " vmls.f32 " R3(ROUTI, RSINV, RINPQ) //output_i -= sin_vals * input_q " vmul.f32 " R3(ROUTQ, RSINV, RINPI) //output_q = sin_vals * input_i @@ -383,7 +384,7 @@ float shift_addfast_cc(complexf *input, complexf* output, int input_size, shift_ [pinput]"+r"(pinput), [poutput]"+r"(poutput) //output operand list -> C variables that we will change from ASM : [pinput_end]"r"(pinput_end), [pdcos]"r"(pdcos), [pdsin]"r"(pdsin), [sin_start]"r"(sin_start), [cos_start]"r"(cos_start) //input operand list - : + : "memory", "q0", "q1", "q2", "q4", "q5", "q6", "q7", "q8", "q9", "cc" //clobber list ); starting_phase+=input_size*d->phase_increment; @@ -409,7 +410,7 @@ float shift_addfast_cc(complexf *input, complexf* output, int input_size, shift_ float cos_start=cos(starting_phase); float sin_start=sin(starting_phase); float register cos_vals_0, cos_vals_1, cos_vals_2, cos_vals_3, - sin_vals_0, sin_vals_1, sin_vals_2, sin_vals_3, + sin_vals_0, sin_vals_1, sin_vals_2, sin_vals_3, dsin_0 = d->dsin[0], dsin_1 = d->dsin[1], dsin_2 = d->dsin[2], dsin_3 = d->dsin[3], dcos_0 = d->dcos[0], dcos_1 = d->dcos[1], dcos_2 = d->dcos[2], dcos_3 = d->dcos[3]; @@ -970,7 +971,7 @@ float deemphasis_wfm_ff (float* input, float* output, int input_size, float tau, output[0]=alpha*input[0]+(1-alpha)*last_output; for (int i=1;i < | | | | | | | | | | | | | (_| | | | \ \ __/ (_| (_) \ V / __/ | | |_| | \_____\__,_|_| |_| |_|\___|_| \___/\/ |_| |_|_| |_| |_|_|_| |_|\__, | |_| \_\___|\___\___/ \_/ \___|_| \__, | __/ | __/ | - |___/ |___/ + |___/ |___/ */ void pll_cc_init_pi_controller(pll_t* p, float bandwidth, float ko, float kd, float damping_factor) @@ -1644,18 +1644,47 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nc } } +void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, int points_size, ...) +{ + fprintf(stderr, "N = %d\nisig = [", signal_size); + for(int i=0;idebug_phase=debug_phase; +} + + void timing_recovery_cc(complexf* input, complexf* output, int input_size, timing_recovery_state_t* state) { - //We always assume that the input starts at center of the first symbol cross before the first symbol. + //We always assume that the input starts at center of the first symbol cross before the first symbol. //Last time we consumed that much from the input samples that it is there. int current_bitstart_index = 0; int num_samples_bit = state->decimation_rate; @@ -1669,18 +1698,26 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin { if(current_bitstart_index + num_samples_halfbit * 3 >= input_size) break; output[si++] = input[current_bitstart_index + num_samples_halfbit]; - error = ( - iof(input, current_bitstart_index + num_samples_halfbit * 3) - iof(input, current_bitstart_index + num_samples_halfbit) + error = ( + iof(input, current_bitstart_index + num_samples_halfbit * 3) - iof(input, current_bitstart_index + num_samples_halfbit) ) * iof(input, current_bitstart_index + num_samples_halfbit * 2); - if(state->use_q) + if(state->use_q) { - error += ( - qof(input, current_bitstart_index + num_samples_halfbit * 3) - qof(input, current_bitstart_index + num_samples_halfbit) + error += ( + qof(input, current_bitstart_index + num_samples_halfbit * 3) - qof(input, current_bitstart_index + num_samples_halfbit) ) * qof(input, current_bitstart_index + num_samples_halfbit * 2); error /= 2; } - current_bitstart_index += num_samples_halfbit * 2 + (error)?((error>0)?1:-1):0; - + if(state->debug_phase == si) + { + state->debug_phase = -1; + octave_plot_point_on_cplxsig(input+current_bitstart_index, state->decimation_rate*2, + num_samples_halfbit * 1, 'r', + num_samples_halfbit * 2, 'r', + num_samples_halfbit * 3, 'r', + 0); //last argument is dummy, for the comma + } + current_bitstart_index += num_samples_halfbit * 2 + (error)?((error>0)?1:-1):0; } state->input_processed = current_bitstart_index; state->output_size = si; @@ -1691,19 +1728,28 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin { if(current_bitstart_index + num_samples_bit >= input_size) break; output[si++] = input[current_bitstart_index + num_samples_halfbit]; - error = ( - iof(input, current_bitstart_index + num_samples_quarterbit * 3) - iof(input, current_bitstart_index + num_samples_quarterbit) + error = ( + iof(input, current_bitstart_index + num_samples_quarterbit * 3) - iof(input, current_bitstart_index + num_samples_quarterbit) ); //* iof(input, current_bitstart_index + num_samples_halfbit); //I don't think we need the end of the Nutaq formula - if(state->use_q) + if(state->use_q) { error += qof(input, current_bitstart_index + num_samples_quarterbit * 3) - qof(input, current_bitstart_index + num_samples_quarterbit); error /= 2; } //Correction method #1: this version can only move a single sample in any direction - //current_bitstart_index += num_samples_halfbit * 2 + (error)?((error<0)?1:-1):0; + //current_bitstart_index += num_samples_halfbit * 2 + (error)?((error<0)?1:-1):0; //Correction method #2: this can move in proportional to the error if(error>2) error=2; if(error<-2) error=-2; + if(state->debug_phase == si) + { + state->debug_phase = -1; + octave_plot_point_on_cplxsig(input+current_bitstart_index, state->decimation_rate*2, + num_samples_quarterbit * 1, 'r', + num_samples_quarterbit * 2, 'r', + num_samples_quarterbit * 3, 'r', + 0); + } current_bitstart_index += num_samples_halfbit * 2 + num_samples_halfbit * (-error/2); } state->input_processed = current_bitstart_index; @@ -1731,28 +1777,6 @@ char* timing_recovery_get_string_from_algorithm(timing_recovery_algorithm_t algo return "INVALID"; } -/* -in struct: - char* debug_string; - char* debug_string_end; - int debug_string_length; - int debug_mode; - int debug_first_n_symbols; -func: -void timing_recovery_write_debug_string -( - int input, - int input_length, - int current_bitstart_index, - int current_output_index, - int current_p1_index, - int current_p2_index, - timing_recovery_state_t* state -) -{ - if(state->debug_string_end==state->debug_string+debug_string_length) return; -}*/ - /* _____ _ _ diff --git a/libcsdr.h b/libcsdr.h index 754a4a2..9757ce0 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -303,9 +303,12 @@ typedef struct timing_recovery_state_s int output_size; int input_processed; int use_q; //use both I and Q for calculating the error + int debug_phase; } timing_recovery_state_t; timing_recovery_state_t timing_recovery_init(timing_recovery_algorithm_t algorithm, int decimation_rate, int use_q); void timing_recovery_cc(complexf* input, complexf* output, int input_length, timing_recovery_state_t* state); timing_recovery_algorithm_t timing_recovery_get_algorithm_from_string(char* input); char* timing_recovery_get_string_from_algorithm(timing_recovery_algorithm_t algorithm); +void timing_recovery_trigger_debug(timing_recovery_state_t* state, int debug_phase); +void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, int points_size, ...); From 969992f734480d7a95aec0b962a57d700637b9fb Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Fri, 3 Mar 2017 18:23:11 +0100 Subject: [PATCH 025/111] timing_recovery_cc outputs data, but segfaults with --octave --- csdr.c | 5 +++-- libcsdr.c | 13 ++++++++++--- libcsdr.h | 1 + 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/csdr.c b/csdr.c index 40d2271..ee74b34 100644 --- a/csdr.c +++ b/csdr.c @@ -2353,7 +2353,7 @@ int main(int argc, char *argv[]) } } - if(!strcmp(argv[1],"timing_recovery_cc")) // [--add_q] + if(!strcmp(argv[1],"timing_recovery_cc")) // [--add_q [--octave ]] { if(argc<=2) return badsyntax("need required parameter (algorithm)"); timing_recovery_algorithm_t algorithm = timing_recovery_get_algorithm_from_string(argv[2]); @@ -2368,6 +2368,7 @@ int main(int argc, char *argv[]) int debug_n = 0; if(argc>=7 && !strcmp(argv[5], "--octave")) debug_n = atoi(argv[6]); + if(debug_n<0) badsyntax("debug_n should be >= 0"); if(!initialize_buffers()) return -2; sendbufsize(the_bufsize/decimation); @@ -2379,8 +2380,8 @@ int main(int argc, char *argv[]) for(;;) { FEOF_CHECK; + if(debug_n && ++debug_i%debug_n==0) timing_recovery_trigger_debug(&state, 3); timing_recovery_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, &state); - if(++debug_i%debug_n==0) timing_recovery_trigger_debug(&state, 3); //fprintf(stderr, "os %d\n",state.output_size); fwrite(output_buffer, sizeof(complexf), state.output_size, stdout); fflush(stdout); diff --git a/libcsdr.c b/libcsdr.c index 4c323f9..9efbceb 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1673,6 +1673,7 @@ timing_recovery_state_t timing_recovery_init(timing_recovery_algorithm_t algorit to_return.decimation_rate = decimation_rate; to_return.use_q = use_q; to_return.debug_phase = -1; + to_return.debug_count = 3; return to_return; } @@ -1681,6 +1682,7 @@ void timing_recovery_trigger_debug(timing_recovery_state_t* state, int debug_pha state->debug_phase=debug_phase; } +#define MTIMINGR_HDEBUG 1 void timing_recovery_cc(complexf* input, complexf* output, int input_size, timing_recovery_state_t* state) { @@ -1690,8 +1692,10 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin int num_samples_bit = state->decimation_rate; int num_samples_halfbit = state->decimation_rate / 2; int num_samples_quarterbit = state->decimation_rate / 4; + int debug_i = state->debug_count; float error; int si; + if(MTIMINGR_HDEBUG) fprintf(stderr, "timing_recovery_cci started, nsb = %d, nshb = %d, nsqb = %d\n", num_samples_bit, num_samples_halfbit, num_samples_quarterbit); if(state->algorithm == TIMING_RECOVERY_ALGORITHM_GARDNER) { for(si=0;;si++) @@ -1708,16 +1712,19 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin ) * qof(input, current_bitstart_index + num_samples_halfbit * 2); error /= 2; } - if(state->debug_phase == si) + if(state->debug_phase >= si && debug_i) { - state->debug_phase = -1; + debug_i--; + if(!debug_i) state->debug_phase = -1; octave_plot_point_on_cplxsig(input+current_bitstart_index, state->decimation_rate*2, num_samples_halfbit * 1, 'r', num_samples_halfbit * 2, 'r', num_samples_halfbit * 3, 'r', 0); //last argument is dummy, for the comma } - current_bitstart_index += num_samples_halfbit * 2 + (error)?((error>0)?1:-1):0; + if(MTIMINGR_HDEBUG) fprintf(stderr, "current_bitstart_index = %d, error = %g\n", current_bitstart_index, error); + current_bitstart_index += num_samples_halfbit * 2 + ((error)?((error>0)?1:-1):0); + if(MTIMINGR_HDEBUG) fprintf(stderr, "new current_bitstart_index = %d\n", current_bitstart_index); } state->input_processed = current_bitstart_index; state->output_size = si; diff --git a/libcsdr.h b/libcsdr.h index 9757ce0..9501c21 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -304,6 +304,7 @@ typedef struct timing_recovery_state_s int input_processed; int use_q; //use both I and Q for calculating the error int debug_phase; + int debug_count; } timing_recovery_state_t; timing_recovery_state_t timing_recovery_init(timing_recovery_algorithm_t algorithm, int decimation_rate, int use_q); From 818b6b11576d17c2a9e421d96f7e8f4e5ced8c93 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Fri, 3 Mar 2017 18:45:03 +0100 Subject: [PATCH 026/111] timing_recovery_cc --octave now works --- libcsdr.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libcsdr.c b/libcsdr.c index 9efbceb..82be0de 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1652,17 +1652,18 @@ void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, int points_ for(int i=0;idebug_phase=debug_phase; } -#define MTIMINGR_HDEBUG 1 +#define MTIMINGR_HDEBUG 0 void timing_recovery_cc(complexf* input, complexf* output, int input_size, timing_recovery_state_t* state) { @@ -1717,6 +1718,7 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin debug_i--; if(!debug_i) state->debug_phase = -1; octave_plot_point_on_cplxsig(input+current_bitstart_index, state->decimation_rate*2, + 3, num_samples_halfbit * 1, 'r', num_samples_halfbit * 2, 'r', num_samples_halfbit * 3, 'r', From e1d4a4ff3b1e8d04cedeb1417e09eb848fa1f5ef Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sat, 4 Mar 2017 19:17:11 +0100 Subject: [PATCH 027/111] Less stdout at octave --- csdr.c | 4 ++-- libcsdr.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/csdr.c b/csdr.c index ee74b34..ce14a5b 100644 --- a/csdr.c +++ b/csdr.c @@ -2357,8 +2357,8 @@ int main(int argc, char *argv[]) { if(argc<=2) return badsyntax("need required parameter (algorithm)"); timing_recovery_algorithm_t algorithm = timing_recovery_get_algorithm_from_string(argv[2]); - /* if(algorithm == TIMING_RECOVERY_ALGORITHM_DEFAULT) */ - fprintf(stderr,"timing_recovery_cc: algorithm = %s\n",timing_recovery_get_string_from_algorithm(algorithm)); + if(algorithm == TIMING_RECOVERY_ALGORITHM_DEFAULT) + fprintf(stderr,"#timing_recovery_cc: algorithm = %s\n",timing_recovery_get_string_from_algorithm(algorithm)); if(argc<=3) return badsyntax("need required parameter (decimation factor)"); int decimation; sscanf(argv[3],"%d",&decimation); diff --git a/libcsdr.c b/libcsdr.c index 82be0de..a3aa435 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1646,11 +1646,11 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nc void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, int points_size, ...) { - fprintf(stderr, "N = %d\nisig = [", signal_size); + fprintf(stderr, "N = %d;\nisig = [", signal_size); for(int i=0;i Date: Sat, 4 Mar 2017 19:50:11 +0100 Subject: [PATCH 028/111] timing_recovery_cc: a better graph --- csdr.c | 1 + libcsdr.c | 45 +++++++++++++++++++++++++++++++-------------- libcsdr.h | 3 ++- 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/csdr.c b/csdr.c index ce14a5b..2ad9773 100644 --- a/csdr.c +++ b/csdr.c @@ -2376,6 +2376,7 @@ int main(int argc, char *argv[]) timing_recovery_state_t state = timing_recovery_init(algorithm, decimation, add_q); int debug_i=0; + state.debug_force = !!debug_n; //should remove that later FREAD_C; for(;;) { diff --git a/libcsdr.c b/libcsdr.c index a3aa435..d31a9c0 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1644,24 +1644,40 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nc } } -void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, int points_size, ...) +void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error, int points_size, ...) { - fprintf(stderr, "N = %d;\nisig = [", signal_size); - for(int i=0;idebug_phase >= si && debug_i) + if( state->debug_force || (state->debug_phase >= si && debug_i) ) { debug_i--; if(!debug_i) state->debug_phase = -1; - octave_plot_point_on_cplxsig(input+current_bitstart_index, state->decimation_rate*2, + octave_plot_point_on_cplxsig(input+current_bitstart_index, state->decimation_rate*2, error, 3, num_samples_halfbit * 1, 'r', num_samples_halfbit * 2, 'r', @@ -1753,7 +1770,7 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin if(state->debug_phase == si) { state->debug_phase = -1; - octave_plot_point_on_cplxsig(input+current_bitstart_index, state->decimation_rate*2, + octave_plot_point_on_cplxsig(input+current_bitstart_index, state->decimation_rate*2, error, num_samples_quarterbit * 1, 'r', num_samples_quarterbit * 2, 'r', num_samples_quarterbit * 3, 'r', diff --git a/libcsdr.h b/libcsdr.h index 9501c21..28427cb 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -305,6 +305,7 @@ typedef struct timing_recovery_state_s int use_q; //use both I and Q for calculating the error int debug_phase; int debug_count; + int debug_force; } timing_recovery_state_t; timing_recovery_state_t timing_recovery_init(timing_recovery_algorithm_t algorithm, int decimation_rate, int use_q); @@ -312,4 +313,4 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_length, tim timing_recovery_algorithm_t timing_recovery_get_algorithm_from_string(char* input); char* timing_recovery_get_string_from_algorithm(timing_recovery_algorithm_t algorithm); void timing_recovery_trigger_debug(timing_recovery_state_t* state, int debug_phase); -void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, int points_size, ...); +void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error, int points_size, ...); From a1a64b3a72d75d1c980e98a64784ec64ac02fbfa Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 5 Mar 2017 16:30:12 +0100 Subject: [PATCH 029/111] EARLYLATE is also being plotted --- libcsdr.c | 38 +++++++++++++++++++++++++++----------- libcsdr.h | 2 +- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/libcsdr.c b/libcsdr.c index d31a9c0..0f058d8 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1644,7 +1644,7 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nc } } -void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error, int points_size, ...) +void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error, int index, int points_size, ...) { int* points_z = (int*)malloc(sizeof(int)*points_size); int* points_color = (int*)malloc(sizeof(int)*points_size); @@ -1666,7 +1666,7 @@ void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error (char)points_color[i]&0xff, (idebug_phase=debug_phase; } -#define MTIMINGR_HDEBUG 0 +#define MTIMINGR_HDEBUG 1 void timing_recovery_cc(complexf* input, complexf* output, int input_size, timing_recovery_state_t* state) { @@ -1713,6 +1714,7 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin int debug_i = state->debug_count; float error; int si; + if(state->debug_force) fprintf(stderr, "disp(\"begin timing_recovery_cc\");\n"); if(MTIMINGR_HDEBUG) fprintf(stderr, "timing_recovery_cci started, nsb = %d, nshb = %d, nsqb = %d\n", num_samples_bit, num_samples_halfbit, num_samples_quarterbit); if(state->algorithm == TIMING_RECOVERY_ALGORITHM_GARDNER) { @@ -1734,16 +1736,19 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin { debug_i--; if(!debug_i) state->debug_phase = -1; - octave_plot_point_on_cplxsig(input+current_bitstart_index, state->decimation_rate*2, error, - 3, + octave_plot_point_on_cplxsig(input+current_bitstart_index, state->decimation_rate*2, + error, + current_bitstart_index, + 3, //number of points to draw below: num_samples_halfbit * 1, 'r', num_samples_halfbit * 2, 'r', num_samples_halfbit * 3, 'r', 0); //last argument is dummy, for the comma } if(MTIMINGR_HDEBUG) fprintf(stderr, "current_bitstart_index = %d, error = %g\n", current_bitstart_index, error); - current_bitstart_index += num_samples_halfbit * 2 + ((error)?((error>0)?1:-1):0); + current_bitstart_index += num_samples_bit + ((error)?((error>0)?1:-1):0); if(MTIMINGR_HDEBUG) fprintf(stderr, "new current_bitstart_index = %d\n", current_bitstart_index); + if(si>=input_size) { break; } } state->input_processed = current_bitstart_index; state->output_size = si; @@ -1753,6 +1758,8 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin for(si=0;;si++) { if(current_bitstart_index + num_samples_bit >= input_size) break; + if(MTIMINGR_HDEBUG) fprintf(stderr, "current_bitstart_index = %d, input_size = %d\n", + current_bitstart_index, input_size); output[si++] = input[current_bitstart_index + num_samples_halfbit]; error = ( iof(input, current_bitstart_index + num_samples_quarterbit * 3) - iof(input, current_bitstart_index + num_samples_quarterbit) @@ -1767,16 +1774,25 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin //Correction method #2: this can move in proportional to the error if(error>2) error=2; if(error<-2) error=-2; - if(state->debug_phase == si) + if( state->debug_force || (state->debug_phase >= si && debug_i) ) { - state->debug_phase = -1; - octave_plot_point_on_cplxsig(input+current_bitstart_index, state->decimation_rate*2, error, + debug_i--; + if(!debug_i) state->debug_phase = -1; + octave_plot_point_on_cplxsig(input+current_bitstart_index, state->decimation_rate*2, + error, + current_bitstart_index, + 3, num_samples_quarterbit * 1, 'r', num_samples_quarterbit * 2, 'r', num_samples_quarterbit * 3, 'r', 0); } - current_bitstart_index += num_samples_halfbit * 2 + num_samples_halfbit * (-error/2); + current_bitstart_index += num_samples_bit + num_samples_halfbit * (-error/2); + if(si>=input_size) + { + if(MTIMINGR_HDEBUG) fprintf(stderr, "oops_out_of_si!\n"); + break; + } } state->input_processed = current_bitstart_index; state->output_size = si; diff --git a/libcsdr.h b/libcsdr.h index 28427cb..4c758cc 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -313,4 +313,4 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_length, tim timing_recovery_algorithm_t timing_recovery_get_algorithm_from_string(char* input); char* timing_recovery_get_string_from_algorithm(timing_recovery_algorithm_t algorithm); void timing_recovery_trigger_debug(timing_recovery_state_t* state, int debug_phase); -void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error, int points_size, ...); +void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error, int index, int points_size, ...); From f93e7c4a9927e96f9bc508c26649e9ff4a3f6f26 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 5 Mar 2017 17:21:38 +0100 Subject: [PATCH 030/111] Octave figures are now written into PNGs --- csdr.c | 2 +- libcsdr.c | 8 +++++++- libcsdr.h | 3 ++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/csdr.c b/csdr.c index 2ad9773..5281bed 100644 --- a/csdr.c +++ b/csdr.c @@ -2376,7 +2376,7 @@ int main(int argc, char *argv[]) timing_recovery_state_t state = timing_recovery_init(algorithm, decimation, add_q); int debug_i=0; - state.debug_force = !!debug_n; //should remove that later + state.debug_writefiles = state.debug_force = !!debug_n; //should remove that later FREAD_C; for(;;) { diff --git a/libcsdr.c b/libcsdr.c index 0f058d8..3e99e8c 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1644,8 +1644,9 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nc } } -void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error, int index, int points_size, ...) +void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error, int index, int writefiles, int points_size, ...) { + static int figure_output_counter = 0; int* points_z = (int*)malloc(sizeof(int)*points_size); int* points_color = (int*)malloc(sizeof(int)*points_size); va_list vl; @@ -1655,6 +1656,7 @@ void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error points_z[i] = va_arg(vl, int); points_color[i] = va_arg(vl, int); } + if(writefiles && !figure_output_counter) fprintf(stderr, "cf=figure();\n"); fprintf(stderr, "N = %d;\nisig = [", signal_size); for(int i=0;idecimation_rate*2, error, current_bitstart_index, + state->debug_writefiles, 3, //number of points to draw below: num_samples_halfbit * 1, 'r', num_samples_halfbit * 2, 'r', @@ -1781,6 +1786,7 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin octave_plot_point_on_cplxsig(input+current_bitstart_index, state->decimation_rate*2, error, current_bitstart_index, + state->debug_writefiles, 3, num_samples_quarterbit * 1, 'r', num_samples_quarterbit * 2, 'r', diff --git a/libcsdr.h b/libcsdr.h index 4c758cc..f6195a3 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -306,6 +306,7 @@ typedef struct timing_recovery_state_s int debug_phase; int debug_count; int debug_force; + int debug_writefiles; } timing_recovery_state_t; timing_recovery_state_t timing_recovery_init(timing_recovery_algorithm_t algorithm, int decimation_rate, int use_q); @@ -313,4 +314,4 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_length, tim timing_recovery_algorithm_t timing_recovery_get_algorithm_from_string(char* input); char* timing_recovery_get_string_from_algorithm(timing_recovery_algorithm_t algorithm); void timing_recovery_trigger_debug(timing_recovery_state_t* state, int debug_phase); -void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error, int index, int points_size, ...); +void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error, int index, int writefiles, int points_size, ...); From 306e4aeb9198b205d41a2655fe585dff5c0242b3 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 5 Mar 2017 19:16:34 +0100 Subject: [PATCH 031/111] EARLYLATE actually works --- csdr.c | 1 + libcsdr.c | 17 +++++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/csdr.c b/csdr.c index 5281bed..c91e376 100644 --- a/csdr.c +++ b/csdr.c @@ -2387,6 +2387,7 @@ int main(int argc, char *argv[]) fwrite(output_buffer, sizeof(complexf), state.output_size, stdout); fflush(stdout); TRY_YIELD; + fprintf(stderr, "state.input_processed = %d\n", state.input_processed); memmove((complexf*)input_buffer,((complexf*)input_buffer)+state.input_processed,(the_bufsize-state.input_processed)*sizeof(complexf)); //memmove lets the source and destination overlap fread(((complexf*)input_buffer)+(the_bufsize-state.input_processed), sizeof(complexf), state.input_processed, stdin); //fprintf(stderr,"iskip=%d state.output_size=%d start=%x target=%x skipcount=%x \n",state.input_processed,state.output_size,input_buffer, ((complexf*)input_buffer)+(BIG_BUFSIZE-state.input_processed),(BIG_BUFSIZE-state.input_processed)); diff --git a/libcsdr.c b/libcsdr.c index 3e99e8c..e7ac80a 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1697,6 +1697,7 @@ timing_recovery_state_t timing_recovery_init(timing_recovery_algorithm_t algorit to_return.debug_count = 3; to_return.debug_force = 0; to_return.debug_writefiles = 0; + //to_return.last_phase_offset = 0; return to_return; } @@ -1705,7 +1706,7 @@ void timing_recovery_trigger_debug(timing_recovery_state_t* state, int debug_pha state->debug_phase=debug_phase; } -#define MTIMINGR_HDEBUG 1 +#define MTIMINGR_HDEBUG 0 void timing_recovery_cc(complexf* input, complexf* output, int input_size, timing_recovery_state_t* state) { @@ -1719,7 +1720,7 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin float error; int si; if(state->debug_force) fprintf(stderr, "disp(\"begin timing_recovery_cc\");\n"); - if(MTIMINGR_HDEBUG) fprintf(stderr, "timing_recovery_cci started, nsb = %d, nshb = %d, nsqb = %d\n", num_samples_bit, num_samples_halfbit, num_samples_quarterbit); + if(MTIMINGR_HDEBUG) fprintf(stderr, "timing_recovery_cc started, nsb = %d, nshb = %d, nsqb = %d\n", num_samples_bit, num_samples_halfbit, num_samples_quarterbit); if(state->algorithm == TIMING_RECOVERY_ALGORITHM_GARDNER) { for(si=0;;si++) @@ -1760,18 +1761,21 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin } else if(state->algorithm == TIMING_RECOVERY_ALGORITHM_EARLYLATE) { + //bitstart index should be at symbol maximum effect point for(si=0;;si++) { - if(current_bitstart_index + num_samples_bit >= input_size) break; + if(current_bitstart_index + num_samples_halfbit * 3 >= input_size) break; if(MTIMINGR_HDEBUG) fprintf(stderr, "current_bitstart_index = %d, input_size = %d\n", current_bitstart_index, input_size); - output[si++] = input[current_bitstart_index + num_samples_halfbit]; + output[si++] = input[current_bitstart_index]; error = ( iof(input, current_bitstart_index + num_samples_quarterbit * 3) - iof(input, current_bitstart_index + num_samples_quarterbit) - ); //* iof(input, current_bitstart_index + num_samples_halfbit); //I don't think we need the end of the Nutaq formula + ) * iof(input, current_bitstart_index + num_samples_halfbit); if(state->use_q) { - error += qof(input, current_bitstart_index + num_samples_quarterbit * 3) - qof(input, current_bitstart_index + num_samples_quarterbit); + error += ( + qof(input, current_bitstart_index + num_samples_quarterbit * 3) - qof(input, current_bitstart_index + num_samples_quarterbit) + ) * qof(input, current_bitstart_index + num_samples_halfbit); error /= 2; } //Correction method #1: this version can only move a single sample in any direction @@ -1791,6 +1795,7 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin num_samples_quarterbit * 1, 'r', num_samples_quarterbit * 2, 'r', num_samples_quarterbit * 3, 'r', + 0 , 'b', 0); } current_bitstart_index += num_samples_bit + num_samples_halfbit * (-error/2); From dde8fa0d08db46bc597f02c890c62581a78d0f27 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 5 Mar 2017 19:56:15 +0100 Subject: [PATCH 032/111] GARDNER works, but we need a better way to calculate the error --- libcsdr.c | 54 +++++++++++++++++++++++++++++++++--------------------- libcsdr.h | 3 ++- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/libcsdr.c b/libcsdr.c index e7ac80a..3ab4ebf 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1644,7 +1644,7 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nc } } -void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error, int index, int writefiles, int points_size, ...) +void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error, int index, int correction_offset, int writefiles, int points_size, ...) { static int figure_output_counter = 0; int* points_z = (int*)malloc(sizeof(int)*points_size); @@ -1668,7 +1668,7 @@ void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error (char)points_color[i]&0xff, (ilast_correction_offset; int current_bitstart_index = 0; int num_samples_bit = state->decimation_rate; int num_samples_halfbit = state->decimation_rate / 2; @@ -1744,6 +1745,7 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin octave_plot_point_on_cplxsig(input+current_bitstart_index, state->decimation_rate*2, error, current_bitstart_index, + correction_offset, state->debug_writefiles, 3, //number of points to draw below: num_samples_halfbit * 1, 'r', @@ -1756,33 +1758,40 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin if(MTIMINGR_HDEBUG) fprintf(stderr, "new current_bitstart_index = %d\n", current_bitstart_index); if(si>=input_size) { break; } } - state->input_processed = current_bitstart_index; - state->output_size = si; } else if(state->algorithm == TIMING_RECOVERY_ALGORITHM_EARLYLATE) { //bitstart index should be at symbol maximum effect point for(si=0;;si++) { + //the MathWorks style algorithm has correction_offset. + //correction_offset = 0; if(current_bitstart_index + num_samples_halfbit * 3 >= input_size) break; - if(MTIMINGR_HDEBUG) fprintf(stderr, "current_bitstart_index = %d, input_size = %d\n", - current_bitstart_index, input_size); + if(MTIMINGR_HDEBUG) fprintf(stderr, "current_bitstart_index = %d, input_size = %d, correction_offset(prev) = %d\n", + current_bitstart_index, input_size, correction_offset); + + if(correction_offset<=-num_samples_quarterbit*0.9 || correction_offset>=0.9*num_samples_quarterbit) + { + if(MTIMINGR_HDEBUG) fprintf(stderr, "correction_offset = %d, reset to 0!\n", correction_offset); + correction_offset = 0; + } output[si++] = input[current_bitstart_index]; - error = ( - iof(input, current_bitstart_index + num_samples_quarterbit * 3) - iof(input, current_bitstart_index + num_samples_quarterbit) - ) * iof(input, current_bitstart_index + num_samples_halfbit); + int el_point_left_index = current_bitstart_index + num_samples_quarterbit * 3; + int el_point_right_index = current_bitstart_index + num_samples_quarterbit * 1 - correction_offset; + int el_point_mid_index = current_bitstart_index + num_samples_halfbit; + + error = ( iof(input, el_point_left_index) - iof(input, el_point_right_index)) * iof(input, el_point_mid_index); if(state->use_q) { - error += ( - qof(input, current_bitstart_index + num_samples_quarterbit * 3) - qof(input, current_bitstart_index + num_samples_quarterbit) - ) * qof(input, current_bitstart_index + num_samples_halfbit); + error += ( qof(input, el_point_left_index) - qof(input, el_point_right_index)) * qof(input, el_point_mid_index); error /= 2; } //Correction method #1: this version can only move a single sample in any direction - //current_bitstart_index += num_samples_halfbit * 2 + (error)?((error<0)?1:-1):0; + //current_bitstart_index += num_samples_halfbit * 2 + (error)?((error<0)?1:-1):0; + //Correction method #2: this can move in proportional to the error - if(error>2) error=2; - if(error<-2) error=-2; + if(error>2) error=2; + if(error<-2) error=-2; if( state->debug_force || (state->debug_phase >= si && debug_i) ) { debug_i--; @@ -1790,24 +1799,27 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin octave_plot_point_on_cplxsig(input+current_bitstart_index, state->decimation_rate*2, error, current_bitstart_index, + correction_offset, state->debug_writefiles, - 3, + 4, + 0 , 'b', num_samples_quarterbit * 1, 'r', num_samples_quarterbit * 2, 'r', num_samples_quarterbit * 3, 'r', - 0 , 'b', 0); } - current_bitstart_index += num_samples_bit + num_samples_halfbit * (-error/2); + correction_offset = num_samples_halfbit * (-error/2); + current_bitstart_index += num_samples_bit + correction_offset; if(si>=input_size) { if(MTIMINGR_HDEBUG) fprintf(stderr, "oops_out_of_si!\n"); break; } } - state->input_processed = current_bitstart_index; - state->output_size = si; } + state->input_processed = current_bitstart_index; + state->output_size = si; + state->last_correction_offset = correction_offset; } #define MTIMINGR_GAS(NAME) \ diff --git a/libcsdr.h b/libcsdr.h index f6195a3..9ca4cb0 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -307,6 +307,7 @@ typedef struct timing_recovery_state_s int debug_count; int debug_force; int debug_writefiles; + int last_correction_offset; } timing_recovery_state_t; timing_recovery_state_t timing_recovery_init(timing_recovery_algorithm_t algorithm, int decimation_rate, int use_q); @@ -314,4 +315,4 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_length, tim timing_recovery_algorithm_t timing_recovery_get_algorithm_from_string(char* input); char* timing_recovery_get_string_from_algorithm(timing_recovery_algorithm_t algorithm); void timing_recovery_trigger_debug(timing_recovery_state_t* state, int debug_phase); -void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error, int index, int writefiles, int points_size, ...); +void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error, int index, int correction_offset, int writefiles, int points_size, ...); From 09c873c13dda8082444f5fec79a852518973de0e Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Mon, 6 Mar 2017 22:31:32 +0100 Subject: [PATCH 033/111] EARLYLATE now verified --- csdr.c | 3 ++- libcsdr.c | 20 ++++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/csdr.c b/csdr.c index c91e376..131b165 100644 --- a/csdr.c +++ b/csdr.c @@ -2376,7 +2376,8 @@ int main(int argc, char *argv[]) timing_recovery_state_t state = timing_recovery_init(algorithm, decimation, add_q); int debug_i=0; - state.debug_writefiles = state.debug_force = !!debug_n; //should remove that later + state.debug_writefiles = 1; + state.debug_force = !!debug_n; //should remove that later FREAD_C; for(;;) { diff --git a/libcsdr.c b/libcsdr.c index 3ab4ebf..4336e81 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1727,6 +1727,10 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin for(si=0;;si++) { if(current_bitstart_index + num_samples_halfbit * 3 >= input_size) break; + + int el_point_left_index = current_bitstart_index + num_samples_quarterbit * 3; + int el_point_right_index = current_bitstart_index + num_samples_quarterbit * 1 - correction_offset; + int el_point_mid_index = current_bitstart_index + num_samples_halfbit; output[si++] = input[current_bitstart_index + num_samples_halfbit]; error = ( iof(input, current_bitstart_index + num_samples_halfbit * 3) - iof(input, current_bitstart_index + num_samples_halfbit) @@ -1754,14 +1758,17 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin 0); //last argument is dummy, for the comma } if(MTIMINGR_HDEBUG) fprintf(stderr, "current_bitstart_index = %d, error = %g\n", current_bitstart_index, error); - current_bitstart_index += num_samples_bit + ((error)?((error>0)?1:-1):0); + //hey, this should be fixed here: + correction_offset = num_samples_halfbit * (-error/2); + current_bitstart_index += num_samples_bit + correction_offset; + //current_bitstart_index += num_samples_bit + ((error)?((error>0)?1:-1):0); if(MTIMINGR_HDEBUG) fprintf(stderr, "new current_bitstart_index = %d\n", current_bitstart_index); if(si>=input_size) { break; } } } else if(state->algorithm == TIMING_RECOVERY_ALGORITHM_EARLYLATE) { - //bitstart index should be at symbol maximum effect point + //bitstart index should be at symbol edge, maximum effect point is at current_bitstart_index + num_samples_halfbit for(si=0;;si++) { //the MathWorks style algorithm has correction_offset. @@ -1775,10 +1782,12 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin if(MTIMINGR_HDEBUG) fprintf(stderr, "correction_offset = %d, reset to 0!\n", correction_offset); correction_offset = 0; } - output[si++] = input[current_bitstart_index]; + //should check if the sign of the correction_offset (or disabling it) has an effect on the EVM. + //it is also a possibility to disable multiplying with the magnitude int el_point_left_index = current_bitstart_index + num_samples_quarterbit * 3; int el_point_right_index = current_bitstart_index + num_samples_quarterbit * 1 - correction_offset; int el_point_mid_index = current_bitstart_index + num_samples_halfbit; + output[si++] = input[current_bitstart_index + el_point_mid_index]; error = ( iof(input, el_point_left_index) - iof(input, el_point_right_index)) * iof(input, el_point_mid_index); if(state->use_q) @@ -1801,14 +1810,13 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin current_bitstart_index, correction_offset, state->debug_writefiles, - 4, - 0 , 'b', + 3, num_samples_quarterbit * 1, 'r', num_samples_quarterbit * 2, 'r', num_samples_quarterbit * 3, 'r', 0); } - correction_offset = num_samples_halfbit * (-error/2); + correction_offset = num_samples_halfbit * (error/2); current_bitstart_index += num_samples_bit + correction_offset; if(si>=input_size) { From 79a33b0d242273abcae91669df1ecee5fce26561 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Mon, 6 Mar 2017 23:00:34 +0100 Subject: [PATCH 034/111] Integrated EARLYLATE and GARDNER into one loop, tested only EARLYLATE --- csdr.c | 2 +- libcsdr.c | 89 +++++++++++++++++++------------------------------------ libcsdr.h | 1 + 3 files changed, 33 insertions(+), 59 deletions(-) diff --git a/csdr.c b/csdr.c index 131b165..735f8c0 100644 --- a/csdr.c +++ b/csdr.c @@ -2376,7 +2376,7 @@ int main(int argc, char *argv[]) timing_recovery_state_t state = timing_recovery_init(algorithm, decimation, add_q); int debug_i=0; - state.debug_writefiles = 1; + state.debug_writefiles = 0; state.debug_force = !!debug_n; //should remove that later FREAD_C; for(;;) diff --git a/libcsdr.c b/libcsdr.c index 4336e81..ce0b195 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1698,6 +1698,7 @@ timing_recovery_state_t timing_recovery_init(timing_recovery_algorithm_t algorit to_return.debug_force = 0; to_return.debug_writefiles = 0; to_return.last_correction_offset = 0; + to_return.earlylate_ratio = 0.25; //0..0.5 return to_return; } @@ -1717,58 +1718,14 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin int num_samples_bit = state->decimation_rate; int num_samples_halfbit = state->decimation_rate / 2; int num_samples_quarterbit = state->decimation_rate / 4; + int num_samples_earlylate_wing = num_samples_bit * state->earlylate_ratio; int debug_i = state->debug_count; float error; + int el_point_left_index, el_point_right_index, el_point_mid_index; int si; if(state->debug_force) fprintf(stderr, "disp(\"begin timing_recovery_cc\");\n"); if(MTIMINGR_HDEBUG) fprintf(stderr, "timing_recovery_cc started, nsb = %d, nshb = %d, nsqb = %d\n", num_samples_bit, num_samples_halfbit, num_samples_quarterbit); - if(state->algorithm == TIMING_RECOVERY_ALGORITHM_GARDNER) { - for(si=0;;si++) - { - if(current_bitstart_index + num_samples_halfbit * 3 >= input_size) break; - - int el_point_left_index = current_bitstart_index + num_samples_quarterbit * 3; - int el_point_right_index = current_bitstart_index + num_samples_quarterbit * 1 - correction_offset; - int el_point_mid_index = current_bitstart_index + num_samples_halfbit; - output[si++] = input[current_bitstart_index + num_samples_halfbit]; - error = ( - iof(input, current_bitstart_index + num_samples_halfbit * 3) - iof(input, current_bitstart_index + num_samples_halfbit) - ) * iof(input, current_bitstart_index + num_samples_halfbit * 2); - if(state->use_q) - { - error += ( - qof(input, current_bitstart_index + num_samples_halfbit * 3) - qof(input, current_bitstart_index + num_samples_halfbit) - ) * qof(input, current_bitstart_index + num_samples_halfbit * 2); - error /= 2; - } - if( state->debug_force || (state->debug_phase >= si && debug_i) ) - { - debug_i--; - if(!debug_i) state->debug_phase = -1; - octave_plot_point_on_cplxsig(input+current_bitstart_index, state->decimation_rate*2, - error, - current_bitstart_index, - correction_offset, - state->debug_writefiles, - 3, //number of points to draw below: - num_samples_halfbit * 1, 'r', - num_samples_halfbit * 2, 'r', - num_samples_halfbit * 3, 'r', - 0); //last argument is dummy, for the comma - } - if(MTIMINGR_HDEBUG) fprintf(stderr, "current_bitstart_index = %d, error = %g\n", current_bitstart_index, error); - //hey, this should be fixed here: - correction_offset = num_samples_halfbit * (-error/2); - current_bitstart_index += num_samples_bit + correction_offset; - //current_bitstart_index += num_samples_bit + ((error)?((error>0)?1:-1):0); - if(MTIMINGR_HDEBUG) fprintf(stderr, "new current_bitstart_index = %d\n", current_bitstart_index); - if(si>=input_size) { break; } - } - } - else if(state->algorithm == TIMING_RECOVERY_ALGORITHM_EARLYLATE) - { - //bitstart index should be at symbol edge, maximum effect point is at current_bitstart_index + num_samples_halfbit for(si=0;;si++) { //the MathWorks style algorithm has correction_offset. @@ -1782,23 +1739,35 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin if(MTIMINGR_HDEBUG) fprintf(stderr, "correction_offset = %d, reset to 0!\n", correction_offset); correction_offset = 0; } - //should check if the sign of the correction_offset (or disabling it) has an effect on the EVM. - //it is also a possibility to disable multiplying with the magnitude - int el_point_left_index = current_bitstart_index + num_samples_quarterbit * 3; - int el_point_right_index = current_bitstart_index + num_samples_quarterbit * 1 - correction_offset; - int el_point_mid_index = current_bitstart_index + num_samples_halfbit; - output[si++] = input[current_bitstart_index + el_point_mid_index]; + //should check if the sign of the correction_offset (or disabling it) has an effect on the EVM. + //it is also a possibility to disable multiplying with the magnitude + if(state->algorithm == TIMING_RECOVERY_ALGORITHM_EARLYLATE) + { + //bitstart index should be at symbol edge, maximum effect point is at current_bitstart_index + num_samples_halfbit + el_point_right_index = current_bitstart_index + num_samples_earlylate_wing * 3; + el_point_left_index = current_bitstart_index + num_samples_earlylate_wing * 1 - correction_offset; + el_point_mid_index = current_bitstart_index + num_samples_halfbit; + output[si++] = input[current_bitstart_index + el_point_mid_index]; + } + else if(state->algorithm == TIMING_RECOVERY_ALGORITHM_GARDNER) + { + //maximum effect point is at current_bitstart_index + el_point_right_index = current_bitstart_index + num_samples_halfbit * 3; + el_point_left_index = current_bitstart_index + num_samples_halfbit * 1; + el_point_mid_index = current_bitstart_index + num_samples_halfbit * 2; + output[si++] = input[current_bitstart_index + num_samples_halfbit * 1]; + } + else break; - error = ( iof(input, el_point_left_index) - iof(input, el_point_right_index)) * iof(input, el_point_mid_index); + error = ( iof(input, el_point_right_index) - iof(input, el_point_left_index)) * iof(input, el_point_mid_index); if(state->use_q) { - error += ( qof(input, el_point_left_index) - qof(input, el_point_right_index)) * qof(input, el_point_mid_index); + error += ( qof(input, el_point_right_index) - qof(input, el_point_left_index)) * qof(input, el_point_mid_index); error /= 2; } - //Correction method #1: this version can only move a single sample in any direction + //Original correction method: this version can only move a single sample in any direction //current_bitstart_index += num_samples_halfbit * 2 + (error)?((error<0)?1:-1):0; - //Correction method #2: this can move in proportional to the error if(error>2) error=2; if(error<-2) error=-2; if( state->debug_force || (state->debug_phase >= si && debug_i) ) @@ -1811,12 +1780,16 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin correction_offset, state->debug_writefiles, 3, - num_samples_quarterbit * 1, 'r', + num_samples_quarterbit, 'r', num_samples_quarterbit * 2, 'r', num_samples_quarterbit * 3, 'r', + //el_point_left_index - current_bitstart_index, 'r', + //el_point_right_index - current_bitstart_index, 'r', + //el_point_mid_index - current_bitstart_index, 'r', 0); } - correction_offset = num_samples_halfbit * (error/2); + int error_sign = (state->algorithm == TIMING_RECOVERY_ALGORITHM_GARDNER) ? -1 : 1; + correction_offset = num_samples_halfbit * error_sign * (error/2); current_bitstart_index += num_samples_bit + correction_offset; if(si>=input_size) { diff --git a/libcsdr.h b/libcsdr.h index 9ca4cb0..79588b1 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -308,6 +308,7 @@ typedef struct timing_recovery_state_s int debug_force; int debug_writefiles; int last_correction_offset; + float earlylate_ratio; } timing_recovery_state_t; timing_recovery_state_t timing_recovery_init(timing_recovery_algorithm_t algorithm, int decimation_rate, int use_q); From a7ba9c91c96cc7dbcfa0f50e9f0e37d2ced3779e Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Mon, 6 Mar 2017 23:02:06 +0100 Subject: [PATCH 035/111] Fixed display of points --- libcsdr.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libcsdr.c b/libcsdr.c index ce0b195..f0f3821 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1780,12 +1780,12 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin correction_offset, state->debug_writefiles, 3, - num_samples_quarterbit, 'r', - num_samples_quarterbit * 2, 'r', - num_samples_quarterbit * 3, 'r', - //el_point_left_index - current_bitstart_index, 'r', - //el_point_right_index - current_bitstart_index, 'r', - //el_point_mid_index - current_bitstart_index, 'r', + //num_samples_quarterbit, 'r', + //num_samples_quarterbit * 2, 'r', + //num_samples_quarterbit * 3, 'r', + el_point_left_index - current_bitstart_index, 'r', + el_point_right_index - current_bitstart_index, 'r', + el_point_mid_index - current_bitstart_index, 'r', 0); } int error_sign = (state->algorithm == TIMING_RECOVERY_ALGORITHM_GARDNER) ? -1 : 1; From eaea93c1e24edbf7510c3fae3793d28640146695 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Mon, 6 Mar 2017 23:04:20 +0100 Subject: [PATCH 036/111] GARDNER works as well! --- libcsdr.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/libcsdr.c b/libcsdr.c index f0f3821..ebb0502 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1780,9 +1780,6 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin correction_offset, state->debug_writefiles, 3, - //num_samples_quarterbit, 'r', - //num_samples_quarterbit * 2, 'r', - //num_samples_quarterbit * 3, 'r', el_point_left_index - current_bitstart_index, 'r', el_point_right_index - current_bitstart_index, 'r', el_point_mid_index - current_bitstart_index, 'r', From 2d5c27d3dc4aaf4df4f4bd4673561ab46328611c Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Tue, 14 Mar 2017 09:12:09 +0100 Subject: [PATCH 037/111] Added bpsk_costas_loop_cc base --- csdr.c | 2 +- libcsdr.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/csdr.c b/csdr.c index 735f8c0..131b165 100644 --- a/csdr.c +++ b/csdr.c @@ -2376,7 +2376,7 @@ int main(int argc, char *argv[]) timing_recovery_state_t state = timing_recovery_init(algorithm, decimation, add_q); int debug_i=0; - state.debug_writefiles = 0; + state.debug_writefiles = 1; state.debug_force = !!debug_n; //should remove that later FREAD_C; for(;;) diff --git a/libcsdr.c b/libcsdr.c index ebb0502..363d6b3 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1820,6 +1820,41 @@ char* timing_recovery_get_string_from_algorithm(timing_recovery_algorithm_t algo return "INVALID"; } +typedef struct bpsk_costas_loop_state_s +{ + float pll_alpha; + float pll_beta; + float pll_iir_temp; + float pll_phase; +} bpsk_costas_loop_state_t; + +void init_bpsk_carrier_recovery_cc(bpsk_costas_loop_state_t* state) +{ + state->pll_alpha = state->pll_beta = 0; //TODO <-- + state->pll_phase = 0; + state->pll_iir_temp = 0; +} + +void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, bpsk_costas_loop_state_t* state) +{ + complexf ejphi; //downconvert with that + for(int i=0;ipll_phase); + cmult(&output[i], &input[i], &ejphi); + + float error = iof(output,i) * qof(output, i); + if(error>2) error=2; + if(error<-2) error=-2; + + state->pll_phase = error * state->pll_alpha + state->pll_iir_temp; + state->pll_iir_temp += error * state->pll_beta; + + while(state->pll_phase>PI) state->pll_phase-=2*PI; + while(state->pll_phase<-PI) state->pll_phase+=2*PI; + } +} + /* _____ _ _ From fabca1145049e74d7eed0c787a70166e54735400 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sat, 25 Mar 2017 23:47:23 +0100 Subject: [PATCH 038/111] Added some algorithms (untested) --- libcsdr.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/libcsdr.c b/libcsdr.c index 363d6b3..b3ba0c4 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1413,6 +1413,29 @@ char psk31_varicode_decoder_push(unsigned long long* status_shr, unsigned char s return 0; } +void psk31_varicode_encoder_u8_u8(unsigned char* input, unsigned char* output, int input_size, int output_max_size, int* input_processed, int* output_size) +{ + *output_size=0; + for(*input_processed=0; *input_processed>(current_varicode.bitcount-bi-1))&1; + *output_size++; + output_max_size--; + } + break; + } + } + } +} + rtty_baudot_item_t rtty_baudot_items[] = { { .code = 0b00000, .ascii_letter=0, .ascii_figure=0 }, @@ -1572,6 +1595,47 @@ void binary_slicer_f_u8(float* input, unsigned char* output, int input_size) for(int i=0;i 0; } +void psk_modulator_u8_c(unsigned char* input, complexf* output, int input_size, int npsk) +{ + //outputs one complex sample per input symbol + for(int i=0;i>bi)&1; +} + + /* _____ _ _______ _ _ _____ / ____| (_) ___ |__ __(_) (_) | __ \ From c23693e885d300accaa9bdb8897145bd33e0be42 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 26 Mar 2017 16:55:28 +0200 Subject: [PATCH 039/111] Added psk_modulator_u8_ci, duplicate_samples_ntimes_u8_u8i, psk31_interpolate_sine_cci, pack_bits_8to1_u8_u8i, psk31_varicode_encoder_u8_u8i --- csdr.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++- libcsdr.c | 12 +++--- libcsdr.h | 5 +++ 3 files changed, 126 insertions(+), 7 deletions(-) diff --git a/csdr.c b/csdr.c index 131b165..0d7440e 100644 --- a/csdr.c +++ b/csdr.c @@ -973,7 +973,7 @@ int main(int argc, char *argv[]) } } - if(!strcmp(argv[1],"floatdump_f")) + if(!strcmp(argv[1],"floatdump_f") || !strcmp(argv[1],"dump_f")) { if(!sendbufsize(initialize_buffers())) return -2; for(;;) @@ -2428,6 +2428,120 @@ int main(int argc, char *argv[]) } } + if(!strcmp(argv[1],"psk_modulator_u8_c")) // + { + int n_psk; + if(argc<=2) return badsyntax("need required parameter (n_psk)"); + sscanf(argv[2],"%d",&n_psk); + if(n_psk<=0 || n_psk>256) badsyntax("n_psk should be between 1 and 256"); + + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize); + + for(;;) + { + FEOF_CHECK; + fread((unsigned char*)input_buffer, sizeof(unsigned char), the_bufsize, stdin); + psk_modulator_u8_c((unsigned char*)input_buffer, (complexf*)output_buffer, the_bufsize, n_psk); + FWRITE_C; + TRY_YIELD; + } + } + + if(!strcmp(argv[1],"duplicate_samples_ntimes_u8_u8")) // + { + int sample_size_bytes, ntimes; + if(argc<=2) return badsyntax("need required parameter (sample_size_bytes)"); + sscanf(argv[2],"%d",&sample_size_bytes); + if(argc<=3) return badsyntax("need required parameter (ntimes)"); + sscanf(argv[3],"%d",&ntimes); + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize*ntimes); + unsigned char* local_input_buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize*sample_size_bytes); + unsigned char* local_output_buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize*sample_size_bytes*ntimes); + for(;;) + { + FEOF_CHECK; + fread((void*)local_input_buffer, sizeof(unsigned char), the_bufsize*sample_size_bytes, stdin); + duplicate_samples_ntimes_u8_u8(local_input_buffer, local_input_buffer, the_bufsize*sample_size_bytes, sample_size_bytes, ntimes); + fwrite((void*)local_output_buffer, sizeof(unsigned char), the_bufsize*sample_size_bytes*ntimes, stdout); + TRY_YIELD; + } + } + + if(!strcmp(argv[1],"psk31_interpolate_sine_cc")) // + { + int interpolation; + if(argc<=2) return badsyntax("need required parameter (interpolation)"); + sscanf(argv[2],"%d",&interpolation); + if(interpolation<=0) badsyntax("interpolation should be >0"); + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize*interpolation); + complexf* local_output_buffer = (complexf*)malloc(sizeof(complexf)*the_bufsize*interpolation); + complexf last_input; + iof(&last_input,0) = 0; + qof(&last_input,0) = 0; + for(;;) + { + FEOF_CHECK; + FREAD_C; + last_input = psk31_interpolate_sine_cc((complexf*)input_buffer, local_output_buffer, the_bufsize, interpolation, last_input); + fwrite((void*)local_output_buffer, sizeof(complexf), the_bufsize*interpolation, stdout); + TRY_YIELD; + } + } + + if(!strcmp(argv[1],"pack_bits_8to1_u8_u8")) + { + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize*8); + unsigned char* local_input_buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize); + unsigned char* local_output_buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize*8); + for(;;) + { + FEOF_CHECK; + fread((void*)local_input_buffer, sizeof(unsigned char), the_bufsize, stdin); + pack_bits_8to1_u8_u8(local_input_buffer, local_output_buffer, the_bufsize); + fwrite((void*)local_output_buffer, sizeof(unsigned char), the_bufsize*8, stdout); + TRY_YIELD; + } + } + + if(!strcmp(argv[1],"psk31_varicode_encoder_u8_u8")) + { + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize*8); + int output_max_size=the_bufsize*30; + int output_size; + int input_processed; + unsigned char* local_input_buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize); + unsigned char* local_output_buffer = (unsigned char*)malloc(sizeof(unsigned char)*output_max_size); + fread((void*)local_input_buffer, sizeof(unsigned char), the_bufsize, stdin); + for(;;) + { + psk31_varicode_encoder_u8_u8(local_input_buffer, local_output_buffer, the_bufsize, output_max_size, &input_processed, &output_size); + fwrite((void*)local_output_buffer, sizeof(unsigned char), output_size, stdout); + FEOF_CHECK; + memmove(local_input_buffer, local_input_buffer+input_processed, the_bufsize-input_processed); + fread(input_buffer+the_bufsize-input_processed, sizeof(unsigned char), input_processed, stdin); + TRY_YIELD; + } + } + + if(!strcmp(argv[1],"dump_u8")) + { + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize*3); + unsigned char* local_input_buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize); + for(;;) + { + FEOF_CHECK; + fread((void*)local_input_buffer, sizeof(unsigned char), the_bufsize, stdin); + for(int i=0;i>(current_varicode.bitcount-bi-1))&1; + output[*output_size]=(psk31_varicode_items[ci].code>>(current_varicode.bitcount-bi-1))&1; *output_size++; output_max_size--; } @@ -1595,12 +1595,12 @@ void binary_slicer_f_u8(float* input, unsigned char* output, int input_size) for(int i=0;i 0; } -void psk_modulator_u8_c(unsigned char* input, complexf* output, int input_size, int npsk) +void psk_modulator_u8_c(unsigned char* input, complexf* output, int input_size, int n_psk) { //outputs one complex sample per input symbol for(int i=0;i Date: Mon, 27 Mar 2017 13:44:01 +0200 Subject: [PATCH 040/111] Working PSK31 generator --- README.md | 34 ++++++++++++++++++++++++++++++++-- csdr.c | 41 +++++++++++++++++++++++++++++++++++++---- libcsdr.c | 43 +++++++++++++++++++++++++++++++++---------- libcsdr.h | 1 + 4 files changed, 103 insertions(+), 16 deletions(-) mode change 100644 => 100755 csdr.c diff --git a/README.md b/README.md index e0f2ddc..9215045 100644 --- a/README.md +++ b/README.md @@ -185,20 +185,34 @@ Else, after outputing `buf_times` number of buffers (the size of which is stated Along with copying its input samples to the output, it prints a warning message to *stderr* if it finds any IEEE floating point NaN values among the samples. - floatdump_f + dump_f + +It prints all floating point input samples as text. -It prints any floating point input samples. The format string used is `"%g "`. +You can also use it to print complex float values, then you will see the I and Q samples interleaved, like: `I Q I Q I Q ...` + +Alternatively, you can use the `od` command (built into most Linux distributions). To display a list of floating point values with their addresses as well, you can use: `od -vf` + + dump_u8 + +It prints all input bytes as text, in hexadecimal form. + +Alternatively, you can use the `xxd` command (built into most Linux distributions). To display a hexadecimal dump of the standard input (with addresses at the beginning of rows), you can use: `xxd -g1` + flowcontrol It limits the data rate of a stream to a given `data_rate` number of bytes per second. + It copies `data_rate / reads_per_second` bytes from the input to the output, doing it `reads_per_second` times every second. shift_math_cc It shifts the signal in the frequency domain by `rate`. + `rate` is a floating point number between -0.5 and 0.5. + `rate` is relative to the sampling rate. Internally, a sine and cosine wave is generated to perform this function, and this function uses `math.h` for this purpose, which is quite accurate, but not always very fast. @@ -417,6 +431,22 @@ This is a controllable squelch, which reads the squelch level input from ` [buf_times]\n" " detect_nan_ff\n" -" floatdump_f\n" +" dump_f\n" " flowcontrol [prebuffer_sec] [thrust]\n" " shift_math_cc \n" " shift_math_cc --fifo \n" @@ -124,6 +124,14 @@ char usage[]= " serial_line_decoder_sy_u8\n" " octave_complex_c \n" " timing_recovery_cc [--add_q]\n" +" psk31_varicode_encoder_u8_u8\n" +" differential_encoder_u8_u8\n" +" differential_decoder_u8_u8\n" +" dump_u8\n" +" psk_modulator_u8_c \n" +" psk31_interpolate_sine_cc\n" +" duplicate_samples_ntimes_u8_u8 \n" +" ?\n" " \n" ; @@ -2405,6 +2413,8 @@ int main(int argc, char *argv[]) int out_of_n_samples = 0; sscanf(argv[3], "%d", &out_of_n_samples); if(out_of_n_samples4) mode2d = !strcmp(argv[4], "--2d"); complexf* read_buf = (complexf*)malloc(sizeof(complexf)*the_bufsize); if(!sendbufsize(initialize_buffers())) return -2; @@ -2415,7 +2425,9 @@ int main(int argc, char *argv[]) for(int i=0;i { - int sample_size_bytes, ntimes; + int sample_size_bytes = 0, ntimes = 0; if(argc<=2) return badsyntax("need required parameter (sample_size_bytes)"); sscanf(argv[2],"%d",&sample_size_bytes); + if(sample_size_bytes<=0) badsyntax("sample_size_bytes should be >0"); if(argc<=3) return badsyntax("need required parameter (ntimes)"); sscanf(argv[3],"%d",&ntimes); + if(ntimes<=0) badsyntax("ntimes should be >0"); if(!initialize_buffers()) return -2; sendbufsize(the_bufsize*ntimes); unsigned char* local_input_buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize*sample_size_bytes); @@ -2463,7 +2477,7 @@ int main(int argc, char *argv[]) { FEOF_CHECK; fread((void*)local_input_buffer, sizeof(unsigned char), the_bufsize*sample_size_bytes, stdin); - duplicate_samples_ntimes_u8_u8(local_input_buffer, local_input_buffer, the_bufsize*sample_size_bytes, sample_size_bytes, ntimes); + duplicate_samples_ntimes_u8_u8(local_input_buffer, local_output_buffer, the_bufsize*sample_size_bytes, sample_size_bytes, ntimes); fwrite((void*)local_output_buffer, sizeof(unsigned char), the_bufsize*sample_size_bytes*ntimes, stdout); TRY_YIELD; } @@ -2520,6 +2534,7 @@ int main(int argc, char *argv[]) for(;;) { psk31_varicode_encoder_u8_u8(local_input_buffer, local_output_buffer, the_bufsize, output_max_size, &input_processed, &output_size); + //fprintf(stderr, "os = %d\n", output_size); fwrite((void*)local_output_buffer, sizeof(unsigned char), output_size, stdout); FEOF_CHECK; memmove(local_input_buffer, local_input_buffer+input_processed, the_bufsize-input_processed); @@ -2542,6 +2557,24 @@ int main(int argc, char *argv[]) } } + int differential_codec_encode = 0; + if( (differential_codec_encode = !strcmp(argv[1],"differential_encoder_u8_u8")) || (!strcmp(argv[1],"differential_decoder_u8_u8")) ) + { + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize); + unsigned char* local_input_buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize); + unsigned char* local_output_buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize); + unsigned char state = 0; + for(;;) + { + FEOF_CHECK; + fread((void*)local_input_buffer, sizeof(unsigned char), the_bufsize, stdin); + state = differential_codec(local_input_buffer, local_output_buffer, the_bufsize, differential_codec_encode, state); + fwrite((void*)local_output_buffer, sizeof(unsigned char), the_bufsize, stdout); + TRY_YIELD; + } + } + if(!strcmp(argv[1],"none")) { return 0; diff --git a/libcsdr.c b/libcsdr.c index b3e5e50..50e808b 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1415,19 +1415,22 @@ char psk31_varicode_decoder_push(unsigned long long* status_shr, unsigned char s void psk31_varicode_encoder_u8_u8(unsigned char* input, unsigned char* output, int input_size, int output_max_size, int* input_processed, int* output_size) { - *output_size=0; - for(*input_processed=0; *input_processed>(current_varicode.bitcount-bi-1))&1; - *output_size++; + //fprintf(stderr, "bi = %d\n", bi); + output[*output_size] = (bi>(current_varicode.bitcount-bi-1))&1 : 0; + (*output_size)++; output_max_size--; } break; @@ -1598,9 +1601,10 @@ void binary_slicer_f_u8(float* input, unsigned char* output, int input_size) void psk_modulator_u8_c(unsigned char* input, complexf* output, int input_size, int n_psk) { //outputs one complex sample per input symbol + float phase_increment = (2*M_PI)/n_psk; for(int i=0;i>bi)&1; } +unsigned char differential_codec(unsigned char* input, unsigned char* output, int input_size, int encode, unsigned char state) +{ + if(!encode) + for(int i=0;i Date: Tue, 28 Mar 2017 11:52:29 +0200 Subject: [PATCH 041/111] Added vim swapfiles to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1d4be5f..1ca4103 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ ddcd *.so tags dumpvect.*.vect +*.swp From 7590dd78ab090717a7a9e081bea2c0613b2fa49f Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Wed, 29 Mar 2017 13:09:19 +0200 Subject: [PATCH 042/111] Added a costas loop algorithm --- libcsdr.c | 51 +++++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/libcsdr.c b/libcsdr.c index 50e808b..a990b50 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1909,36 +1909,44 @@ char* timing_recovery_get_string_from_algorithm(timing_recovery_algorithm_t algo typedef struct bpsk_costas_loop_state_s { - float pll_alpha; - float pll_beta; - float pll_iir_temp; - float pll_phase; + float rc_filter_alpha; + float vco_phase_addition_multiplier; + float vco_phase; + float last_lpfi_output; + float last_lpfq_output; } bpsk_costas_loop_state_t; -void init_bpsk_carrier_recovery_cc(bpsk_costas_loop_state_t* state) +void init_bpsk_costas_loop_cc(bpsk_costas_loop_state_t* state, float samples_per_bits) { - state->pll_alpha = state->pll_beta = 0; //TODO <-- - state->pll_phase = 0; - state->pll_iir_temp = 0; + state->vco_phase = 0; + float virtual_sampling_rate = 10000; + float virtual_data_rate = virtual_sampling_rate / samples_per_bits; + float rc_filter_cutoff = virtual_data_rate/2; + float rc_filter_rc = 1/(2*M_PI*rc_filter_cutoff); //as of Equation 24 in Feigin + float virtual_sampling_dt = 1.0/virtual_sampling_rate; + state->rc_filter_alpha = virtual_sampling_dt/(rc_filter_rc+virtual_sampling_dt); //https://en.wikipedia.org/wiki/Low-pass_filter + float rc_filter_omega_cutoff = 2*M_PI*rc_filter_cutoff; + state->vco_phase_addition_multiplier = 8*rc_filter_omega_cutoff; //as of Equation 25 in Feigin, assuming input signal amplitude of 1 (to 1V) and (state->vco_phase_addition_multiplier*), a value in radians, will be added to the vco_phase directly. } void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, bpsk_costas_loop_state_t* state) { - complexf ejphi; //downconvert with that for(int i=0;ipll_phase); - cmult(&output[i], &input[i], &ejphi); - - float error = iof(output,i) * qof(output, i); - if(error>2) error=2; - if(error<-2) error=-2; - - state->pll_phase = error * state->pll_alpha + state->pll_iir_temp; - state->pll_iir_temp += error * state->pll_beta; - - while(state->pll_phase>PI) state->pll_phase-=2*PI; - while(state->pll_phase<-PI) state->pll_phase+=2*PI; + float input_phase = atan2(input[i].q, input[i].i); + float input_and_vco_mixed_phase = input_phase - state->vco_phase; + complexf input_and_vco_mixed_sample; + e_powj(&input_and_vco_mixed_sample, input_and_vco_mixed_phase); + float loop_output_i = + input_and_vco_mixed_sample.i * state->rc_filter_alpha + state->last_lpfi_output * (1-state->rc_filter_alpha); + float loop_output_q = + input_and_vco_mixed_sample.q * state->rc_filter_alpha + state->last_lpfq_output * (1-state->rc_filter_alpha); + state->last_lpfi_output = loop_output_i; + state->last_lpfq_output = loop_output_q; + float vco_phase_addition = loop_output_i * loop_output_q * state->vco_phase_addition_multiplier; + state->vco_phase += vco_phase_addition; + while(state->vco_phase>PI) state->vco_phase-=2*PI; + while(state->vco_phase<-PI) state->vco_phase+=2*PI; } } @@ -2029,7 +2037,6 @@ void convert_s24_f(unsigned char* input, float* output, int input_size, int bige } } - int trivial_vectorize() { //this function is trivial to vectorize and should pass on both NEON and SSE From ca578ea4bc77902c0ba228335683868eab8d1fe8 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Fri, 31 Mar 2017 21:23:07 +0200 Subject: [PATCH 043/111] bpsk_costas_loop_cc function added to csdr --- csdr.c | 25 ++++++++++++++++++++++++- libcsdr.c | 29 ++++++++++++++++------------- libcsdr.h | 12 ++++++++++++ 3 files changed, 52 insertions(+), 14 deletions(-) diff --git a/csdr.c b/csdr.c index 90eaba8..cc8a087 100755 --- a/csdr.c +++ b/csdr.c @@ -131,6 +131,7 @@ char usage[]= " psk_modulator_u8_c \n" " psk31_interpolate_sine_cc\n" " duplicate_samples_ntimes_u8_u8 \n" +" bpsk_costas_loop_cc \n" " ?\n" " \n" ; @@ -2396,7 +2397,7 @@ int main(int argc, char *argv[]) fwrite(output_buffer, sizeof(complexf), state.output_size, stdout); fflush(stdout); TRY_YIELD; - fprintf(stderr, "state.input_processed = %d\n", state.input_processed); + //fprintf(stderr, "state.input_processed = %d\n", state.input_processed); memmove((complexf*)input_buffer,((complexf*)input_buffer)+state.input_processed,(the_bufsize-state.input_processed)*sizeof(complexf)); //memmove lets the source and destination overlap fread(((complexf*)input_buffer)+(the_bufsize-state.input_processed), sizeof(complexf), state.input_processed, stdin); //fprintf(stderr,"iskip=%d state.output_size=%d start=%x target=%x skipcount=%x \n",state.input_processed,state.output_size,input_buffer, ((complexf*)input_buffer)+(BIG_BUFSIZE-state.input_processed),(BIG_BUFSIZE-state.input_processed)); @@ -2575,6 +2576,28 @@ int main(int argc, char *argv[]) } } + if(!strcmp(argv[1],"bpsk_costas_loop_cc")) // + { + float samples_per_bits; + if(argc<=2) return badsyntax("need required parameter (samples_per_bits)"); + sscanf(argv[2],"%f",&samples_per_bits); + if(samples_per_bits<=0) badsyntax("samples_per_bits should be >= 0"); + + bpsk_costas_loop_state_t state = init_bpsk_costas_loop_cc(samples_per_bits); + + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize); + + for(;;) + { + FEOF_CHECK; + FREAD_C; + bpsk_costas_loop_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, &state); + FWRITE_C; + TRY_YIELD; + } + } + if(!strcmp(argv[1],"none")) { return 0; diff --git a/libcsdr.c b/libcsdr.c index a990b50..e9fa2c3 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1907,34 +1907,35 @@ char* timing_recovery_get_string_from_algorithm(timing_recovery_algorithm_t algo return "INVALID"; } -typedef struct bpsk_costas_loop_state_s -{ - float rc_filter_alpha; - float vco_phase_addition_multiplier; - float vco_phase; - float last_lpfi_output; - float last_lpfq_output; -} bpsk_costas_loop_state_t; - -void init_bpsk_costas_loop_cc(bpsk_costas_loop_state_t* state, float samples_per_bits) +bpsk_costas_loop_state_t init_bpsk_costas_loop_cc(float samples_per_bits) { - state->vco_phase = 0; + bpsk_costas_loop_state_t state; + state.vco_phase = 0; float virtual_sampling_rate = 10000; float virtual_data_rate = virtual_sampling_rate / samples_per_bits; + fprintf(stderr, "virtual_sampling_rate = %g, virtual_data_rate = %g\n", virtual_sampling_rate, virtual_data_rate); float rc_filter_cutoff = virtual_data_rate/2; float rc_filter_rc = 1/(2*M_PI*rc_filter_cutoff); //as of Equation 24 in Feigin float virtual_sampling_dt = 1.0/virtual_sampling_rate; - state->rc_filter_alpha = virtual_sampling_dt/(rc_filter_rc+virtual_sampling_dt); //https://en.wikipedia.org/wiki/Low-pass_filter + fprintf(stderr, "rc_filter_cutoff = %g, rc_filter_rc = %g, virtual_sampling_dt = %g\n", + rc_filter_cutoff, rc_filter_rc, virtual_sampling_dt); + state.rc_filter_alpha = virtual_sampling_dt/(rc_filter_rc+virtual_sampling_dt); //https://en.wikipedia.org/wiki/Low-pass_filter float rc_filter_omega_cutoff = 2*M_PI*rc_filter_cutoff; - state->vco_phase_addition_multiplier = 8*rc_filter_omega_cutoff; //as of Equation 25 in Feigin, assuming input signal amplitude of 1 (to 1V) and (state->vco_phase_addition_multiplier*), a value in radians, will be added to the vco_phase directly. + state.vco_phase_addition_multiplier = 8*rc_filter_omega_cutoff; //as of Equation 25 in Feigin, assuming input signal amplitude of 1 (to 1V) and (state.vco_phase_addition_multiplier*), a value in radians, will be added to the vco_phase directly. + fprintf(stderr, "rc_filter_alpha = %g, rc_filter_omega_cutoff = %g, vco_phase_addition_multiplier = %g\n", + state.rc_filter_alpha, rc_filter_omega_cutoff, state.vco_phase_addition_multiplier); + return state; } void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, bpsk_costas_loop_state_t* state) { + int debug = 0; + if(debug) fprintf(stderr, "costas:\n"); for(int i=0;ivco_phase; + if(debug) fprintf(stderr, "%g | %g\n", input_and_vco_mixed_phase, input_phase), debug--; complexf input_and_vco_mixed_sample; e_powj(&input_and_vco_mixed_sample, input_and_vco_mixed_phase); float loop_output_i = @@ -1947,6 +1948,8 @@ void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, bpsk state->vco_phase += vco_phase_addition; while(state->vco_phase>PI) state->vco_phase-=2*PI; while(state->vco_phase<-PI) state->vco_phase+=2*PI; + output[i].i = loop_output_i; + output[i].q = loop_output_q; } } diff --git a/libcsdr.h b/libcsdr.h index bc90506..bbca50f 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -323,3 +323,15 @@ complexf psk31_interpolate_sine_cc(complexf* input, complexf* output, int input_ void pack_bits_8to1_u8_u8(unsigned char* input, unsigned char* output, int input_size); void psk31_varicode_encoder_u8_u8(unsigned char* input, unsigned char* output, int input_size, int output_max_size, int* input_processed, int* output_size); unsigned char differential_codec(unsigned char* input, unsigned char* output, int input_size, int encode, unsigned char state); + +typedef struct bpsk_costas_loop_state_s +{ + float rc_filter_alpha; + float vco_phase_addition_multiplier; + float vco_phase; + float last_lpfi_output; + float last_lpfq_output; +} bpsk_costas_loop_state_t; + +bpsk_costas_loop_state_t init_bpsk_costas_loop_cc(float samples_per_bits); +void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, bpsk_costas_loop_state_t* state); From a6964c8cc9a58e9b9a6c38cc01d256f3ea547108 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Fri, 31 Mar 2017 21:26:08 +0200 Subject: [PATCH 044/111] Added GRC test for bpsk_costas_loop_cc --- grc_tests/test_bpsk_costas_loop.grc | 767 ++++++++++++++++++++++++++++ 1 file changed, 767 insertions(+) create mode 100644 grc_tests/test_bpsk_costas_loop.grc diff --git a/grc_tests/test_bpsk_costas_loop.grc b/grc_tests/test_bpsk_costas_loop.grc new file mode 100644 index 0000000..256f34f --- /dev/null +++ b/grc_tests/test_bpsk_costas_loop.grc @@ -0,0 +1,767 @@ + + + + Sat Oct 31 16:06:38 2015 + + options + + author + + + + window_size + 1280, 1024 + + + category + Custom + + + comment + + + + description + + + + _enabled + True + + + _coordinate + (10, 10) + + + _rotation + 0 + + + generate_options + wx_gui + + + id + top_block + + + max_nouts + 0 + + + realtime_scheduling + + + + run_options + prompt + + + run + True + + + thread_safe_setters + + + + title + + + + + variable_slider + + comment + + + + converver + float_converter + + + value + 1000 + + + _enabled + True + + + _coordinate + (296, 11) + + + _rotation + 0 + + + grid_pos + + + + id + freq + + + label + + + + max + samp_rate/2 + + + min + 0 + + + notebook + + + + num_steps + 100 + + + style + wx.SL_HORIZONTAL + + + + variable_slider + + comment + + + + converver + float_converter + + + value + 0 + + + _enabled + True + + + _coordinate + (960, 171) + + + _rotation + 0 + + + grid_pos + + + + id + freq_add + + + label + + + + max + samp_rate*0.01 + + + min + -samp_rate*0.01 + + + notebook + + + + num_steps + 100 + + + style + wx.SL_HORIZONTAL + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (176, 11) + + + _rotation + 0 + + + id + samp_rate + + + value + 1000000 + + + + analog_random_source_x + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (16, 187) + + + _rotation + 0 + + + id + analog_random_source_x_0 + + + maxoutbuf + 0 + + + max + 1 + + + minoutbuf + 0 + + + min + 0 + + + num_samps + 1 + + + type + byte + + + repeat + True + + + + blocks_throttle + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (176, 211) + + + _rotation + 0 + + + id + blocks_throttle_0 + + + ignoretag + True + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + samples_per_second + samp_rate + + + type + byte + + + vlen + 1 + + + + digital_psk_mod + + alias + + + + comment + + + + affinity + + + + differential + True + + + _enabled + True + + + excess_bw + 0.35 + + + _coordinate + (376, 179) + + + _rotation + 0 + + + mod_code + "none" + + + id + digital_psk_mod_0 + + + log + False + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + constellation_points + 2 + + + samples_per_symbol + 256 + + + verbose + False + + + + freq_xlating_fir_filter_xxx + + alias + + + + center_freq + freq_add + + + comment + + + + affinity + + + + decim + 1 + + + _enabled + True + + + _coordinate + (672, 211) + + + _rotation + 0 + + + id + freq_xlating_fir_filter_xxx_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + samp_rate + samp_rate + + + taps + [1] + + + type + ccc + + + + ha5kfu_execproc_xx + + alias + + + + commandline + csdr bpsk_costas_loop_cc 1 + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (120, 523) + + + _rotation + 0 + + + id + ha5kfu_execproc_xx_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + cc + + + + ha5kfu_execproc_xx + + alias + + + + commandline + csdr timing_recovery_cc GARDNER 256 + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (112, 395) + + + _rotation + 0 + + + id + ha5kfu_execproc_xx_0_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + cc + + + + wxgui_scopesink2 + + ac_couple + False + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (544, 371) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_scopesink2_0 + + + notebook + + + + num_inputs + 1 + + + samp_rate + samp_rate/256 + + + t_scale + 0 + + + title + After timing recovery + + + trig_mode + wxgui.TRIG_MODE_AUTO + + + type + complex + + + v_offset + 0 + + + v_scale + 0 + + + win_size + + + + xy_mode + True + + + y_axis_label + Counts + + + + wxgui_scopesink2 + + ac_couple + False + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (536, 523) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_scopesink2_0_0 + + + notebook + + + + num_inputs + 1 + + + samp_rate + samp_rate/256 + + + t_scale + 0 + + + title + After Costas Loop + + + trig_mode + wxgui.TRIG_MODE_AUTO + + + type + complex + + + v_offset + 0 + + + v_scale + 0 + + + win_size + + + + xy_mode + True + + + y_axis_label + Counts + + + + analog_random_source_x_0 + blocks_throttle_0 + 0 + 0 + + + blocks_throttle_0 + digital_psk_mod_0 + 0 + 0 + + + digital_psk_mod_0 + freq_xlating_fir_filter_xxx_0 + 0 + 0 + + + freq_xlating_fir_filter_xxx_0 + ha5kfu_execproc_xx_0_0 + 0 + 0 + + + ha5kfu_execproc_xx_0 + wxgui_scopesink2_0_0 + 0 + 0 + + + ha5kfu_execproc_xx_0_0 + ha5kfu_execproc_xx_0 + 0 + 0 + + + ha5kfu_execproc_xx_0_0 + wxgui_scopesink2_0 + 0 + 0 + + From bc299725b9037ae4724af1bf264020d36fd3b8e9 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Fri, 31 Mar 2017 21:26:52 +0200 Subject: [PATCH 045/111] Added top_block.py to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1ca4103..3aad0c2 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ ddcd tags dumpvect.*.vect *.swp +grc_tests/top_block.py From ca40a41d5a0b8ac2e6be87477a9492557dc0603d Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sat, 1 Apr 2017 12:54:21 +0200 Subject: [PATCH 046/111] Fixed timing_recovery_cc output data --- csdr.c | 4 +- grc_tests/test_bpsk_costas_loop.grc | 474 +++++++++++++++++++++++----- libcsdr.c | 8 +- 3 files changed, 393 insertions(+), 93 deletions(-) diff --git a/csdr.c b/csdr.c index 38bc915..9cdb81d 100755 --- a/csdr.c +++ b/csdr.c @@ -131,7 +131,7 @@ char usage[]= " differential_decoder_u8_u8\n" " dump_u8\n" " psk_modulator_u8_c \n" -" psk31_interpolate_sine_cc\n" +" psk31_interpolate_sine_cc \n" " duplicate_samples_ntimes_u8_u8 \n" " bpsk_costas_loop_cc \n" " ?\n" @@ -2455,7 +2455,7 @@ int main(int argc, char *argv[]) FEOF_CHECK; if(debug_n && ++debug_i%debug_n==0) timing_recovery_trigger_debug(&state, 3); timing_recovery_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, &state); - //fprintf(stderr, "os %d\n",state.output_size); + //fprintf(stderr, "trcc is=%d, os=%d, ip=%d\n",the_bufsize, state.output_size, state.input_processed); fwrite(output_buffer, sizeof(complexf), state.output_size, stdout); fflush(stdout); TRY_YIELD; diff --git a/grc_tests/test_bpsk_costas_loop.grc b/grc_tests/test_bpsk_costas_loop.grc index 256f34f..360a9c2 100644 --- a/grc_tests/test_bpsk_costas_loop.grc +++ b/grc_tests/test_bpsk_costas_loop.grc @@ -69,65 +69,6 @@ - - variable_slider - - comment - - - - converver - float_converter - - - value - 1000 - - - _enabled - True - - - _coordinate - (296, 11) - - - _rotation - 0 - - - grid_pos - - - - id - freq - - - label - - - - max - samp_rate/2 - - - min - 0 - - - notebook - - - - num_steps - 100 - - - style - wx.SL_HORIZONTAL - - variable_slider @@ -148,7 +89,7 @@ _coordinate - (960, 171) + (288, 11) _rotation @@ -211,7 +152,7 @@ value - 1000000 + 2**18 @@ -250,7 +191,7 @@ max - 1 + 2 minoutbuf @@ -262,7 +203,7 @@ num_samps - 1 + 1000 type @@ -273,6 +214,104 @@ True + + blocks_complex_to_float + + alias + + + + comment + + + + affinity + + + + _enabled + 0 + + + _coordinate + (960, 265) + + + _rotation + 0 + + + id + blocks_complex_to_float_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + vlen + 1 + + + + blocks_interleave + + alias + + + + blocksize + 1 + + + comment + + + + affinity + + + + _enabled + 0 + + + _coordinate + (1168, 265) + + + _rotation + 0 + + + id + blocks_interleave_0 + + + type + float + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + num_streams + 2 + + + vlen + 1 + + blocks_throttle @@ -293,7 +332,7 @@ _coordinate - (176, 211) + (456, 211) _rotation @@ -321,7 +360,7 @@ type - byte + complex vlen @@ -356,7 +395,7 @@ _coordinate - (376, 179) + (208, 179) _rotation @@ -388,7 +427,7 @@ samples_per_symbol - 256 + 2 verbose @@ -403,7 +442,7 @@ center_freq - freq_add + -freq_add comment @@ -419,11 +458,11 @@ _enabled - True + 1 _coordinate - (672, 211) + (688, 251) _rotation @@ -455,14 +494,14 @@ - ha5kfu_execproc_xx + ha5kfu_execproc_sink_f alias commandline - csdr bpsk_costas_loop_cc 1 + zsh -c \"csdr timing_recovery_cc GARDNER 16 --add_q --octave 1 1>/dev/null 2> >(octave -i)\" comment @@ -474,7 +513,42 @@ _enabled - True + 0 + + + _coordinate + (824, 427) + + + _rotation + 0 + + + id + ha5kfu_execproc_sink_f_0 + + + + ha5kfu_execproc_xx + + alias + + + + commandline + csdr bpsk_costas_loop_cc 8 + + + comment + + + + affinity + + + + _enabled + 1 _coordinate @@ -509,7 +583,7 @@ commandline - csdr timing_recovery_cc GARDNER 256 + csdr timing_recovery_cc GARDNER 16 --add_q | csdr fir_interpolate_cc 8 comment @@ -521,11 +595,11 @@ _enabled - True + 1 _coordinate - (112, 395) + (112, 403) _rotation @@ -548,6 +622,109 @@ cc + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + 0 + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (960, 59) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_0 + + + notebook + + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate + + + title + FFT Plot + + + type + complex + + + win_size + + + + win + None + + + y_divs + 10 + + + y_per_div + 10 + + wxgui_scopesink2 @@ -568,7 +745,7 @@ _enabled - True + 1 _coordinate @@ -596,7 +773,7 @@ samp_rate - samp_rate/256 + (samp_rate/256)*8 t_scale @@ -655,7 +832,7 @@ _enabled - True + 1 _coordinate @@ -683,7 +860,7 @@ samp_rate - samp_rate/256 + (samp_rate/256)*8 t_scale @@ -722,30 +899,153 @@ Counts + + wxgui_scopesink2 + + ac_couple + False + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (688, 11) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_scopesink2_0_1 + + + notebook + + + + num_inputs + 1 + + + samp_rate + samp_rate + + + t_scale + 0 + + + title + After BPSK modulator + + + trig_mode + wxgui.TRIG_MODE_AUTO + + + type + complex + + + v_offset + 0 + + + v_scale + 0 + + + win_size + + + + xy_mode + False + + + y_axis_label + Counts + + analog_random_source_x_0 - blocks_throttle_0 - 0 - 0 - - - blocks_throttle_0 digital_psk_mod_0 0 0 - digital_psk_mod_0 + blocks_complex_to_float_0 + blocks_interleave_0 + 1 + 1 + + + blocks_complex_to_float_0 + blocks_interleave_0 + 0 + 0 + + + blocks_interleave_0 + ha5kfu_execproc_sink_f_0 + 0 + 0 + + + blocks_throttle_0 freq_xlating_fir_filter_xxx_0 0 0 + + blocks_throttle_0 + wxgui_scopesink2_0_1 + 0 + 0 + + + digital_psk_mod_0 + blocks_throttle_0 + 0 + 0 + + + freq_xlating_fir_filter_xxx_0 + blocks_complex_to_float_0 + 0 + 0 + freq_xlating_fir_filter_xxx_0 ha5kfu_execproc_xx_0_0 0 0 + + freq_xlating_fir_filter_xxx_0 + wxgui_fftsink2_0 + 0 + 0 + ha5kfu_execproc_xx_0 wxgui_scopesink2_0_0 diff --git a/libcsdr.c b/libcsdr.c index 5af8826..15157c8 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1837,11 +1837,11 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin int debug_i = state->debug_count; float error; int el_point_left_index, el_point_right_index, el_point_mid_index; - int si; + int si = 0; if(state->debug_force) fprintf(stderr, "disp(\"begin timing_recovery_cc\");\n"); if(MTIMINGR_HDEBUG) fprintf(stderr, "timing_recovery_cc started, nsb = %d, nshb = %d, nsqb = %d\n", num_samples_bit, num_samples_halfbit, num_samples_quarterbit); { - for(si=0;;si++) + for(;;) { //the MathWorks style algorithm has correction_offset. //correction_offset = 0; @@ -1862,7 +1862,7 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin el_point_right_index = current_bitstart_index + num_samples_earlylate_wing * 3; el_point_left_index = current_bitstart_index + num_samples_earlylate_wing * 1 - correction_offset; el_point_mid_index = current_bitstart_index + num_samples_halfbit; - output[si++] = input[current_bitstart_index + el_point_mid_index]; + output[si++] = input[el_point_mid_index]; } else if(state->algorithm == TIMING_RECOVERY_ALGORITHM_GARDNER) { @@ -1870,7 +1870,7 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin el_point_right_index = current_bitstart_index + num_samples_halfbit * 3; el_point_left_index = current_bitstart_index + num_samples_halfbit * 1; el_point_mid_index = current_bitstart_index + num_samples_halfbit * 2; - output[si++] = input[current_bitstart_index + num_samples_halfbit * 1]; + output[si++] = input[el_point_left_index]; } else break; From c7137dc68e9d8c7255b753b346931fd285acc0db Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sat, 1 Apr 2017 16:08:49 +0200 Subject: [PATCH 047/111] The costas loop seems to at least work --- grc_tests/test_bpsk_costas_loop.grc | 42 ++++++++++++++--------------- libcsdr.c | 4 +-- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/grc_tests/test_bpsk_costas_loop.grc b/grc_tests/test_bpsk_costas_loop.grc index 360a9c2..7ce3934 100644 --- a/grc_tests/test_bpsk_costas_loop.grc +++ b/grc_tests/test_bpsk_costas_loop.grc @@ -517,7 +517,7 @@ _coordinate - (824, 427) + (976, 379) _rotation @@ -536,7 +536,7 @@ commandline - csdr bpsk_costas_loop_cc 8 + csdr bpsk_costas_loop_cc 16 comment @@ -552,7 +552,7 @@ _coordinate - (120, 523) + (128, 411) _rotation @@ -595,11 +595,11 @@ _enabled - 1 + 0 _coordinate - (112, 403) + (432, 411) _rotation @@ -745,11 +745,11 @@ _enabled - 1 + 0 _coordinate - (544, 371) + (824, 507) _rotation @@ -836,7 +836,7 @@ _coordinate - (536, 523) + (432, 507) _rotation @@ -1016,12 +1016,6 @@ 0 0 - - blocks_throttle_0 - wxgui_scopesink2_0_1 - 0 - 0 - digital_psk_mod_0 blocks_throttle_0 @@ -1036,7 +1030,7 @@ freq_xlating_fir_filter_xxx_0 - ha5kfu_execproc_xx_0_0 + ha5kfu_execproc_xx_0 0 0 @@ -1046,18 +1040,24 @@ 0 0 + + freq_xlating_fir_filter_xxx_0 + wxgui_scopesink2_0_1 + 0 + 0 + + + ha5kfu_execproc_xx_0 + ha5kfu_execproc_xx_0_0 + 0 + 0 + ha5kfu_execproc_xx_0 wxgui_scopesink2_0_0 0 0 - - ha5kfu_execproc_xx_0_0 - ha5kfu_execproc_xx_0 - 0 - 0 - ha5kfu_execproc_xx_0_0 wxgui_scopesink2_0 diff --git a/libcsdr.c b/libcsdr.c index 15157c8..4aeecf1 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1874,7 +1874,7 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin } else break; - error = ( iof(input, el_point_right_index) - iof(input, el_point_left_index)) * iof(input, el_point_mid_index); + error = ( iof(input, el_point_right_index) - iof(input, el_point_left_index) ) * iof(input, el_point_mid_index); if(state->use_q) { error += ( qof(input, el_point_right_index) - qof(input, el_point_left_index)) * qof(input, el_point_mid_index); @@ -1949,7 +1949,7 @@ bpsk_costas_loop_state_t init_bpsk_costas_loop_cc(float samples_per_bits) rc_filter_cutoff, rc_filter_rc, virtual_sampling_dt); state.rc_filter_alpha = virtual_sampling_dt/(rc_filter_rc+virtual_sampling_dt); //https://en.wikipedia.org/wiki/Low-pass_filter float rc_filter_omega_cutoff = 2*M_PI*rc_filter_cutoff; - state.vco_phase_addition_multiplier = 8*rc_filter_omega_cutoff; //as of Equation 25 in Feigin, assuming input signal amplitude of 1 (to 1V) and (state.vco_phase_addition_multiplier*), a value in radians, will be added to the vco_phase directly. + state.vco_phase_addition_multiplier = 8*rc_filter_omega_cutoff / (virtual_sampling_rate); //as of Equation 25 in Feigin, assuming input signal amplitude of 1 (to 1V) and (state.vco_phase_addition_multiplier*), a value in radians, will be added to the vco_phase directly. fprintf(stderr, "rc_filter_alpha = %g, rc_filter_omega_cutoff = %g, vco_phase_addition_multiplier = %g\n", state.rc_filter_alpha, rc_filter_omega_cutoff, state.vco_phase_addition_multiplier); return state; From df81d6847e914b464964a128bee06ed283c3e106 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sat, 1 Apr 2017 21:30:58 +0200 Subject: [PATCH 048/111] An actually really working costas loop --- grc_tests/test_bpsk_costas_loop.grc | 380 +++++++++++++++++++++++++++- libcsdr.c | 13 +- 2 files changed, 384 insertions(+), 9 deletions(-) diff --git a/grc_tests/test_bpsk_costas_loop.grc b/grc_tests/test_bpsk_costas_loop.grc index 7ce3934..82ac291 100644 --- a/grc_tests/test_bpsk_costas_loop.grc +++ b/grc_tests/test_bpsk_costas_loop.grc @@ -69,6 +69,65 @@ + + variable_slider + + comment + + + + converver + float_converter + + + value + 1 + + + _enabled + True + + + _coordinate + (480, 3) + + + _rotation + 0 + + + grid_pos + + + + id + amplitude + + + label + + + + max + 2 + + + min + 0 + + + notebook + + + + num_steps + 100 + + + style + wx.SL_HORIZONTAL + + variable_slider @@ -109,11 +168,11 @@ max - samp_rate*0.01 + samp_rate*0.5 min - -samp_rate*0.01 + -samp_rate*0.5 notebook @@ -128,6 +187,65 @@ wx.SL_HORIZONTAL + + variable_slider + + comment + + + + converver + float_converter + + + value + 0.3 + + + _enabled + True + + + _coordinate + (712, 571) + + + _rotation + 0 + + + grid_pos + + + + id + loop_bw + + + label + + + + max + 0.5 + + + min + 0 + + + notebook + nb, 1 + + + num_steps + 100 + + + style + wx.SL_HORIZONTAL + + variable @@ -312,6 +430,57 @@ 1 + + blocks_multiply_const_vxx + + alias + + + + comment + + + + const + amplitude + + + affinity + + + + _enabled + True + + + _coordinate + (496, 155) + + + _rotation + 0 + + + id + blocks_multiply_const_vxx_0 + + + type + complex + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + vlen + 1 + + blocks_throttle @@ -332,7 +501,7 @@ _coordinate - (456, 211) + (488, 211) _rotation @@ -367,6 +536,57 @@ 1 + + digital_costas_loop_cc + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (928, 537) + + + _rotation + 0 + + + id + digital_costas_loop_cc_0 + + + w + loop_bw + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + order + 2 + + + use_snr + False + + digital_psk_mod @@ -599,7 +819,7 @@ _coordinate - (432, 411) + (400, 411) _rotation @@ -622,6 +842,49 @@ cc + + notebook + + alias + + + + comment + + + + _enabled + True + + + _coordinate + (16, 83) + + + _rotation + 0 + + + grid_pos + + + + id + nb + + + labels + ['1', '2'] + + + notebook + + + + style + wx.NB_TOP + + wxgui_fftsink2 @@ -749,7 +1012,7 @@ _coordinate - (824, 507) + (632, 379) _rotation @@ -852,8 +1115,95 @@ notebook + nb, 0 + + + num_inputs + 1 + + + samp_rate + (samp_rate/256)*8 + + + t_scale + 0 + + + title + After Costas Loop + + + trig_mode + wxgui.TRIG_MODE_AUTO + + + type + complex + + + v_offset + 0 + + + v_scale + 0 + + + win_size + + xy_mode + True + + + y_axis_label + Counts + + + + wxgui_scopesink2 + + ac_couple + False + + + alias + + + + comment + + + + affinity + + + + _enabled + 1 + + + _coordinate + (1112, 491) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_scopesink2_0_0_0 + + + notebook + nb, 1 + num_inputs 1 @@ -1010,15 +1360,27 @@ 0 0 + + blocks_multiply_const_vxx_0 + blocks_throttle_0 + 0 + 0 + blocks_throttle_0 freq_xlating_fir_filter_xxx_0 0 0 + + digital_costas_loop_cc_0 + wxgui_scopesink2_0_0_0 + 0 + 0 + digital_psk_mod_0 - blocks_throttle_0 + blocks_multiply_const_vxx_0 0 0 @@ -1028,6 +1390,12 @@ 0 0 + + freq_xlating_fir_filter_xxx_0 + digital_costas_loop_cc_0 + 0 + 0 + freq_xlating_fir_filter_xxx_0 ha5kfu_execproc_xx_0 diff --git a/libcsdr.c b/libcsdr.c index 4aeecf1..cbfddd7 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1942,7 +1942,8 @@ bpsk_costas_loop_state_t init_bpsk_costas_loop_cc(float samples_per_bits) float virtual_sampling_rate = 10000; float virtual_data_rate = virtual_sampling_rate / samples_per_bits; fprintf(stderr, "virtual_sampling_rate = %g, virtual_data_rate = %g\n", virtual_sampling_rate, virtual_data_rate); - float rc_filter_cutoff = virtual_data_rate/2; + //float rc_filter_cutoff = virtual_data_rate * 2; //this is so far the best + float rc_filter_cutoff = virtual_data_rate * 2; float rc_filter_rc = 1/(2*M_PI*rc_filter_cutoff); //as of Equation 24 in Feigin float virtual_sampling_dt = 1.0/virtual_sampling_rate; fprintf(stderr, "rc_filter_cutoff = %g, rc_filter_rc = %g, virtual_sampling_dt = %g\n", @@ -1966,18 +1967,24 @@ void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, bpsk if(debug) fprintf(stderr, "%g | %g\n", input_and_vco_mixed_phase, input_phase), debug--; complexf input_and_vco_mixed_sample; e_powj(&input_and_vco_mixed_sample, input_and_vco_mixed_phase); + + complexf vco_sample; + e_powj(&vco_sample, -state->vco_phase); + //cmult(&input_and_vco_mixed_sample, &input[i], &vco_sample);//if this is enabled, the real input sample is used, not the amplitude normalized + float loop_output_i = input_and_vco_mixed_sample.i * state->rc_filter_alpha + state->last_lpfi_output * (1-state->rc_filter_alpha); float loop_output_q = input_and_vco_mixed_sample.q * state->rc_filter_alpha + state->last_lpfq_output * (1-state->rc_filter_alpha); + //loop_output_i = input_and_vco_mixed_sample.i; + //loop_output_q = input_and_vco_mixed_sample.q; state->last_lpfi_output = loop_output_i; state->last_lpfq_output = loop_output_q; float vco_phase_addition = loop_output_i * loop_output_q * state->vco_phase_addition_multiplier; state->vco_phase += vco_phase_addition; while(state->vco_phase>PI) state->vco_phase-=2*PI; while(state->vco_phase<-PI) state->vco_phase+=2*PI; - output[i].i = loop_output_i; - output[i].q = loop_output_q; + cmult(&output[i], &input[i], &vco_sample); } } From 790281e5333dba4ad3c17292ec158ac81e605e46 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 2 Apr 2017 12:51:53 +0200 Subject: [PATCH 049/111] Added docs for = and ? function, added = function, tinkered around costas loop --- README.md | 18 ++++++++++++++++++ csdr.c | 9 +++++++++ libcsdr.c | 6 ++++-- libcsdr.h | 1 + 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c27117a..87e2d53 100644 --- a/README.md +++ b/README.md @@ -474,6 +474,24 @@ By writing to the given FIFO file with the syntax below, you can control the shi E.g. you can send `-0.05 0.02\n` + ? + +You can search the functions available in `csdr` just as if you typed: `csdr 2>&1 | grep ` + + = + +When running complicated `csdr` commands, we usually run into using `python` to calculate certain parameters. + +This function can eliminate some typing and make our command clearer. + +Instead of having to write: `csdr shift_addition_cc $(python -c "print 1200/2400000.")` + +...we can type: `csdr shift_addition_cc $(csdr =1200/2400000.)` + +If using parenthesis inside the expression, it needs to be escaped (as `bash` would want to parse it): `csdr shift_addition_cc $(csdr =\(1200+300\)/2400000)` + +Another solution is using single quotes to wrap the expression: `csdr shift_addition_cc $(csdr '=(1200+300)/2400000.')` + #### Buffer sizes *csdr* has three modes of determining the buffer sizes, which can be chosen by the appropriate environment variables: diff --git a/csdr.c b/csdr.c index 9cdb81d..65d3332 100755 --- a/csdr.c +++ b/csdr.c @@ -135,6 +135,7 @@ char usage[]= " duplicate_samples_ntimes_u8_u8 \n" " bpsk_costas_loop_cc \n" " ?\n" +" =\n" " \n" ; @@ -2674,5 +2675,13 @@ int main(int argc, char *argv[]) return 0; } + if(argv[1][0]=='=') + { + char buffer[100]; + snprintf(buffer, 100-1, "python -c \"print %s\"", argv[1]+1); + system(buffer); + return 0; + } + fprintf(stderr,"csdr: function name given in argument 1 (%s) does not exist. Possible causes:\n- You mistyped the commandline.\n- You need to update csdr to a newer version (if available).\n", argv[1]); return -1; } diff --git a/libcsdr.c b/libcsdr.c index cbfddd7..2121f52 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1939,11 +1939,11 @@ bpsk_costas_loop_state_t init_bpsk_costas_loop_cc(float samples_per_bits) { bpsk_costas_loop_state_t state; state.vco_phase = 0; + state.last_vco_phase_addition = 0; float virtual_sampling_rate = 10000; float virtual_data_rate = virtual_sampling_rate / samples_per_bits; fprintf(stderr, "virtual_sampling_rate = %g, virtual_data_rate = %g\n", virtual_sampling_rate, virtual_data_rate); - //float rc_filter_cutoff = virtual_data_rate * 2; //this is so far the best - float rc_filter_cutoff = virtual_data_rate * 2; + float rc_filter_cutoff = virtual_data_rate * 2; //this is so far the best float rc_filter_rc = 1/(2*M_PI*rc_filter_cutoff); //as of Equation 24 in Feigin float virtual_sampling_dt = 1.0/virtual_sampling_rate; fprintf(stderr, "rc_filter_cutoff = %g, rc_filter_rc = %g, virtual_sampling_dt = %g\n", @@ -1981,6 +1981,8 @@ void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, bpsk state->last_lpfi_output = loop_output_i; state->last_lpfq_output = loop_output_q; float vco_phase_addition = loop_output_i * loop_output_q * state->vco_phase_addition_multiplier; + //vco_phase_addition = vco_phase_addition * state->rc_filter_alpha + state->last_vco_phase_addition * (1-state->rc_filter_alpha); + //state->last_vco_phase_addition = vco_phase_addition; state->vco_phase += vco_phase_addition; while(state->vco_phase>PI) state->vco_phase-=2*PI; while(state->vco_phase<-PI) state->vco_phase+=2*PI; diff --git a/libcsdr.h b/libcsdr.h index 81f05e7..1c15f90 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -332,6 +332,7 @@ typedef struct bpsk_costas_loop_state_s float vco_phase; float last_lpfi_output; float last_lpfq_output; + float last_vco_phase_addition; } bpsk_costas_loop_state_t; bpsk_costas_loop_state_t init_bpsk_costas_loop_cc(float samples_per_bits); From 6c842ed65a23fb7985bbd38acdeffc2b4b409e71 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 2 Apr 2017 12:54:58 +0200 Subject: [PATCH 050/111] Docs --- README.md | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 87e2d53..39d037d 100644 --- a/README.md +++ b/README.md @@ -484,13 +484,21 @@ When running complicated `csdr` commands, we usually run into using `python` to This function can eliminate some typing and make our command clearer. -Instead of having to write: `csdr shift_addition_cc $(python -c "print 1200/2400000.")` +Instead of having to write: -...we can type: `csdr shift_addition_cc $(csdr =1200/2400000.)` + csdr shift_addition_cc $(python -c "print 1200/2400000.") -If using parenthesis inside the expression, it needs to be escaped (as `bash` would want to parse it): `csdr shift_addition_cc $(csdr =\(1200+300\)/2400000)` +...we can type: -Another solution is using single quotes to wrap the expression: `csdr shift_addition_cc $(csdr '=(1200+300)/2400000.')` + csdr shift_addition_cc $(csdr =1200/2400000.) + +If using parenthesis inside the expression, it needs to be escaped (as `bash` would want to parse it): + + csdr shift_addition_cc $(csdr =\(1200+300\)/2400000) + +Another solution is using single quotes to wrap the expression: + + csdr shift_addition_cc $(csdr '=(1200+300)/2400000.') #### Buffer sizes @@ -546,7 +554,7 @@ Example of initialization if the process always works with a fixed output size, `csdr` was tested with GNU Radio Companion flowgraphs. These flowgraphs are available under the directory `grc_tests`, and they require the gr-ha5kfu set of blocks for GNU Radio. -## [sdr.js] (#sdrjs) +## [sdr.js](#sdrjs) *sdr.js* is *libcsdr* compiled to JavaScript code with *Emscripten*. Nowadays JavaScript runs quite fast in browsers, as all major browser vendors included JavaScript JIT machines into their product. You can find a great introductory slideshow here on the concept behind *Emscripten* and *asm.js*. @@ -568,7 +576,7 @@ To remove *sdr.js* and the compiled dependencies: make emcc-clean -## [nmux] (#nmux) +## [nmux](#nmux) The repo also contains a command line tool called `nmux`, which is a TCP stream multiplexer. It reads data from the standard input, and sends it to each client connected through TCP sockets. Available command line options are: * `--port (-p), --address (-a):` TCP port and address to listen. @@ -577,7 +585,7 @@ The repo also contains a command line tool called `nmux`, which is a TCP stream `nmux` was originally written for use in OpenWebRX. -## [Licensing] (#licensing) +## [Licensing](#licensing) Most of the code of `libcsdr` is under BSD license. However, before the implementation of some algoritms, GPL-licensed code from other applications have been reviewed. From 35b899906883736a95c53a5d5adf6b7663249347 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 2 Apr 2017 12:59:23 +0200 Subject: [PATCH 051/111] Docs: trying formatting --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 39d037d..4a0f909 100644 --- a/README.md +++ b/README.md @@ -140,17 +140,21 @@ You can use these commands on complex streams, too, as they are only interleaved > Note: The the functions with `i16` in their names have been renamed, but still work (e.g. `csdr convert_f_i16`). -#### csdr commands +### csdr commands `csdr` should be considered as a reference implementation on using `libcsdr`. For additional details on how to use the library, check `csdr.c` and `libcsdr.c`. Regarding `csdr`, the first command-line parameter is the name of a function, others are the parameters for the given function. Compulsory parameters are noted as ``, optional parameters are noted as `[parameter]`. Optional parameters have safe defaults, for more info look at the code. +### [realpart_cf](#realpart_cf) + realpart_cf It takes the real part of the complex signal, and throws away the imaginary part. +### [clipdetect_ff](#clipdetect_ff) + clipdetect_ff It clones the signal (the input and the output is the same), but it prints a warning on `stderr` if any sample value is out of the -1.0 ... 1.0 range. @@ -478,6 +482,8 @@ E.g. you can send `-0.05 0.02\n` You can search the functions available in `csdr` just as if you typed: `csdr 2>&1 | grep ` +### [=](#evaluate-python-expression> + = When running complicated `csdr` commands, we usually run into using `python` to calculate certain parameters. From 4df9d52d67f1ab3c47d2e45127e7b047e51fb1cb Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 2 Apr 2017 13:02:53 +0200 Subject: [PATCH 052/111] Docs: even more formatting --- README.md | 46 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 4a0f909..51c7ab2 100644 --- a/README.md +++ b/README.md @@ -149,40 +149,70 @@ Optional parameters have safe defaults, for more info look at the code. ### [realpart_cf](#realpart_cf) - realpart_cf +Syntax: + + csdr realpart_cf It takes the real part of the complex signal, and throws away the imaginary part. ### [clipdetect_ff](#clipdetect_ff) - clipdetect_ff +Syntax: + + csdr clipdetect_ff It clones the signal (the input and the output is the same), but it prints a warning on `stderr` if any sample value is out of the -1.0 ... 1.0 range. - limit_ff [max_amplitude] +### [limit_ff](#limit_ff) + +Syntax: + + csdr limit_ff [max_amplitude] The input signal amplitude will not be let out of the `-max_amplitude ... max_amplitude` range. - gain_ff +### [gain_ff](#gain_ff) + +Syntax: + + csdr gain_ff It multiplies all samples by `gain`. - clone +### [clone](#clone) + +Syntax: + + csdr clone It copies the input to the output. - through +### [through](#through) + +Syntax: + + csdr through It copies the input to the output, while also displaying the speed of the data going through it. - none +### [none](#none) + +Syntax: + + csdr none The `csdr` process just exits with 0. - yes_f [buf_times] +### [yes_f](#yes_f) + +Syntax: + + csdr yes_f [buf_times] It outputs continously the `to_repeat` float number. + If `buf_times` is not given, it never stops. + Else, after outputing `buf_times` number of buffers (the size of which is stated in the `BUFSIZE` macro), it exits. detect_nan_ff From d6bc505da82cf9e9e8d8a0b480f0d520b9ce3ab6 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 2 Apr 2017 13:04:05 +0200 Subject: [PATCH 053/111] Docs: even more formatting --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index 51c7ab2..31c93e3 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,8 @@ You can use these commands on complex streams, too, as they are only interleaved Regarding `csdr`, the first command-line parameter is the name of a function, others are the parameters for the given function. Compulsory parameters are noted as ``, optional parameters are noted as `[parameter]`. Optional parameters have safe defaults, for more info look at the code. +---- + ### [realpart_cf](#realpart_cf) Syntax: @@ -155,6 +157,8 @@ Syntax: It takes the real part of the complex signal, and throws away the imaginary part. +---- + ### [clipdetect_ff](#clipdetect_ff) Syntax: @@ -163,6 +167,8 @@ Syntax: It clones the signal (the input and the output is the same), but it prints a warning on `stderr` if any sample value is out of the -1.0 ... 1.0 range. +---- + ### [limit_ff](#limit_ff) Syntax: @@ -171,6 +177,8 @@ Syntax: The input signal amplitude will not be let out of the `-max_amplitude ... max_amplitude` range. +---- + ### [gain_ff](#gain_ff) Syntax: @@ -179,6 +187,8 @@ Syntax: It multiplies all samples by `gain`. +---- + ### [clone](#clone) Syntax: @@ -187,6 +197,8 @@ Syntax: It copies the input to the output. +---- + ### [through](#through) Syntax: @@ -195,6 +207,8 @@ Syntax: It copies the input to the output, while also displaying the speed of the data going through it. +---- + ### [none](#none) Syntax: @@ -203,6 +217,8 @@ Syntax: The `csdr` process just exits with 0. +---- + ### [yes_f](#yes_f) Syntax: From 8fa845bd00a718dccb061156284fe8bef2c65ed4 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 2 Apr 2017 13:23:56 +0200 Subject: [PATCH 054/111] A lot of README formatting, changed csdr through format --- README.md | 475 +++++++++++++++++++++++++++++++++++++++++++++--------- csdr.c | 2 +- 2 files changed, 396 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index 31c93e3..890685d 100644 --- a/README.md +++ b/README.md @@ -205,7 +205,7 @@ Syntax: csdr through -It copies the input to the output, while also displaying the speed of the data going through it. +It copies the input to the output, while also displaying the data rate going through it. ---- @@ -231,33 +231,65 @@ If `buf_times` is not given, it never stops. Else, after outputing `buf_times` number of buffers (the size of which is stated in the `BUFSIZE` macro), it exits. - detect_nan_ff +---- + +### [detect_nan_ff](#detect_nan_ff) + +Syntax: + + csdr detect_nan_ff Along with copying its input samples to the output, it prints a warning message to *stderr* if it finds any IEEE floating point NaN values among the samples. - dump_f +---- + +### [dump_f](#dump_f) + +Syntax: + + csdr dump_f It prints all floating point input samples as text. -The format string used is `"%g "`. +The C format string used is `"%g "`. You can also use it to print complex float values, then you will see the I and Q samples interleaved, like: `I Q I Q I Q ...` Alternatively, you can use the `od` command (built into most Linux distributions). To display a list of floating point values with their addresses as well, you can use: `od -vf` - dump_u8 +Aliases for this function: `floatdump_f` + +---- + +### [dump_u8](#dump_u8) + +Syntax: + + csdr dump_u8 It prints all input bytes as text, in hexadecimal form. Alternatively, you can use the `xxd` command (built into most Linux distributions). To display a hexadecimal dump of the standard input (with addresses at the beginning of rows), you can use: `xxd -g1` - flowcontrol +---- + +### [flowcontrol](#flowcontrol) + +Syntax: + + csdr flowcontrol It limits the data rate of a stream to a given `data_rate` number of bytes per second. It copies `data_rate / reads_per_second` bytes from the input to the output, doing it `reads_per_second` times every second. - shift_math_cc +---- + +### [shift_math_cc](#shift_math_cc) + +Syntax: + + csdr shift_math_cc It shifts the signal in the frequency domain by `rate`. @@ -265,31 +297,63 @@ It shifts the signal in the frequency domain by `rate`. `rate` is relative to the sampling rate. -Internally, a sine and cosine wave is generated to perform this function, and this function uses `math.h` for this purpose, which is quite accurate, but not always very fast. +Internally, a sine and cosine wave is generated, and this function uses `math.h` for this purpose, which is quite accurate, but not always very fast. - shift_addition_cc +---- + +### [shift_addition_cc](#shift_addition_cc) + +Syntax: + + csdr shift_addition_cc Operation is the same as for `shift_math_cc`. Internally, this function uses trigonometric addition formulas to generate sine and cosine, which is a bit faster. (About 4 times on the machine I have tested it on.) - shift_addition_cc_test +---- + +### [shift_addition_cc_test](#shift_addition_cc_test) + +Syntax: + + csdr shift_addition_cc_test This function was used to test the accuracy of the method above. - shift_table_cc [table_size] +---- + +### [shift_table_cc](#shift_table_cc) + +Syntax: + + csdr shift_table_cc [table_size] Operation is the same as with `shift_math_cc`. + Internally, this function uses a look-up table (LUT) to recall the values of the sine function (for the first quadrant). + The higher the table size is, the smaller the phase error is. - shift_addfast_cc +---- + +### [shift_addfast_cc](#shift_addfast_cc) + +Syntax: + + csdr shift_addfast_cc Operation is the same as for `shift_math_cc`. Internally, this function uses a NEON-accelerated algorithm on capable systems, so it is advised to use this one on ARM boards. - shift_unroll_cc +---- + +### [shift_unroll_cc](#shift_unroll_cc) + +Syntax: + + csdr shift_unroll_cc Operation is the same as for `shift_math_cc`. @@ -297,103 +361,224 @@ This uses a modified algoritm that first stores a vector of sine and cosine valu The loop in this function unrolls quite well if compiled on a PC. It was the fastest one on an i7 CPU during the tests. - decimating_shift_addition_cc [decimation] +---- + +### [decimating_shift_addition_cc](#decimating_shift_addition_cc) + +Syntax: + + csdr decimating_shift_addition_cc [decimation] It shifts the input signal in the frequency domain, and also decimates it, without filtering. It will be useful as a part of the FFT channelizer implementation (to be done). + It cannot be used as a channelizer by itself, use `fir_decimate_cc` instead. - dcblock_ff +---- + +### [dcblock_ff](#dcblock_ff) + +Syntax: + + csdr dcblock_ff This is a DC blocking IIR filter. - fastdcblock_ff +---- + +### [fastdcblock_ff](#fastdcblock_ff) + +Syntax: + + csdr fastdcblock_ff This is a DC blocker that works based on the average of the buffer. - fmdemod_atan_cf +---- + +### [fmdemod_atan_cf](#fmdemod_atan_cf) + +Syntax: + + csdr fmdemod_atan_cf It is an FM demodulator that internally uses the `atan` function in `math.h`, so it is not so fast. - fmdemod_quadri_cf +---- + +### [fmdemod_quadri_cf](#fmdemod_quadri_cf) + +Syntax: + + csdr fmdemod_quadri_cf It is an FM demodulator that is based on the quadri-correlator method, and it can be effectively auto-vectorized, so it should be faster. - fmdemod_quadri_novect_cf +---- + +### [fmdemod_quadri_novect_cf](#fmdemod_quadri_novect_cf) + +Syntax: + + csdr fmdemod_quadri_novect_cf It has more easily understandable code than the previous one, but can't be auto-vectorized. - deemphasis_wfm_ff +---- + +### [deemphasis_wfm_ff](#deemphasis_wfm_ff) + +Syntax: + + csdr deemphasis_wfm_ff It does de-emphasis with the given RC time constant `tau`. + Different parts of the world use different pre-emphasis filters for FM broadcasting. + In Europe, `tau` should be chosen as `50e-6`, and in the USA, `tau` should be `75e-6`. - deemphasis_nfm_ff +---- + +### [deemphasis_nfm_ff](#deemphasis_nfm_ff) + +Syntax: + + csdr deemphasis_nfm_ff It does de-emphasis on narrow-band FM for communication equipment (e.g. two-way radios). -It uses fixed filters so it works only on predefined sample rates, for the actual list of them run: `cat libcsdr.c | grep DNFMFF_ADD_ARRAY` - amdemod_cf +It uses fixed filters so it works only on predefined sample rates, for the actual list of them run: + + cat libcsdr.c | grep DNFMFF_ADD_ARRAY + +---- + +### [amdemod_cf](#amdemod_cf) + +Syntax: + + csdr amdemod_cf It is an AM demodulator that uses `sqrt`. On some architectures `sqrt` can be directly calculated by dedicated CPU instructions, but on others it may be slower. - amdemod_estimator_cf +---- + +### [amdemod_estimator_cf](#amdemod_estimator_cf) + +Syntax: + + csdr amdemod_estimator_cf It is an AM demodulator that uses an estimation method that is faster but less accurate than `amdemod_cf`. - firdes_lowpass_f [window [--octave]] +---- + +### [firdes_lowpass_f](#firdes_lowpass_f) + +Syntax: + + csdr firdes_lowpass_f [window [--octave]] Low-pass FIR filter design function to output real taps, with a `cutoff_rate` proportional to the sampling frequency, using the windowed sinc filter design method. + `cutoff_rate` can be between 0 and 0.5. `length` is the number of filter taps to output, and should be odd. + The longer the filter kernel is, the shorter the transition bandwidth is, but the more CPU time it takes to process the filter. + The transition bandwidth (proportional to the sampling rate) can be calculated as: `transition_bw = 4 / length`. + Some functions (below) require the `transition_bw` to be given instead of filter `length`. Try to find the best compromise between speed and accuracy by changing this parameter. `window` is the window function used to compensate finite filter length. Its typical values are: `HAMMING`, `BLACKMAN`, `BOXCAR`. For the actual list of values, run: `cpp libcsdr.c | grep window\ ==` The `--octave` parameter lets you directly view the filter response in `octave`. For more information, look at the [Usage by example] section. - firdes_bandpass_c [window [--octave]] +---- + +### [firdes_bandpass_c](#firdes_bandpass_c) + +Syntax: + + csdr firdes_bandpass_c [window [--octave]] Band-pass FIR filter design function to output complex taps. + `low_cut` and ` high_cut` both may be between -0.5 and 0.5, and are also proportional to the sampling frequency. Other parameters were explained above at `firdes_lowpass_f`. - fir_decimate_cc [transition_bw [window]] +---- + +### [fir_decimate_cc](#fir_decimate_cc) + +Syntax: + + csdr fir_decimate_cc [transition_bw [window]] It is a decimator that keeps one sample out of `decimation_factor` samples. + To avoid aliasing, it runs a filter on the signal and removes spectral components above `0.5 × nyquist_frequency × decimation_factor` from the input signal. - fir_interpolate_cc [transition_bw [window]] +---- + +### [fir_interpolate_cc](#fir_interpolate_cc) + +Syntax: + + csdr fir_interpolate_cc [transition_bw [window]] It is an interpolator that generates `interpolation_factor` number of output samples from one input sample. + To avoid aliasing, it runs a filter on the signal and removes spectral components above `0.5 × nyquist_frequency / interpolation_factor` from the output signal. `transition_bw` and `window` are the parameters of the filter. - rational_resampler_ff [transition_bw [window]] +---- + +### [rational_resampler_ff](#rational_resampler_ff) + +Syntax: + + csdr rational_resampler_ff [transition_bw [window]] It is a resampler that takes integer values of `interpolation` and `decimation`. The output sample rate will be `interpolation / decimation × input_sample_rate`. `transition_bw` and `window` are the parameters of the filter. - fractional_decimator_ff [transition_bw [window]] +---- + +### [fractional_decimator_ff](#fractional_decimator_ff) + +Syntax: + + csdr fractional_decimator_ff [transition_bw [window]] It can decimate by a floating point ratio. `transition_bw` and `window` are the parameters of the filter. - bandpass_fir_fft_cc [window] +---- + +### [bandpass_fir_fft_cc](#bandpass_fir_fft_cc) + +Syntax: + + csdr bandpass_fir_fft_cc [window] It performs a bandpass FIR filter on complex samples, using FFT and the overlap-add method. Parameters are described under `firdes_bandpass_c` and `firdes_lowpass_f`. - agc_ff [hang_time [reference [attack_rate [decay_rate [max_gain [attack_wait [filter_alpha]]]]]]] +---- + +### [agc_ff](#agc_ff) + +Syntax: + + csdr agc_ff [hang_time [reference [attack_rate [decay_rate [max_gain [attack_wait [filter_alpha]]]]]]] It is an automatic gain control function. @@ -407,11 +592,23 @@ It is an automatic gain control function. Its default parameters work best for an audio signal sampled at 48000 Hz. - fastagc_ff [block_size [reference]] +---- + +### [fastagc_ff](#fastagc_ff) + +Syntax: + + csdr fastagc_ff [block_size [reference]] It is a faster AGC that linearly changes the gain, taking the highest amplitude peak in the buffer into consideration. Its output will never exceed `-reference ... reference`. - fft_cc [window [--octave] [--benchmark]] +---- + +### [fft_cc](#fft_cc) + +Syntax: + + csdr fft_cc [window [--octave] [--benchmark]] It performs an FFT on the first `fft_size` samples out of `out_of_every_n_samples`, thus skipping `out_of_every_n_samples - fft_size` samples in the input. @@ -419,62 +616,160 @@ It can draw the spectrum by using `--octave`, for more information, look at the FFTW can be faster if we let it optimalize a while before starting the first transform, hence the `--benchmark` switch. - fft_benchmark [--benchmark] +---- + +### [fft_benchmark](#fft_benchmark) + +Syntax: + + csdr fft_benchmark [--benchmark] It measures the time taken to process `fft_cycles` transforms of `fft_size`. It lets FFTW optimalize if used with the `--benchmark` switch. - logpower_cf [add_db] +---- + +### [logpower_cf](#logpower_cf) + +Syntax: + + csdr logpower_cf [add_db] Calculates `10*log10(i^2+q^2)+add_db` for the input complex samples. It is useful for drawing power spectrum graphs. - encode_ima_adpcm_i16_u8 +---- + +### [encode_ima_adpcm_i16_u8](#encode_ima_adpcm_i16_u8) + +Syntax: + +---- + +### [csdr](#csdr) + +Syntax: + + csdr csdr encode_ima_adpcm_i16_u8 Encodes the audio stream to IMA ADPCM, which decreases the size to 25% of the original. - decode_ima_adpcm_u8_i16 +---- + +### [decode_ima_adpcm_u8_i16](#decode_ima_adpcm_u8_i16) + +Syntax: + + csdr decode_ima_adpcm_u8_i16 Decodes the audio stream from IMA ADPCM. - compress_fft_adpcm_f_u8 +---- + +### [compress_fft_adpcm_f_u8](#compress_fft_adpcm_f_u8) + +Syntax: + + csdr compress_fft_adpcm_f_u8 Encodes the FFT output vectors of `fft_size`. It should be used on the data output from `logpower_cf`. -It resets the ADPCM encoder at the beginning of every vector, and to compensate it, `COMPRESS_FFT_PAD_N` samples are added at beginning (these equal to the first relevant sample). -The actual number of padding samples can be determined by running `cat csdr.c | grep "define COMPRESS_FFT_PAD_N"`. - fft_exchange_sides_ff +It resets the ADPCM encoder at the beginning of every vector, and to compensate it, `COMPRESS_FFT_PAD_N` samples are added at beginning (these equal to the first relevant sample). + +The actual number of padding samples can be determined by running: + + cat csdr.c | grep "define COMPRESS_FFT_PAD_N" + +---- + +### [fft_exchange_sides_ff](#fft_exchange_sides_ff) + +Syntax: + + csdr fft_exchange_sides_ff It exchanges the first and second part of the FFT vector, to prepare it for the waterfall/spectrum display. It should operate on the data output from `logpower_cf`. - dsb_fc [q_value] +---- + +### [dsb_fc](#dsb_fc) + +Syntax: + + csdr dsb_fc [q_value] It converts a real signal to a double sideband complex signal centered around DC. + It does so by generating a complex signal: * the real part of which is the input real signal, * the imaginary part of which is `q_value` (0 by default). + With `q_value = 0` it is an AM-DSB/SC modulator. If you want to get an AM-DSB signal, you will have to add a carrier to it. - add_dcoffset_cc +---- + +### [add_dcoffset_cc](#add_dcoffset_cc) + +Syntax: + + csdr add_dcoffset_cc It adds a DC offset to the complex signal: `i_output = 0.5 + i_input / 2, q_output = q_input / 2` - convert_f_samplerf +---- + +### [convert_f_samplerf](#convert_f_samplerf) + +Syntax: + + csdr convert_f_samplerf It converts a real signal to the `-mRF` input format of [https://github.com/F5OEO/rpitx](rpitx), so it allows you to generate frequency modulation. The input signal will be the modulating signal. The `` parameter is the value for `rpitx` indicating the time to wait between samples. For a sampling rate of 48 ksps, this is 20833. - fmmod_fc +---- + +### [fmmod_fc](#fmmod_fc) + +Syntax: + + csdr fmmod_fc It generates a complex FM modulated output from a real input signal. - fixed_amplitude_cc +---- + +### [fixed_amplitude_cc](#fixed_amplitude_cc) + +Syntax: + + csdr fixed_amplitude_cc It changes the amplitude of every complex input sample to a fixed value. It does not change the phase information of the samples. - mono2stereo_s16 +---- -It doubles every input sample. +### [mono2stereo_s16](#mono2stereo_s16) - setbuf +Syntax: + + csdr mono2stereo_s16 + +It doubles every input sample. + +Example: if the input samples are 16 bit signed integers: + + 23 -452 3112 + +The output will be: + + 23 23 -452 -452 3112 3112 + +---- + +### [setbuf](#setbuf) + +Syntax: + + csdr setbuf See the [buffer sizes](#buffer_sizes) section. @@ -482,11 +777,23 @@ See the [buffer sizes](#buffer_sizes) section. This is a controllable squelch, which reads the squelch level input from `` and writes the power level output to ``. Both input and output are in the format of `%g\n`. While calculating the power level, it takes only every `` sample into consideration. It writes the S-meter value for every `` buffer to ``. If the squelch level is set to 0, it it forces the squelch to be open. If the squelch is closed, it fills the output with zero. - fifo +---- + +### [fifo](#fifo) + +Syntax: + + csdr fifo It is similar to `clone`, but internally it uses a circular buffer. It reads as much as possible from the input. It discards input samples if the input buffer is full. - psk31_varicode_encoder_u8_u8 +---- + +### [psk31_varicode_encoder_u8_u8](#psk31_varicode_encoder_u8_u8) + +Syntax: + + csdr psk31_varicode_encoder_u8_u8 It encodes ASCII characters into varicode for PSK31 transmission. It puts a `00` sequence between the varicode characters (which acts as a separator). @@ -502,6 +809,42 @@ For this input, the output of `psk31_varicode_encoder_u8_u8` will be the followi 00 00 ``` +---- + +### [?](#search_the_function_list) + +Syntax: + + csdr ? + +You can search the functions available in `csdr` just as if you typed: `csdr 2>&1 | grep ` + +### [=](#evaluate-python-expression) + +Syntax: + + csdr = + +When running complicated `csdr` commands, we usually run into using `python` to calculate certain parameters. + +This function can eliminate some typing and make our command clearer. + +Instead of having to write: + + csdr shift_addition_cc $(python -c "print 1200/2400000.") + +...we can type: + + csdr shift_addition_cc $(csdr =1200/2400000.) + +If using parenthesis inside the expression, it needs to be escaped (as `bash` would want to parse it): + + csdr shift_addition_cc $(csdr =\(1200+300\)/2400000) + +Another solution is using single quotes to wrap the expression: + + csdr shift_addition_cc $(csdr '=(1200+300)/2400000.') + #### Control via pipes Some parameters can be changed while the `csdr` process is running. To achieve this, some `csdr` functions have special parameters. You have to supply a fifo previously created by the `mkfifo` command. Processing will only start after the first control command has been received by `csdr` over the FIFO. @@ -524,34 +867,6 @@ By writing to the given FIFO file with the syntax below, you can control the shi E.g. you can send `-0.05 0.02\n` - ? - -You can search the functions available in `csdr` just as if you typed: `csdr 2>&1 | grep ` - -### [=](#evaluate-python-expression> - - = - -When running complicated `csdr` commands, we usually run into using `python` to calculate certain parameters. - -This function can eliminate some typing and make our command clearer. - -Instead of having to write: - - csdr shift_addition_cc $(python -c "print 1200/2400000.") - -...we can type: - - csdr shift_addition_cc $(csdr =1200/2400000.) - -If using parenthesis inside the expression, it needs to be escaped (as `bash` would want to parse it): - - csdr shift_addition_cc $(csdr =\(1200+300\)/2400000) - -Another solution is using single quotes to wrap the expression: - - csdr shift_addition_cc $(csdr '=(1200+300)/2400000.') - #### Buffer sizes *csdr* has three modes of determining the buffer sizes, which can be chosen by the appropriate environment variables: diff --git a/csdr.c b/csdr.c index 65d3332..15c13f6 100755 --- a/csdr.c +++ b/csdr.c @@ -1923,7 +1923,7 @@ int main(int argc, char *argv[]) float timetaken; if(time_now_sec<(timetaken=TIME_TAKEN(start_time,end_time))) { - fprintf( stderr, "through: %lu bytes/s %d\n", (unsigned long)floor((float)buffer_count*the_bufsize*sizeof(float)/timetaken), buffer_count ); + fprintf( stderr, "through: %lu bytes/s, buffer #%d\n", (unsigned long)floor((float)buffer_count*the_bufsize*sizeof(float)/timetaken), buffer_count ); time_now_sec=ceil(timetaken); } } From 0e71b332f952ad55223e3a561eaace00b1d994eb Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 2 Apr 2017 16:16:30 +0200 Subject: [PATCH 055/111] Working PSK31 demodulator (just slow because of the pipes and buffering) --- csdr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/csdr.c b/csdr.c index 15c13f6..d647827 100755 --- a/csdr.c +++ b/csdr.c @@ -134,6 +134,7 @@ char usage[]= " psk31_interpolate_sine_cc \n" " duplicate_samples_ntimes_u8_u8 \n" " bpsk_costas_loop_cc \n" +" binary_slicer_f_u8\n" " ?\n" " =\n" " \n" From 72efc31976660c51eb5b35263835a22ae28eb845 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 2 Apr 2017 16:18:20 +0200 Subject: [PATCH 056/111] Added BPSK31 demod test GRC --- grc_tests/test_bpsk31_parts.grc | 985 ++++++++++++++++++++++++++++++++ 1 file changed, 985 insertions(+) create mode 100644 grc_tests/test_bpsk31_parts.grc diff --git a/grc_tests/test_bpsk31_parts.grc b/grc_tests/test_bpsk31_parts.grc new file mode 100644 index 0000000..c44b6e2 --- /dev/null +++ b/grc_tests/test_bpsk31_parts.grc @@ -0,0 +1,985 @@ + + + + Mon Oct 13 20:03:23 2014 + + options + + author + + + + window_size + 1280, 1024 + + + category + Custom + + + comment + + + + description + + + + _enabled + True + + + _coordinate + (10, 10) + + + _rotation + 0 + + + generate_options + wx_gui + + + id + top_block + + + max_nouts + 0 + + + realtime_scheduling + + + + run_options + prompt + + + run + True + + + thread_safe_setters + + + + title + + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (184, 11) + + + _rotation + 0 + + + id + samp_rate + + + value + 48e3 + + + + audio_source + + alias + + + + comment + + + + affinity + + + + device_name + + + + _enabled + True + + + _coordinate + (56, 107) + + + _rotation + 0 + + + id + audio_source_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + num_outputs + 1 + + + ok_to_block + True + + + samp_rate + int(samp_rate) + + + + blocks_deinterleave + + alias + + + + blocksize + 1 + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (656, 113) + + + _rotation + 0 + + + id + blocks_deinterleave_0 + + + type + float + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + num_streams + 2 + + + vlen + 1 + + + + blocks_float_to_complex + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (808, 113) + + + _rotation + 0 + + + id + blocks_float_to_complex_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + vlen + 1 + + + + ha5kfu_execproc_xx + + alias + + + + commandline + csdr dsb_fc | csdr shift_addition_cc $(csdr =-2000./48e3) | csdr fir_decimate_cc 32 + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (384, 123) + + + _rotation + 0 + + + id + ha5kfu_execproc_xx_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + ff + + + + ha5kfu_execproc_xx + + alias + + + + commandline + csdr bpsk_costas_loop_cc 48 + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (608, 219) + + + _rotation + 0 + + + id + ha5kfu_execproc_xx_0_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + cc + + + + ha5kfu_execproc_xx + + alias + + + + commandline + csdr timing_recovery_cc EARLYLATE 48 --add_q | csdr detect_nan_ff + + + comment + + + + affinity + + + + _enabled + 1 + + + _coordinate + (608, 299) + + + _rotation + 0 + + + id + ha5kfu_execproc_xx_0_0_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + cc + + + + notebook + + alias + + + + comment + + + + _enabled + True + + + _coordinate + (400, 40) + + + _rotation + 0 + + + grid_pos + + + + id + nb + + + labels + ['tab1', 'tab2', 'tab3', 'tab4'] + + + notebook + + + + style + wx.NB_TOP + + + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (1008, 51) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_0 + + + notebook + nb, 1 + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate/32 + + + title + FFT Plot + + + type + complex + + + win_size + + + + win + None + + + y_divs + 10 + + + y_per_div + 10 + + + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (280, 227) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_0_0 + + + notebook + nb, 0 + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate + + + title + Input signal + + + type + float + + + win_size + + + + win + None + + + y_divs + 10 + + + y_per_div + 10 + + + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (1008, 371) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_0_1 + + + notebook + nb, 2 + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate/32 + + + title + FFT Plot + + + type + complex + + + win_size + + + + win + None + + + y_divs + 10 + + + y_per_div + 10 + + + + wxgui_scopesink2 + + ac_couple + False + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (1008, 267) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_scopesink2_0 + + + notebook + nb,2 + + + num_inputs + 1 + + + samp_rate + samp_rate/32 + + + t_scale + 0 + + + title + Scope Plot + + + trig_mode + wxgui.TRIG_MODE_AUTO + + + type + complex + + + v_offset + 0 + + + v_scale + 0 + + + win_size + + + + xy_mode + False + + + y_axis_label + Counts + + + + wxgui_scopesink2 + + ac_couple + False + + + alias + + + + comment + + + + affinity + + + + _enabled + 1 + + + _coordinate + (992, 595) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_scopesink2_0_0 + + + notebook + nb,3 + + + num_inputs + 1 + + + samp_rate + samp_rate/32/48 + + + t_scale + 0 + + + title + Scope Plot + + + trig_mode + wxgui.TRIG_MODE_AUTO + + + type + complex + + + v_offset + 0 + + + v_scale + 0 + + + win_size + + + + xy_mode + False + + + y_axis_label + Counts + + + + audio_source_0 + ha5kfu_execproc_xx_0 + 0 + 0 + + + audio_source_0 + wxgui_fftsink2_0_0 + 0 + 0 + + + blocks_deinterleave_0 + blocks_float_to_complex_0 + 0 + 0 + + + blocks_deinterleave_0 + blocks_float_to_complex_0 + 1 + 1 + + + blocks_float_to_complex_0 + ha5kfu_execproc_xx_0_0 + 0 + 0 + + + blocks_float_to_complex_0 + wxgui_fftsink2_0 + 0 + 0 + + + ha5kfu_execproc_xx_0 + blocks_deinterleave_0 + 0 + 0 + + + ha5kfu_execproc_xx_0_0 + ha5kfu_execproc_xx_0_0_0 + 0 + 0 + + + ha5kfu_execproc_xx_0_0 + wxgui_fftsink2_0_1 + 0 + 0 + + + ha5kfu_execproc_xx_0_0 + wxgui_scopesink2_0 + 0 + 0 + + + ha5kfu_execproc_xx_0_0_0 + wxgui_scopesink2_0_0 + 0 + 0 + + From 52a225d79121a6c5f03b967e9669cde361d11e7c Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Wed, 5 Apr 2017 19:59:29 +0200 Subject: [PATCH 057/111] Varied the bufsizes to produce output with PSK31 --- csdr.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/csdr.c b/csdr.c index d647827..ad02b9c 100755 --- a/csdr.c +++ b/csdr.c @@ -155,7 +155,7 @@ int bigbufs = 0; //change on on 2015-08-29: we don't yield at all. fread() will do it if it blocks #define YIELD_EVERY_N_TIMES 3 //#define TRY_YIELD if(++yield_counter%YIELD_EVERY_N_TIMES==0) sched_yield() -#define TRY_YIELD +#define TRY_YIELD fflush(stdout);sched_yield() //unsigned yield_counter=0; int badsyntax(char* why) @@ -295,7 +295,7 @@ int the_bufsize = 0; char **argv_global; -#define UNITROUND_UNIT 128 +#define UNITROUND_UNIT 4 int unitround(int what) { @@ -313,11 +313,20 @@ int initialize_buffers() buffer_u8 = (unsigned char*)malloc(the_bufsize*sizeof(unsigned char)); buffer_i16 = (short*) malloc(the_bufsize*sizeof(short)); temp_f = (float*) malloc(the_bufsize*sizeof(float) * 4); + if(the_bufsize<=4096) //this is hacky, should be done correctly + { + fcntl(STDIN_FILENO, F_SETPIPE_SZ, 4096); + fcntl(STDOUT_FILENO, F_SETPIPE_SZ, 4096); + } return the_bufsize; } int sendbufsize(int size) { + if(size<=4096) + { + fcntl(STDOUT_FILENO, F_SETPIPE_SZ, 4096); + } //The first word is a preamble, "csdr". //If the next csdr process detects it, sets the buffer size according to the second word if(!env_csdr_dynamic_bufsize_on) return env_csdr_fixed_bufsize; From ad36d1160ec69ef04ddd356f8493db4cb3586f01 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Wed, 5 Apr 2017 20:06:04 +0200 Subject: [PATCH 058/111] Removed all _sy functions, renamed to u8. --- csdr.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/csdr.c b/csdr.c index ad02b9c..a62877b 100755 --- a/csdr.c +++ b/csdr.c @@ -119,14 +119,14 @@ char usage[]= " fft_exchange_sides_ff \n" " squelch_and_smeter_cc --fifo --outfifo \n" " fifo \n" -" bpsk31_varicode2ascii_sy_u8\n" -" invert_sy_sy\n" -" rtty_line_decoder_sy_u8\n" +" invert_u8_u8\n" +" rtty_line_decoder_u8_u8\n" " rtty_baudot2ascii_u8_u8\n" -" serial_line_decoder_sy_u8\n" +" serial_line_decoder_u8_u8\n" " octave_complex_c \n" " timing_recovery_cc [--add_q]\n" " psk31_varicode_encoder_u8_u8\n" +" psk31_varicode_decoder_u8_u8\n" " differential_encoder_u8_u8\n" " differential_decoder_u8_u8\n" " dump_u8\n" @@ -2277,7 +2277,7 @@ int main(int argc, char *argv[]) |___/ */ - if(!strcmp(argv[1],"bpsk31_varicode2ascii_sy_u8")) + if(!!strcmp(argv[1],"bpsk31_varicode_decoder_u8_u8")) { unsigned long long status_shr = 0; unsigned char output; @@ -2292,7 +2292,7 @@ int main(int argc, char *argv[]) } } - if(!strcmp(argv[1],"invert_sy_sy")) + if(!strcmp(argv[1],"invert_u8_u8")) { if(!sendbufsize(initialize_buffers())) return -2; unsigned char i=0; @@ -2305,7 +2305,7 @@ int main(int argc, char *argv[]) } } - if(!strcmp(argv[1],"rtty_line_decoder_sy_u8")) + if(!strcmp(argv[1],"rtty_line_decoder_u8_u8")) { static rtty_baudot_decoder_t status_baudot; //created on .bss -> initialized to 0 unsigned char output; @@ -2358,7 +2358,7 @@ int main(int argc, char *argv[]) if(argc<=2) return badsyntax("need required parameter (samples_per_bits)"); sscanf(argv[2],"%f",&serial.samples_per_bits); if(serial.samples_per_bits<1) return badsyntax("samples_per_bits should be at least 1."); - if(serial.samples_per_bits<5) fprintf(stderr, "serial_line_decoder_sy_u8: warning: this algorithm does not work well if samples_per_bits is too low. It should be at least 5.\n"); + if(serial.samples_per_bits<5) fprintf(stderr, "%s: warning: this algorithm does not work well if samples_per_bits is too low. It should be at least 5.\n", argv[1]); serial.databits=8; if(argc>3) sscanf(argv[3],"%d",&serial.databits); @@ -2384,7 +2384,7 @@ int main(int argc, char *argv[]) else fread(input_buffer, sizeof(float), the_bufsize, stdin); //should happen only on the first run serial_line_decoder_f_u8(&serial,input_buffer, (unsigned char*)output_buffer, the_bufsize); //printf("now in | "); - if(serial.input_used==0) { fprintf(stderr, "serial_line_decoder_sy_u8: error: serial_line_decoder_f_u8() got stuck.\n"); return -3; } + if(serial.input_used==0) { fprintf(stderr, "%s: error: serial_line_decoder_f_u8() got stuck.\n", argv[1]); return -3; } //printf("now out %d | ", serial.output_size); fwrite(output_buffer, sizeof(unsigned char), serial.output_size, stdout); fflush(stdout); @@ -2398,8 +2398,6 @@ int main(int argc, char *argv[]) if(argc<=2) return badsyntax("need required parameter (pll_type)"); sscanf(argv[2],"%d",(int*)&pll.pll_type); - //if(serial.samples_per_bits<1) return badsyntax("samples_per_bits should be at least 1."); - //if(serial.samples_per_bits<5) fprintf(stderr, "serial_line_decoder_sy_u8: warning: this algorithm does not work well if samples_per_bits is too low. It should be at least 5.\n"); if(pll.pll_type == PLL_P_CONTROLLER) { float alpha = 0.01; From 93b996412a59379b6a972ec9ffecc3bd1f233344 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Thu, 6 Apr 2017 15:35:52 +0200 Subject: [PATCH 059/111] Fixed bug that prevented many functions to work; this came from a previous commit --- csdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csdr.c b/csdr.c index a62877b..26aef96 100755 --- a/csdr.c +++ b/csdr.c @@ -2277,7 +2277,7 @@ int main(int argc, char *argv[]) |___/ */ - if(!!strcmp(argv[1],"bpsk31_varicode_decoder_u8_u8")) + if(!strcmp(argv[1],"bpsk31_varicode_decoder_u8_u8")) { unsigned long long status_shr = 0; unsigned char output; From e7f9be41c2c46c5bca56c437eeb56535a92f9f09 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Thu, 6 Apr 2017 15:41:52 +0200 Subject: [PATCH 060/111] Fixed function name --- csdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csdr.c b/csdr.c index 26aef96..3f7521c 100755 --- a/csdr.c +++ b/csdr.c @@ -2277,7 +2277,7 @@ int main(int argc, char *argv[]) |___/ */ - if(!strcmp(argv[1],"bpsk31_varicode_decoder_u8_u8")) + if(!strcmp(argv[1],"psk31_varicode_decoder_u8_u8")) { unsigned long long status_shr = 0; unsigned char output; From fc350d594c353904e9546c9cea96af051b54f8c2 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Thu, 6 Apr 2017 20:38:44 +0200 Subject: [PATCH 061/111] Added simple_agc_cc --- csdr.c | 33 ++++++++++++++++++++++++++++++++- libcsdr.c | 20 ++++++++++++++++++++ libcsdr.h | 1 + 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/csdr.c b/csdr.c index 3f7521c..6ddaa78 100755 --- a/csdr.c +++ b/csdr.c @@ -135,6 +135,7 @@ char usage[]= " duplicate_samples_ntimes_u8_u8 \n" " bpsk_costas_loop_cc \n" " binary_slicer_f_u8\n" +" simple_agc_cc [reference [max_gain]]\n" " ?\n" " =\n" " \n" @@ -2652,7 +2653,7 @@ int main(int argc, char *argv[]) float samples_per_bits; if(argc<=2) return badsyntax("need required parameter (samples_per_bits)"); sscanf(argv[2],"%f",&samples_per_bits); - if(samples_per_bits<=0) badsyntax("samples_per_bits should be >= 0"); + if(samples_per_bits<=0) badsyntax("samples_per_bits should be > 0"); bpsk_costas_loop_state_t state = init_bpsk_costas_loop_cc(samples_per_bits); @@ -2669,6 +2670,36 @@ int main(int argc, char *argv[]) } } + if(!strcmp(argv[1],"simple_agc_cc")) // [reference [max_gain]] + { + float rate; + if(argc<=2) return badsyntax("need required parameter (rate)"); + sscanf(argv[2],"%f",&rate); + if(rate<=0) badsyntax("rate should be > 0"); + + float reference = 1.; + if(argc>3) sscanf(argv[3],"%f",&reference); + if(reference<=0) badsyntax("reference should be > 0"); + + float max_gain = 65535.; + if(argc>4) sscanf(argv[4],"%f",&max_gain); + if(max_gain<=0) badsyntax("max_gain should be > 0"); + + float current_gain = 1.; + + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize); + + for(;;) + { + FEOF_CHECK; + FREAD_C; + simple_agc_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, rate, reference, max_gain, ¤t_gain); + FWRITE_C; + TRY_YIELD; + } + } + if(!strcmp(argv[1],"none")) { return 0; diff --git a/libcsdr.c b/libcsdr.c index 2121f52..14f997e 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1990,6 +1990,26 @@ void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, bpsk } } +void simple_agc_cc(complexf* input, complexf* output, int input_size, float rate, float reference, float max_gain, float* current_gain) +{ + float rate_1minus=1-rate; + int debugn = 0; + for(int i=0;imax_gain) ideal_gain = max_gain; + if(ideal_gain<=0) ideal_gain = 0; + //*current_gain += (ideal_gain-(*current_gain))*rate; + *current_gain = (ideal_gain-(*current_gain))*rate + (*current_gain)*rate_1minus; + if(debugn<100) fprintf(stderr, "cgain: %g\n", *current_gain), debugn++; + output[i].i=(*current_gain)*input[i].i; + output[i].q=(*current_gain)*input[i].q; + } +} + + + /* _____ _ _ diff --git a/libcsdr.h b/libcsdr.h index 1c15f90..988bba8 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -337,3 +337,4 @@ typedef struct bpsk_costas_loop_state_s bpsk_costas_loop_state_t init_bpsk_costas_loop_cc(float samples_per_bits); void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, bpsk_costas_loop_state_t* state); +void simple_agc_cc(complexf* input, complexf* output, int input_size, float rate, float reference, float max_gain, float* current_gain); From dd0d20921ba13713e3f70e94d9ba80ae89407c44 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Thu, 6 Apr 2017 22:03:09 +0200 Subject: [PATCH 062/111] Added simple_agc_cc GRC test --- csdr.c | 2 +- grc_tests/test_simple_agc.grc | 844 ++++++++++++++++++++++++++++++++++ libcsdr.c | 4 +- 3 files changed, 847 insertions(+), 3 deletions(-) create mode 100644 grc_tests/test_simple_agc.grc mode change 100644 => 100755 libcsdr.c diff --git a/csdr.c b/csdr.c index 6ddaa78..e4e0aeb 100755 --- a/csdr.c +++ b/csdr.c @@ -27,7 +27,7 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - + #define _POSIX_C_SOURCE 199309L #define _BSD_SOURCE #define _GNU_SOURCE diff --git a/grc_tests/test_simple_agc.grc b/grc_tests/test_simple_agc.grc new file mode 100644 index 0000000..5e06234 --- /dev/null +++ b/grc_tests/test_simple_agc.grc @@ -0,0 +1,844 @@ + + + + Sun Nov 16 15:12:31 2014 + + options + + author + + + + window_size + 1280, 1024 + + + category + Custom + + + comment + + + + description + + + + _enabled + True + + + _coordinate + (10, 10) + + + _rotation + 0 + + + generate_options + wx_gui + + + id + top_block + + + max_nouts + 0 + + + realtime_scheduling + + + + run_options + prompt + + + run + True + + + thread_safe_setters + + + + title + + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (10, 170) + + + _rotation + 0 + + + id + samp_rate + + + value + 48000 + + + + analog_agc_xx + + alias + + + + comment + + + + affinity + + + + _enabled + 0 + + + _coordinate + (432, 355) + + + _rotation + 0 + + + gain + 1 + + + id + analog_agc_xx_0 + + + max_gain + 65536 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + rate + 1e-2 + + + reference + 0.1 + + + type + complex + + + + audio_sink + + alias + + + + comment + + + + affinity + + + + device_name + + + + _enabled + True + + + _coordinate + (1152, 427) + + + _rotation + 0 + + + id + audio_sink_0 + + + num_inputs + 1 + + + ok_to_block + True + + + samp_rate + samp_rate + + + + band_reject_filter + + beta + 6.76 + + + alias + + + + comment + + + + affinity + + + + decim + 1 + + + _enabled + True + + + type + fir_filter_fff + + + _coordinate + (392, 35) + + + _rotation + 0 + + + gain + 1 + + + high_cutoff_freq + 2000 + + + id + band_reject_filter_0 + + + interp + 1 + + + low_cutoff_freq + 1600 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + samp_rate + samp_rate + + + width + 50 + + + win + firdes.WIN_HAMMING + + + + blocks_complex_to_float + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (928, 289) + + + _rotation + 0 + + + id + blocks_complex_to_float_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + vlen + 1 + + + + blocks_multiply_const_vxx + + alias + + + + comment + + + + const + 0.2 + + + affinity + + + + _enabled + True + + + _coordinate + (968, 427) + + + _rotation + 0 + + + id + blocks_multiply_const_vxx_0 + + + type + float + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + vlen + 1 + + + + blocks_wavfile_source + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + file + /home/pcfl/Asztal/szakdoga/dipterv1/csdr-varicode/grc_tests/outfile.wav + + + _coordinate + (152, 163) + + + _rotation + 0 + + + id + blocks_wavfile_source_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + nchan + 1 + + + repeat + True + + + + freq_xlating_fir_filter_xxx + + alias + + + + center_freq + 2000 + + + comment + + + + affinity + + + + decim + 1 + + + _enabled + True + + + _coordinate + (832, 75) + + + _rotation + 0 + + + id + freq_xlating_fir_filter_xxx_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + samp_rate + samp_rate + + + taps + [1] + + + type + fcc + + + + freq_xlating_fir_filter_xxx + + alias + + + + center_freq + -2000 + + + comment + + + + affinity + + + + decim + 1 + + + _enabled + True + + + _coordinate + (696, 275) + + + _rotation + 0 + + + id + freq_xlating_fir_filter_xxx_0_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + samp_rate + samp_rate + + + taps + [1] + + + type + ccc + + + + ha5kfu_execproc_xx + + alias + + + + commandline + csdr simple_agc_cc 0.001 0.05 + + + comment + + + + affinity + + + + _enabled + 1 + + + _coordinate + (384, 291) + + + _rotation + 0 + + + id + ha5kfu_execproc_xx_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + cc + + + + low_pass_filter + + beta + 6.76 + + + alias + + + + comment + + + + affinity + + + + cutoff_freq + 3000 + + + decim + 1 + + + _enabled + True + + + type + fir_filter_fff + + + _coordinate + (584, 43) + + + _rotation + 0 + + + gain + 1 + + + id + low_pass_filter_0 + + + interp + 1 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + samp_rate + samp_rate + + + width + 50 + + + win + firdes.WIN_HAMMING + + + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (688, 403) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_0 + + + notebook + + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate + + + title + FFT Plot + + + type + complex + + + win_size + + + + win + None + + + y_divs + 10 + + + y_per_div + 10 + + + + analog_agc_xx_0 + freq_xlating_fir_filter_xxx_0_0 + 0 + 0 + + + analog_agc_xx_0 + wxgui_fftsink2_0 + 0 + 0 + + + band_reject_filter_0 + low_pass_filter_0 + 0 + 0 + + + blocks_complex_to_float_0 + blocks_multiply_const_vxx_0 + 0 + 0 + + + blocks_multiply_const_vxx_0 + audio_sink_0 + 0 + 0 + + + blocks_wavfile_source_0 + band_reject_filter_0 + 0 + 0 + + + freq_xlating_fir_filter_xxx_0 + analog_agc_xx_0 + 0 + 0 + + + freq_xlating_fir_filter_xxx_0 + ha5kfu_execproc_xx_0 + 0 + 0 + + + freq_xlating_fir_filter_xxx_0_0 + blocks_complex_to_float_0 + 0 + 0 + + + ha5kfu_execproc_xx_0 + freq_xlating_fir_filter_xxx_0_0 + 0 + 0 + + + ha5kfu_execproc_xx_0 + wxgui_fftsink2_0 + 0 + 0 + + + low_pass_filter_0 + freq_xlating_fir_filter_xxx_0 + 0 + 0 + + diff --git a/libcsdr.c b/libcsdr.c old mode 100644 new mode 100755 index 14f997e..93e3a51 --- a/libcsdr.c +++ b/libcsdr.c @@ -2001,8 +2001,8 @@ void simple_agc_cc(complexf* input, complexf* output, int input_size, float rate if(ideal_gain>max_gain) ideal_gain = max_gain; if(ideal_gain<=0) ideal_gain = 0; //*current_gain += (ideal_gain-(*current_gain))*rate; - *current_gain = (ideal_gain-(*current_gain))*rate + (*current_gain)*rate_1minus; - if(debugn<100) fprintf(stderr, "cgain: %g\n", *current_gain), debugn++; + *current_gain = (ideal_gain-(*current_gain))*rate + (*current_gain); //*rate_1minus; + //if(debugn<100) fprintf(stderr, "cgain: %g\n", *current_gain), debugn++; output[i].i=(*current_gain)*input[i].i; output[i].q=(*current_gain)*input[i].q; } From 50c885748ee92558ab2ca1dcfaf696ebcc7c3483 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Fri, 7 Apr 2017 16:05:38 +0200 Subject: [PATCH 063/111] Working BPSK31 demodulator --- grc_tests/test_bpsk31_parts.grc | 2 +- libcsdr.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/grc_tests/test_bpsk31_parts.grc b/grc_tests/test_bpsk31_parts.grc index c44b6e2..ac3ad4d 100644 --- a/grc_tests/test_bpsk31_parts.grc +++ b/grc_tests/test_bpsk31_parts.grc @@ -257,7 +257,7 @@ commandline - csdr dsb_fc | csdr shift_addition_cc $(csdr =-2000./48e3) | csdr fir_decimate_cc 32 + csdr dsb_fc | csdr shift_addition_cc $(csdr =-2000./48e3) | csdr fir_decimate_cc 32 | csdr simple_agc_cc 0.0001 0.5 comment diff --git a/libcsdr.c b/libcsdr.c index 93e3a51..d63984f 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -1685,6 +1685,7 @@ unsigned char differential_codec(unsigned char* input, unsigned char* output, in if(!input[i]) state=!state; output[i] = state; } + return state; } /* From cdc2996dcc8d7f3d0c007823e66b877b23d2e962 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sat, 8 Apr 2017 12:39:52 +0200 Subject: [PATCH 064/111] Added firdes_carrier_c --- csdr.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ libcsdr.c | 28 ++++++++++++++++++++++++++++ libcsdr.h | 1 + 3 files changed, 75 insertions(+) diff --git a/csdr.c b/csdr.c index e4e0aeb..5b53ffa 100755 --- a/csdr.c +++ b/csdr.c @@ -136,6 +136,7 @@ char usage[]= " bpsk_costas_loop_cc \n" " binary_slicer_f_u8\n" " simple_agc_cc [reference [max_gain]]\n" +" firdes_carrier_c [window [--octave]]\n" " ?\n" " =\n" " \n" @@ -2700,6 +2701,51 @@ int main(int argc, char *argv[]) } } + if(!strcmp(argv[1],"firdes_carrier_c")) // [window [--octave]] + { + //Process the params + if(argc<=3) return badsyntax("need required parameters (rate, length)"); + + float rate; + sscanf(argv[2],"%g",&rate); + int length; + sscanf(argv[3],"%d",&length); + if(length%2==0) return badsyntax("number of symmetric FIR filter taps should be odd"); + + window_t window = WINDOW_DEFAULT; + if(argc>=5) + { + window=firdes_get_window_from_string(argv[4]); + } + else fprintf(stderr,"firdes_carrier_c: window = %s\n",firdes_get_string_from_window(window)); + + int octave=(argc>=6 && !strcmp("--octave",argv[5])); + + complexf* taps=(complexf*)malloc(sizeof(complexf)*length); + + //Make the filter + firdes_carrier_c(taps, length, rate, window); + + //Do the output + if(octave) printf("taps=["); + for(int i=0;i2*M_PI) phase-=2*M_PI; + } + + //Normalize filter kernel + float sum=0; + for(int i=0;i Date: Sat, 8 Apr 2017 16:36:10 +0200 Subject: [PATCH 065/111] firdes_carrier_c to firdes_add_carrier_c --- csdr.c | 4 ++-- libcsdr.c | 20 +++++++++++++------- libcsdr.h | 2 +- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/csdr.c b/csdr.c index 5b53ffa..8f0a730 100755 --- a/csdr.c +++ b/csdr.c @@ -2721,10 +2721,10 @@ int main(int argc, char *argv[]) int octave=(argc>=6 && !strcmp("--octave",argv[5])); - complexf* taps=(complexf*)malloc(sizeof(complexf)*length); + complexf* taps=(complexf*)calloc(sizeof(complexf),length); //Make the filter - firdes_carrier_c(taps, length, rate, window); + firdes_add_carrier_c(taps, length, rate, window); //Do the output if(octave) printf("taps=["); diff --git a/libcsdr.c b/libcsdr.c index 298d239..05c11f9 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -2009,17 +2009,18 @@ void simple_agc_cc(complexf* input, complexf* output, int input_size, float rate } } -void firdes_carrier_c(complexf* output, int length, float rate, window_t window) +void firdes_add_carrier_c(complexf* output, int length, float rate, window_t window) { + complexf* taps = (complexf*)malloc(sizeof(complexf)*length); int middle=length/2; float phase = 0, phase_addition = rate*M_PI*2; float (*window_function)(float) = firdes_get_window_kernel(window); for(int i=0; i2*M_PI) phase-=2*M_PI; } @@ -2028,12 +2029,17 @@ void firdes_carrier_c(complexf* output, int length, float rate, window_t window) float sum=0; for(int i=0;i Date: Sun, 9 Apr 2017 14:53:22 +0200 Subject: [PATCH 066/111] Added resonator FIR --- csdr.c | 64 +++++++++++++++++++++++++++++++++++++++++++++---------- libcsdr.c | 24 ++++++++++++++++----- libcsdr.h | 3 ++- 3 files changed, 74 insertions(+), 17 deletions(-) diff --git a/csdr.c b/csdr.c index 8f0a730..4180d8c 100755 --- a/csdr.c +++ b/csdr.c @@ -136,7 +136,8 @@ char usage[]= " bpsk_costas_loop_cc \n" " binary_slicer_f_u8\n" " simple_agc_cc [reference [max_gain]]\n" -" firdes_carrier_c [window [--octave]]\n" +" firdes_resonator_c [window [--octave]]\n" +" resonators_fir_cc [resonator_rate × N]\n" " ?\n" " =\n" " \n" @@ -1054,6 +1055,7 @@ int main(int argc, char *argv[]) TRY_YIELD; } } + if(!strcmp(argv[1],"fir_decimate_cc")) { bigbufs=1; @@ -1111,7 +1113,6 @@ int main(int argc, char *argv[]) output_size=fir_decimate_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, factor, taps, padded_taps_length); //fprintf(stderr, "os %d\n",output_size); fwrite(output_buffer, sizeof(complexf), output_size, stdout); - fflush(stdout); TRY_YIELD; input_skip=factor*output_size; memmove((complexf*)input_buffer,((complexf*)input_buffer)+input_skip,(the_bufsize-input_skip)*sizeof(complexf)); //memmove lets the source and destination overlap @@ -1167,7 +1168,6 @@ int main(int argc, char *argv[]) output_size=fir_interpolate_cc((complexf*)input_buffer, (complexf*)interp_output_buffer, the_bufsize, factor, taps, taps_length); //fprintf(stderr, "os %d\n",output_size); fwrite(interp_output_buffer, sizeof(complexf), output_size, stdout); - fflush(stdout); TRY_YIELD; input_skip=output_size/factor; memmove((complexf*)input_buffer,((complexf*)input_buffer)+input_skip,(the_bufsize-input_skip)*sizeof(complexf)); //memmove lets the source and destination overlap @@ -2389,7 +2389,6 @@ int main(int argc, char *argv[]) if(serial.input_used==0) { fprintf(stderr, "%s: error: serial_line_decoder_f_u8() got stuck.\n", argv[1]); return -3; } //printf("now out %d | ", serial.output_size); fwrite(output_buffer, sizeof(unsigned char), serial.output_size, stdout); - fflush(stdout); TRY_YIELD; } } @@ -2468,7 +2467,6 @@ int main(int argc, char *argv[]) timing_recovery_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, &state); //fprintf(stderr, "trcc is=%d, os=%d, ip=%d\n",the_bufsize, state.output_size, state.input_processed); fwrite(output_buffer, sizeof(complexf), state.output_size, stdout); - fflush(stdout); TRY_YIELD; //fprintf(stderr, "state.input_processed = %d\n", state.input_processed); memmove((complexf*)input_buffer,((complexf*)input_buffer)+state.input_processed,(the_bufsize-state.input_processed)*sizeof(complexf)); //memmove lets the source and destination overlap @@ -2701,7 +2699,7 @@ int main(int argc, char *argv[]) } } - if(!strcmp(argv[1],"firdes_carrier_c")) // [window [--octave]] + if(!strcmp(argv[1],"firdes_resonator_c")) // [window [--octave]] { //Process the params if(argc<=3) return badsyntax("need required parameters (rate, length)"); @@ -2717,14 +2715,14 @@ int main(int argc, char *argv[]) { window=firdes_get_window_from_string(argv[4]); } - else fprintf(stderr,"firdes_carrier_c: window = %s\n",firdes_get_string_from_window(window)); + else fprintf(stderr,"firdes_resonator_c: window = %s\n",firdes_get_string_from_window(window)); int octave=(argc>=6 && !strcmp("--octave",argv[5])); complexf* taps=(complexf*)calloc(sizeof(complexf),length); //Make the filter - firdes_add_carrier_c(taps, length, rate, window); + firdes_add_resonator_c(taps, length, rate, window); //Do the output if(octave) printf("taps=["); @@ -2736,15 +2734,59 @@ int main(int argc, char *argv[]) "];figure(\"Position\",[0 0 1000 1000]);fser=fft([taps,zeros(1,%d)]);ampl=abs(fser).^2;halfindex=floor(1+size(ampl)(2)/2);\n" "amplrev=[ampl(halfindex:end),ampl(1:halfindex)];\n" //we have to swap the output of FFT "subplot(2,1,1);plot(amplrev);\n" - "subplot(2,1,2);plot(arg(fser));\n" - "#figure(2);freqz(taps);\n" - "#figur(3);plot3(taps);\n",fft_length-length); + "subplot(2,1,2);plot(arg(fser));\n",fft_length-length); //Wait forever, so that octave won't close just after popping up the window. //You can close it with ^C. if(octave) { fflush(stdout); getchar(); } return 0; } + + if(!strcmp(argv[1],"resonators_fir_cc")) // + { + + if(argc<=2) return badsyntax("need required parameter (taps_length)"); + int taps_length; + sscanf(argv[2],"%d",&taps_length); + + int num_resonators = argc-3; + float* resonator_rate = (float*)malloc(sizeof(float)*num_resonators); + for(int i=0;i2*M_PI) phase-=2*M_PI; + while(phase<0) phase+=2*M_PI; } //Normalize filter kernel float sum=0; - for(int i=0;i Date: Sun, 9 Apr 2017 19:00:07 +0200 Subject: [PATCH 067/111] Working FIR resonator and related GRC test --- csdr.c | 19 +- grc_tests/test_bpsk31_to_octave.grc | 675 +++++++++++++++++++++++++ grc_tests/test_resonators_fir.grc | 752 ++++++++++++++++++++++++++++ libcsdr.c | 35 +- libcsdr.h | 2 +- 5 files changed, 1457 insertions(+), 26 deletions(-) create mode 100644 grc_tests/test_bpsk31_to_octave.grc create mode 100644 grc_tests/test_resonators_fir.grc diff --git a/csdr.c b/csdr.c index 4180d8c..73e6234 100755 --- a/csdr.c +++ b/csdr.c @@ -2719,10 +2719,10 @@ int main(int argc, char *argv[]) int octave=(argc>=6 && !strcmp("--octave",argv[5])); - complexf* taps=(complexf*)calloc(sizeof(complexf),length); + complexf* taps=(complexf*)malloc(sizeof(complexf)*length); //Make the filter - firdes_add_resonator_c(taps, length, rate, window); + firdes_add_resonator_c(taps, length, rate, window, 0, 1); //Do the output if(octave) printf("taps=["); @@ -2744,6 +2744,7 @@ int main(int argc, char *argv[]) if(!strcmp(argv[1],"resonators_fir_cc")) // { + //rule of thumb: bw = 2/taps_length, which does not equal to transition_bw if(argc<=2) return badsyntax("need required parameter (taps_length)"); int taps_length; @@ -2754,24 +2755,20 @@ int main(int argc, char *argv[]) for(int i=0;i + + + Mon Oct 13 20:03:23 2014 + + options + + author + + + + window_size + 1280, 1024 + + + category + Custom + + + comment + + + + description + + + + _enabled + True + + + _coordinate + (10, 10) + + + _rotation + 0 + + + generate_options + wx_gui + + + id + top_block + + + max_nouts + 0 + + + realtime_scheduling + + + + run_options + prompt + + + run + True + + + thread_safe_setters + + + + title + + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (184, 11) + + + _rotation + 0 + + + id + samp_rate + + + value + 48e3 + + + + audio_source + + alias + + + + comment + + + + affinity + + + + device_name + + + + _enabled + True + + + _coordinate + (56, 107) + + + _rotation + 0 + + + id + audio_source_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + num_outputs + 1 + + + ok_to_block + True + + + samp_rate + int(samp_rate) + + + + blocks_file_sink + + append + False + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + file + /home/pcfl/Asztal/szakdoga/dipterv1/bpsk31_input_f.raw + + + _coordinate + (232, 251) + + + _rotation + 0 + + + id + blocks_file_sink_0 + + + type + float + + + unbuffered + False + + + vlen + 1 + + + + blocks_file_sink + + append + False + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + file + /home/pcfl/Asztal/szakdoga/dipterv1/bpsk31_baseband_c.raw + + + _coordinate + (1032, 91) + + + _rotation + 0 + + + id + blocks_file_sink_0_0 + + + type + complex + + + unbuffered + False + + + vlen + 1 + + + + freq_xlating_fir_filter_xxx + + alias + + + + center_freq + 2000 + + + comment + + + + affinity + + + + decim + 1 + + + _enabled + True + + + _coordinate + (296, 123) + + + _rotation + 0 + + + id + freq_xlating_fir_filter_xxx_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + samp_rate + samp_rate + + + taps + [1] + + + type + fcc + + + + low_pass_filter + + beta + 6.76 + + + alias + + + + comment + + + + affinity + + + + cutoff_freq + 1000 + + + decim + 1 + + + _enabled + True + + + type + fir_filter_ccf + + + _coordinate + (536, 99) + + + _rotation + 0 + + + gain + 1 + + + id + low_pass_filter_0 + + + interp + 1 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + samp_rate + samp_rate + + + width + 100 + + + win + firdes.WIN_HAMMING + + + + notebook + + alias + + + + comment + + + + _enabled + True + + + _coordinate + (280, 11) + + + _rotation + 0 + + + grid_pos + + + + id + nb + + + labels + ['tab1', 'tab2', 'tab3', 'tab4'] + + + notebook + + + + style + wx.NB_TOP + + + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (1032, 187) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_0 + + + notebook + + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate + + + title + FFT Plot + + + type + complex + + + win_size + + + + win + None + + + y_divs + 10 + + + y_per_div + 10 + + + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (232, 339) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_0_0 + + + notebook + + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate + + + title + FFT Plot + + + type + float + + + win_size + + + + win + None + + + y_divs + 10 + + + y_per_div + 10 + + + + audio_source_0 + blocks_file_sink_0 + 0 + 0 + + + audio_source_0 + freq_xlating_fir_filter_xxx_0 + 0 + 0 + + + audio_source_0 + wxgui_fftsink2_0_0 + 0 + 0 + + + freq_xlating_fir_filter_xxx_0 + low_pass_filter_0 + 0 + 0 + + + low_pass_filter_0 + blocks_file_sink_0_0 + 0 + 0 + + + low_pass_filter_0 + wxgui_fftsink2_0 + 0 + 0 + + diff --git a/grc_tests/test_resonators_fir.grc b/grc_tests/test_resonators_fir.grc new file mode 100644 index 0000000..f3c6324 --- /dev/null +++ b/grc_tests/test_resonators_fir.grc @@ -0,0 +1,752 @@ + + + + Sun Nov 16 15:12:31 2014 + + options + + author + + + + window_size + 1280, 1024 + + + category + Custom + + + comment + + + + description + + + + _enabled + True + + + _coordinate + (10, 10) + + + _rotation + 0 + + + generate_options + wx_gui + + + id + top_block + + + max_nouts + 0 + + + realtime_scheduling + + + + run_options + prompt + + + run + True + + + thread_safe_setters + + + + title + + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (8, 83) + + + _rotation + 0 + + + id + samp_rate + + + value + 100e3 + + + + analog_random_source_x + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (8, 155) + + + _rotation + 0 + + + id + analog_random_source_x_0 + + + maxoutbuf + 0 + + + max + 2147483647 + + + minoutbuf + 0 + + + min + -2147483648 + + + num_samps + 1000 + + + type + int + + + repeat + True + + + + blocks_deinterleave + + alias + + + + blocksize + 1 + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (384, 169) + + + _rotation + 0 + + + id + blocks_deinterleave_0 + + + type + float + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + num_streams + 2 + + + vlen + 1 + + + + blocks_float_to_complex + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (544, 169) + + + _rotation + 0 + + + id + blocks_float_to_complex_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + vlen + 1 + + + + blocks_int_to_float + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (208, 179) + + + _rotation + 0 + + + id + blocks_int_to_float_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + scale + 2147483647. + + + vlen + 1 + + + + blocks_throttle + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (736, 179) + + + _rotation + 0 + + + id + blocks_throttle_0 + + + ignoretag + True + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + samples_per_second + samp_rate + + + type + complex + + + vlen + 1 + + + + ha5kfu_execproc_xx + + alias + + + + commandline + csdr resonators_fir_cc 101 -0.2 -0.1 0 0.1 0.2 + + + comment + + + + affinity + + + + _enabled + 1 + + + _coordinate + (168, 339) + + + _rotation + 0 + + + id + ha5kfu_execproc_xx_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + cc + + + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (472, 435) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_0 + + + notebook + + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate + + + title + FFT Plot + + + type + complex + + + win_size + + + + win + None + + + y_divs + 10 + + + y_per_div + 10 + + + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (976, 107) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_0_0 + + + notebook + + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate + + + title + FFT Plot + + + type + complex + + + win_size + + + + win + None + + + y_divs + 10 + + + y_per_div + 10 + + + + wxgui_scopesink2 + + ac_couple + False + + + alias + + + + comment + + + + affinity + + + + _enabled + 0 + + + _coordinate + (480, 299) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_scopesink2_0 + + + notebook + + + + num_inputs + 1 + + + samp_rate + samp_rate + + + t_scale + 0 + + + title + Scope Plot + + + trig_mode + wxgui.TRIG_MODE_AUTO + + + type + complex + + + v_offset + 0 + + + v_scale + 0 + + + win_size + + + + xy_mode + False + + + y_axis_label + Counts + + + + analog_random_source_x_0 + blocks_int_to_float_0 + 0 + 0 + + + blocks_deinterleave_0 + blocks_float_to_complex_0 + 0 + 0 + + + blocks_deinterleave_0 + blocks_float_to_complex_0 + 1 + 1 + + + blocks_float_to_complex_0 + blocks_throttle_0 + 0 + 0 + + + blocks_int_to_float_0 + blocks_deinterleave_0 + 0 + 0 + + + blocks_throttle_0 + ha5kfu_execproc_xx_0 + 0 + 0 + + + blocks_throttle_0 + wxgui_fftsink2_0_0 + 0 + 0 + + + ha5kfu_execproc_xx_0 + wxgui_fftsink2_0 + 0 + 0 + + + ha5kfu_execproc_xx_0 + wxgui_scopesink2_0 + 0 + 0 + + diff --git a/libcsdr.c b/libcsdr.c index d8e93f3..c62cb5b 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -2009,8 +2009,10 @@ void simple_agc_cc(complexf* input, complexf* output, int input_size, float rate } } -void firdes_add_resonator_c(complexf* output, int length, float rate, window_t window) +void firdes_add_resonator_c(complexf* output, int length, float rate, window_t window, int add, int normalize) { + //add=0: malloc output previously + //add=1: calloc output previously complexf* taps = (complexf*)malloc(sizeof(complexf)*length); int middle=length/2; float phase = 0, phase_addition = -rate*M_PI*2; @@ -2027,20 +2029,25 @@ void firdes_add_resonator_c(complexf* output, int length, float rate, window_t w } //Normalize filter kernel - float sum=0; - for(int i=0;i Date: Tue, 18 Apr 2017 11:22:26 +0200 Subject: [PATCH 068/111] Changed labels in Costas GRC --- grc_tests/test_bpsk_costas_loop.grc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/grc_tests/test_bpsk_costas_loop.grc b/grc_tests/test_bpsk_costas_loop.grc index 82ac291..9d2262e 100644 --- a/grc_tests/test_bpsk_costas_loop.grc +++ b/grc_tests/test_bpsk_costas_loop.grc @@ -1131,7 +1131,7 @@ title - After Costas Loop + BPSK modulated signal after Costas Loop trig_mode @@ -1305,7 +1305,7 @@ title - After BPSK modulator + BPSK modulated signal with frequency offset trig_mode From 82ff09acc023325f4054e2d15885bf3a2c0ded9e Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Thu, 20 Apr 2017 16:48:57 +0200 Subject: [PATCH 069/111] Added RTTY tests --- grc_tests/test_rtty_parts.grc | 746 ++++++++++++++++++++++++++++++++++ 1 file changed, 746 insertions(+) create mode 100644 grc_tests/test_rtty_parts.grc diff --git a/grc_tests/test_rtty_parts.grc b/grc_tests/test_rtty_parts.grc new file mode 100644 index 0000000..fb3ab96 --- /dev/null +++ b/grc_tests/test_rtty_parts.grc @@ -0,0 +1,746 @@ + + + + Mon Oct 13 20:03:23 2014 + + options + + author + + + + window_size + 1280, 1024 + + + category + Custom + + + comment + + + + description + + + + _enabled + True + + + _coordinate + (10, 10) + + + _rotation + 0 + + + generate_options + wx_gui + + + id + top_block + + + max_nouts + 0 + + + realtime_scheduling + + + + run_options + prompt + + + run + True + + + thread_safe_setters + + + + title + + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (184, 11) + + + _rotation + 0 + + + id + samp_rate + + + value + 48e3 + + + + audio_source + + alias + + + + comment + + + + affinity + + + + device_name + + + + _enabled + True + + + _coordinate + (56, 107) + + + _rotation + 0 + + + id + audio_source_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + num_outputs + 1 + + + ok_to_block + True + + + samp_rate + int(samp_rate) + + + + blocks_deinterleave + + alias + + + + blocksize + 1 + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (656, 113) + + + _rotation + 0 + + + id + blocks_deinterleave_0 + + + type + float + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + num_streams + 2 + + + vlen + 1 + + + + blocks_float_to_complex + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (808, 113) + + + _rotation + 0 + + + id + blocks_float_to_complex_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + vlen + 1 + + + + ha5kfu_execproc_xx + + alias + + + + commandline + csdr dsb_fc | csdr shift_addition_cc $(csdr =-2000/48e3) | csdr fir_decimate_cc 48 + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (384, 123) + + + _rotation + 0 + + + id + ha5kfu_execproc_xx_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + ff + + + + ha5kfu_execproc_xx + + alias + + + + commandline + csdr resonators_fir_cc 31 $(csdr =85/1e3) $(csdr =-85/1e3) | CSDR_FIXED_BUFSIZE=128 csdr simple_agc_cc 0.0001 0.5 + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (752, 275) + + + _rotation + 0 + + + id + ha5kfu_execproc_xx_0_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + cc + + + + notebook + + alias + + + + comment + + + + _enabled + True + + + _coordinate + (400, 40) + + + _rotation + 0 + + + grid_pos + + + + id + nb + + + labels + ['input signal', 'decimated', 'filtered', 'tab4'] + + + notebook + + + + style + wx.NB_TOP + + + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (1048, 251) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_0 + + + notebook + nb, 2 + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate/48 + + + title + FFT Plot + + + type + complex + + + win_size + + + + win + None + + + y_divs + 10 + + + y_per_div + 10 + + + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (280, 227) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_0_0 + + + notebook + nb, 0 + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate + + + title + Input signal + + + type + float + + + win_size + + + + win + None + + + y_divs + 10 + + + y_per_div + 10 + + + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (1048, 11) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_0_1 + + + notebook + nb, 1 + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate/48 + + + title + FFT Plot + + + type + complex + + + win_size + + + + win + None + + + y_divs + 10 + + + y_per_div + 10 + + + + audio_source_0 + ha5kfu_execproc_xx_0 + 0 + 0 + + + audio_source_0 + wxgui_fftsink2_0_0 + 0 + 0 + + + blocks_deinterleave_0 + blocks_float_to_complex_0 + 0 + 0 + + + blocks_deinterleave_0 + blocks_float_to_complex_0 + 1 + 1 + + + blocks_float_to_complex_0 + ha5kfu_execproc_xx_0_0 + 0 + 0 + + + blocks_float_to_complex_0 + wxgui_fftsink2_0_1 + 0 + 0 + + + ha5kfu_execproc_xx_0 + blocks_deinterleave_0 + 0 + 0 + + + ha5kfu_execproc_xx_0_0 + wxgui_fftsink2_0 + 0 + 0 + + From 6a5c76f6a4668eae17f2a6f46e67102a6d75e034 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Thu, 20 Apr 2017 16:51:34 +0200 Subject: [PATCH 070/111] Added fft one side --- csdr.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/csdr.c b/csdr.c index d67f099..8035144 100755 --- a/csdr.c +++ b/csdr.c @@ -1660,6 +1660,25 @@ int main(int argc, char *argv[]) } } + if(!strcmp(argv[1],"fft_one_side_ff")) + { + if(argc<=2) return badsyntax("need required parameters (fft_size)"); + int fft_size; + sscanf(argv[2],"%d",&fft_size); + if(!getbufsize()) return -2; + sendbufsize(fft_size); + float* input_buffer_s1 = (float*)malloc(sizeof(float)*fft_size/2); + float* input_buffer_s2 = (float*)malloc(sizeof(float)*fft_size/2); + for(;;) + { + FEOF_CHECK; + fread(input_buffer_s1, sizeof(float), fft_size/2, stdin); + fread(input_buffer_s2, sizeof(float), fft_size/2, stdin); + fwrite(input_buffer_s1, sizeof(float), fft_size/2, stdout); + TRY_YIELD; + } + } + #ifdef USE_IMA_ADPCM From 22bd8baa151490b7c166fe672a0195ebb6c129b2 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Fri, 28 Apr 2017 10:20:13 +0200 Subject: [PATCH 071/111] Added a --octave to help --- csdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csdr.c b/csdr.c index 8035144..1283254 100755 --- a/csdr.c +++ b/csdr.c @@ -125,7 +125,7 @@ char usage[]= " rtty_baudot2ascii_u8_u8\n" " serial_line_decoder_u8_u8\n" " octave_complex_c \n" -" timing_recovery_cc [--add_q]\n" +" timing_recovery_cc [--add_q] [--octave ]\n" " psk31_varicode_encoder_u8_u8\n" " psk31_varicode_decoder_u8_u8\n" " differential_encoder_u8_u8\n" From d391ea2ef62c0d4335b8096a2abd3422a7d9370a Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Fri, 28 Apr 2017 14:20:14 +0200 Subject: [PATCH 072/111] Added BPSK31 S-curve generator script, added repeat_u8 and error output fortiming_recovery_cc --- README.md | 17 ++++++++ csdr.c | 25 ++++++++++-- ...aseband_sample_complex_8000_sps_010101.raw | Bin 0 -> 20608 bytes grc_tests/bpsk31_scurve.m | 38 ++++++++++++++++++ libcsdr.c | 4 +- libcsdr.h | 2 +- 6 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 grc_tests/bpsk31_baseband_sample_complex_8000_sps_010101.raw create mode 100755 grc_tests/bpsk31_scurve.m diff --git a/README.md b/README.md index 90445c3..576e757 100755 --- a/README.md +++ b/README.md @@ -828,6 +828,23 @@ For this input, the output of `psk31_varicode_encoder_u8_u8` will be the followi ---- +### [repeat_u8](#repeat_u8) + +Syntax: + + repeat_u8 [resonator_rate × N]\n" + +It repeatedly outputs a set of data bytes (given with decimal numbers). + +For example, `csdr repeat_u8 1 1 0 0` will output: + +``` +01 01 00 00 01 01 00 00 +01 01 00 00 01 01 00 00 +``` + +---- + ### [?](#search_the_function_list) Syntax: diff --git a/csdr.c b/csdr.c index 1283254..4e3aec8 100755 --- a/csdr.c +++ b/csdr.c @@ -139,6 +139,7 @@ char usage[]= " simple_agc_cc [reference [max_gain]]\n" " firdes_resonator_c [window [--octave]]\n" " resonators_fir_cc [resonator_rate × N]\n" +" repeat_u8 \n" " ?\n" " =\n" " \n" @@ -2516,7 +2517,7 @@ int main(int argc, char *argv[]) } } - if(!strcmp(argv[1],"timing_recovery_cc")) // [--add_q [--octave ]] + if(!strcmp(argv[1],"timing_recovery_cc")) // [--add_q [--output_error | --octave ]] { if(argc<=2) return badsyntax("need required parameter (algorithm)"); timing_recovery_algorithm_t algorithm = timing_recovery_get_algorithm_from_string(argv[2]); @@ -2530,8 +2531,12 @@ int main(int argc, char *argv[]) int add_q = (argc>=5 && !strcmp(argv[4], "--add_q")); int debug_n = 0; + int output_error = 0; if(argc>=7 && !strcmp(argv[5], "--octave")) debug_n = atoi(argv[6]); if(debug_n<0) badsyntax("debug_n should be >= 0"); + if(argc>=6 && !strcmp(argv[5], "--output_error")) output_error = 1; + float* timing_error = NULL; + if(output_error) timing_error = (float*)malloc(sizeof(float)*the_bufsize); if(!initialize_buffers()) return -2; sendbufsize(the_bufsize/decimation); @@ -2546,9 +2551,10 @@ int main(int argc, char *argv[]) { FEOF_CHECK; if(debug_n && ++debug_i%debug_n==0) timing_recovery_trigger_debug(&state, 3); - timing_recovery_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, &state); + timing_recovery_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, timing_error, &state); //fprintf(stderr, "trcc is=%d, os=%d, ip=%d\n",the_bufsize, state.output_size, state.input_processed); - fwrite(output_buffer, sizeof(complexf), state.output_size, stdout); + if(timing_error) fwrite(timing_error, sizeof(float), state.output_size, stdout); + else fwrite(output_buffer, sizeof(complexf), state.output_size, stdout); TRY_YIELD; //fprintf(stderr, "state.input_processed = %d\n", state.input_processed); memmove((complexf*)input_buffer,((complexf*)input_buffer)+state.input_processed,(the_bufsize-state.input_processed)*sizeof(complexf)); //memmove lets the source and destination overlap @@ -2867,6 +2873,19 @@ int main(int argc, char *argv[]) } } + if(!strcmp(argv[1], "repeat_u8")) + { + if(argc<=2) badsyntax("no data to repeat"); + unsigned char* repeat_buffer = (unsigned char*)malloc(sizeof(unsigned char)*(argc-2)); + for(int i=0;i}Z%5#qz1MobpAT!V^^)Wt zS@64`ARqkeYWJli|H!^?&go6Z{Yv^CY5Nid7d3Tt`}ze6t{URHvof5LIxltA>k~#k z2S0Ib{;3Nk<#=2NcXg&PyVx~hY$pmU{ML24K?h2pN3N<9A(V2Vz7?>z9VJCHwL-cF zQ|{q**1%iO(auKQtdIA$q<_ZuwVs{SoQ|I!Y~5@XL_ST%SfN(}snPgJ)@^qHCAnu= z{l+(<;tPwcfo=Th`0`|{enkUHU7KRz1!^)|ul)p?RD`o#Z*>OOw6&Lf19P*s9miqrF1Md`BKbQO< z$K;h*w?6t#o?Cjsa*wt*SKHsZ}IYot4_op>~8l?=HUB2E^3AjkIXAj*0t%fQr5 zqBMEAjJn-f{N=NS@@n6%;&k~Ong2nU=n?XkEG-Vl^-PiXYP~2ze~Xpv`n)9iEq+z@ zpV3?R1->Httm`YjEE*yoWm)1>N`E=y?B7NAsVX4i+sAgvfv|BSqw|tz~6Fv=}t9x%AyJOpGjUEQ6Q4BDRe6mtxpR5%aj79MWvG zD9x)W!>^1H?OXrht=K$P+^W3m9W^9IbgOmK`}W<}#rTM8-WI8`qCE4GcTATFqH5?l zZyhyJgtjj7wi`4_R5%Vx%j zWU7ybozs^kY?yLW{Sa3PX+c0{j$oqY+cj9}qg#Z3&-c*_`2A&w}-Ch?~uTGqHt@F_iBUrVsHP3UcX24MU9vm-ZNJh zh?jDI^3=;;C@yTj>^ZagA0lVk8BgWtMPk2SwkJJcu?X9++q3=bV$tB?29NK&CE{NH zWRD75D(+sL?m3^aRQ&u$l&53gWr8ZgJf)v66Wca5^JMf{F4{Nr^_)ArTtt3ao)yyg zU9liHJIkB!u6TLo#;o{L?~2Q_;<94=6UES8-Lv9{CyHyme6up%PZWP%&(3Tl6UFAW zahd5~C5rYh`(_UK(RrQGs47u>V8uud}8T$LT4)Aq;K72!5 zrhdN{E3z~7`w#E!>wMlM{dxHO#MyDq^+e%%^!4q+_37)KhwIhXAA;-G_fv%X(f5~+ z`_uOu^k0 zR>PT(!tinJ zL)Xha)Qhg47N{RxPg_t=F{rP$s4rb_lTmNF{_3LsbUoUrM_r#?P@lS9eTJQL>bDH_ z%k`}5I~4V;>%9W?uIs-e>R;!f7aYA zY2IB2@0fp@hY8@J=3_AU$h_42Oanieryao8ufW$5@HQ8`y$SxNgTHy;aWr_$e0~MI zUIkt=zx#pbq2PH5_`VH%XWj>a|38BNk?_G{_@EQ~Fdcrl17ECyFW4W?!Y8NT6ZXr8 z@Xbv4raSy|0{&?WABDq5>?iisdH8Dp{KY;CfZuMxZ|pnvANz1O{I~{wq$j>ie&SE| zDf^Xu>w);zk9*wUE%ZfPyEil{~!N5zYoCw1qWjy zwEqjc?CY=nUpV`>0ownCVCc@rk-@vy^pOws31&V22EyV|JxmhCldT`uggm!_}@NKx`I#-_Wbf>g8%KaH{K)o-`;coeM0@% zfBLK>_}@O~_aULa>{^Xe2>!RXHD5*Wzn#+hBZB|!<84Q=jt3H7Ur zgVz%3S(Ub0N2qW0ebe=XdRGC@Y#`LX8d!THArET7!;OS|DEIA61pljpS5gW2QRyX{ z33*bJkA6bPm#W;JM#!6bb!9ri|0-eT7D67C815$IQ{{HuO316a)NmUiziQ2mZG=3l zOD8@h?H6&)$!j&;DgF6-$n4h%HF%1;D6O*)*b>+RB_l| z0$@k9W zR6HFc_(%<_lS}ZEIx;qw;48ItPcFesyAcv3BFWy*W?rYshZ~H6MU*RT+b)?RV}PnK=8jR3N0Y`S1pPxAoyQx zoQBuK6IH;n0)nsA{dENd|0~zd0)o%g_ZbBQzpJ}P@&8qc>WzW|{QjS$y4wGJ&0pv5 z=bz{IEOIH?BXfN3Kt z&JX8_^9BE_P~?sC$9d#@a$ezoC%^E&I*L4VzB%ulfB0Wjfd|Y7<^}VEdBS{Q-oXEA z4*0`7Vm>jim|yU}Isl$A->@5C1#-hyNWP!2gaP;D5&#><{?geh8niU*LboH}JpXANb$#5&MaK z1^?U4;VAkl{~#4F5ZRhW{O3 z!~cbI;BWZ9up4|1{}&v9-{F6={x|D?v;H^hf3yBK>wmNUH|u}1{x|FYr|Sc={x|D? z{k*`e|Er%Lne~75^F*`$uYSI4*8gVz-|YXJ{eQFnZ}$Jq{=eD(H~ar)|KIHYoBjW% z`_pFs-#M>f_W!HTubBORv;VKpvzh&WbN=6)|2OCV&G~nGxbN@K^lXHJLuQ$2>-1Prf|2+bJ nKEcl``1u7t&*0}9{Jg{T|5yM03)BB!{r6Bz|Ns9-|NnmgC4HxD literal 0 HcmV?d00001 diff --git a/grc_tests/bpsk31_scurve.m b/grc_tests/bpsk31_scurve.m new file mode 100755 index 0000000..5e0b3a8 --- /dev/null +++ b/grc_tests/bpsk31_scurve.m @@ -0,0 +1,38 @@ +#!/usr/bin/octave + +%{ +function [output]=fgc(path, type) + if(type(1)=='f') + elseif(type(1)=='c') + end +end +%} + +function output=shrunf(cmd) + SIGTERM=15; + output=[]; + [pin, pout, pid]=popen2('bash',{'-c', cmd}); + %fclose(pin); + sleep(0.1) + do + current_output=fread(pout, Inf, 'float32'); + output=[output; current_output]; + until(feof(pout)) + waitpid(pid); + %kill(pid, SIGTERM); +end + +function error_value=run_tr(skip) + out_vect=shrunf(sprintf('dd bs=8 skip=%d if=grc_tests/bpsk31_baseband_sample_complex_8000_sps_010101.raw | csdr timing_recovery_cc EARLYLATE 256 --add_q --output_error',skip)); + error_value=out_vect(2); +end + +skips=0:400 +error_values=[] +for skip=skips + error_values=[error_values run_tr(skip)]; +end + +error_values +plot(skips, error_values); +pause diff --git a/libcsdr.c b/libcsdr.c index e0a6851..2901331 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -1919,7 +1919,7 @@ void timing_recovery_trigger_debug(timing_recovery_state_t* state, int debug_pha #define MTIMINGR_HDEBUG 0 -void timing_recovery_cc(complexf* input, complexf* output, int input_size, timing_recovery_state_t* state) +void timing_recovery_cc(complexf* input, complexf* output, int input_size, float* timing_error, timing_recovery_state_t* state) { //We always assume that the input starts at center of the first symbol cross before the first symbol. //Last time we consumed that much from the input samples that it is there. @@ -1977,6 +1977,8 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, timin } //Original correction method: this version can only move a single sample in any direction //current_bitstart_index += num_samples_halfbit * 2 + (error)?((error<0)?1:-1):0; + + if(timing_error) timing_error[si-1]=error; //it is not written if NULL if(error>2) error=2; if(error<-2) error=-2; diff --git a/libcsdr.h b/libcsdr.h index 0a0febf..8617282 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -334,7 +334,7 @@ typedef struct timing_recovery_state_s } timing_recovery_state_t; timing_recovery_state_t timing_recovery_init(timing_recovery_algorithm_t algorithm, int decimation_rate, int use_q); -void timing_recovery_cc(complexf* input, complexf* output, int input_length, timing_recovery_state_t* state); +void timing_recovery_cc(complexf* input, complexf* output, int input_size, float* timing_error, timing_recovery_state_t* state); timing_recovery_algorithm_t timing_recovery_get_algorithm_from_string(char* input); char* timing_recovery_get_string_from_algorithm(timing_recovery_algorithm_t algorithm); void timing_recovery_trigger_debug(timing_recovery_state_t* state, int debug_phase); From e31c7648a55928cc59ab33134a6a6ad69cbce634 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Fri, 28 Apr 2017 15:34:14 +0200 Subject: [PATCH 073/111] Added noise_f --- csdr.c | 30 ++ grc_tests/test_noise.grc | 702 +++++++++++++++++++++++++++++++++++++++ libcsdr.c | 18 + libcsdr.h | 5 + 4 files changed, 755 insertions(+) create mode 100644 grc_tests/test_noise.grc diff --git a/csdr.c b/csdr.c index 4e3aec8..686b3b1 100755 --- a/csdr.c +++ b/csdr.c @@ -2877,15 +2877,45 @@ int main(int argc, char *argv[]) { if(argc<=2) badsyntax("no data to repeat"); unsigned char* repeat_buffer = (unsigned char*)malloc(sizeof(unsigned char)*(argc-2)); + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize); //this is really (c-2) but this is a very fast source block so it makes no sense to send out a small number here for(int i=0;i + + + Sun Nov 16 15:12:31 2014 + + options + + author + + + + window_size + 1280, 1024 + + + category + Custom + + + comment + + + + description + + + + _enabled + True + + + _coordinate + (10, 10) + + + _rotation + 0 + + + generate_options + wx_gui + + + id + top_block + + + max_nouts + 0 + + + realtime_scheduling + + + + run_options + prompt + + + run + True + + + thread_safe_setters + + + + title + + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (8, 83) + + + _rotation + 0 + + + id + samp_rate + + + value + 100e3 + + + + analog_const_source_x + + alias + + + + comment + + + + const + 0 + + + affinity + + + + _enabled + True + + + _coordinate + (40, 179) + + + _rotation + 0 + + + id + analog_const_source_x_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + complex + + + + blocks_complex_to_float + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (392, 313) + + + _rotation + 0 + + + id + blocks_complex_to_float_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + vlen + 1 + + + + blocks_throttle + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (216, 179) + + + _rotation + 0 + + + id + blocks_throttle_0 + + + ignoretag + True + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + samples_per_second + 0 + + + type + complex + + + vlen + 1 + + + + blocks_throttle + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (680, 91) + + + _rotation + 0 + + + id + blocks_throttle_0_0 + + + ignoretag + True + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + samples_per_second + samp_rate + + + type + complex + + + vlen + 1 + + + + blocks_throttle + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (800, 331) + + + _rotation + 0 + + + id + blocks_throttle_0_0_0 + + + ignoretag + True + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + samples_per_second + samp_rate + + + type + float + + + vlen + 1 + + + + ha5kfu_execproc_xx + + alias + + + + commandline + csdr noise_f + + + comment + + + + affinity + + + + _enabled + 1 + + + _coordinate + (400, 227) + + + _rotation + 0 + + + id + ha5kfu_execproc_xx_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + cc + + + + ha5kfu_execproc_xx + + alias + + + + commandline + csdr noise_f + + + comment + + + + affinity + + + + _enabled + 1 + + + _coordinate + (568, 307) + + + _rotation + 0 + + + id + ha5kfu_execproc_xx_0_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + ff + + + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (896, 11) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_0_0 + + + notebook + + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate + + + title + FFT Plot + + + type + complex + + + win_size + + + + win + None + + + y_divs + 10 + + + y_per_div + 10 + + + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (976, 259) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_0_0_0 + + + notebook + + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate + + + title + FFT Plot + + + type + float + + + win_size + + + + win + None + + + y_divs + 10 + + + y_per_div + 10 + + + + analog_const_source_x_0 + blocks_throttle_0 + 0 + 0 + + + blocks_complex_to_float_0 + ha5kfu_execproc_xx_0_0 + 0 + 0 + + + blocks_throttle_0 + blocks_complex_to_float_0 + 0 + 0 + + + blocks_throttle_0 + ha5kfu_execproc_xx_0 + 0 + 0 + + + blocks_throttle_0_0 + wxgui_fftsink2_0_0 + 0 + 0 + + + blocks_throttle_0_0_0 + wxgui_fftsink2_0_0_0 + 0 + 0 + + + ha5kfu_execproc_xx_0 + blocks_throttle_0_0 + 0 + 0 + + + ha5kfu_execproc_xx_0_0 + blocks_throttle_0_0_0 + 0 + 0 + + diff --git a/libcsdr.c b/libcsdr.c index 2901331..0f97fc6 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -2249,6 +2249,24 @@ void convert_s24_f(unsigned char* input, float* output, int input_size, int bige } } +FILE* init_get_awgn_samples_f() +{ + return fopen("/dev/urandom", "r"); +} + +void get_awgn_samples_f(float* output, int output_size, FILE* status) +{ + int* pioutput = (int*)output; + fread((unsigned char*)output, sizeof(float), output_size, status); + for(int i=0;i Date: Fri, 28 Apr 2017 19:34:55 +0200 Subject: [PATCH 074/111] Added agwn_cc --- README.md | 34 +- csdr.c | 46 ++- grc_tests/test_awgn.grc | 669 ++++++++++++++++++++++++++++++++++++++++ libcsdr.c | 56 +++- libcsdr.h | 9 +- 5 files changed, 799 insertions(+), 15 deletions(-) create mode 100644 grc_tests/test_awgn.grc diff --git a/README.md b/README.md index 576e757..6da9ce1 100755 --- a/README.md +++ b/README.md @@ -832,7 +832,7 @@ For this input, the output of `psk31_varicode_encoder_u8_u8` will be the followi Syntax: - repeat_u8 [resonator_rate × N]\n" + csdr repeat_u8 [resonator_rate × N]\n" It repeatedly outputs a set of data bytes (given with decimal numbers). @@ -845,6 +845,28 @@ For example, `csdr repeat_u8 1 1 0 0` will output: ---- +### [noise_f](#noise_f) + +Syntax: + + csdr noise_f + +It outputs white noise within the range [-1.0, 1.0]. + +---- + +### [awgn_cc](#awgn_cc) + +Syntax: + + csdr awgn_cc [--snrshow] + +It adds white noise with the given SNR to a signal assumed to be of 0 dB power. + +If the `--snrshow` switch is given, it also shows the actual SNR based on the calculated power of signal and noise components. + +---- + ### [?](#search_the_function_list) Syntax: @@ -879,6 +901,16 @@ Another solution is using single quotes to wrap the expression: csdr shift_addition_cc $(csdr '=(1200+300)/2400000.') +Current version of `csdr` executes the following python script for this function: + +```python +import os, sys +from math import * +print +``` + +This means that one can also call math functions like `sqrt()`. + #### Control via pipes Some parameters can be changed while the `csdr` process is running. To achieve this, some `csdr` functions have special parameters. You have to supply a fifo previously created by the `mkfifo` command. Processing will only start after the first control command has been received by `csdr` over the FIFO. diff --git a/csdr.c b/csdr.c index 686b3b1..7842726 100755 --- a/csdr.c +++ b/csdr.c @@ -140,6 +140,8 @@ char usage[]= " firdes_resonator_c [window [--octave]]\n" " resonators_fir_cc [resonator_rate × N]\n" " repeat_u8 \n" +" noise_f\n" +" awgn_cc [--snrshow]\n" " ?\n" " =\n" " \n" @@ -2892,25 +2894,55 @@ int main(int argc, char *argv[]) if(!strcmp(argv[1], "awgn_cc")) { - if(argc<=2) badsyntax("no data to repeat"); + FILE* urandom = init_get_random_samples_f(); + if(argc<=2) badsyntax("required parameter is missing."); float snr_db = 0; sscanf(argv[2],"%f",&snr_db); + int snrshow = 0; + if(argc>=4 && !strcmp(argv[3],"--snrshow")) snrshow = 1; float signal_amplitude_per_noise = pow(10,snr_db/20); float a_signal=signal_amplitude_per_noise/(signal_amplitude_per_noise+1.0); float a_noise=1.0/(signal_amplitude_per_noise+1.0); - - + fprintf(stderr, "csdr awgn_cc: a_signal = %f, a_noise = %f\n", a_signal, a_noise); + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize); + complexf* awgn_buffer = (complexf*)malloc(sizeof(complexf)*the_bufsize); + for(;;) + { + FEOF_CHECK; + FREAD_C; + //get_awgn_samples_f((float*)awgn_buffer, the_bufsize*2, urandom); + get_random_gaussian_samples_c(awgn_buffer, the_bufsize, urandom); + /*if(snrshow) + { + float power_signal = total_logpower_cf((complexf*)input_buffer, the_bufsize); + float power_noise = total_logpower_cf(awgn_buffer, the_bufsize); + fprintf(stderr, "csdr awgn_cc: at the beginning, power_signal = %f dB, power_noise = %f dB\n", power_signal, power_noise); + }*/ + gain_ff(input_buffer, input_buffer, the_bufsize*2, a_signal); + gain_ff((float*)awgn_buffer, (float*)awgn_buffer, the_bufsize*2, a_noise*0.707); + if(snrshow) + { + float power_signal = total_logpower_cf((complexf*)input_buffer, the_bufsize); + float power_noise = total_logpower_cf(awgn_buffer, the_bufsize); + //fprintf(stderr, "csdr awgn_cc: after gain_ff, power_signal = %f dB, power_noise = %f dB\n", power_signal, power_noise); + fprintf(stderr, "csdr awgn_cc: SNR = %f dB\n", power_signal - power_noise); + } + add_ff(input_buffer, (float*)awgn_buffer, (float*)output_buffer, the_bufsize*2); + FWRITE_C; + TRY_YIELD; + } } - if(!strcmp(argv[1], "noise_f")) + if(!strcmp(argv[1], "uniform_noise_f")) { - FILE* urandom = init_get_awgn_samples_f(); + FILE* urandom = init_get_random_samples_f(); if(!initialize_buffers()) return -2; sendbufsize(the_bufsize); for(;;) { FEOF_CHECK; - get_awgn_samples_f(output_buffer, the_bufsize, urandom); + get_random_samples_f(output_buffer, the_bufsize, urandom); FWRITE_R; TRY_YIELD; } @@ -2933,7 +2965,7 @@ int main(int argc, char *argv[]) if(argv[1][0]=='=') { char buffer[100]; - snprintf(buffer, 100-1, "python -c \"print %s\"", argv[1]+1); + snprintf(buffer, 100-1, "python -c \"import os, sys\nfrom math import *\nprint %s\"", argv[1]+1); system(buffer); return 0; } diff --git a/grc_tests/test_awgn.grc b/grc_tests/test_awgn.grc new file mode 100644 index 0000000..a55b924 --- /dev/null +++ b/grc_tests/test_awgn.grc @@ -0,0 +1,669 @@ + + + + Sun Nov 16 15:12:31 2014 + + options + + author + + + + window_size + 1280, 1024 + + + category + Custom + + + comment + + + + description + + + + _enabled + True + + + _coordinate + (10, 10) + + + _rotation + 0 + + + generate_options + wx_gui + + + id + top_block + + + max_nouts + 0 + + + realtime_scheduling + + + + run_options + prompt + + + run + True + + + thread_safe_setters + + + + title + + + + + variable_slider + + comment + + + + converver + float_converter + + + value + 1 + + + _enabled + True + + + _coordinate + (120, 147) + + + _rotation + 0 + + + grid_pos + + + + id + amplitude + + + label + + + + max + 2 + + + min + 0 + + + notebook + + + + num_steps + 100 + + + style + wx.SL_HORIZONTAL + + + + variable_slider + + comment + + + + converver + float_converter + + + value + 0 + + + _enabled + True + + + _coordinate + (8, 147) + + + _rotation + 0 + + + grid_pos + + + + id + frequency + + + label + + + + max + samp_rate/2 + + + min + -samp_rate/2 + + + notebook + + + + num_steps + 100 + + + style + wx.SL_HORIZONTAL + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (8, 83) + + + _rotation + 0 + + + id + samp_rate + + + value + 40e3 + + + + analog_sig_source_x + + amp + 1 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + freq + frequency + + + _coordinate + (184, 11) + + + _rotation + 0 + + + id + analog_sig_source_x_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + offset + 0 + + + type + complex + + + samp_rate + samp_rate + + + waveform + analog.GR_COS_WAVE + + + + blocks_multiply_const_vxx + + alias + + + + comment + + + + const + amplitude + + + affinity + + + + _enabled + True + + + _coordinate + (344, 43) + + + _rotation + 0 + + + id + blocks_multiply_const_vxx_0 + + + type + complex + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + vlen + 1 + + + + blocks_throttle + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (496, 43) + + + _rotation + 0 + + + id + blocks_throttle_0_0 + + + ignoretag + True + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + samples_per_second + samp_rate + + + type + complex + + + vlen + 1 + + + + ha5kfu_execproc_xx + + alias + + + + commandline + csdr awgn_cc 10 --snrshow + + + comment + + + + affinity + + + + _enabled + 1 + + + _coordinate + (344, 275) + + + _rotation + 0 + + + id + ha5kfu_execproc_xx_0_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + cc + + + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (616, 203) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_0_0 + + + notebook + + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate + + + title + FFT Plot + + + type + complex + + + win_size + + + + win + None + + + y_divs + 10 + + + y_per_div + 10 + + + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (856, 75) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_0_0_0 + + + notebook + + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate + + + title + FFT Plot + + + type + complex + + + win_size + + + + win + None + + + y_divs + 10 + + + y_per_div + 10 + + + + analog_sig_source_x_0 + blocks_multiply_const_vxx_0 + 0 + 0 + + + blocks_multiply_const_vxx_0 + blocks_throttle_0_0 + 0 + 0 + + + blocks_throttle_0_0 + ha5kfu_execproc_xx_0_0 + 0 + 0 + + + blocks_throttle_0_0 + wxgui_fftsink2_0_0_0 + 0 + 0 + + + ha5kfu_execproc_xx_0_0 + wxgui_fftsink2_0_0 + 0 + 0 + + diff --git a/libcsdr.c b/libcsdr.c index 0f97fc6..304870c 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -1306,6 +1306,12 @@ void log_ff(float* input, float* output, int size, float add_db) { for(int i=0;i1); + iof(output, i)=(1/0.82)*iof(output, i); + qof(output, i)=(1/0.82)*qof(output, i); + } +} +*/ + + +int deinit_get_random_samples_f(FILE* status) { return fclose(status); } +float* add_ff(float* input1, float* input2, float* output, int input_size) +{ + for(int i=0;i Date: Sat, 29 Apr 2017 11:43:54 +0200 Subject: [PATCH 075/111] Better font for S-curve graph --- grc_tests/bpsk31_scurve.m | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/grc_tests/bpsk31_scurve.m b/grc_tests/bpsk31_scurve.m index 5e0b3a8..dc0bab4 100755 --- a/grc_tests/bpsk31_scurve.m +++ b/grc_tests/bpsk31_scurve.m @@ -23,16 +23,28 @@ function output=shrunf(cmd) end function error_value=run_tr(skip) - out_vect=shrunf(sprintf('dd bs=8 skip=%d if=grc_tests/bpsk31_baseband_sample_complex_8000_sps_010101.raw | csdr timing_recovery_cc EARLYLATE 256 --add_q --output_error',skip)); + out_vect=shrunf(sprintf('dd bs=8 skip=%d if=bpsk31_baseband_sample_complex_8000_sps_010101.raw | csdr timing_recovery_cc EARLYLATE 256 --add_q --output_error',skip)); error_value=out_vect(2); end -skips=0:400 +skips=0:256; error_values=[] for skip=skips error_values=[error_values run_tr(skip)]; end error_values -plot(skips, error_values); + +%graphics_toolkit("gnuplot") +h=figure(1); +plot(skips, error_values, 'linewidth', 2); +xlabel('Phase offset in number of samples'); +ylabel('Error value (TED output)'); + +FN = findall(h,'-property','FontName'); +set(FN,'FontName','/usr/share/fonts/truetype/ttf-dejavu/DejaVuSerifCondensed.ttf'); +set(FN,'FontName','times'); +FS = findall(h,'-property','FontSize'); +set(FS,'FontSize',18); + pause From a9dc49c8d91086d5928680d547a09a99b2f855a0 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sat, 29 Apr 2017 12:28:56 +0200 Subject: [PATCH 076/111] Added S-curve for Gardner --- csdr.c | 12 +++++----- grc_tests/bpsk31_scurve.m | 47 ++++++++++++++++++++++++++------------- 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/csdr.c b/csdr.c index 7842726..98e3604 100755 --- a/csdr.c +++ b/csdr.c @@ -2523,8 +2523,8 @@ int main(int argc, char *argv[]) { if(argc<=2) return badsyntax("need required parameter (algorithm)"); timing_recovery_algorithm_t algorithm = timing_recovery_get_algorithm_from_string(argv[2]); - if(algorithm == TIMING_RECOVERY_ALGORITHM_DEFAULT) - fprintf(stderr,"#timing_recovery_cc: algorithm = %s\n",timing_recovery_get_string_from_algorithm(algorithm)); + //if(algorithm == TIMING_RECOVERY_ALGORITHM_DEFAULT) + // fprintf(stderr,"#timing_recovery_cc: algorithm = %s\n",timing_recovery_get_string_from_algorithm(algorithm)); if(argc<=3) return badsyntax("need required parameter (decimation factor)"); int decimation; sscanf(argv[3],"%d",&decimation); @@ -2533,12 +2533,12 @@ int main(int argc, char *argv[]) int add_q = (argc>=5 && !strcmp(argv[4], "--add_q")); int debug_n = 0; - int output_error = 0; + int output_error = 0; if(argc>=7 && !strcmp(argv[5], "--octave")) debug_n = atoi(argv[6]); if(debug_n<0) badsyntax("debug_n should be >= 0"); - if(argc>=6 && !strcmp(argv[5], "--output_error")) output_error = 1; - float* timing_error = NULL; - if(output_error) timing_error = (float*)malloc(sizeof(float)*the_bufsize); + if(argc>=6 && !strcmp(argv[5], "--output_error")) output_error = 1; + float* timing_error = NULL; + if(output_error) timing_error = (float*)malloc(sizeof(float)*the_bufsize); if(!initialize_buffers()) return -2; sendbufsize(the_bufsize/decimation); diff --git a/grc_tests/bpsk31_scurve.m b/grc_tests/bpsk31_scurve.m index dc0bab4..a1cfac2 100755 --- a/grc_tests/bpsk31_scurve.m +++ b/grc_tests/bpsk31_scurve.m @@ -20,31 +20,46 @@ function output=shrunf(cmd) until(feof(pout)) waitpid(pid); %kill(pid, SIGTERM); + fclose(pin); + fclose(pout); end -function error_value=run_tr(skip) - out_vect=shrunf(sprintf('dd bs=8 skip=%d if=bpsk31_baseband_sample_complex_8000_sps_010101.raw | csdr timing_recovery_cc EARLYLATE 256 --add_q --output_error',skip)); +function error_value=run_tr(skip, which_ted) + out_vect=shrunf(sprintf('dd bs=8 skip=%d if=bpsk31_baseband_sample_complex_8000_sps_010101.raw | csdr timing_recovery_cc %s 256 --add_q --output_error', skip, which_ted)); error_value=out_vect(2); end -skips=0:256; -error_values=[] -for skip=skips - error_values=[error_values run_tr(skip)]; +function error_values=mkscurve(which_ted, skips) + error_values=[] + for skip=skips + error_values=[error_values run_tr(skip, which_ted)]; + end end -error_values +function fmtplot(h) + FN = findall(h,'-property','FontName'); + set(FN,'FontName','/usr/share/fonts/truetype/ttf-dejavu/DejaVuSerifCondensed.ttf'); + set(FN,'FontName','times'); + FS = findall(h,'-property','FontSize'); + set(FS,'FontSize',18); + xlabel('Phase offset in number of samples'); + ylabel('Error value (TED output)'); +end + +skips_gardner=0:256 +error_values_gardner=mkscurve('GARDNER',skips_gardner); +skips_earlylate=0:256 +error_values_earlylate=mkscurve('EARLYLATE',skips_earlylate); %graphics_toolkit("gnuplot") h=figure(1); -plot(skips, error_values, 'linewidth', 2); -xlabel('Phase offset in number of samples'); -ylabel('Error value (TED output)'); - -FN = findall(h,'-property','FontName'); -set(FN,'FontName','/usr/share/fonts/truetype/ttf-dejavu/DejaVuSerifCondensed.ttf'); -set(FN,'FontName','times'); -FS = findall(h,'-property','FontSize'); -set(FS,'FontSize',18); +plot(skips_gardner, error_values_gardner, 'linewidth', 2); +title('S-curve for Gardner TED'); +fmtplot(h) +pause + +plot(skips_earlylate, error_values_earlylate, 'linewidth', 2); +title('S-curve for early-late TED'); +fmtplot(h) pause From 80ee1645eccd97915a5352d84b2a9aa490af4690 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sat, 29 Apr 2017 18:10:53 +0200 Subject: [PATCH 077/111] Added normalized_timing_variance_u32_f, ??, etc. --- README.md | 36 ++++++++++++++++++++++++++ csdr.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++------ libcsdr.c | 28 +++++++++++++++++++- libcsdr.h | 3 ++- 4 files changed, 133 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 6da9ce1..55349ef 100755 --- a/README.md +++ b/README.md @@ -855,6 +855,32 @@ It outputs white noise within the range [-1.0, 1.0]. ---- +### [pack_bits_8to1_u8_u8](#pack_bits_8to1_u8_u8) + +Syntax: + + csdr pack_bits_8to1_u8_u8 + +It serializes the bytes on the input: it outputs each bit of the input byte as a single byte valued 0x00 or 0x01, starting from the lowest bit and going to the highest bit. + +The output is 8 times as large in size as the input. + +For example, the input byte 0x43 will result in eight bytes at the output: + +``` +01 01 00 00 00 00 01 00 +``` + +For consequtive 0x02, 0x03, 0xff bytes on the input, the output will be: + +``` +00 01 00 00 00 00 00 00 +01 01 00 00 00 00 00 00 +01 01 01 01 01 01 01 01 +``` + +---- + ### [awgn_cc](#awgn_cc) Syntax: @@ -867,6 +893,16 @@ If the `--snrshow` switch is given, it also shows the actual SNR based on the ca ---- +### [add_n_zero_samples_at_beginning_f](#add_n_zero_samples_at_beginning_f) + +Syntax: + + csdr add_n_zero_samples_at_beginning_f + +When the function is executed, it furst writes `` 32-bit floating point zeros at the output, after that it just clones the input at the output. + +---- + ### [?](#search_the_function_list) Syntax: diff --git a/csdr.c b/csdr.c index 98e3604..069a6db 100755 --- a/csdr.c +++ b/csdr.c @@ -75,7 +75,6 @@ char usage[]= " yes_f [buf_times]\n" " detect_nan_ff\n" " dump_f\n" -" flowcontrol [prebuffer_sec] [thrust]\n" " shift_math_cc \n" " shift_math_cc --fifo \n" " shift_addition_cc \n" @@ -125,7 +124,7 @@ char usage[]= " rtty_baudot2ascii_u8_u8\n" " serial_line_decoder_u8_u8\n" " octave_complex_c \n" -" timing_recovery_cc [--add_q] [--octave ]\n" +" timing_recovery_cc [--add_q [--output_error | --output_indexes | --octave ]] \n" " psk31_varicode_encoder_u8_u8\n" " psk31_varicode_decoder_u8_u8\n" " differential_encoder_u8_u8\n" @@ -142,6 +141,8 @@ char usage[]= " repeat_u8 \n" " noise_f\n" " awgn_cc [--snrshow]\n" +" pack_bits_8to1_u8_u8\n" +" add_n_zero_samples_at_beginning_f \n" " ?\n" " =\n" " \n" @@ -2519,7 +2520,7 @@ int main(int argc, char *argv[]) } } - if(!strcmp(argv[1],"timing_recovery_cc")) // [--add_q [--output_error | --octave ]] + if(!strcmp(argv[1],"timing_recovery_cc")) // [--add_q [--output_error | --output_indexes | --octave ]] { if(argc<=2) return badsyntax("need required parameter (algorithm)"); timing_recovery_algorithm_t algorithm = timing_recovery_get_algorithm_from_string(argv[2]); @@ -2534,12 +2535,18 @@ int main(int argc, char *argv[]) int debug_n = 0; int output_error = 0; + int output_indexes = 0; if(argc>=7 && !strcmp(argv[5], "--octave")) debug_n = atoi(argv[6]); if(debug_n<0) badsyntax("debug_n should be >= 0"); - if(argc>=6 && !strcmp(argv[5], "--output_error")) output_error = 1; + + if(argc>=6 && !strcmp(argv[5], "--output_error")) output_error = 1; float* timing_error = NULL; if(output_error) timing_error = (float*)malloc(sizeof(float)*the_bufsize); + if(argc>=6 && !strcmp(argv[5], "--output_indexes")) output_indexes = 1; + unsigned* sampled_indexes = NULL; + if(output_indexes) sampled_indexes = (unsigned*)malloc(sizeof(float)*the_bufsize); + if(!initialize_buffers()) return -2; sendbufsize(the_bufsize/decimation); @@ -2549,16 +2556,23 @@ int main(int argc, char *argv[]) state.debug_writefiles = 1; state.debug_force = !!debug_n; //should remove that later FREAD_C; + unsigned buffer_start_counter = 0; for(;;) { FEOF_CHECK; if(debug_n && ++debug_i%debug_n==0) timing_recovery_trigger_debug(&state, 3); - timing_recovery_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, timing_error, &state); + timing_recovery_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, timing_error, (int*)sampled_indexes, &state); //fprintf(stderr, "trcc is=%d, os=%d, ip=%d\n",the_bufsize, state.output_size, state.input_processed); if(timing_error) fwrite(timing_error, sizeof(float), state.output_size, stdout); + else if(sampled_indexes) + { + for(int i=0;i + { + int samples_per_symbol = 0; + if(argc<=2) badsyntax("required parameter is missing."); + sscanf(argv[2],"%d",&samples_per_symbol); + + int initial_sample_offset = 0; + if(argc<=3) badsyntax("required parameter is missing."); + sscanf(argv[3],"%d",&initial_sample_offset); + + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize); + float* temp_buffer = (float*)malloc(sizeof(float)*the_bufsize); + for(;;) + { + FEOF_CHECK; + FREAD_R; //doesn't count, reads 4 bytes per sample anyway + float nv = normalized_timing_variance_u32_f((unsigned*)input_buffer, temp_buffer, the_bufsize, samples_per_symbol, initial_sample_offset); + fwrite(&nv, sizeof(float), 1, stdout); + fprintf(stderr, "csdr normalized_timing_variance_u32_f: normalized variance = %f\n", nv); + FWRITE_R; + TRY_YIELD; + } + } + + if(!strcmp(argv[1], "add_n_zero_samples_at_beginning_f")) // + { + int n_zero_samples = 0; + if(argc<=2) badsyntax("required parameter is missing."); + sscanf(argv[2],"%d",&n_zero_samples); + if(!sendbufsize(initialize_buffers())) return -2; + float* zeros=(float*)calloc(sizeof(float),n_zero_samples); + fwrite(zeros, sizeof(float), n_zero_samples, stdout); + clone_(the_bufsize); + } + + if(!strcmp(argv[1],"none")) { return 0; } + if(argv[1][0]=='?' && argv[1][1]=='?') + { + char buffer[1000]; + snprintf(buffer, 1000-1, "xdg-open https://github.com/simonyiszk/csdr/blob/master/README.md#$(csdr ?%s | head -n1 | awk '{print $1;}')", argv[1]+2); + fprintf(stderr, "csdr ??: %s\n", buffer); + system(buffer); + return 0; + } + if(argv[1][0]=='?') { - char buffer[100]; - snprintf(buffer, 100-1, "csdr 2>&1 | grep %s", argv[1]+1); + char buffer[1000]; + snprintf(buffer, 1000-1, "csdr 2>&1 | grep %s", argv[1]+1); fprintf(stderr, "csdr ?: %s\n", buffer); system(buffer); return 0; diff --git a/libcsdr.c b/libcsdr.c index 304870c..5503e37 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -1925,7 +1925,7 @@ void timing_recovery_trigger_debug(timing_recovery_state_t* state, int debug_pha #define MTIMINGR_HDEBUG 0 -void timing_recovery_cc(complexf* input, complexf* output, int input_size, float* timing_error, timing_recovery_state_t* state) +void timing_recovery_cc(complexf* input, complexf* output, int input_size, float* timing_error, int* sampled_indexes, timing_recovery_state_t* state) { //We always assume that the input starts at center of the first symbol cross before the first symbol. //Last time we consumed that much from the input samples that it is there. @@ -1963,6 +1963,7 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, float el_point_right_index = current_bitstart_index + num_samples_earlylate_wing * 3; el_point_left_index = current_bitstart_index + num_samples_earlylate_wing * 1 - correction_offset; el_point_mid_index = current_bitstart_index + num_samples_halfbit; + if(sampled_indexes) sampled_indexes[si]=el_point_mid_index; output[si++] = input[el_point_mid_index]; } else if(state->algorithm == TIMING_RECOVERY_ALGORITHM_GARDNER) @@ -1971,6 +1972,7 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, float el_point_right_index = current_bitstart_index + num_samples_halfbit * 3; el_point_left_index = current_bitstart_index + num_samples_halfbit * 1; el_point_mid_index = current_bitstart_index + num_samples_halfbit * 2; + if(sampled_indexes) sampled_indexes[si]=el_point_left_index; output[si++] = input[el_point_left_index]; } else break; @@ -2167,7 +2169,31 @@ int apply_fir_cc(complexf* input, complexf* output, int input_size, complexf* ta return i; } +float normalized_timing_variance_u32_f(unsigned* input, float* temp, int input_size, int samples_per_symbol, int initial_sample_offset) +{ + float *ndiff_rad = temp; + float ndiff_rad_mean = 0; + for(int i=0;isamples_per_symbol/2) sinearest++; + unsigned sicorrect = initial_sample_offset+(sinearest*samples_per_symbol); //the sample offset which input[i] should have been, in order to sample at the maximum effect point + int sidiff = abs(sicorrect-input[i]); + float ndiff = sidiff/samples_per_symbol; + fprintf(stderr, "ndiff = %f\n", ndiff); + ndiff_rad[i] = ndiff*PI; + ndiff_rad_mean = ndiff_rad_mean*(((float)i-1)/i)+(ndiff_rad[i]/i); + } + fprintf(stderr, "ndiff_rad_mean = %f\n", ndiff_rad_mean); + + float result = 0; + for(int i=0;i Date: Sat, 29 Apr 2017 22:48:43 +0200 Subject: [PATCH 078/111] Added tedvar Octave script --- csdr.c | 1 - grc_tests/bpsk31_tedvar.m | 83 +++++++++++++++++++++++++++++++++++++++ libcsdr.c | 14 +++---- 3 files changed, 90 insertions(+), 8 deletions(-) create mode 100755 grc_tests/bpsk31_tedvar.m diff --git a/csdr.c b/csdr.c index 069a6db..11a2336 100755 --- a/csdr.c +++ b/csdr.c @@ -2982,7 +2982,6 @@ int main(int argc, char *argv[]) float nv = normalized_timing_variance_u32_f((unsigned*)input_buffer, temp_buffer, the_bufsize, samples_per_symbol, initial_sample_offset); fwrite(&nv, sizeof(float), 1, stdout); fprintf(stderr, "csdr normalized_timing_variance_u32_f: normalized variance = %f\n", nv); - FWRITE_R; TRY_YIELD; } } diff --git a/grc_tests/bpsk31_tedvar.m b/grc_tests/bpsk31_tedvar.m new file mode 100755 index 0000000..07cd03f --- /dev/null +++ b/grc_tests/bpsk31_tedvar.m @@ -0,0 +1,83 @@ +#!/usr/bin/octave + +%you need to first install the parallel and struct packages: +%pkg install -forge struct +%pkg install -forge parallel +pkg load parallel + +system('cat /dev/urandom | csdr pack_bits_8to1_u8_u8 | csdr psk_modulator_u8_c 2 | csdr gain_ff 0.25 | csdr psk31_interpolate_sine_cc 256 | csdr add_n_zero_samples_at_beginning_f 170 | dd bs=32M count=1 of=/tmp/psk31-raw-data'); + +function output=shrun(cmd, type, minsize) + SIGTERM=15; + output=[]; + cmd + [pin, pout, pid]=popen2('bash',{'-c', cmd}); + %fclose(pin); + do + sleep(0.3) + disp('size(output)'); + %size(output) + %output + current_output=fread(pout, Inf, type) + frewind(pout) + output=[output; current_output]; + until(size(output)(1)>=minsize) + waitpid(pid); + kill(pid, SIGTERM); + fclose(pin); + fclose(pout); +end + +function variance=run_var(snr, which_ted) + disp('ran a command') + out_vect=shrun(sprintf('cat /tmp/psk31-raw-data | csdr awgn_cc %d | csdr timing_recovery_cc %s 256 --add_q --output_indexes | CSDR_FIXED_BUFSIZE=65536 csdr normalized_timing_variance_u32_f 256 85', snr, which_ted), 'float32', 1); + disp('run_var output:'); + out_vect' + variance=out_vect(1); +end + +function variances=mkvarplot(which_ted, snrs) + %{ + fun = @(x) run_var(x, which_ted); + variances=pararrayfun(nproc, fun, snrs); + %} + variances=[] + for snr=snrs + snr + variances=[variances run_var(snr, which_ted)]; + end +end + +function fmtplot(h) + FN = findall(h,'-property','FontName'); + set(FN,'FontName','/usr/share/fonts/truetype/ttf-dejavu/DejaVuSerifCondensed.ttf'); + set(FN,'FontName','times'); + FS = findall(h,'-property','FontSize'); + set(FS,'FontSize',18); + xlabel('Phase offset in number of samples'); + ylabel('Error value (TED output)'); +end + +snrs_gardner=-30:5:40 +error_values_gardner=mkvarplot('GARDNER',snrs_gardner); +%{ +snrs_earlylate=0:256 +error_values_earlylate=mkvarplot('EARLYLATE',snrs_earlylate); +%} + +%graphics_toolkit("gnuplot") +h=figure(1); + +semilogy(snrs_gardner, error_values_gardner, 'linewidth', 2); +title('S-curve for Gardner TED'); +fmtplot(h) +pause + +%{ +semilogy(snrs_earlylate, error_values_earlylate, 'linewidth', 2); +title('S-curve for early-late TED'); +fmtplot(h) +pause +%} + +system('rm /tmp/psk31-raw-data'); diff --git a/libcsdr.c b/libcsdr.c index 5503e37..7be06db 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -2179,19 +2179,19 @@ float normalized_timing_variance_u32_f(unsigned* input, float* temp, int input_s unsigned sinearest = (input[i]-initial_sample_offset) / samples_per_symbol; unsigned sinearest_remain = (input[i]-initial_sample_offset) % samples_per_symbol; if(sinearest_remain>samples_per_symbol/2) sinearest++; - unsigned sicorrect = initial_sample_offset+(sinearest*samples_per_symbol); //the sample offset which input[i] should have been, in order to sample at the maximum effect point - int sidiff = abs(sicorrect-input[i]); - float ndiff = sidiff/samples_per_symbol; + unsigned socorrect = initial_sample_offset+(sinearest*samples_per_symbol); //the sample offset which input[i] should have been, in order to sample at the maximum effect point + int sodiff = abs(socorrect-input[i]); + float ndiff = (float)sodiff/samples_per_symbol; - fprintf(stderr, "ndiff = %f\n", ndiff); ndiff_rad[i] = ndiff*PI; - ndiff_rad_mean = ndiff_rad_mean*(((float)i-1)/i)+(ndiff_rad[i]/i); + ndiff_rad_mean = ndiff_rad_mean*(((float)i)/(i+1))+(ndiff_rad[i]/(i+1)); + //fprintf(stderr, "input[%d] = %u, sinearest = %u, socorrect = %u, sodiff = %u, ndiff = %f, ndiff_rad[i] = %f, ndiff_rad_mean = %f\n", i, input[i], sinearest, socorrect, sodiff, ndiff, ndiff_rad[i], ndiff_rad_mean); } - fprintf(stderr, "ndiff_rad_mean = %f\n", ndiff_rad_mean); + //fprintf(stderr, "ndiff_rad_mean = %f\n", ndiff_rad_mean); float result = 0; for(int i=0;i Date: Sat, 29 Apr 2017 23:27:39 +0200 Subject: [PATCH 079/111] We process a higher amount of data --- grc_tests/bpsk31_tedvar.m | 23 ++++++++++++----------- libcsdr.c | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/grc_tests/bpsk31_tedvar.m b/grc_tests/bpsk31_tedvar.m index 07cd03f..2050b47 100755 --- a/grc_tests/bpsk31_tedvar.m +++ b/grc_tests/bpsk31_tedvar.m @@ -5,7 +5,7 @@ %pkg install -forge parallel pkg load parallel -system('cat /dev/urandom | csdr pack_bits_8to1_u8_u8 | csdr psk_modulator_u8_c 2 | csdr gain_ff 0.25 | csdr psk31_interpolate_sine_cc 256 | csdr add_n_zero_samples_at_beginning_f 170 | dd bs=32M count=1 of=/tmp/psk31-raw-data'); +system('cat /dev/urandom | csdr pack_bits_8to1_u8_u8 | csdr psk_modulator_u8_c 2 | csdr gain_ff 0.25 | csdr psk31_interpolate_sine_cc 256 | csdr add_n_zero_samples_at_beginning_f 170 | dd iflag=fullblock bs=4M count=1 of=/tmp/psk31-raw-data'); function output=shrun(cmd, type, minsize) SIGTERM=15; @@ -15,11 +15,11 @@ function output=shrun(cmd, type, minsize) %fclose(pin); do sleep(0.3) - disp('size(output)'); + fwrite(stdout,'.'); %size(output) %output - current_output=fread(pout, Inf, type) - frewind(pout) + current_output=fread(pout, Inf, type); + frewind(pout); output=[output; current_output]; until(size(output)(1)>=minsize) waitpid(pid); @@ -30,22 +30,22 @@ end function variance=run_var(snr, which_ted) disp('ran a command') - out_vect=shrun(sprintf('cat /tmp/psk31-raw-data | csdr awgn_cc %d | csdr timing_recovery_cc %s 256 --add_q --output_indexes | CSDR_FIXED_BUFSIZE=65536 csdr normalized_timing_variance_u32_f 256 85', snr, which_ted), 'float32', 1); + out_vect=shrun(sprintf('cat /tmp/psk31-raw-data | csdr awgn_cc %d --snrshow-no| csdr timing_recovery_cc %s 256 --add_q --output_indexes | CSDR_FIXED_BUFSIZE=131072 csdr normalized_timing_variance_u32_f 256 85', snr, which_ted), 'float32', 1); disp('run_var output:'); out_vect' variance=out_vect(1); end function variances=mkvarplot(which_ted, snrs) - %{ fun = @(x) run_var(x, which_ted); variances=pararrayfun(nproc, fun, snrs); - %} + %{ variances=[] for snr=snrs snr variances=[variances run_var(snr, which_ted)]; end + %} end function fmtplot(h) @@ -54,11 +54,12 @@ function fmtplot(h) set(FN,'FontName','times'); FS = findall(h,'-property','FontSize'); set(FS,'FontSize',18); - xlabel('Phase offset in number of samples'); - ylabel('Error value (TED output)'); + xlabel('SNR [dB]'); + ylabel('Phase error variance [rad^2]'); end -snrs_gardner=-30:5:40 +snrs_gardner=-70:5:40 +%snrs_gardner=[10] error_values_gardner=mkvarplot('GARDNER',snrs_gardner); %{ snrs_earlylate=0:256 @@ -69,7 +70,7 @@ error_values_earlylate=mkvarplot('EARLYLATE',snrs_earlylate); h=figure(1); semilogy(snrs_gardner, error_values_gardner, 'linewidth', 2); -title('S-curve for Gardner TED'); +title('Variance curve'); fmtplot(h) pause diff --git a/libcsdr.c b/libcsdr.c index 7be06db..1e9ba2f 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -2187,7 +2187,7 @@ float normalized_timing_variance_u32_f(unsigned* input, float* temp, int input_s ndiff_rad_mean = ndiff_rad_mean*(((float)i)/(i+1))+(ndiff_rad[i]/(i+1)); //fprintf(stderr, "input[%d] = %u, sinearest = %u, socorrect = %u, sodiff = %u, ndiff = %f, ndiff_rad[i] = %f, ndiff_rad_mean = %f\n", i, input[i], sinearest, socorrect, sodiff, ndiff, ndiff_rad[i], ndiff_rad_mean); } - //fprintf(stderr, "ndiff_rad_mean = %f\n", ndiff_rad_mean); + fprintf(stderr, "ndiff_rad_mean = %f\n", ndiff_rad_mean); float result = 0; for(int i=0;i Date: Sat, 29 Apr 2017 23:56:29 +0200 Subject: [PATCH 080/111] Very detailed, but correct looking phase variance diagram --- grc_tests/bpsk31_tedvar.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/grc_tests/bpsk31_tedvar.m b/grc_tests/bpsk31_tedvar.m index 2050b47..7d41ef4 100755 --- a/grc_tests/bpsk31_tedvar.m +++ b/grc_tests/bpsk31_tedvar.m @@ -5,7 +5,7 @@ %pkg install -forge parallel pkg load parallel -system('cat /dev/urandom | csdr pack_bits_8to1_u8_u8 | csdr psk_modulator_u8_c 2 | csdr gain_ff 0.25 | csdr psk31_interpolate_sine_cc 256 | csdr add_n_zero_samples_at_beginning_f 170 | dd iflag=fullblock bs=4M count=1 of=/tmp/psk31-raw-data'); +system('cat /dev/urandom | csdr pack_bits_8to1_u8_u8 | csdr psk_modulator_u8_c 2 | csdr gain_ff 0.25 | csdr psk31_interpolate_sine_cc 256 | csdr add_n_zero_samples_at_beginning_f 170 | dd iflag=fullblock bs=8M count=1 of=/tmp/psk31-raw-data'); function output=shrun(cmd, type, minsize) SIGTERM=15; @@ -30,10 +30,10 @@ end function variance=run_var(snr, which_ted) disp('ran a command') - out_vect=shrun(sprintf('cat /tmp/psk31-raw-data | csdr awgn_cc %d --snrshow-no| csdr timing_recovery_cc %s 256 --add_q --output_indexes | CSDR_FIXED_BUFSIZE=131072 csdr normalized_timing_variance_u32_f 256 85', snr, which_ted), 'float32', 1); + out_vect=shrun(sprintf('cat /tmp/psk31-raw-data | csdr awgn_cc %d --snrshow-no| csdr timing_recovery_cc %s 256 --add_q --output_indexes | CSDR_FIXED_BUFSIZE=2048 csdr normalized_timing_variance_u32_f 256 85', snr, which_ted), 'float32', 2); disp('run_var output:'); out_vect' - variance=out_vect(1); + variance=out_vect(2); end function variances=mkvarplot(which_ted, snrs) @@ -58,7 +58,7 @@ function fmtplot(h) ylabel('Phase error variance [rad^2]'); end -snrs_gardner=-70:5:40 +snrs_gardner=-70:2:100 %snrs_gardner=[10] error_values_gardner=mkvarplot('GARDNER',snrs_gardner); %{ From 35f059aecc621ec6f9f5676e79cfe7ca70135405 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 30 Apr 2017 00:04:38 +0200 Subject: [PATCH 081/111] Diagram almost OK for thesis --- grc_tests/bpsk31_tedvar.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/grc_tests/bpsk31_tedvar.m b/grc_tests/bpsk31_tedvar.m index 7d41ef4..275aece 100755 --- a/grc_tests/bpsk31_tedvar.m +++ b/grc_tests/bpsk31_tedvar.m @@ -58,9 +58,9 @@ function fmtplot(h) ylabel('Phase error variance [rad^2]'); end -snrs_gardner=-70:2:100 +snrs_gardner=-10:2:50 %snrs_gardner=[10] -error_values_gardner=mkvarplot('GARDNER',snrs_gardner); +error_values_gardner=mkvarplot('EARLYLATE',snrs_gardner); %{ snrs_earlylate=0:256 error_values_earlylate=mkvarplot('EARLYLATE',snrs_earlylate); From 5934d1f7a3750b2107d3903c22b4857a606dc7c2 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 30 Apr 2017 00:16:56 +0200 Subject: [PATCH 082/111] Now graph is acceptable --- grc_tests/bpsk31_tedvar.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grc_tests/bpsk31_tedvar.m b/grc_tests/bpsk31_tedvar.m index 275aece..9416ed8 100755 --- a/grc_tests/bpsk31_tedvar.m +++ b/grc_tests/bpsk31_tedvar.m @@ -58,7 +58,7 @@ function fmtplot(h) ylabel('Phase error variance [rad^2]'); end -snrs_gardner=-10:2:50 +snrs_gardner=0:5:30 %snrs_gardner=[10] error_values_gardner=mkvarplot('EARLYLATE',snrs_gardner); %{ From addd52f14851cfe2dcccb49a7a13f9b13a192620 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 30 Apr 2017 10:06:31 +0200 Subject: [PATCH 083/111] Now showing E_b/N_0 in the plot --- grc_tests/bpsk31_tedvar.m | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/grc_tests/bpsk31_tedvar.m b/grc_tests/bpsk31_tedvar.m index 9416ed8..32729de 100755 --- a/grc_tests/bpsk31_tedvar.m +++ b/grc_tests/bpsk31_tedvar.m @@ -54,13 +54,13 @@ function fmtplot(h) set(FN,'FontName','times'); FS = findall(h,'-property','FontSize'); set(FS,'FontSize',18); - xlabel('SNR [dB]'); + xlabel('E_b/N_0 [dB]'); ylabel('Phase error variance [rad^2]'); end -snrs_gardner=0:5:30 -%snrs_gardner=[10] -error_values_gardner=mkvarplot('EARLYLATE',snrs_gardner); +snrs=-5:5:30 +%snrs=[10] +error_values_gardner=mkvarplot('EARLYLATE',snrs); %{ snrs_earlylate=0:256 error_values_earlylate=mkvarplot('EARLYLATE',snrs_earlylate); @@ -69,8 +69,12 @@ error_values_earlylate=mkvarplot('EARLYLATE',snrs_earlylate); %graphics_toolkit("gnuplot") h=figure(1); -semilogy(snrs_gardner, error_values_gardner, 'linewidth', 2); -title('Variance curve'); + +ebn0=snrs-13.26-10*log10(1/256.) +%13.56 dB is the difference between the real (measured) SNR and the number input to awgn_cc + +semilogy(ebn0, error_values_gardner, 'linewidth', 2); +title('Estimation variance'); fmtplot(h) pause From 3464174c07beb69a2eb23c799bbad1a7500eadfc Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 30 Apr 2017 10:18:26 +0200 Subject: [PATCH 084/111] Current version --- grc_tests/bpsk31_tedvar.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/grc_tests/bpsk31_tedvar.m b/grc_tests/bpsk31_tedvar.m index 32729de..f05c84a 100755 --- a/grc_tests/bpsk31_tedvar.m +++ b/grc_tests/bpsk31_tedvar.m @@ -70,8 +70,9 @@ error_values_earlylate=mkvarplot('EARLYLATE',snrs_earlylate); h=figure(1); -ebn0=snrs-13.26-10*log10(1/256.) -%13.56 dB is the difference between the real (measured) SNR and the number input to awgn_cc +ebn0=snrs-13.26-10*log10(1/256.) +%13.56 dB is the difference between the real (measured) SNR and the number input to awgn_cc. +%This is because agwn_cc assumes a signal with 0dB power at te input, while our BPSK31 baseband signal is of -13.26 dB. semilogy(ebn0, error_values_gardner, 'linewidth', 2); title('Estimation variance'); From 2a4e2ce19084a2b4f93ac4c20a52800a26de6254 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 30 Apr 2017 11:40:36 +0200 Subject: [PATCH 085/111] Added code quality check, --awgnfile and gaussian_noise_c --- Makefile | 6 +++-- README.md | 16 ++++++++--- csdr.c | 80 +++++++++++++++++++++++++++++++++++++++---------------- libcsdr.c | 4 +-- libcsdr.h | 2 +- 5 files changed, 77 insertions(+), 31 deletions(-) diff --git a/Makefile b/Makefile index 7db181a..dfe3df2 100644 --- a/Makefile +++ b/Makefile @@ -43,8 +43,8 @@ PARAMS_MISC = -Wno-unused-result #PARAMS_DEBUG = $(if $(DEBUG_ON),-g,) FFTW_PACKAGE = fftw-3.3.3 -.PHONY: clean-vect clean -all: csdr nmux +.PHONY: clean-vect clean codequality +all: codequality csdr nmux libcsdr.so: fft_fftw.c fft_rpi.c libcsdr_wrapper.c libcsdr.c libcsdr_gpl.c fastddc.c fastddc.h fft_fftw.h fft_rpi.h ima_adpcm.h libcsdr_gpl.h libcsdr.h predefined.h @echo NOTE: you may have to manually edit Makefile to optimize for your CPU \(especially if you compile on ARM, please edit PARAMS_NEON\). @echo Auto-detected optimization parameters: $(PARAMS_SIMD) @@ -96,3 +96,5 @@ emcc: cat sdr.js/sdrjs-header.js sdr.js/sdrjs-compiled.js sdr.js/sdrjs-footer.js > sdr.js/sdr.js emcc-beautify: bash -c 'type js-beautify >/dev/null 2>&1; if [ $$? -eq 0 ]; then js-beautify sdr.js/sdr.js >sdr.js/sdr.js.beautiful; mv sdr.js/sdr.js.beautiful sdr.js/sdr.js; fi' +codequality: + @bash -c 'if [ `cat csdr.c | grep badsyntax | grep -v return | wc -l` -ne 1 ]; then echo "error at code quality check: badsyntax() used in csdr.c without return."; exit 1; else exit 0; fi' diff --git a/README.md b/README.md index 55349ef..0035732 100755 --- a/README.md +++ b/README.md @@ -845,13 +845,23 @@ For example, `csdr repeat_u8 1 1 0 0` will output: ---- -### [noise_f](#noise_f) +### [uniform_noise_f](#uniform_noise_f) Syntax: - csdr noise_f + csdr uniform_noise_f -It outputs white noise within the range [-1.0, 1.0]. +It outputs uniform white noise. All samples are within the range [-1.0, 1.0]. + +---- + +### [gaussian_noise_c](#gaussian_noise_c) + +Syntax: + + csdr gaussian_noise_c + +It outputs Gaussian white noise. All samples are within the unit circle. ---- diff --git a/csdr.c b/csdr.c index 11a2336..04a330d 100755 --- a/csdr.c +++ b/csdr.c @@ -139,7 +139,8 @@ char usage[]= " firdes_resonator_c [window [--octave]]\n" " resonators_fir_cc [resonator_rate × N]\n" " repeat_u8 \n" -" noise_f\n" +" uniform_noise_f\n" +" gaussian_noise_c\n" " awgn_cc [--snrshow]\n" " pack_bits_8to1_u8_u8\n" " add_n_zero_samples_at_beginning_f \n" @@ -2529,7 +2530,7 @@ int main(int argc, char *argv[]) if(argc<=3) return badsyntax("need required parameter (decimation factor)"); int decimation; sscanf(argv[3],"%d",&decimation); - if(decimation<=4 || decimation&3) badsyntax("decimation factor should be a positive integer divisible by 4"); + if(decimation<=4 || decimation&3) return badsyntax("decimation factor should be a positive integer divisible by 4"); int add_q = (argc>=5 && !strcmp(argv[4], "--add_q")); @@ -2537,7 +2538,7 @@ int main(int argc, char *argv[]) int output_error = 0; int output_indexes = 0; if(argc>=7 && !strcmp(argv[5], "--octave")) debug_n = atoi(argv[6]); - if(debug_n<0) badsyntax("debug_n should be >= 0"); + if(debug_n<0) return badsyntax("debug_n should be >= 0"); if(argc>=6 && !strcmp(argv[5], "--output_error")) output_error = 1; float* timing_error = NULL; @@ -2584,11 +2585,11 @@ int main(int argc, char *argv[]) if(argc<=2) return badsyntax("need required parameter (samples_to_plot)"); int samples_to_plot = 0; sscanf(argv[2], "%d", &samples_to_plot); - if(samples_to_plot<=0) badsyntax("Number of samples to plot should be > 0"); + if(samples_to_plot<=0) return badsyntax("Number of samples to plot should be > 0"); if(argc<=3) return badsyntax("need required parameter (out_of_n_samples)"); int out_of_n_samples = 0; sscanf(argv[3], "%d", &out_of_n_samples); - if(out_of_n_samples4) mode2d = !strcmp(argv[4], "--2d"); complexf* read_buf = (complexf*)malloc(sizeof(complexf)*the_bufsize); @@ -2621,7 +2622,7 @@ int main(int argc, char *argv[]) int n_psk; if(argc<=2) return badsyntax("need required parameter (n_psk)"); sscanf(argv[2],"%d",&n_psk); - if(n_psk<=0 || n_psk>256) badsyntax("n_psk should be between 1 and 256"); + if(n_psk<=0 || n_psk>256) return badsyntax("n_psk should be between 1 and 256"); if(!initialize_buffers()) return -2; sendbufsize(the_bufsize); @@ -2641,10 +2642,10 @@ int main(int argc, char *argv[]) int sample_size_bytes = 0, ntimes = 0; if(argc<=2) return badsyntax("need required parameter (sample_size_bytes)"); sscanf(argv[2],"%d",&sample_size_bytes); - if(sample_size_bytes<=0) badsyntax("sample_size_bytes should be >0"); + if(sample_size_bytes<=0) return badsyntax("sample_size_bytes should be >0"); if(argc<=3) return badsyntax("need required parameter (ntimes)"); sscanf(argv[3],"%d",&ntimes); - if(ntimes<=0) badsyntax("ntimes should be >0"); + if(ntimes<=0) return badsyntax("ntimes should be >0"); if(!initialize_buffers()) return -2; sendbufsize(the_bufsize*ntimes); unsigned char* local_input_buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize*sample_size_bytes); @@ -2664,7 +2665,7 @@ int main(int argc, char *argv[]) int interpolation; if(argc<=2) return badsyntax("need required parameter (interpolation)"); sscanf(argv[2],"%d",&interpolation); - if(interpolation<=0) badsyntax("interpolation should be >0"); + if(interpolation<=0) return badsyntax("interpolation should be >0"); if(!initialize_buffers()) return -2; sendbufsize(the_bufsize*interpolation); complexf* local_output_buffer = (complexf*)malloc(sizeof(complexf)*the_bufsize*interpolation); @@ -2756,7 +2757,7 @@ int main(int argc, char *argv[]) float samples_per_bits; if(argc<=2) return badsyntax("need required parameter (samples_per_bits)"); sscanf(argv[2],"%f",&samples_per_bits); - if(samples_per_bits<=0) badsyntax("samples_per_bits should be > 0"); + if(samples_per_bits<=0) return badsyntax("samples_per_bits should be > 0"); bpsk_costas_loop_state_t state = init_bpsk_costas_loop_cc(samples_per_bits); @@ -2778,15 +2779,15 @@ int main(int argc, char *argv[]) float rate; if(argc<=2) return badsyntax("need required parameter (rate)"); sscanf(argv[2],"%f",&rate); - if(rate<=0) badsyntax("rate should be > 0"); + if(rate<=0) return badsyntax("rate should be > 0"); float reference = 1.; if(argc>3) sscanf(argv[3],"%f",&reference); - if(reference<=0) badsyntax("reference should be > 0"); + if(reference<=0) return badsyntax("reference should be > 0"); float max_gain = 65535.; if(argc>4) sscanf(argv[4],"%f",&max_gain); - if(max_gain<=0) badsyntax("max_gain should be > 0"); + if(max_gain<=0) return badsyntax("max_gain should be > 0"); float current_gain = 1.; @@ -2866,7 +2867,7 @@ int main(int argc, char *argv[]) if(!initialize_buffers()) return -2; sendbufsize(the_bufsize); - if(the_bufsize - taps_length <= 0 ) badsyntax("taps_length is below buffer size, decrease taps_length"); + if(the_bufsize - taps_length <= 0 ) return badsyntax("taps_length is below buffer size, decrease taps_length"); complexf* taps = (complexf*)calloc(sizeof(complexf),taps_length); for(int i=0; i is missing."); + if(argc<=2) return badsyntax("required parameter is missing."); float snr_db = 0; sscanf(argv[2],"%f",&snr_db); + FILE* awgnfile = NULL; + if(argc>=5 && !strcmp(argv[3],"--awgnfile")) + { + awgnfile=fopen(argv[4], "r"); + if(!awgnfile) return badsyntax("failed to open the --awgnfile"); + } + int parnumadd=2*(!!awgnfile); int snrshow = 0; - if(argc>=4 && !strcmp(argv[3],"--snrshow")) snrshow = 1; + if(argc>=4+parnumadd && !strcmp(argv[3+parnumadd],"--snrshow")) snrshow = 1; float signal_amplitude_per_noise = pow(10,snr_db/20); float a_signal=signal_amplitude_per_noise/(signal_amplitude_per_noise+1.0); float a_noise=1.0/(signal_amplitude_per_noise+1.0); @@ -2926,7 +2934,16 @@ int main(int argc, char *argv[]) FEOF_CHECK; FREAD_C; //get_awgn_samples_f((float*)awgn_buffer, the_bufsize*2, urandom); - get_random_gaussian_samples_c(awgn_buffer, the_bufsize, urandom); + if(!awgnfile) get_random_gaussian_samples_c(awgn_buffer, the_bufsize, urandom); + else + { + for(;;) + { + int items_read=fread(awgn_buffer, sizeof(complexf), the_bufsize, awgnfile); + if(items_read + if(!strcmp(argv[1], "gaussian_noise_c")) + { + FILE* urandom = init_get_random_samples_f(); + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize); + for(;;) + { + FEOF_CHECK; + get_random_gaussian_samples_c((complexf*)output_buffer, the_bufsize, urandom); + FWRITE_C; + TRY_YIELD; + } + } + + if(!strcmp(argv[1], "normalized_timing_variance_u32_f")) // [--debug] { int samples_per_symbol = 0; - if(argc<=2) badsyntax("required parameter is missing."); + if(argc<=2) return badsyntax("required parameter is missing."); sscanf(argv[2],"%d",&samples_per_symbol); int initial_sample_offset = 0; - if(argc<=3) badsyntax("required parameter is missing."); + if(argc<=3) return badsyntax("required parameter is missing."); sscanf(argv[3],"%d",&initial_sample_offset); + int debug_print = 0; + if(argc>4 && !strcmp(argv[4],"--debug")) debug_print = 1; + if(!initialize_buffers()) return -2; sendbufsize(the_bufsize); float* temp_buffer = (float*)malloc(sizeof(float)*the_bufsize); @@ -2979,7 +3013,7 @@ int main(int argc, char *argv[]) { FEOF_CHECK; FREAD_R; //doesn't count, reads 4 bytes per sample anyway - float nv = normalized_timing_variance_u32_f((unsigned*)input_buffer, temp_buffer, the_bufsize, samples_per_symbol, initial_sample_offset); + float nv = normalized_timing_variance_u32_f((unsigned*)input_buffer, temp_buffer, the_bufsize, samples_per_symbol, initial_sample_offset, debug_print); fwrite(&nv, sizeof(float), 1, stdout); fprintf(stderr, "csdr normalized_timing_variance_u32_f: normalized variance = %f\n", nv); TRY_YIELD; @@ -2989,7 +3023,7 @@ int main(int argc, char *argv[]) if(!strcmp(argv[1], "add_n_zero_samples_at_beginning_f")) // { int n_zero_samples = 0; - if(argc<=2) badsyntax("required parameter is missing."); + if(argc<=2) return badsyntax("required parameter is missing."); sscanf(argv[2],"%d",&n_zero_samples); if(!sendbufsize(initialize_buffers())) return -2; float* zeros=(float*)calloc(sizeof(float),n_zero_samples); diff --git a/libcsdr.c b/libcsdr.c index 1e9ba2f..177a095 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -2169,7 +2169,7 @@ int apply_fir_cc(complexf* input, complexf* output, int input_size, complexf* ta return i; } -float normalized_timing_variance_u32_f(unsigned* input, float* temp, int input_size, int samples_per_symbol, int initial_sample_offset) +float normalized_timing_variance_u32_f(unsigned* input, float* temp, int input_size, int samples_per_symbol, int initial_sample_offset, int debug_print) { float *ndiff_rad = temp; float ndiff_rad_mean = 0; @@ -2185,7 +2185,7 @@ float normalized_timing_variance_u32_f(unsigned* input, float* temp, int input_s ndiff_rad[i] = ndiff*PI; ndiff_rad_mean = ndiff_rad_mean*(((float)i)/(i+1))+(ndiff_rad[i]/(i+1)); - //fprintf(stderr, "input[%d] = %u, sinearest = %u, socorrect = %u, sodiff = %u, ndiff = %f, ndiff_rad[i] = %f, ndiff_rad_mean = %f\n", i, input[i], sinearest, socorrect, sodiff, ndiff, ndiff_rad[i], ndiff_rad_mean); + if(debug_print) fprintf(stderr, "input[%d] = %u, sinearest = %u, socorrect = %u, sodiff = %u, ndiff = %f, ndiff_rad[i] = %f, ndiff_rad_mean = %f\n", i, input[i], sinearest, socorrect, sodiff, ndiff, ndiff_rad[i], ndiff_rad_mean); } fprintf(stderr, "ndiff_rad_mean = %f\n", ndiff_rad_mean); diff --git a/libcsdr.h b/libcsdr.h index a2b7774..1153251 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -369,4 +369,4 @@ void get_random_gaussian_samples_c(complexf* output, int output_size, FILE* stat int deinit_get_random_samples_f(FILE* status); float* add_ff(float* input1, float* input2, float* output, int input_size); float total_logpower_cf(complexf* input, int input_size); -float normalized_timing_variance_u32_f(unsigned* input, float* temp, int input_size, int samples_per_symbol, int initial_sample_offset); +float normalized_timing_variance_u32_f(unsigned* input, float* temp, int input_size, int samples_per_symbol, int initial_sample_offset, int debug_print); From d7d36a70a81b5c059f8b654d73f1d123a5a568b9 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 30 Apr 2017 13:51:12 +0200 Subject: [PATCH 086/111] Actually this plot now looks OK --- grc_tests/bpsk31_tedvar.m | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/grc_tests/bpsk31_tedvar.m b/grc_tests/bpsk31_tedvar.m index f05c84a..af43a8f 100755 --- a/grc_tests/bpsk31_tedvar.m +++ b/grc_tests/bpsk31_tedvar.m @@ -5,7 +5,26 @@ %pkg install -forge parallel pkg load parallel -system('cat /dev/urandom | csdr pack_bits_8to1_u8_u8 | csdr psk_modulator_u8_c 2 | csdr gain_ff 0.25 | csdr psk31_interpolate_sine_cc 256 | csdr add_n_zero_samples_at_beginning_f 170 | dd iflag=fullblock bs=8M count=1 of=/tmp/psk31-raw-data'); +function y=inarg(x) + for i=1:length(argv()) + if strcmp(argv(){i},x) + y=1; + return + end + end + y=0; +end + +if !inarg('--nogen') + fwrite(stdout, "===========================================\nGenerating baseband signal from random data\n===========================================\n"); + system('cat /dev/urandom | csdr pack_bits_8to1_u8_u8 | csdr psk_modulator_u8_c 2 | csdr gain_ff 0.25 | csdr psk31_interpolate_sine_cc 256 | csdr add_n_zero_samples_at_beginning_f 170 | pv -ps 2g | dd iflag=fullblock bs=128M count=16 of=/tmp/psk31-raw-data'); + fwrite(stdout, "===========================================\nGenerating Gaussian white noise for agwn_cc\n===========================================\n"); + system('csdr gaussian_noise_c | pv -ps 256m | dd of=/tmp/psk31-gaussian-noise iflag=fullblock bs=256M count=1'); +end +if inarg('--onlygen') + exit(0) +end +fwrite(stdout, "===========================================\nCalculating variance graph data \n===========================================\n"); function output=shrun(cmd, type, minsize) SIGTERM=15; @@ -30,10 +49,10 @@ end function variance=run_var(snr, which_ted) disp('ran a command') - out_vect=shrun(sprintf('cat /tmp/psk31-raw-data | csdr awgn_cc %d --snrshow-no| csdr timing_recovery_cc %s 256 --add_q --output_indexes | CSDR_FIXED_BUFSIZE=2048 csdr normalized_timing_variance_u32_f 256 85', snr, which_ted), 'float32', 2); + out_vect=shrun(sprintf('cat /tmp/psk31-raw-data | csdr awgn_cc %d --awgnfile /tmp/psk31-gaussian-noise | csdr timing_recovery_cc %s 256 --add_q --output_indexes | CSDR_FIXED_BUFSIZE=1048576 csdr normalized_timing_variance_u32_f 256 85', snr, which_ted), 'float32', 1); disp('run_var output:'); out_vect' - variance=out_vect(2); + variance=out_vect(1); end function variances=mkvarplot(which_ted, snrs) @@ -60,7 +79,7 @@ end snrs=-5:5:30 %snrs=[10] -error_values_gardner=mkvarplot('EARLYLATE',snrs); +error_values_gardner=mkvarplot('GARDNER',snrs); %{ snrs_earlylate=0:256 error_values_earlylate=mkvarplot('EARLYLATE',snrs_earlylate); @@ -69,7 +88,6 @@ error_values_earlylate=mkvarplot('EARLYLATE',snrs_earlylate); %graphics_toolkit("gnuplot") h=figure(1); - ebn0=snrs-13.26-10*log10(1/256.) %13.56 dB is the difference between the real (measured) SNR and the number input to awgn_cc. %This is because agwn_cc assumes a signal with 0dB power at te input, while our BPSK31 baseband signal is of -13.26 dB. @@ -86,4 +104,6 @@ fmtplot(h) pause %} -system('rm /tmp/psk31-raw-data'); +if !inarg('--nogen') + system('rm /tmp/psk31-raw-data /tmp/psk31-gaussian-noise'); +end From 0878d3bd4352f95b4d250c2414a6891172fe8c32 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 30 Apr 2017 14:30:13 +0200 Subject: [PATCH 087/111] Retabbed most source files to 4 spaces --- README.md | 182 +- csdr.c | 4803 +++++++++++++++++++++++++++-------------------------- libcsdr.c | 3164 +++++++++++++++++------------------ libcsdr.h | 180 +- 4 files changed, 4174 insertions(+), 4155 deletions(-) diff --git a/README.md b/README.md index 0035732..c133c91 100755 --- a/README.md +++ b/README.md @@ -13,8 +13,8 @@ Most of the code is available under the permissive BSD license, with some option How to compile -------------- - make - sudo make install + make + sudo make install The project was only tested on Linux. It has the following dependencies: `libfftw3-dev` @@ -24,7 +24,7 @@ To run the examples, you will also need /dev/null + rtl_sdr -s 2400000 -f 104300000 -g 20 - | csdr convert_u8_f | csdr fft_cc 1024 1200000 HAMMING --octave | octave -i > /dev/null - We calculate the Fast Fourier Transform by `csdr fft_cc` on the first 1024 samples of every block of 1200000 complex samples coming after each other. (We calculate FFT from 1024 samples and then skip 1200000-1024=1198976 samples. This way we will calculate FFT two times every second.) - The window used for FFT is the Hamming window, and the output consists of commands that can be directly interpreted by GNU Octave which plots us the spectrum. @@ -153,7 +153,7 @@ Optional parameters have safe defaults, for more info look at the code. Syntax: - csdr realpart_cf + csdr realpart_cf It takes the real part of the complex signal, and throws away the imaginary part. @@ -163,7 +163,7 @@ It takes the real part of the complex signal, and throws away the imaginary part Syntax: - csdr clipdetect_ff + csdr clipdetect_ff It clones the signal (the input and the output is the same), but it prints a warning on `stderr` if any sample value is out of the -1.0 ... 1.0 range. @@ -173,7 +173,7 @@ It clones the signal (the input and the output is the same), but it prints a war Syntax: - csdr limit_ff [max_amplitude] + csdr limit_ff [max_amplitude] The input signal amplitude will not be let out of the `-max_amplitude ... max_amplitude` range. @@ -183,7 +183,7 @@ The input signal amplitude will not be let out of the `-max_amplitude ... max_am Syntax: - csdr gain_ff + csdr gain_ff It multiplies all samples by `gain`. @@ -193,7 +193,7 @@ It multiplies all samples by `gain`. Syntax: - csdr clone + csdr clone It copies the input to the output. @@ -203,7 +203,7 @@ It copies the input to the output. Syntax: - csdr through + csdr through It copies the input to the output, while also displaying the data rate going through it. @@ -213,7 +213,7 @@ It copies the input to the output, while also displaying the data rate going thr Syntax: - csdr none + csdr none The `csdr` process just exits with 0. @@ -223,7 +223,7 @@ The `csdr` process just exits with 0. Syntax: - csdr yes_f [buf_times] + csdr yes_f [buf_times] It outputs continously the `to_repeat` float number. @@ -237,7 +237,7 @@ Else, after outputing `buf_times` number of buffers (the size of which is stated Syntax: - csdr detect_nan_ff + csdr detect_nan_ff Along with copying its input samples to the output, it prints a warning message to *stderr* if it finds any IEEE floating point NaN values among the samples. @@ -247,7 +247,7 @@ Along with copying its input samples to the output, it prints a warning message Syntax: - csdr dump_f + csdr dump_f It prints all floating point input samples as text. @@ -265,7 +265,7 @@ Aliases for this function: `floatdump_f` Syntax: - csdr dump_u8 + csdr dump_u8 It prints all input bytes as text, in hexadecimal form. @@ -277,7 +277,7 @@ Alternatively, you can use the `xxd` command (built into most Linux distribution Syntax: - csdr flowcontrol + csdr flowcontrol It limits the data rate of a stream to a given `data_rate` number of bytes per second. @@ -289,7 +289,7 @@ It copies `data_rate / reads_per_second` bytes from the input to the output, doi Syntax: - csdr shift_math_cc + csdr shift_math_cc It shifts the signal in the frequency domain by `rate`. @@ -305,7 +305,7 @@ Internally, a sine and cosine wave is generated, and this function uses `math.h` Syntax: - csdr shift_addition_cc + csdr shift_addition_cc Operation is the same as for `shift_math_cc`. @@ -317,7 +317,7 @@ Internally, this function uses trigonometric addition formulas to generate sine Syntax: - csdr shift_addition_cc_test + csdr shift_addition_cc_test This function was used to test the accuracy of the method above. @@ -327,7 +327,7 @@ This function was used to test the accuracy of the method above. Syntax: - csdr shift_table_cc [table_size] + csdr shift_table_cc [table_size] Operation is the same as with `shift_math_cc`. @@ -341,7 +341,7 @@ The higher the table size is, the smaller the phase error is. Syntax: - csdr shift_addfast_cc + csdr shift_addfast_cc Operation is the same as for `shift_math_cc`. @@ -353,7 +353,7 @@ Internally, this function uses a NEON-accelerated algorithm on capable systems, Syntax: - csdr shift_unroll_cc + csdr shift_unroll_cc Operation is the same as for `shift_math_cc`. @@ -367,7 +367,7 @@ The loop in this function unrolls quite well if compiled on a PC. It was the fas Syntax: - csdr decimating_shift_addition_cc [decimation] + csdr decimating_shift_addition_cc [decimation] It shifts the input signal in the frequency domain, and also decimates it, without filtering. It will be useful as a part of the FFT channelizer implementation (to be done). @@ -379,7 +379,7 @@ It cannot be used as a channelizer by itself, use `fir_decimate_cc` instead. Syntax: - csdr dcblock_ff + csdr dcblock_ff This is a DC blocking IIR filter. @@ -389,7 +389,7 @@ This is a DC blocking IIR filter. Syntax: - csdr fastdcblock_ff + csdr fastdcblock_ff This is a DC blocker that works based on the average of the buffer. @@ -399,7 +399,7 @@ This is a DC blocker that works based on the average of the buffer. Syntax: - csdr fmdemod_atan_cf + csdr fmdemod_atan_cf It is an FM demodulator that internally uses the `atan` function in `math.h`, so it is not so fast. @@ -409,7 +409,7 @@ It is an FM demodulator that internally uses the `atan` function in `math.h`, so Syntax: - csdr fmdemod_quadri_cf + csdr fmdemod_quadri_cf It is an FM demodulator that is based on the quadri-correlator method, and it can be effectively auto-vectorized, so it should be faster. @@ -419,7 +419,7 @@ It is an FM demodulator that is based on the quadri-correlator method, and it ca Syntax: - csdr fmdemod_quadri_novect_cf + csdr fmdemod_quadri_novect_cf It has more easily understandable code than the previous one, but can't be auto-vectorized. @@ -429,7 +429,7 @@ It has more easily understandable code than the previous one, but can't be auto- Syntax: - csdr deemphasis_wfm_ff + csdr deemphasis_wfm_ff It does de-emphasis with the given RC time constant `tau`. @@ -443,13 +443,13 @@ In Europe, `tau` should be chosen as `50e-6`, and in the USA, `tau` should be `7 Syntax: - csdr deemphasis_nfm_ff + csdr deemphasis_nfm_ff It does de-emphasis on narrow-band FM for communication equipment (e.g. two-way radios). It uses fixed filters so it works only on predefined sample rates, for the actual list of them run: - cat libcsdr.c | grep DNFMFF_ADD_ARRAY + cat libcsdr.c | grep DNFMFF_ADD_ARRAY ---- @@ -457,7 +457,7 @@ It uses fixed filters so it works only on predefined sample rates, for the actua Syntax: - csdr amdemod_cf + csdr amdemod_cf It is an AM demodulator that uses `sqrt`. On some architectures `sqrt` can be directly calculated by dedicated CPU instructions, but on others it may be slower. @@ -467,7 +467,7 @@ It is an AM demodulator that uses `sqrt`. On some architectures `sqrt` can be di Syntax: - csdr amdemod_estimator_cf + csdr amdemod_estimator_cf It is an AM demodulator that uses an estimation method that is faster but less accurate than `amdemod_cf`. @@ -477,7 +477,7 @@ It is an AM demodulator that uses an estimation method that is faster but less a Syntax: - csdr firdes_lowpass_f [window [--octave]] + csdr firdes_lowpass_f [window [--octave]] Low-pass FIR filter design function to output real taps, with a `cutoff_rate` proportional to the sampling frequency, using the windowed sinc filter design method. @@ -501,7 +501,7 @@ The `--octave` parameter lets you directly view the filter response in `octave`. Syntax: - csdr firdes_bandpass_c [window [--octave]] + csdr firdes_bandpass_c [window [--octave]] Band-pass FIR filter design function to output complex taps. @@ -515,7 +515,7 @@ Other parameters were explained above at `firdes_lowpass_f`. Syntax: - csdr fir_decimate_cc [transition_bw [window]] + csdr fir_decimate_cc [transition_bw [window]] It is a decimator that keeps one sample out of `decimation_factor` samples. @@ -527,7 +527,7 @@ To avoid aliasing, it runs a filter on the signal and removes spectral component Syntax: - csdr fir_interpolate_cc [transition_bw [window]] + csdr fir_interpolate_cc [transition_bw [window]] It is an interpolator that generates `interpolation_factor` number of output samples from one input sample. @@ -541,7 +541,7 @@ To avoid aliasing, it runs a filter on the signal and removes spectral component Syntax: - csdr rational_resampler_ff [transition_bw [window]] + csdr rational_resampler_ff [transition_bw [window]] It is a resampler that takes integer values of `interpolation` and `decimation`. The output sample rate will be `interpolation / decimation × input_sample_rate`. @@ -554,7 +554,7 @@ The output sample rate will be `interpolation / decimation × input_sample_rate` Syntax: - csdr fractional_decimator_ff [num_poly_points ( [transition_bw [window]] | --prefilter )] + csdr fractional_decimator_ff [num_poly_points ( [transition_bw [window]] | --prefilter )] It can decimate by a floating point ratio. @@ -571,7 +571,7 @@ It can filter the signal with an anti-aliasing FIR filter before applying the La Syntax: - csdr old_fractional_decimator_ff [transition_bw [window]] + csdr old_fractional_decimator_ff [transition_bw [window]] This is the deprecated, old algorithm to decimate by a floating point ratio, superseded by `fractional_decimator_ff`. @@ -583,7 +583,7 @@ This is the deprecated, old algorithm to decimate by a floating point ratio, sup Syntax: - csdr bandpass_fir_fft_cc [window] + csdr bandpass_fir_fft_cc [window] It performs a bandpass FIR filter on complex samples, using FFT and the overlap-add method. @@ -595,7 +595,7 @@ Parameters are described under `firdes_bandpass_c` and `firdes_lowpass_f`. Syntax: - csdr agc_ff [hang_time [reference [attack_rate [decay_rate [max_gain [attack_wait [filter_alpha]]]]]]] + csdr agc_ff [hang_time [reference [attack_rate [decay_rate [max_gain [attack_wait [filter_alpha]]]]]]] It is an automatic gain control function. @@ -615,7 +615,7 @@ Its default parameters work best for an audio signal sampled at 48000 Hz. Syntax: - csdr fastagc_ff [block_size [reference]] + csdr fastagc_ff [block_size [reference]] It is a faster AGC that linearly changes the gain, taking the highest amplitude peak in the buffer into consideration. Its output will never exceed `-reference ... reference`. @@ -625,7 +625,7 @@ It is a faster AGC that linearly changes the gain, taking the highest amplitude Syntax: - csdr fft_cc [window [--octave] [--benchmark]] + csdr fft_cc [window [--octave] [--benchmark]] It performs an FFT on the first `fft_size` samples out of `out_of_every_n_samples`, thus skipping `out_of_every_n_samples - fft_size` samples in the input. @@ -639,7 +639,7 @@ FFTW can be faster if we let it optimalize a while before starting the first tra Syntax: - csdr fft_benchmark [--benchmark] + csdr fft_benchmark [--benchmark] It measures the time taken to process `fft_cycles` transforms of `fft_size`. It lets FFTW optimalize if used with the `--benchmark` switch. @@ -650,7 +650,7 @@ It lets FFTW optimalize if used with the `--benchmark` switch. Syntax: - csdr logpower_cf [add_db] + csdr logpower_cf [add_db] Calculates `10*log10(i^2+q^2)+add_db` for the input complex samples. It is useful for drawing power spectrum graphs. @@ -666,7 +666,7 @@ Syntax: Syntax: - csdr csdr encode_ima_adpcm_i16_u8 + csdr csdr encode_ima_adpcm_i16_u8 Encodes the audio stream to IMA ADPCM, which decreases the size to 25% of the original. @@ -676,7 +676,7 @@ Encodes the audio stream to IMA ADPCM, which decreases the size to 25% of the or Syntax: - csdr decode_ima_adpcm_u8_i16 + csdr decode_ima_adpcm_u8_i16 Decodes the audio stream from IMA ADPCM. @@ -686,7 +686,7 @@ Decodes the audio stream from IMA ADPCM. Syntax: - csdr compress_fft_adpcm_f_u8 + csdr compress_fft_adpcm_f_u8 Encodes the FFT output vectors of `fft_size`. It should be used on the data output from `logpower_cf`. @@ -694,7 +694,7 @@ It resets the ADPCM encoder at the beginning of every vector, and to compensate The actual number of padding samples can be determined by running: - cat csdr.c | grep "define COMPRESS_FFT_PAD_N" + cat csdr.c | grep "define COMPRESS_FFT_PAD_N" ---- @@ -702,7 +702,7 @@ The actual number of padding samples can be determined by running: Syntax: - csdr fft_exchange_sides_ff + csdr fft_exchange_sides_ff It exchanges the first and second part of the FFT vector, to prepare it for the waterfall/spectrum display. It should operate on the data output from `logpower_cf`. @@ -712,7 +712,7 @@ It exchanges the first and second part of the FFT vector, to prepare it for the Syntax: - csdr dsb_fc [q_value] + csdr dsb_fc [q_value] It converts a real signal to a double sideband complex signal centered around DC. @@ -728,7 +728,7 @@ With `q_value = 0` it is an AM-DSB/SC modulator. If you want to get an AM-DSB si Syntax: - csdr add_dcoffset_cc + csdr add_dcoffset_cc It adds a DC offset to the complex signal: `i_output = 0.5 + i_input / 2, q_output = q_input / 2` @@ -738,7 +738,7 @@ It adds a DC offset to the complex signal: `i_output = 0.5 + i_input / 2, q_outp Syntax: - csdr convert_f_samplerf + csdr convert_f_samplerf It converts a real signal to the `-mRF` input format of [https://github.com/F5OEO/rpitx](rpitx), so it allows you to generate frequency modulation. The input signal will be the modulating signal. The `` parameter is the value for `rpitx` indicating the time to wait between samples. For a sampling rate of 48 ksps, this is 20833. @@ -748,7 +748,7 @@ It converts a real signal to the `-mRF` input format of [https://github.com/F5OE Syntax: - csdr fmmod_fc + csdr fmmod_fc It generates a complex FM modulated output from a real input signal. @@ -758,7 +758,7 @@ It generates a complex FM modulated output from a real input signal. Syntax: - csdr fixed_amplitude_cc + csdr fixed_amplitude_cc It changes the amplitude of every complex input sample to a fixed value. It does not change the phase information of the samples. @@ -768,17 +768,17 @@ It changes the amplitude of every complex input sample to a fixed value. It does Syntax: - csdr mono2stereo_s16 + csdr mono2stereo_s16 It doubles every input sample. Example: if the input samples are 16 bit signed integers: - 23 -452 3112 + 23 -452 3112 The output will be: - 23 23 -452 -452 3112 3112 + 23 23 -452 -452 3112 3112 ---- @@ -786,11 +786,11 @@ The output will be: Syntax: - csdr setbuf + csdr setbuf See the [buffer sizes](#buffer_sizes) section. - squelch_and_smeter_cc --fifo --outfifo + squelch_and_smeter_cc --fifo --outfifo This is a controllable squelch, which reads the squelch level input from `` and writes the power level output to ``. Both input and output are in the format of `%g\n`. While calculating the power level, it takes only every `` sample into consideration. It writes the S-meter value for every `` buffer to ``. If the squelch level is set to 0, it it forces the squelch to be open. If the squelch is closed, it fills the output with zero. @@ -800,7 +800,7 @@ This is a controllable squelch, which reads the squelch level input from ` + csdr fifo It is similar to `clone`, but internally it uses a circular buffer. It reads as much as possible from the input. It discards input samples if the input buffer is full. @@ -810,7 +810,7 @@ It is similar to `clone`, but internally it uses a circular buffer. It reads as Syntax: - csdr psk31_varicode_encoder_u8_u8 + csdr psk31_varicode_encoder_u8_u8 It encodes ASCII characters into varicode for PSK31 transmission. It puts a `00` sequence between the varicode characters (which acts as a separator). @@ -832,7 +832,7 @@ For this input, the output of `psk31_varicode_encoder_u8_u8` will be the followi Syntax: - csdr repeat_u8 [resonator_rate × N]\n" + csdr repeat_u8 [resonator_rate × N]\n" It repeatedly outputs a set of data bytes (given with decimal numbers). @@ -849,7 +849,7 @@ For example, `csdr repeat_u8 1 1 0 0` will output: Syntax: - csdr uniform_noise_f + csdr uniform_noise_f It outputs uniform white noise. All samples are within the range [-1.0, 1.0]. @@ -859,7 +859,7 @@ It outputs uniform white noise. All samples are within the range [-1.0, 1.0]. Syntax: - csdr gaussian_noise_c + csdr gaussian_noise_c It outputs Gaussian white noise. All samples are within the unit circle. @@ -869,7 +869,7 @@ It outputs Gaussian white noise. All samples are within the unit circle. Syntax: - csdr pack_bits_8to1_u8_u8 + csdr pack_bits_8to1_u8_u8 It serializes the bytes on the input: it outputs each bit of the input byte as a single byte valued 0x00 or 0x01, starting from the lowest bit and going to the highest bit. @@ -895,7 +895,7 @@ For consequtive 0x02, 0x03, 0xff bytes on the input, the output will be: Syntax: - csdr awgn_cc [--snrshow] + csdr awgn_cc [--snrshow] It adds white noise with the given SNR to a signal assumed to be of 0 dB power. @@ -907,7 +907,7 @@ If the `--snrshow` switch is given, it also shows the actual SNR based on the ca Syntax: - csdr add_n_zero_samples_at_beginning_f + csdr add_n_zero_samples_at_beginning_f When the function is executed, it furst writes `` 32-bit floating point zeros at the output, after that it just clones the input at the output. @@ -917,7 +917,7 @@ When the function is executed, it furst writes `` 32-bit floatin Syntax: - csdr ? + csdr ? You can search the functions available in `csdr` just as if you typed: `csdr 2>&1 | grep ` @@ -925,7 +925,7 @@ You can search the functions available in `csdr` just as if you typed: `csdr 2>& Syntax: - csdr = + csdr = When running complicated `csdr` commands, we usually run into using `python` to calculate certain parameters. @@ -933,19 +933,19 @@ This function can eliminate some typing and make our command clearer. Instead of having to write: - csdr shift_addition_cc $(python -c "print 1200/2400000.") + csdr shift_addition_cc $(python -c "print 1200/2400000.") ...we can type: - csdr shift_addition_cc $(csdr =1200/2400000.) + csdr shift_addition_cc $(csdr =1200/2400000.) If using parenthesis inside the expression, it needs to be escaped (as `bash` would want to parse it): - csdr shift_addition_cc $(csdr =\(1200+300\)/2400000) + csdr shift_addition_cc $(csdr =\(1200+300\)/2400000) Another solution is using single quotes to wrap the expression: - csdr shift_addition_cc $(csdr '=(1200+300)/2400000.') + csdr shift_addition_cc $(csdr '=(1200+300)/2400000.') Current version of `csdr` executes the following python script for this function: @@ -961,21 +961,21 @@ This means that one can also call math functions like `sqrt()`. Some parameters can be changed while the `csdr` process is running. To achieve this, some `csdr` functions have special parameters. You have to supply a fifo previously created by the `mkfifo` command. Processing will only start after the first control command has been received by `csdr` over the FIFO. - shift_addition_cc --fifo + shift_addition_cc --fifo By writing to the given FIFO file with the syntax below, you can control the shift rate: - \n + \n E.g. you can send `-0.3\n` Processing will only start after the first control command has been received by `csdr` over the FIFO. - bandpass_fir_fft_cc --fifo [window] + bandpass_fir_fft_cc --fifo [window] By writing to the given FIFO file with the syntax below, you can control the shift rate: - \n + \n E.g. you can send `-0.05 0.02\n` @@ -1043,17 +1043,17 @@ To compile *sdr.js*, first get Emscripten. To install and build dependencies (for now, only FFTW3): - make emcc-get-deps + make emcc-get-deps To compile *sdr.js* (which will be created in the `sdr.js` subdirectory): - make emcc + make emcc You can test *sdr.js* by opening *sdr.html*. It contains a test for *firdes_lowpass_f* for this time. To remove *sdr.js* and the compiled dependencies: - make emcc-clean + make emcc-clean ## [nmux](#nmux) diff --git a/csdr.c b/csdr.c index 04a330d..52f1c66 100755 --- a/csdr.c +++ b/csdr.c @@ -169,73 +169,73 @@ int bigbufs = 0; int badsyntax(char* why) { - if(why==0) fprintf(stderr, "%s", usage); - else fprintf(stderr, "csdr: %s\n\n", why); - return -1; + if(why==0) fprintf(stderr, "%s", usage); + else fprintf(stderr, "csdr: %s\n\n", why); + return -1; } int clipdetect_ff(float* input, int input_size) { - for(int i=0;i1.0) { fprintf(stderr, "csdr clipdetect_ff: Signal value above 1.0!\n"); return 1; } - } - return 0; + for(int i=0;i1.0) { fprintf(stderr, "csdr clipdetect_ff: Signal value above 1.0!\n"); return 1; } + } + return 0; } int clone_(int bufsize_param) { - unsigned char* clone_buffer; - clone_buffer = (unsigned char*)malloc(bufsize_param*sizeof(unsigned char)); - for(;;) - { - fread(clone_buffer, sizeof(unsigned char), bufsize_param, stdin); - fwrite(clone_buffer, sizeof(unsigned char), bufsize_param, stdout); - TRY_YIELD; - } + unsigned char* clone_buffer; + clone_buffer = (unsigned char*)malloc(bufsize_param*sizeof(unsigned char)); + for(;;) + { + fread(clone_buffer, sizeof(unsigned char), bufsize_param, stdin); + fwrite(clone_buffer, sizeof(unsigned char), bufsize_param, stdout); + TRY_YIELD; + } } -#define FREAD_U8 fread (input_buffer, sizeof(unsigned char), the_bufsize, stdin) -#define FWRITE_U8 fwrite (output_buffer, sizeof(unsigned char), the_bufsize, stdout) -#define FREAD_R fread (input_buffer, sizeof(float), the_bufsize, stdin) -#define FREAD_C fread (input_buffer, sizeof(float)*2, the_bufsize, stdin) -#define FWRITE_R fwrite (output_buffer, sizeof(float), the_bufsize, stdout) -#define FWRITE_C fwrite (output_buffer, sizeof(float)*2, the_bufsize, stdout) -#define FEOF_CHECK if(feof(stdin)) return 0 +#define FREAD_U8 fread (input_buffer, sizeof(unsigned char), the_bufsize, stdin) +#define FWRITE_U8 fwrite (output_buffer, sizeof(unsigned char), the_bufsize, stdout) +#define FREAD_R fread (input_buffer, sizeof(float), the_bufsize, stdin) +#define FREAD_C fread (input_buffer, sizeof(float)*2, the_bufsize, stdin) +#define FWRITE_R fwrite (output_buffer, sizeof(float), the_bufsize, stdout) +#define FWRITE_C fwrite (output_buffer, sizeof(float)*2, the_bufsize, stdout) +#define FEOF_CHECK if(feof(stdin)) return 0 //#define BIG_FREAD_C fread(input_buffer, sizeof(float)*2, BIG_BUFSIZE, stdin) //#define BIG_FWRITE_C fwrite(output_buffer, sizeof(float)*2, BIG_BUFSIZE, stdout) int init_fifo(int argc, char *argv[]) { - if(argc>=4) - { - if(!strcmp(argv[2],"--fifo")) - { - fprintf(stderr,"csdr: fifo control mode on\n"); - int fd = open(argv[3], O_RDONLY); - int flags = fcntl(fd, F_GETFL, 0); - fcntl(fd, F_SETFL, flags | O_NONBLOCK); - return fd; - } - else if(!strcmp(argv[2],"--fd")) - { - //to use this: - //1. Create a pipe(pipedesc) in your process. - //2. fork() and execl() your process to run csdr, and give pipedesc[0] as parameter after --fd - // Note: when forking, the child process will get a copy of the file descriptor table! That's why this - // works at all, as file descriptor indexes are normally not transferable between processes, except for a *NIX socket way which is quite complicated... - //3. From your parent process, write into pipedesc[1]. - //This is implemented in ddcd, check there to see how to do it! - int fd; - if(sscanf(argv[3], "%d",&fd)<=0) return 0; - fprintf(stderr,"csdr: fd control mode on, fd=%d\n", fd); - int flags = fcntl(fd, F_GETFL, 0); - fcntl(fd, F_SETFL, flags | O_NONBLOCK); - return fd; - } - } - return 0; + if(argc>=4) + { + if(!strcmp(argv[2],"--fifo")) + { + fprintf(stderr,"csdr: fifo control mode on\n"); + int fd = open(argv[3], O_RDONLY); + int flags = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + return fd; + } + else if(!strcmp(argv[2],"--fd")) + { + //to use this: + //1. Create a pipe(pipedesc) in your process. + //2. fork() and execl() your process to run csdr, and give pipedesc[0] as parameter after --fd + // Note: when forking, the child process will get a copy of the file descriptor table! That's why this + // works at all, as file descriptor indexes are normally not transferable between processes, except for a *NIX socket way which is quite complicated... + //3. From your parent process, write into pipedesc[1]. + //This is implemented in ddcd, check there to see how to do it! + int fd; + if(sscanf(argv[3], "%d",&fd)<=0) return 0; + fprintf(stderr,"csdr: fd control mode on, fd=%d\n", fd); + int flags = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + return fd; + } + } + return 0; } @@ -244,38 +244,38 @@ int init_fifo(int argc, char *argv[]) int read_fifo_ctl(int fd, char* format, ...) { - if(!fd) return 0; - static char buffer[RFCTL_BUFSIZE]; - static int buffer_index=0; - int bytes_read=read(fd,buffer+buffer_index,(RFCTL_BUFSIZE-buffer_index)*sizeof(char)); - if(bytes_read<=0) return 0; + if(!fd) return 0; + static char buffer[RFCTL_BUFSIZE]; + static int buffer_index=0; + int bytes_read=read(fd,buffer+buffer_index,(RFCTL_BUFSIZE-buffer_index)*sizeof(char)); + if(bytes_read<=0) return 0; - int prev_newline_at=0; - int last_newline_at=0; - for(int i=0;i\" at the beginning of the chain! Falling back to default buffer size: " STRINGIFY_VALUE(SETBUF_DEFAULT_BUFSIZE)); return SETBUF_DEFAULT_BUFSIZE; } - if(recv_first[1]<=0) { badsyntax("warning! Invalid buffer size." ); return 0; } - return recv_first[1]; + if(!env_csdr_dynamic_bufsize_on) return (bigbufs) ? env_csdr_fixed_big_bufsize : env_csdr_fixed_bufsize; + int recv_first[2]; + fread(recv_first, sizeof(int), 2, stdin); + if(memcmp(recv_first, SETBUF_PREAMBLE, sizeof(char)*4)!=0) + { badsyntax("warning! Did not match preamble on the beginning of the stream. You should put \"csdr setbuf \" at the beginning of the chain! Falling back to default buffer size: " STRINGIFY_VALUE(SETBUF_DEFAULT_BUFSIZE)); return SETBUF_DEFAULT_BUFSIZE; } + if(recv_first[1]<=0) { badsyntax("warning! Invalid buffer size." ); return 0; } + return recv_first[1]; } @@ -308,1381 +308,1381 @@ char **argv_global; int unitround(int what) { - if(what<=0) return UNITROUND_UNIT; - return ((what-1)&~(UNITROUND_UNIT-1))+UNITROUND_UNIT; + if(what<=0) return UNITROUND_UNIT; + return ((what-1)&~(UNITROUND_UNIT-1))+UNITROUND_UNIT; } int initialize_buffers() { - if(!(the_bufsize=getbufsize())) return 0; - the_bufsize=unitround(the_bufsize); - if(env_csdr_print_bufsizes) fprintf(stderr,"%s %s: buffer size set to %d\n",argv_global[0], argv_global[1], the_bufsize); - input_buffer = (float*) malloc(the_bufsize*sizeof(float) * 2); //need the 2× because we might also put complex floats into it - output_buffer = (float*) malloc(the_bufsize*sizeof(float) * 2); - buffer_u8 = (unsigned char*)malloc(the_bufsize*sizeof(unsigned char)); - buffer_i16 = (short*) malloc(the_bufsize*sizeof(short)); - temp_f = (float*) malloc(the_bufsize*sizeof(float) * 4); - if(the_bufsize<=4096) //this is hacky, should be done correctly - { - fcntl(STDIN_FILENO, F_SETPIPE_SZ, 4096); - fcntl(STDOUT_FILENO, F_SETPIPE_SZ, 4096); - } - return the_bufsize; + if(!(the_bufsize=getbufsize())) return 0; + the_bufsize=unitround(the_bufsize); + if(env_csdr_print_bufsizes) fprintf(stderr,"%s %s: buffer size set to %d\n",argv_global[0], argv_global[1], the_bufsize); + input_buffer = (float*) malloc(the_bufsize*sizeof(float) * 2); //need the 2× because we might also put complex floats into it + output_buffer = (float*) malloc(the_bufsize*sizeof(float) * 2); + buffer_u8 = (unsigned char*)malloc(the_bufsize*sizeof(unsigned char)); + buffer_i16 = (short*) malloc(the_bufsize*sizeof(short)); + temp_f = (float*) malloc(the_bufsize*sizeof(float) * 4); + if(the_bufsize<=4096) //this is hacky, should be done correctly + { + fcntl(STDIN_FILENO, F_SETPIPE_SZ, 4096); + fcntl(STDOUT_FILENO, F_SETPIPE_SZ, 4096); + } + return the_bufsize; } int sendbufsize(int size) { - if(size<=4096) - { - fcntl(STDOUT_FILENO, F_SETPIPE_SZ, 4096); - } - //The first word is a preamble, "csdr". - //If the next csdr process detects it, sets the buffer size according to the second word - if(!env_csdr_dynamic_bufsize_on) return env_csdr_fixed_bufsize; - if(env_csdr_print_bufsizes) fprintf(stderr,"%s %s: next process proposed input buffer size is %d\n",argv_global[0], argv_global[1], size); - int send_first[2]; - memcpy((char*)send_first, SETBUF_PREAMBLE, 4*sizeof(char)); - send_first[1] = size; - fwrite(send_first, sizeof(int), 2, stdout); - return size; + if(size<=4096) + { + fcntl(STDOUT_FILENO, F_SETPIPE_SZ, 4096); + } + //The first word is a preamble, "csdr". + //If the next csdr process detects it, sets the buffer size according to the second word + if(!env_csdr_dynamic_bufsize_on) return env_csdr_fixed_bufsize; + if(env_csdr_print_bufsizes) fprintf(stderr,"%s %s: next process proposed input buffer size is %d\n",argv_global[0], argv_global[1], size); + int send_first[2]; + memcpy((char*)send_first, SETBUF_PREAMBLE, 4*sizeof(char)); + send_first[1] = size; + fwrite(send_first, sizeof(int), 2, stdout); + return size; } int parse_env() { - char* envtmp; - envtmp=getenv("CSDR_DYNAMIC_BUFSIZE_ON"); - //fprintf(stderr, "envtmp: %s\n",envtmp); - if(envtmp) - { - env_csdr_dynamic_bufsize_on = !!atoi(envtmp); - env_csdr_fixed_bufsize = 0; - } - else - { - envtmp=getenv("CSDR_FIXED_BUFSIZE"); - if(envtmp) - { - env_csdr_fixed_big_bufsize = env_csdr_fixed_bufsize = atoi(envtmp); - } - } - envtmp=getenv("CSDR_PRINT_BUFSIZES"); - if(envtmp) - { - env_csdr_print_bufsizes = atoi(envtmp); - } + char* envtmp; + envtmp=getenv("CSDR_DYNAMIC_BUFSIZE_ON"); + //fprintf(stderr, "envtmp: %s\n",envtmp); + if(envtmp) + { + env_csdr_dynamic_bufsize_on = !!atoi(envtmp); + env_csdr_fixed_bufsize = 0; + } + else + { + envtmp=getenv("CSDR_FIXED_BUFSIZE"); + if(envtmp) + { + env_csdr_fixed_big_bufsize = env_csdr_fixed_bufsize = atoi(envtmp); + } + } + envtmp=getenv("CSDR_PRINT_BUFSIZES"); + if(envtmp) + { + env_csdr_print_bufsizes = atoi(envtmp); + } } int main(int argc, char *argv[]) { - parse_env(); - argv_global=argv; - if(argc<=1) return badsyntax(0); - if(!strcmp(argv[1],"--help")) return badsyntax(0); + parse_env(); + argv_global=argv; + if(argc<=1) return badsyntax(0); + if(!strcmp(argv[1],"--help")) return badsyntax(0); - fcntl(STDIN_FILENO, F_SETPIPE_SZ, 65536*32); - fcntl(STDOUT_FILENO, F_SETPIPE_SZ, 65536*32); - //fprintf(stderr, "csdr: F_SETPIPE_SZ\n"); + fcntl(STDIN_FILENO, F_SETPIPE_SZ, 65536*32); + fcntl(STDOUT_FILENO, F_SETPIPE_SZ, 65536*32); + //fprintf(stderr, "csdr: F_SETPIPE_SZ\n"); - if(!strcmp(argv[1],"setbuf")) - { - if(argc<=2) return badsyntax("need required parameter (buffer size)"); - sscanf(argv[2],"%d",&the_bufsize); - if(the_bufsize<=0) return badsyntax("buffer size <= 0 is invalid"); - sendbufsize(the_bufsize); - clone_(the_bufsize); //After sending the buffer size out, just copy stdin to stdout - } + if(!strcmp(argv[1],"setbuf")) + { + if(argc<=2) return badsyntax("need required parameter (buffer size)"); + sscanf(argv[2],"%d",&the_bufsize); + if(the_bufsize<=0) return badsyntax("buffer size <= 0 is invalid"); + sendbufsize(the_bufsize); + clone_(the_bufsize); //After sending the buffer size out, just copy stdin to stdout + } - if(!strcmp(argv[1],"clone")) - { - if(!sendbufsize(initialize_buffers())) return -2; - clone_(the_bufsize); - } + if(!strcmp(argv[1],"clone")) + { + if(!sendbufsize(initialize_buffers())) return -2; + clone_(the_bufsize); + } #define SET_NONBLOCK(fd) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) - if(!strcmp(argv[1],"fifo")) - { - if(!sendbufsize(initialize_buffers())) return -2; + if(!strcmp(argv[1],"fifo")) + { + if(!sendbufsize(initialize_buffers())) return -2; - int fifo_buffer_size; - if(argc<=2) return badsyntax("need required parameter (buffer_size)"); - sscanf(argv[2],"%d",&fifo_buffer_size); - int fifo_num_buffers; - if(argc<=3) return badsyntax("need required parameter (number of buffers)"); - sscanf(argv[3],"%d",&fifo_num_buffers); + int fifo_buffer_size; + if(argc<=2) return badsyntax("need required parameter (buffer_size)"); + sscanf(argv[2],"%d",&fifo_buffer_size); + int fifo_num_buffers; + if(argc<=3) return badsyntax("need required parameter (number of buffers)"); + sscanf(argv[3],"%d",&fifo_num_buffers); - char** fifo_buffers = (char**)malloc(sizeof(char*)*fifo_num_buffers); - for(int i=0;i STDIN_FILENO) ? STDOUT_FILENO : STDIN_FILENO) + 1; + int highfd = ((STDOUT_FILENO > STDIN_FILENO) ? STDOUT_FILENO : STDIN_FILENO) + 1; - int fifo_actual_buffer_wr = fifo_num_buffers - 1; - int fifo_actual_buffer_rd = 0; - int fifo_actual_buffer_wr_pos = 0; - int fifo_actual_buffer_rd_pos = 0; - int fifo_error = 0; - int fifo_overrun_shown = 0; + int fifo_actual_buffer_wr = fifo_num_buffers - 1; + int fifo_actual_buffer_rd = 0; + int fifo_actual_buffer_wr_pos = 0; + int fifo_actual_buffer_rd_pos = 0; + int fifo_error = 0; + int fifo_overrun_shown = 0; - for(;;) - { - select(highfd, &read_fds, NULL, NULL, NULL); + for(;;) + { + select(highfd, &read_fds, NULL, NULL, NULL); - //try to read until buffer is full - if(FD_ISSET(STDIN_FILENO, &read_fds)) for(;;) - { - int read_bytes=read(STDIN_FILENO, fifo_buffers[fifo_actual_buffer_rd]+fifo_actual_buffer_rd_pos, fifo_buffer_size-fifo_actual_buffer_rd_pos); - //fprintf(stderr, "r %d %d | %d %d\n", read_bytes, fifo_buffer_size-fifo_actual_buffer_rd_pos, fifo_actual_buffer_rd, fifo_actual_buffer_rd_pos); - if(!read_bytes || ((read_bytes<0)&&(fifo_error=read_bytes)) ) break; - fifo_actual_buffer_rd_pos+=read_bytes; - if(!((fifo_actual_buffer_rd==fifo_actual_buffer_wr-1)||(fifo_actual_buffer_wr==0&&fifo_actual_buffer_rd==fifo_num_buffers-1))) - { - if(fifo_actual_buffer_rd_pos==fifo_buffer_size) - { - fifo_overrun_shown = 0; - fifo_actual_buffer_rd++; - fifo_actual_buffer_rd_pos = 0; - if(fifo_actual_buffer_rd>=fifo_num_buffers) fifo_actual_buffer_rd=0; - } - } - else - { - if(fifo_actual_buffer_rd_pos==fifo_buffer_size) - { - fifo_actual_buffer_rd_pos = 0; //rewrite same buffer - if(!fifo_overrun_shown) { fifo_overrun_shown=1; fprintf(stderr, "fifo: circular buffer full, dropping samples\n"); } - } - } - } - //try to write until buffer is empty - if(FD_ISSET(STDOUT_FILENO, &write_fds)) for(;;) - { - if(fifo_actual_buffer_wr == fifo_actual_buffer_rd) break; - int written_bytes=write(STDOUT_FILENO, fifo_buffers[fifo_actual_buffer_wr]+fifo_actual_buffer_wr_pos, fifo_buffer_size-fifo_actual_buffer_wr_pos); - //fprintf(stderr, "w %d %d | %d %d\n", written_bytes, fifo_buffer_size-fifo_actual_buffer_wr_pos, fifo_actual_buffer_wr, fifo_actual_buffer_wr_pos); - if(!written_bytes || ((written_bytes<0)&&(fifo_error=written_bytes)) ) break; - fifo_actual_buffer_wr_pos+=written_bytes; - if(fifo_actual_buffer_wr_pos==fifo_buffer_size) - { - fifo_actual_buffer_wr++; - fifo_actual_buffer_wr_pos = 0; - if(fifo_actual_buffer_wr>=fifo_num_buffers) fifo_actual_buffer_wr=0; - } + //try to read until buffer is full + if(FD_ISSET(STDIN_FILENO, &read_fds)) for(;;) + { + int read_bytes=read(STDIN_FILENO, fifo_buffers[fifo_actual_buffer_rd]+fifo_actual_buffer_rd_pos, fifo_buffer_size-fifo_actual_buffer_rd_pos); + //fprintf(stderr, "r %d %d | %d %d\n", read_bytes, fifo_buffer_size-fifo_actual_buffer_rd_pos, fifo_actual_buffer_rd, fifo_actual_buffer_rd_pos); + if(!read_bytes || ((read_bytes<0)&&(fifo_error=read_bytes)) ) break; + fifo_actual_buffer_rd_pos+=read_bytes; + if(!((fifo_actual_buffer_rd==fifo_actual_buffer_wr-1)||(fifo_actual_buffer_wr==0&&fifo_actual_buffer_rd==fifo_num_buffers-1))) + { + if(fifo_actual_buffer_rd_pos==fifo_buffer_size) + { + fifo_overrun_shown = 0; + fifo_actual_buffer_rd++; + fifo_actual_buffer_rd_pos = 0; + if(fifo_actual_buffer_rd>=fifo_num_buffers) fifo_actual_buffer_rd=0; + } + } + else + { + if(fifo_actual_buffer_rd_pos==fifo_buffer_size) + { + fifo_actual_buffer_rd_pos = 0; //rewrite same buffer + if(!fifo_overrun_shown) { fifo_overrun_shown=1; fprintf(stderr, "fifo: circular buffer full, dropping samples\n"); } + } + } + } + //try to write until buffer is empty + if(FD_ISSET(STDOUT_FILENO, &write_fds)) for(;;) + { + if(fifo_actual_buffer_wr == fifo_actual_buffer_rd) break; + int written_bytes=write(STDOUT_FILENO, fifo_buffers[fifo_actual_buffer_wr]+fifo_actual_buffer_wr_pos, fifo_buffer_size-fifo_actual_buffer_wr_pos); + //fprintf(stderr, "w %d %d | %d %d\n", written_bytes, fifo_buffer_size-fifo_actual_buffer_wr_pos, fifo_actual_buffer_wr, fifo_actual_buffer_wr_pos); + if(!written_bytes || ((written_bytes<0)&&(fifo_error=written_bytes)) ) break; + fifo_actual_buffer_wr_pos+=written_bytes; + if(fifo_actual_buffer_wr_pos==fifo_buffer_size) + { + fifo_actual_buffer_wr++; + fifo_actual_buffer_wr_pos = 0; + if(fifo_actual_buffer_wr>=fifo_num_buffers) fifo_actual_buffer_wr=0; + } - } - if(fifo_error&&errno!=11) { fprintf(stderr,"fifo: fifo_error (%d)", errno); return -1; } - } + } + if(fifo_error&&errno!=11) { fprintf(stderr,"fifo: fifo_error (%d)", errno); return -1; } + } - return -1; + return -1; - } + } - if(!strcmp(argv[1],"convert_u8_f")) - { - if(!sendbufsize(initialize_buffers())) return -2; - for(;;) - { - FEOF_CHECK; - fread(buffer_u8, sizeof(unsigned char), the_bufsize, stdin); - convert_u8_f(buffer_u8, output_buffer, the_bufsize); - FWRITE_R; - TRY_YIELD; - } - } - if(!strcmp(argv[1],"convert_f_u8")) //not tested - { - if(!sendbufsize(initialize_buffers())) return -2; - for(;;) - { - FEOF_CHECK; - FREAD_R; - convert_f_u8(input_buffer, buffer_u8, the_bufsize); - fwrite(buffer_u8, sizeof(unsigned char), the_bufsize, stdout); - TRY_YIELD; - } - } - if(!strcmp(argv[1],"convert_s8_f")) - { - if(!sendbufsize(initialize_buffers())) return -2; - for(;;) - { - FEOF_CHECK; - fread((signed char*)buffer_u8, sizeof(signed char), the_bufsize, stdin); - convert_s8_f((signed char*)buffer_u8, output_buffer, the_bufsize); - FWRITE_R; - TRY_YIELD; - } - } - if(!strcmp(argv[1],"convert_f_s8")) //not tested - { - if(!sendbufsize(initialize_buffers())) return -2; - for(;;) - { - FEOF_CHECK; - FREAD_R; - convert_f_s8(input_buffer, (signed char*)buffer_u8, the_bufsize); - fwrite((signed char*)buffer_u8, sizeof(signed char), the_bufsize, stdout); - TRY_YIELD; - } - } - if((!strcmp(argv[1],"convert_f_i16")) || (!strcmp(argv[1],"convert_f_s16"))) - { - if(!sendbufsize(initialize_buffers())) return -2; - for(;;) - { - FEOF_CHECK; - FREAD_R; - convert_f_i16(input_buffer, buffer_i16, the_bufsize); - fwrite(buffer_i16, sizeof(short), the_bufsize, stdout); - TRY_YIELD; - } - } - if((!strcmp(argv[1],"convert_i16_f")) || (!strcmp(argv[1],"convert_s16_f"))) - { - if(!sendbufsize(initialize_buffers())) return -2; - for(;;) - { - FEOF_CHECK; - fread(buffer_i16, sizeof(short), the_bufsize, stdin); - convert_i16_f(buffer_i16, output_buffer, the_bufsize); - FWRITE_R; - TRY_YIELD; - } - } - if(!strcmp(argv[1],"convert_f_s24")) - { - int bigendian = (argc>2) && (!strcmp(argv[2],"--bigendian")); - unsigned char* s24buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize*3); - if(!sendbufsize(initialize_buffers())) return -2; - for(;;) - { - FEOF_CHECK; - FREAD_R; - convert_f_s24(input_buffer, s24buffer, the_bufsize, bigendian); - fwrite(s24buffer, sizeof(unsigned char)*3, the_bufsize, stdout); - TRY_YIELD; - } - } - if(!strcmp(argv[1],"convert_s24_f")) - { - int bigendian = (argc>2) && (!strcmp(argv[2],"--bigendian")); - unsigned char* s24buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize*3); - if(!sendbufsize(initialize_buffers())) return -2; - for(;;) - { - FEOF_CHECK; - fread(s24buffer, sizeof(unsigned char)*3, the_bufsize, stdin); - convert_s24_f(s24buffer, output_buffer, the_bufsize, bigendian); - FWRITE_R; - TRY_YIELD; - } - } - if(!strcmp(argv[1],"realpart_cf")) - { - if(!sendbufsize(initialize_buffers())) return -2; - for(;;) - { - FEOF_CHECK; - FREAD_C; - for(int i=0;i=3) sscanf(argv[2],"%g",&max_amplitude); - if(!sendbufsize(initialize_buffers())) return -2; - for(;;) - { - FEOF_CHECK; - FREAD_R; - limit_ff(input_buffer, output_buffer, the_bufsize, max_amplitude); - FWRITE_R; - TRY_YIELD; - } - } - if(!strcmp(argv[1],"yes_f")) - { - if(argc<=2) return badsyntax("need required parameter (to_repeat)"); - float to_repeat; - sscanf(argv[2],"%g",&to_repeat); - int buf_times = 0; - if(argc>=4) sscanf(argv[3],"%d",&buf_times); - if(!sendbufsize(initialize_buffers())) return -2; - for(int i=0;i/dev/null - //csdr yes_f 1 1000000 | time csdr shift_addition_cc 0.2 >/dev/null - //csdr yes_f 1 1000000 | time csdr shift_table_cc 0.2 >/dev/null + if(!strcmp(argv[1],"convert_u8_f")) + { + if(!sendbufsize(initialize_buffers())) return -2; + for(;;) + { + FEOF_CHECK; + fread(buffer_u8, sizeof(unsigned char), the_bufsize, stdin); + convert_u8_f(buffer_u8, output_buffer, the_bufsize); + FWRITE_R; + TRY_YIELD; + } + } + if(!strcmp(argv[1],"convert_f_u8")) //not tested + { + if(!sendbufsize(initialize_buffers())) return -2; + for(;;) + { + FEOF_CHECK; + FREAD_R; + convert_f_u8(input_buffer, buffer_u8, the_bufsize); + fwrite(buffer_u8, sizeof(unsigned char), the_bufsize, stdout); + TRY_YIELD; + } + } + if(!strcmp(argv[1],"convert_s8_f")) + { + if(!sendbufsize(initialize_buffers())) return -2; + for(;;) + { + FEOF_CHECK; + fread((signed char*)buffer_u8, sizeof(signed char), the_bufsize, stdin); + convert_s8_f((signed char*)buffer_u8, output_buffer, the_bufsize); + FWRITE_R; + TRY_YIELD; + } + } + if(!strcmp(argv[1],"convert_f_s8")) //not tested + { + if(!sendbufsize(initialize_buffers())) return -2; + for(;;) + { + FEOF_CHECK; + FREAD_R; + convert_f_s8(input_buffer, (signed char*)buffer_u8, the_bufsize); + fwrite((signed char*)buffer_u8, sizeof(signed char), the_bufsize, stdout); + TRY_YIELD; + } + } + if((!strcmp(argv[1],"convert_f_i16")) || (!strcmp(argv[1],"convert_f_s16"))) + { + if(!sendbufsize(initialize_buffers())) return -2; + for(;;) + { + FEOF_CHECK; + FREAD_R; + convert_f_i16(input_buffer, buffer_i16, the_bufsize); + fwrite(buffer_i16, sizeof(short), the_bufsize, stdout); + TRY_YIELD; + } + } + if((!strcmp(argv[1],"convert_i16_f")) || (!strcmp(argv[1],"convert_s16_f"))) + { + if(!sendbufsize(initialize_buffers())) return -2; + for(;;) + { + FEOF_CHECK; + fread(buffer_i16, sizeof(short), the_bufsize, stdin); + convert_i16_f(buffer_i16, output_buffer, the_bufsize); + FWRITE_R; + TRY_YIELD; + } + } + if(!strcmp(argv[1],"convert_f_s24")) + { + int bigendian = (argc>2) && (!strcmp(argv[2],"--bigendian")); + unsigned char* s24buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize*3); + if(!sendbufsize(initialize_buffers())) return -2; + for(;;) + { + FEOF_CHECK; + FREAD_R; + convert_f_s24(input_buffer, s24buffer, the_bufsize, bigendian); + fwrite(s24buffer, sizeof(unsigned char)*3, the_bufsize, stdout); + TRY_YIELD; + } + } + if(!strcmp(argv[1],"convert_s24_f")) + { + int bigendian = (argc>2) && (!strcmp(argv[2],"--bigendian")); + unsigned char* s24buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize*3); + if(!sendbufsize(initialize_buffers())) return -2; + for(;;) + { + FEOF_CHECK; + fread(s24buffer, sizeof(unsigned char)*3, the_bufsize, stdin); + convert_s24_f(s24buffer, output_buffer, the_bufsize, bigendian); + FWRITE_R; + TRY_YIELD; + } + } + if(!strcmp(argv[1],"realpart_cf")) + { + if(!sendbufsize(initialize_buffers())) return -2; + for(;;) + { + FEOF_CHECK; + FREAD_C; + for(int i=0;i=3) sscanf(argv[2],"%g",&max_amplitude); + if(!sendbufsize(initialize_buffers())) return -2; + for(;;) + { + FEOF_CHECK; + FREAD_R; + limit_ff(input_buffer, output_buffer, the_bufsize, max_amplitude); + FWRITE_R; + TRY_YIELD; + } + } + if(!strcmp(argv[1],"yes_f")) + { + if(argc<=2) return badsyntax("need required parameter (to_repeat)"); + float to_repeat; + sscanf(argv[2],"%g",&to_repeat); + int buf_times = 0; + if(argc>=4) sscanf(argv[3],"%d",&buf_times); + if(!sendbufsize(initialize_buffers())) return -2; + for(int i=0;i/dev/null + //csdr yes_f 1 1000000 | time csdr shift_addition_cc 0.2 >/dev/null + //csdr yes_f 1 1000000 | time csdr shift_table_cc 0.2 >/dev/null - if(!strcmp(argv[1],"shift_table_cc")) - { - bigbufs=1; - if(argc<=2) return badsyntax("need required parameter (rate)"); - float starting_phase=0; - float rate; - int table_size=65536; - sscanf(argv[2],"%g",&rate); - if(argc>3) sscanf(argv[3],"%d",&table_size); - if(!sendbufsize(initialize_buffers())) return -2; - shift_table_data_t table_data=shift_table_init(table_size); - fprintf(stderr,"shift_table_cc: LUT initialized\n"); - for(;;) - { - FEOF_CHECK; - if(!FREAD_C) break; - starting_phase=shift_table_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, rate, table_data, starting_phase); - FWRITE_C; - TRY_YIELD; - } - return 0; - } + if(!strcmp(argv[1],"shift_table_cc")) + { + bigbufs=1; + if(argc<=2) return badsyntax("need required parameter (rate)"); + float starting_phase=0; + float rate; + int table_size=65536; + sscanf(argv[2],"%g",&rate); + if(argc>3) sscanf(argv[3],"%d",&table_size); + if(!sendbufsize(initialize_buffers())) return -2; + shift_table_data_t table_data=shift_table_init(table_size); + fprintf(stderr,"shift_table_cc: LUT initialized\n"); + for(;;) + { + FEOF_CHECK; + if(!FREAD_C) break; + starting_phase=shift_table_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, rate, table_data, starting_phase); + FWRITE_C; + TRY_YIELD; + } + return 0; + } - if(!strcmp(argv[1],"shift_addfast_cc")) - { - bigbufs=1; + if(!strcmp(argv[1],"shift_addfast_cc")) + { + bigbufs=1; - float starting_phase=0; - float rate; + float starting_phase=0; + float rate; - int fd; - if(fd=init_fifo(argc,argv)) - { - while(!read_fifo_ctl(fd,"%g\n",&rate)) usleep(10000); - } - else - { - if(argc<=2) return badsyntax("need required parameter (rate)"); - sscanf(argv[2],"%g",&rate); - } + int fd; + if(fd=init_fifo(argc,argv)) + { + while(!read_fifo_ctl(fd,"%g\n",&rate)) usleep(10000); + } + else + { + if(argc<=2) return badsyntax("need required parameter (rate)"); + sscanf(argv[2],"%g",&rate); + } - if(!sendbufsize(initialize_buffers())) return -2; - for(;;) - { - shift_addfast_data_t data=shift_addfast_init(rate); - fprintf(stderr,"shift_addfast_cc: reinitialized to %g\n",rate); - int remain, current_size; - float* ibufptr; - float* obufptr; - for(;;) - { - FEOF_CHECK; - if(!FREAD_C) break; - remain=the_bufsize; - ibufptr=input_buffer; - obufptr=output_buffer; - while(remain) - { - current_size=(remain>1024)?1024:remain; - starting_phase=shift_addfast_cc((complexf*)ibufptr, (complexf*)obufptr, current_size, &data, starting_phase); - ibufptr+=current_size*2; - obufptr+=current_size*2; - remain-=current_size; - } - FWRITE_C; - if(read_fifo_ctl(fd,"%g\n",&rate)) break; - TRY_YIELD; - } - } - return 0; - } + if(!sendbufsize(initialize_buffers())) return -2; + for(;;) + { + shift_addfast_data_t data=shift_addfast_init(rate); + fprintf(stderr,"shift_addfast_cc: reinitialized to %g\n",rate); + int remain, current_size; + float* ibufptr; + float* obufptr; + for(;;) + { + FEOF_CHECK; + if(!FREAD_C) break; + remain=the_bufsize; + ibufptr=input_buffer; + obufptr=output_buffer; + while(remain) + { + current_size=(remain>1024)?1024:remain; + starting_phase=shift_addfast_cc((complexf*)ibufptr, (complexf*)obufptr, current_size, &data, starting_phase); + ibufptr+=current_size*2; + obufptr+=current_size*2; + remain-=current_size; + } + FWRITE_C; + if(read_fifo_ctl(fd,"%g\n",&rate)) break; + TRY_YIELD; + } + } + return 0; + } - if(!strcmp(argv[1],"shift_unroll_cc")) - { - bigbufs=1; + if(!strcmp(argv[1],"shift_unroll_cc")) + { + bigbufs=1; - float starting_phase=0; - float rate; + float starting_phase=0; + float rate; - int fd; - if(fd=init_fifo(argc,argv)) - { - while(!read_fifo_ctl(fd,"%g\n",&rate)) usleep(10000); - } - else - { - if(argc<=2) return badsyntax("need required parameter (rate)"); - sscanf(argv[2],"%g",&rate); - } + int fd; + if(fd=init_fifo(argc,argv)) + { + while(!read_fifo_ctl(fd,"%g\n",&rate)) usleep(10000); + } + else + { + if(argc<=2) return badsyntax("need required parameter (rate)"); + sscanf(argv[2],"%g",&rate); + } - if(!sendbufsize(initialize_buffers())) return -2; - for(;;) - { - shift_unroll_data_t data=shift_unroll_init(rate, 1024); - fprintf(stderr,"shift_unroll_cc: reinitialized to %g\n",rate); - int remain, current_size; - float* ibufptr; - float* obufptr; - for(;;) - { - FEOF_CHECK; - if(!FREAD_C) break; - remain=the_bufsize; - ibufptr=input_buffer; - obufptr=output_buffer; - while(remain) - { - current_size=(remain>1024)?1024:remain; - starting_phase=shift_unroll_cc((complexf*)ibufptr, (complexf*)obufptr, current_size, &data, starting_phase); - ibufptr+=current_size*2; - obufptr+=current_size*2; - remain-=current_size; - } - FWRITE_C; - if(read_fifo_ctl(fd,"%g\n",&rate)) break; - TRY_YIELD; - } - } - return 0; - } + if(!sendbufsize(initialize_buffers())) return -2; + for(;;) + { + shift_unroll_data_t data=shift_unroll_init(rate, 1024); + fprintf(stderr,"shift_unroll_cc: reinitialized to %g\n",rate); + int remain, current_size; + float* ibufptr; + float* obufptr; + for(;;) + { + FEOF_CHECK; + if(!FREAD_C) break; + remain=the_bufsize; + ibufptr=input_buffer; + obufptr=output_buffer; + while(remain) + { + current_size=(remain>1024)?1024:remain; + starting_phase=shift_unroll_cc((complexf*)ibufptr, (complexf*)obufptr, current_size, &data, starting_phase); + ibufptr+=current_size*2; + obufptr+=current_size*2; + remain-=current_size; + } + FWRITE_C; + if(read_fifo_ctl(fd,"%g\n",&rate)) break; + TRY_YIELD; + } + } + return 0; + } #ifdef LIBCSDR_GPL - if(!strcmp(argv[1],"decimating_shift_addition_cc")) - { - bigbufs=1; - if(argc<=2) return badsyntax("need required parameter (rate)"); - float starting_phase=0; - float rate; - int decimation=1; - sscanf(argv[2],"%g",&rate); - if(argc>3) sscanf(argv[3],"%d",&decimation); - if(!initialize_buffers()) return -2; - sendbufsize(the_bufsize/decimation); - shift_addition_data_t d=decimating_shift_addition_init(rate, decimation); - decimating_shift_addition_status_t s; - s.decimation_remain=0; - s.starting_phase=0; - for(;;) - { - FEOF_CHECK; - if(!FREAD_C) break; - s=decimating_shift_addition_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, d, decimation, s); - fwrite(output_buffer, sizeof(float)*2, s.output_size, stdout); - TRY_YIELD; - } - return 0; - } + if(!strcmp(argv[1],"decimating_shift_addition_cc")) + { + bigbufs=1; + if(argc<=2) return badsyntax("need required parameter (rate)"); + float starting_phase=0; + float rate; + int decimation=1; + sscanf(argv[2],"%g",&rate); + if(argc>3) sscanf(argv[3],"%d",&decimation); + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize/decimation); + shift_addition_data_t d=decimating_shift_addition_init(rate, decimation); + decimating_shift_addition_status_t s; + s.decimation_remain=0; + s.starting_phase=0; + for(;;) + { + FEOF_CHECK; + if(!FREAD_C) break; + s=decimating_shift_addition_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, d, decimation, s); + fwrite(output_buffer, sizeof(float)*2, s.output_size, stdout); + TRY_YIELD; + } + return 0; + } - if(!strcmp(argv[1],"shift_addition_cc")) - { - bigbufs=1; + if(!strcmp(argv[1],"shift_addition_cc")) + { + bigbufs=1; - float starting_phase=0; - float rate; + float starting_phase=0; + float rate; - int fd; - if(fd=init_fifo(argc,argv)) - { - while(!read_fifo_ctl(fd,"%g\n",&rate)) usleep(10000); - } - else - { - if(argc<=2) return badsyntax("need required parameter (rate)"); - sscanf(argv[2],"%g",&rate); - } + int fd; + if(fd=init_fifo(argc,argv)) + { + while(!read_fifo_ctl(fd,"%g\n",&rate)) usleep(10000); + } + else + { + if(argc<=2) return badsyntax("need required parameter (rate)"); + sscanf(argv[2],"%g",&rate); + } - if(!sendbufsize(initialize_buffers())) return -2; - for(;;) - { - shift_addition_data_t data=shift_addition_init(rate); - fprintf(stderr,"shift_addition_cc: reinitialized to %g\n",rate); - int remain, current_size; - float* ibufptr; - float* obufptr; - for(;;) - { - FEOF_CHECK; - if(!FREAD_C) break; - remain=the_bufsize; - ibufptr=input_buffer; - obufptr=output_buffer; - while(remain) - { - current_size=(remain>1024)?1024:remain; - starting_phase=shift_addition_cc((complexf*)ibufptr, (complexf*)obufptr, current_size, data, starting_phase); - ibufptr+=current_size*2; - obufptr+=current_size*2; - remain-=current_size; - } - FWRITE_C; - if(read_fifo_ctl(fd,"%g\n",&rate)) break; - TRY_YIELD; - } - } - return 0; - } + if(!sendbufsize(initialize_buffers())) return -2; + for(;;) + { + shift_addition_data_t data=shift_addition_init(rate); + fprintf(stderr,"shift_addition_cc: reinitialized to %g\n",rate); + int remain, current_size; + float* ibufptr; + float* obufptr; + for(;;) + { + FEOF_CHECK; + if(!FREAD_C) break; + remain=the_bufsize; + ibufptr=input_buffer; + obufptr=output_buffer; + while(remain) + { + current_size=(remain>1024)?1024:remain; + starting_phase=shift_addition_cc((complexf*)ibufptr, (complexf*)obufptr, current_size, data, starting_phase); + ibufptr+=current_size*2; + obufptr+=current_size*2; + remain-=current_size; + } + FWRITE_C; + if(read_fifo_ctl(fd,"%g\n",&rate)) break; + TRY_YIELD; + } + } + return 0; + } - if(!strcmp(argv[1],"shift_addition_cc_test")) - { - if(argc<=2) return badsyntax("need required parameter (rate)"); - float rate; - sscanf(argv[2],"%g",&rate); - //if(initialize_buffers()) return -2; //most likely we don't need this here - shift_addition_data_t data=shift_addition_init(rate); - shift_addition_cc_test(data); - return 0; - } + if(!strcmp(argv[1],"shift_addition_cc_test")) + { + if(argc<=2) return badsyntax("need required parameter (rate)"); + float rate; + sscanf(argv[2],"%g",&rate); + //if(initialize_buffers()) return -2; //most likely we don't need this here + shift_addition_data_t data=shift_addition_init(rate); + shift_addition_cc_test(data); + return 0; + } #endif - if(!strcmp(argv[1],"dcblock_ff")) - { - static dcblock_preserve_t dcp; //will be 0 as .bss is set to 0 - if(!sendbufsize(initialize_buffers())) return -2; - for(;;) - { - FEOF_CHECK; - FREAD_R; - dcp=dcblock_ff(input_buffer, output_buffer, the_bufsize, 0, dcp); - FWRITE_R; - TRY_YIELD; - } - } + if(!strcmp(argv[1],"dcblock_ff")) + { + static dcblock_preserve_t dcp; //will be 0 as .bss is set to 0 + if(!sendbufsize(initialize_buffers())) return -2; + for(;;) + { + FEOF_CHECK; + FREAD_R; + dcp=dcblock_ff(input_buffer, output_buffer, the_bufsize, 0, dcp); + FWRITE_R; + TRY_YIELD; + } + } - if(!strcmp(argv[1],"fastdcblock_ff")) - { - int dcblock_bufsize=SETBUF_DEFAULT_BUFSIZE; - if(argc>=3) sscanf(argv[2],"%d",&dcblock_bufsize); - float* dcblock_buffer=(float*)malloc(sizeof(float)*dcblock_bufsize); - static float last_dc_level=0.0; - getbufsize(); //it is just dummy - sendbufsize(dcblock_bufsize); - for(;;) - { - FEOF_CHECK; - fread(dcblock_buffer, sizeof(float), dcblock_bufsize, stdin); - last_dc_level=fastdcblock_ff(dcblock_buffer, dcblock_buffer, dcblock_bufsize, last_dc_level); - fwrite(dcblock_buffer, sizeof(float), dcblock_bufsize, stdout); - TRY_YIELD; - } - } + if(!strcmp(argv[1],"fastdcblock_ff")) + { + int dcblock_bufsize=SETBUF_DEFAULT_BUFSIZE; + if(argc>=3) sscanf(argv[2],"%d",&dcblock_bufsize); + float* dcblock_buffer=(float*)malloc(sizeof(float)*dcblock_bufsize); + static float last_dc_level=0.0; + getbufsize(); //it is just dummy + sendbufsize(dcblock_bufsize); + for(;;) + { + FEOF_CHECK; + fread(dcblock_buffer, sizeof(float), dcblock_bufsize, stdin); + last_dc_level=fastdcblock_ff(dcblock_buffer, dcblock_buffer, dcblock_bufsize, last_dc_level); + fwrite(dcblock_buffer, sizeof(float), dcblock_bufsize, stdout); + TRY_YIELD; + } + } - if(!strcmp(argv[1],"fmdemod_atan_cf")) - { - if(!sendbufsize(initialize_buffers())) return -2; - float last_phase=0; - for(;;) - { - FEOF_CHECK; - FREAD_C; - if(feof(stdin)) return 0; - last_phase=fmdemod_atan_cf((complexf*)input_buffer, output_buffer, the_bufsize, last_phase); - FWRITE_R; - TRY_YIELD; - } - } - if(!strcmp(argv[1],"fmdemod_quadri_cf")) - { - if(!sendbufsize(initialize_buffers())) return -2; - complexf last_sample; - last_sample.i=0.; - last_sample.q=0.; - for(;;) - { - FEOF_CHECK; - FREAD_C; - last_sample=fmdemod_quadri_cf((complexf*)input_buffer, output_buffer, the_bufsize, temp_f, last_sample); - FWRITE_R; - TRY_YIELD; - } - } - if(!strcmp(argv[1],"fmdemod_quadri_novect_cf")) - { - if(!sendbufsize(initialize_buffers())) return -2; - complexf last_sample; - last_sample.i=0.; - last_sample.q=0.; - for(;;) - { - FEOF_CHECK; - FREAD_C; - last_sample=fmdemod_quadri_novect_cf((complexf*)input_buffer, output_buffer, the_bufsize, last_sample); - FWRITE_R; - TRY_YIELD; - } - } - if(!strcmp(argv[1],"deemphasis_wfm_ff")) - { - if(argc<=3) return badsyntax("need required parameters (sample rate, tau)"); - if(!sendbufsize(initialize_buffers())) return -2; - int sample_rate; - sscanf(argv[2],"%d",&sample_rate); - float tau; - sscanf(argv[3],"%g",&tau); - fprintf(stderr,"deemphasis_wfm_ff: tau = %g, sample_rate = %d\n",tau,sample_rate); - float last_output=0; - for(;;) - { - FEOF_CHECK; - FREAD_R; - last_output=deemphasis_wfm_ff(input_buffer, output_buffer, the_bufsize, tau, sample_rate, last_output); - FWRITE_R; - TRY_YIELD; - } - } + if(!strcmp(argv[1],"fmdemod_atan_cf")) + { + if(!sendbufsize(initialize_buffers())) return -2; + float last_phase=0; + for(;;) + { + FEOF_CHECK; + FREAD_C; + if(feof(stdin)) return 0; + last_phase=fmdemod_atan_cf((complexf*)input_buffer, output_buffer, the_bufsize, last_phase); + FWRITE_R; + TRY_YIELD; + } + } + if(!strcmp(argv[1],"fmdemod_quadri_cf")) + { + if(!sendbufsize(initialize_buffers())) return -2; + complexf last_sample; + last_sample.i=0.; + last_sample.q=0.; + for(;;) + { + FEOF_CHECK; + FREAD_C; + last_sample=fmdemod_quadri_cf((complexf*)input_buffer, output_buffer, the_bufsize, temp_f, last_sample); + FWRITE_R; + TRY_YIELD; + } + } + if(!strcmp(argv[1],"fmdemod_quadri_novect_cf")) + { + if(!sendbufsize(initialize_buffers())) return -2; + complexf last_sample; + last_sample.i=0.; + last_sample.q=0.; + for(;;) + { + FEOF_CHECK; + FREAD_C; + last_sample=fmdemod_quadri_novect_cf((complexf*)input_buffer, output_buffer, the_bufsize, last_sample); + FWRITE_R; + TRY_YIELD; + } + } + if(!strcmp(argv[1],"deemphasis_wfm_ff")) + { + if(argc<=3) return badsyntax("need required parameters (sample rate, tau)"); + if(!sendbufsize(initialize_buffers())) return -2; + int sample_rate; + sscanf(argv[2],"%d",&sample_rate); + float tau; + sscanf(argv[3],"%g",&tau); + fprintf(stderr,"deemphasis_wfm_ff: tau = %g, sample_rate = %d\n",tau,sample_rate); + float last_output=0; + for(;;) + { + FEOF_CHECK; + FREAD_R; + last_output=deemphasis_wfm_ff(input_buffer, output_buffer, the_bufsize, tau, sample_rate, last_output); + FWRITE_R; + TRY_YIELD; + } + } - if(!strcmp(argv[1],"detect_nan_ff")) - { - if(!sendbufsize(initialize_buffers())) return -2; - for(;;) - { - FEOF_CHECK; - FREAD_R; - int nan_detect=0; - for(int i=0; i=4) sscanf(argv[3],"%g",&transition_bw); + float transition_bw = 0.05; + if(argc>=4) sscanf(argv[3],"%g",&transition_bw); - window_t window = WINDOW_DEFAULT; - if(argc>=5) - { - window=firdes_get_window_from_string(argv[4]); - } - else fprintf(stderr,"fir_decimate_cc: window = %s\n",firdes_get_string_from_window(window)); + window_t window = WINDOW_DEFAULT; + if(argc>=5) + { + window=firdes_get_window_from_string(argv[4]); + } + else fprintf(stderr,"fir_decimate_cc: window = %s\n",firdes_get_string_from_window(window)); - int taps_length=firdes_filter_len(transition_bw); - fprintf(stderr,"fir_decimate_cc: taps_length = %d\n",taps_length); + int taps_length=firdes_filter_len(transition_bw); + fprintf(stderr,"fir_decimate_cc: taps_length = %d\n",taps_length); - while (env_csdr_fixed_big_bufsize < taps_length*2) env_csdr_fixed_big_bufsize*=2; //temporary fix for buffer size if [transition_bw] is low - //fprintf(stderr, "env_csdr_fixed_big_bufsize = %d\n", env_csdr_fixed_big_bufsize); + while (env_csdr_fixed_big_bufsize < taps_length*2) env_csdr_fixed_big_bufsize*=2; //temporary fix for buffer size if [transition_bw] is low + //fprintf(stderr, "env_csdr_fixed_big_bufsize = %d\n", env_csdr_fixed_big_bufsize); - if(!initialize_buffers()) return -2; - sendbufsize(the_bufsize/factor); + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize/factor); - int padded_taps_length = taps_length; - float *taps; + int padded_taps_length = taps_length; + float *taps; #define NEON_ALIGNMENT (4*4*2) #ifdef NEON_OPTS - fprintf(stderr,"taps_length = %d\n", taps_length); - padded_taps_length = taps_length+(NEON_ALIGNMENT/4)-1 - ((taps_length+(NEON_ALIGNMENT/4)-1)%(NEON_ALIGNMENT/4)); - fprintf(stderr,"padded_taps_length = %d\n", padded_taps_length); + fprintf(stderr,"taps_length = %d\n", taps_length); + padded_taps_length = taps_length+(NEON_ALIGNMENT/4)-1 - ((taps_length+(NEON_ALIGNMENT/4)-1)%(NEON_ALIGNMENT/4)); + fprintf(stderr,"padded_taps_length = %d\n", padded_taps_length); - taps = (float*) (float*)malloc((padded_taps_length+NEON_ALIGNMENT)*sizeof(float)); - fprintf(stderr,"taps = %x\n", taps); - taps = (float*)((((unsigned)taps)+NEON_ALIGNMENT-1) & ~(NEON_ALIGNMENT-1)); - fprintf(stderr,"taps = %x\n", taps); - for(int i=0;i= 1); + int factor; + sscanf(argv[2],"%d",&factor); + assert(factor >= 1); - float transition_bw = 0.05; - if(argc>=4) sscanf(argv[3],"%g",&transition_bw); - assert(transition_bw >= 0 && transition_bw < 1.); + float transition_bw = 0.05; + if(argc>=4) sscanf(argv[3],"%g",&transition_bw); + assert(transition_bw >= 0 && transition_bw < 1.); - window_t window = WINDOW_DEFAULT; - if(argc>=5) - { - window=firdes_get_window_from_string(argv[4]); - } - else fprintf(stderr,"fir_interpolate_cc: window = %s\n",firdes_get_string_from_window(window)); + window_t window = WINDOW_DEFAULT; + if(argc>=5) + { + window=firdes_get_window_from_string(argv[4]); + } + else fprintf(stderr,"fir_interpolate_cc: window = %s\n",firdes_get_string_from_window(window)); - int taps_length=firdes_filter_len(transition_bw); - fprintf(stderr,"fir_interpolate_cc: taps_length = %d\n",taps_length); - assert(taps_length > 0); + int taps_length=firdes_filter_len(transition_bw); + fprintf(stderr,"fir_interpolate_cc: taps_length = %d\n",taps_length); + assert(taps_length > 0); - while (env_csdr_fixed_big_bufsize < taps_length*2) env_csdr_fixed_big_bufsize*=2; //temporary fix for buffer size if [transition_bw] is low - //fprintf(stderr, "env_csdr_fixed_big_bufsize = %d\n", env_csdr_fixed_big_bufsize); + while (env_csdr_fixed_big_bufsize < taps_length*2) env_csdr_fixed_big_bufsize*=2; //temporary fix for buffer size if [transition_bw] is low + //fprintf(stderr, "env_csdr_fixed_big_bufsize = %d\n", env_csdr_fixed_big_bufsize); - if(!initialize_buffers()) return -2; - sendbufsize(the_bufsize*factor); - assert(the_bufsize > 0); + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize*factor); + assert(the_bufsize > 0); - float *taps; - taps=(float*)malloc(taps_length*sizeof(float)); - assert(taps); + float *taps; + taps=(float*)malloc(taps_length*sizeof(float)); + assert(taps); - firdes_lowpass_f(taps,taps_length,0.5/(float)factor,window); + firdes_lowpass_f(taps,taps_length,0.5/(float)factor,window); - int input_skip=0; - int output_size=0; - float* interp_output_buffer = (float*)malloc(sizeof(float)*2*the_bufsize*factor); - for(;;) - { - FEOF_CHECK; - output_size=fir_interpolate_cc((complexf*)input_buffer, (complexf*)interp_output_buffer, the_bufsize, factor, taps, taps_length); - //fprintf(stderr, "os %d\n",output_size); - fwrite(interp_output_buffer, sizeof(complexf), output_size, stdout); - TRY_YIELD; - input_skip=output_size/factor; - memmove((complexf*)input_buffer,((complexf*)input_buffer)+input_skip,(the_bufsize-input_skip)*sizeof(complexf)); //memmove lets the source and destination overlap - fread(((complexf*)input_buffer)+(the_bufsize-input_skip), sizeof(complexf), input_skip, stdin); - //fprintf(stderr,"iskip=%d output_size=%d start=%x target=%x skipcount=%x \n",input_skip,output_size,input_buffer, ((complexf*)input_buffer)+(BIG_BUFSIZE-input_skip),(BIG_BUFSIZE-input_skip)); - } - } + int input_skip=0; + int output_size=0; + float* interp_output_buffer = (float*)malloc(sizeof(float)*2*the_bufsize*factor); + for(;;) + { + FEOF_CHECK; + output_size=fir_interpolate_cc((complexf*)input_buffer, (complexf*)interp_output_buffer, the_bufsize, factor, taps, taps_length); + //fprintf(stderr, "os %d\n",output_size); + fwrite(interp_output_buffer, sizeof(complexf), output_size, stdout); + TRY_YIELD; + input_skip=output_size/factor; + memmove((complexf*)input_buffer,((complexf*)input_buffer)+input_skip,(the_bufsize-input_skip)*sizeof(complexf)); //memmove lets the source and destination overlap + fread(((complexf*)input_buffer)+(the_bufsize-input_skip), sizeof(complexf), input_skip, stdin); + //fprintf(stderr,"iskip=%d output_size=%d start=%x target=%x skipcount=%x \n",input_skip,output_size,input_buffer, ((complexf*)input_buffer)+(BIG_BUFSIZE-input_skip),(BIG_BUFSIZE-input_skip)); + } + } - /*if(!strcmp(argv[1],"ejw_test")) - { - printf("ejqd=["); - complexf ejw; - float phase=0; - for(int i=0;i<63;i++) - { - e_powj(&ejw,phase); - phase+=PI*0.3; - printf("%g+(%g)*i ",iof(&ejw,0),qof(&ejw,0)); - } - printf("];"); - return 0; - }*/ - if(!strcmp(argv[1],"firdes_lowpass_f")) - { - //Process the params - if(argc<=3) return badsyntax("need required parameters (cutoff_rate, length)"); + /*if(!strcmp(argv[1],"ejw_test")) + { + printf("ejqd=["); + complexf ejw; + float phase=0; + for(int i=0;i<63;i++) + { + e_powj(&ejw,phase); + phase+=PI*0.3; + printf("%g+(%g)*i ",iof(&ejw,0),qof(&ejw,0)); + } + printf("];"); + return 0; + }*/ + if(!strcmp(argv[1],"firdes_lowpass_f")) + { + //Process the params + if(argc<=3) return badsyntax("need required parameters (cutoff_rate, length)"); - float cutoff_rate; - sscanf(argv[2],"%g",&cutoff_rate); + float cutoff_rate; + sscanf(argv[2],"%g",&cutoff_rate); - int length; - sscanf(argv[3],"%d",&length); - if(length%2==0) return badsyntax("number of symmetric FIR filter taps should be odd"); + int length; + sscanf(argv[3],"%d",&length); + if(length%2==0) return badsyntax("number of symmetric FIR filter taps should be odd"); - window_t window = WINDOW_DEFAULT; - if(argc>=5) - { - window=firdes_get_window_from_string(argv[4]); - } - else fprintf(stderr,"firdes_lowpass_f: window = %s\n",firdes_get_string_from_window(window)); + window_t window = WINDOW_DEFAULT; + if(argc>=5) + { + window=firdes_get_window_from_string(argv[4]); + } + else fprintf(stderr,"firdes_lowpass_f: window = %s\n",firdes_get_string_from_window(window)); - int octave=(argc>=6 && !strcmp("--octave",argv[5])); + int octave=(argc>=6 && !strcmp("--octave",argv[5])); - float* taps=(float*)malloc(sizeof(float)*length); + float* taps=(float*)malloc(sizeof(float)*length); - //Make the filter - firdes_lowpass_f(taps,length,cutoff_rate,window); + //Make the filter + firdes_lowpass_f(taps,length,cutoff_rate,window); - //Do the output - if(octave) printf("taps=["); - for(int i=0;i=6) - { - window=firdes_get_window_from_string(argv[5]); - } - else fprintf(stderr,"firdes_bandpass_c: window = %s\n",firdes_get_string_from_window(window)); + window_t window = WINDOW_DEFAULT; + if(argc>=6) + { + window=firdes_get_window_from_string(argv[5]); + } + else fprintf(stderr,"firdes_bandpass_c: window = %s\n",firdes_get_string_from_window(window)); - int octave=(argc>=7 && !strcmp("--octave",argv[6])); + int octave=(argc>=7 && !strcmp("--octave",argv[6])); - complexf* taps=(complexf*)malloc(sizeof(complexf)*length); + complexf* taps=(complexf*)malloc(sizeof(complexf)*length); - //Make the filter - firdes_bandpass_c(taps, length, low_cut, high_cut, window); + //Make the filter + firdes_bandpass_c(taps, length, low_cut, high_cut, window); - //Do the output - if(octave) printf("taps=["); - for(int i=0;i=3) sscanf(argv[2],"%hd",&hang_time); + if(!strcmp(argv[1],"agc_ff")) + { + //Process the params + //Explanation of what these actually do is in the DSP source. + //These good default values are for SSB sampled at 48000 kHz. + short hang_time=200; + if(argc>=3) sscanf(argv[2],"%hd",&hang_time); - float reference=0.2; - if(argc>=4) sscanf(argv[3],"%g",&reference); + float reference=0.2; + if(argc>=4) sscanf(argv[3],"%g",&reference); - float attack_rate=0.01; - if(argc>=5) sscanf(argv[4],"%g",&attack_rate); + float attack_rate=0.01; + if(argc>=5) sscanf(argv[4],"%g",&attack_rate); - float decay_rate=0.0001; - if(argc>=6) sscanf(argv[5],"%g",&decay_rate); + float decay_rate=0.0001; + if(argc>=6) sscanf(argv[5],"%g",&decay_rate); - float max_gain=65536; - if(argc>=7) sscanf(argv[6],"%g",&max_gain); + float max_gain=65536; + if(argc>=7) sscanf(argv[6],"%g",&max_gain); - short attack_wait=0; - if(argc>=8) sscanf(argv[7],"%hd",&attack_wait); + short attack_wait=0; + if(argc>=8) sscanf(argv[7],"%hd",&attack_wait); - float filter_alpha=0.999;//0.001; - if(argc>=9) sscanf(argv[8],"%g",&filter_alpha); + float filter_alpha=0.999;//0.001; + if(argc>=9) sscanf(argv[8],"%g",&filter_alpha); - if(!sendbufsize(initialize_buffers())) return -2; + if(!sendbufsize(initialize_buffers())) return -2; - float last_gain=1.0; - for(;;) - { - FEOF_CHECK; - FREAD_R; - last_gain=agc_ff(input_buffer, output_buffer, the_bufsize, reference, attack_rate, decay_rate, max_gain, hang_time, attack_wait, filter_alpha, last_gain); - FWRITE_R; - TRY_YIELD; - } - } + float last_gain=1.0; + for(;;) + { + FEOF_CHECK; + FREAD_R; + last_gain=agc_ff(input_buffer, output_buffer, the_bufsize, reference, attack_rate, decay_rate, max_gain, hang_time, attack_wait, filter_alpha, last_gain); + FWRITE_R; + TRY_YIELD; + } + } #endif - if(!strcmp(argv[1],"fastagc_ff")) - { + if(!strcmp(argv[1],"fastagc_ff")) + { - static fastagc_ff_t input; //is in .bss and gets cleared to zero before main() + static fastagc_ff_t input; //is in .bss and gets cleared to zero before main() - input.input_size=1024; - if(argc>=3) sscanf(argv[2],"%d",&input.input_size); + input.input_size=1024; + if(argc>=3) sscanf(argv[2],"%d",&input.input_size); - getbufsize(); //dummy - sendbufsize(input.input_size); + getbufsize(); //dummy + sendbufsize(input.input_size); - input.reference=1.0; - if(argc>=4) sscanf(argv[3],"%g",&input.reference); + input.reference=1.0; + if(argc>=4) sscanf(argv[3],"%g",&input.reference); - //input.max_peak_ratio=12.0; - //if(argc>=5) sscanf(argv[3],"%g",&input.max_peak_ratio); + //input.max_peak_ratio=12.0; + //if(argc>=5) sscanf(argv[3],"%g",&input.max_peak_ratio); - input.buffer_1=(float*)calloc(input.input_size,sizeof(float)); - input.buffer_2=(float*)calloc(input.input_size,sizeof(float)); - input.buffer_input=(float*)malloc(sizeof(float)*input.input_size); - float* agc_output_buffer=(float*)malloc(sizeof(float)*input.input_size); - for(;;) - { - FEOF_CHECK; - fread(input.buffer_input, sizeof(float), input.input_size, stdin); - fastagc_ff(&input, agc_output_buffer); - fwrite(agc_output_buffer, sizeof(float), input.input_size, stdout); - TRY_YIELD; - } - } + input.buffer_1=(float*)calloc(input.input_size,sizeof(float)); + input.buffer_2=(float*)calloc(input.input_size,sizeof(float)); + input.buffer_input=(float*)malloc(sizeof(float)*input.input_size); + float* agc_output_buffer=(float*)malloc(sizeof(float)*input.input_size); + for(;;) + { + FEOF_CHECK; + fread(input.buffer_input, sizeof(float), input.input_size, stdin); + fastagc_ff(&input, agc_output_buffer); + fwrite(agc_output_buffer, sizeof(float), input.input_size, stdout); + TRY_YIELD; + } + } - int suboptimal; - if( (suboptimal=!strcmp(argv[1],"suboptimal_rational_resampler_ff"))||(!strcmp(argv[1],"rational_resampler_ff")) ) - { + int suboptimal; + if( (suboptimal=!strcmp(argv[1],"suboptimal_rational_resampler_ff"))||(!strcmp(argv[1],"rational_resampler_ff")) ) + { - //last@2014-11-06: ./docompile; ./csdr yes_f 1.0 | ./csdr suboptimal_rational_resampler_ff 5 2 + //last@2014-11-06: ./docompile; ./csdr yes_f 1.0 | ./csdr suboptimal_rational_resampler_ff 5 2 - //Process the params - if(argc<=3) return badsyntax("need required parameters (interpolation, decimation)"); - int interpolation; - sscanf(argv[2],"%d",&interpolation); - int decimation; - sscanf(argv[3],"%d",&decimation); + //Process the params + if(argc<=3) return badsyntax("need required parameters (interpolation, decimation)"); + int interpolation; + sscanf(argv[2],"%d",&interpolation); + int decimation; + sscanf(argv[3],"%d",&decimation); - float transition_bw=0.05; - if(argc>=5) sscanf(argv[4],"%g",&transition_bw); + float transition_bw=0.05; + if(argc>=5) sscanf(argv[4],"%g",&transition_bw); - window_t window = WINDOW_DEFAULT; - if(argc>=6) - { - window=firdes_get_window_from_string(argv[5]); - } - else fprintf(stderr,"rational_resampler_ff: window = %s\n",firdes_get_string_from_window(window)); + window_t window = WINDOW_DEFAULT; + if(argc>=6) + { + window=firdes_get_window_from_string(argv[5]); + } + else fprintf(stderr,"rational_resampler_ff: window = %s\n",firdes_get_string_from_window(window)); - if(suboptimal) fprintf(stderr,"note: suboptimal rational resampler chosen.\n"); + if(suboptimal) fprintf(stderr,"note: suboptimal rational resampler chosen.\n"); - if(!initialize_buffers()) return -2; + if(!initialize_buffers()) return -2; - if(decimation==1&&interpolation==1) { sendbufsize(the_bufsize); clone_(the_bufsize); } //copy input to output in this special case (and stick in this function). + if(decimation==1&&interpolation==1) { sendbufsize(the_bufsize); clone_(the_bufsize); } //copy input to output in this special case (and stick in this function). - //Alloc output buffer - int resampler_output_buffer_size=(the_bufsize*interpolation)/decimation; - sendbufsize(resampler_output_buffer_size); - float* resampler_output_buffer=(float*)malloc(sizeof(float)*resampler_output_buffer_size); - float* suboptimal_resampler_temp_buffer = (suboptimal)?(float*)malloc(sizeof(float)*the_bufsize*interpolation):NULL; + //Alloc output buffer + int resampler_output_buffer_size=(the_bufsize*interpolation)/decimation; + sendbufsize(resampler_output_buffer_size); + float* resampler_output_buffer=(float*)malloc(sizeof(float)*resampler_output_buffer_size); + float* suboptimal_resampler_temp_buffer = (suboptimal)?(float*)malloc(sizeof(float)*the_bufsize*interpolation):NULL; - //Generate filter taps - int taps_length = firdes_filter_len(transition_bw); - float* taps = (float*)malloc(sizeof(float)*taps_length); - rational_resampler_get_lowpass_f(taps, taps_length, interpolation, decimation, window); + //Generate filter taps + int taps_length = firdes_filter_len(transition_bw); + float* taps = (float*)malloc(sizeof(float)*taps_length); + rational_resampler_get_lowpass_f(taps, taps_length, interpolation, decimation, window); - static rational_resampler_ff_t d; //in .bss => initialized to zero + static rational_resampler_ff_t d; //in .bss => initialized to zero - for(;;) - { - FEOF_CHECK; - if(d.input_processed==0) d.input_processed=the_bufsize; - else memcpy(input_buffer, input_buffer+d.input_processed, sizeof(float)*(the_bufsize-d.input_processed)); - fread(input_buffer+(the_bufsize-d.input_processed), sizeof(float), d.input_processed, stdin); - //if(suboptimal) d=suboptimal_rational_resampler_ff(input_buffer, resampler_output_buffer, the_bufsize, interpolation, decimation, taps, taps_length, suboptimal_resampler_temp_buffer); else - d=rational_resampler_ff(input_buffer, resampler_output_buffer, the_bufsize, interpolation, decimation, taps, taps_length, d.last_taps_delay); - //fprintf(stderr,"resampled %d %d, %d\n",d.output_size, d.input_processed, d.input_processed); - fwrite(resampler_output_buffer, sizeof(float), d.output_size, stdout); - TRY_YIELD; - } - } + for(;;) + { + FEOF_CHECK; + if(d.input_processed==0) d.input_processed=the_bufsize; + else memcpy(input_buffer, input_buffer+d.input_processed, sizeof(float)*(the_bufsize-d.input_processed)); + fread(input_buffer+(the_bufsize-d.input_processed), sizeof(float), d.input_processed, stdin); + //if(suboptimal) d=suboptimal_rational_resampler_ff(input_buffer, resampler_output_buffer, the_bufsize, interpolation, decimation, taps, taps_length, suboptimal_resampler_temp_buffer); else + d=rational_resampler_ff(input_buffer, resampler_output_buffer, the_bufsize, interpolation, decimation, taps, taps_length, d.last_taps_delay); + //fprintf(stderr,"resampled %d %d, %d\n",d.output_size, d.input_processed, d.input_processed); + fwrite(resampler_output_buffer, sizeof(float), d.output_size, stdout); + TRY_YIELD; + } + } - if(!strcmp(argv[1],"fractional_decimator_ff")) - { - //Process the params - if(argc<=2) return badsyntax("need required parameters (rate)"); - float rate; - sscanf(argv[2],"%g",&rate); + if(!strcmp(argv[1],"fractional_decimator_ff")) + { + //Process the params + if(argc<=2) return badsyntax("need required parameters (rate)"); + float rate; + sscanf(argv[2],"%g",&rate); - int num_poly_points = 12; - if(argc>=4) sscanf(argv[3],"%d",&num_poly_points); - if(num_poly_points&1) return badsyntax("num_poly_points should be even"); - if(num_poly_points<2) return badsyntax("num_poly_points should be >= 2"); + int num_poly_points = 12; + if(argc>=4) sscanf(argv[3],"%d",&num_poly_points); + if(num_poly_points&1) return badsyntax("num_poly_points should be even"); + if(num_poly_points<2) return badsyntax("num_poly_points should be >= 2"); - int use_prefilter = 0; - float transition_bw=0.03; - window_t window = WINDOW_DEFAULT; - if(argc>=5) - { - if(!strcmp(argv[4], "--prefilter")) - { - fprintf(stderr, "fractional_decimator_ff: using prefilter with default values\n"); - use_prefilter = 1; - } - else - { - sscanf(argv[4],"%g",&transition_bw); - if(argc>=6) window = firdes_get_window_from_string(argv[5]); - } - } - fprintf(stderr,"fractional_decimator_ff: use_prefilter = %d, num_poly_points = %d, transition_bw = %g, window = %s\n", - use_prefilter, num_poly_points, transition_bw, firdes_get_string_from_window(window)); + int use_prefilter = 0; + float transition_bw=0.03; + window_t window = WINDOW_DEFAULT; + if(argc>=5) + { + if(!strcmp(argv[4], "--prefilter")) + { + fprintf(stderr, "fractional_decimator_ff: using prefilter with default values\n"); + use_prefilter = 1; + } + else + { + sscanf(argv[4],"%g",&transition_bw); + if(argc>=6) window = firdes_get_window_from_string(argv[5]); + } + } + fprintf(stderr,"fractional_decimator_ff: use_prefilter = %d, num_poly_points = %d, transition_bw = %g, window = %s\n", + use_prefilter, num_poly_points, transition_bw, firdes_get_string_from_window(window)); - if(!initialize_buffers()) return -2; - sendbufsize(the_bufsize / rate); + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize / rate); - if(rate==1) clone_(the_bufsize); //copy input to output in this special case (and stick in this function). + if(rate==1) clone_(the_bufsize); //copy input to output in this special case (and stick in this function). - //Generate filter taps - int taps_length = 0; - float* taps = NULL; - if(use_prefilter) - { - taps_length = firdes_filter_len(transition_bw); - fprintf(stderr,"fractional_decimator_ff: taps_length = %d\n",taps_length); - taps = (float*)malloc(sizeof(float)*taps_length); - firdes_lowpass_f(taps, taps_length, 0.5/(rate-transition_bw), window); //0.6 const to compensate rolloff - //for(int=0;i=4) sscanf(argv[3],"%g",&transition_bw); + float transition_bw=0.03; + if(argc>=4) sscanf(argv[3],"%g",&transition_bw); - window_t window = WINDOW_DEFAULT; - if(argc>=5) - { - window = firdes_get_window_from_string(argv[4]); - } - else fprintf(stderr,"old_fractional_decimator_ff: window = %s\n",firdes_get_string_from_window(window)); + window_t window = WINDOW_DEFAULT; + if(argc>=5) + { + window = firdes_get_window_from_string(argv[4]); + } + else fprintf(stderr,"old_fractional_decimator_ff: window = %s\n",firdes_get_string_from_window(window)); - if(!initialize_buffers()) return -2; - sendbufsize(the_bufsize / rate); + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize / rate); - if(rate==1) clone_(the_bufsize); //copy input to output in this special case (and stick in this function). + if(rate==1) clone_(the_bufsize); //copy input to output in this special case (and stick in this function). - //Generate filter taps - int taps_length = firdes_filter_len(transition_bw); - fprintf(stderr,"old_fractional_decimator_ff: taps_length = %d\n",taps_length); - float* taps = (float*)malloc(sizeof(float)*taps_length); - firdes_lowpass_f(taps, taps_length, 0.59*0.5/(rate-transition_bw), window); //0.6 const to compensate rolloff - //for(int=0;i initialized to zero - for(;;) - { - FEOF_CHECK; - if(d.input_processed==0) d.input_processed=the_bufsize; - else memcpy(input_buffer, input_buffer+d.input_processed, sizeof(float)*(the_bufsize-d.input_processed)); - fread(input_buffer+(the_bufsize-d.input_processed), sizeof(float), d.input_processed, stdin); - d = old_fractional_decimator_ff(input_buffer, output_buffer, the_bufsize, rate, taps, taps_length, d); - fwrite(output_buffer, sizeof(float), d.output_size, stdout); - TRY_YIELD; - } - } + static old_fractional_decimator_ff_t d; //in .bss => initialized to zero + for(;;) + { + FEOF_CHECK; + if(d.input_processed==0) d.input_processed=the_bufsize; + else memcpy(input_buffer, input_buffer+d.input_processed, sizeof(float)*(the_bufsize-d.input_processed)); + fread(input_buffer+(the_bufsize-d.input_processed), sizeof(float), d.input_processed, stdin); + d = old_fractional_decimator_ff(input_buffer, output_buffer, the_bufsize, rate, taps, taps_length, d); + fwrite(output_buffer, sizeof(float), d.output_size, stdout); + TRY_YIELD; + } + } - if(!strcmp(argv[1],"fft_cc")) - { - if(argc<=3) return badsyntax("need required parameters (fft_size, out_of_every_n_samples)"); - int fft_size; - sscanf(argv[2],"%d",&fft_size); - if(log2n(fft_size)==-1) return badsyntax("fft_size should be power of 2"); - int every_n_samples; - sscanf(argv[3],"%d",&every_n_samples); - int benchmark=0; - int octave=0; - window_t window = WINDOW_DEFAULT; - if(argc>=5) - { - window=firdes_get_window_from_string(argv[4]); - } - if(argc>=6) - { - benchmark|=!strcmp("--benchmark",argv[5]); - octave|=!strcmp("--octave",argv[5]); - } - if(argc>=7) - { - benchmark|=!strcmp("--benchmark",argv[6]); - octave|=!strcmp("--octave",argv[6]); - } + if(!strcmp(argv[1],"fft_cc")) + { + if(argc<=3) return badsyntax("need required parameters (fft_size, out_of_every_n_samples)"); + int fft_size; + sscanf(argv[2],"%d",&fft_size); + if(log2n(fft_size)==-1) return badsyntax("fft_size should be power of 2"); + int every_n_samples; + sscanf(argv[3],"%d",&every_n_samples); + int benchmark=0; + int octave=0; + window_t window = WINDOW_DEFAULT; + if(argc>=5) + { + window=firdes_get_window_from_string(argv[4]); + } + if(argc>=6) + { + benchmark|=!strcmp("--benchmark",argv[5]); + octave|=!strcmp("--octave",argv[5]); + } + if(argc>=7) + { + benchmark|=!strcmp("--benchmark",argv[6]); + octave|=!strcmp("--octave",argv[6]); + } - if(!initialize_buffers()) return -2; - sendbufsize(fft_size); + if(!initialize_buffers()) return -2; + sendbufsize(fft_size); - //make FFT plan - complexf* input=(complexf*)fft_malloc(sizeof(complexf)*fft_size); - complexf* windowed=(complexf*)fft_malloc(sizeof(complexf)*fft_size); - complexf* output=(complexf*)fft_malloc(sizeof(complexf)*fft_size); - if(benchmark) fprintf(stderr,"fft_cc: benchmarking..."); - FFT_PLAN_T* plan=make_fft_c2c(fft_size, windowed, output, 1, benchmark); - if(benchmark) fprintf(stderr," done\n"); - if(octave) printf("setenv(\"GNUTERM\",\"X11 noraise\");y=zeros(1,%d);semilogy(y,\"ydatasource\",\"y\");\n",fft_size); - float *windowt; - windowt = precalculate_window(fft_size, window); - for(;;) - { - FEOF_CHECK; - if(every_n_samples>fft_size) - { - fread(input, sizeof(complexf), fft_size, stdin); - //skipping samples before next FFT (but fseek doesn't work for pipes) - for(int seek_remain=every_n_samples-fft_size;seek_remain>0;seek_remain-=the_bufsize) - { - fread(temp_f, sizeof(complexf), MIN_M(the_bufsize,seek_remain), stdin); - } - } - else - { - //overlapped FFT - for(int i=0;i=3) sscanf(argv[2],"%g",&add_db); + //make FFT plan + complexf* input=(complexf*)fft_malloc(sizeof(complexf)*fft_size); + complexf* windowed=(complexf*)fft_malloc(sizeof(complexf)*fft_size); + complexf* output=(complexf*)fft_malloc(sizeof(complexf)*fft_size); + if(benchmark) fprintf(stderr,"fft_cc: benchmarking..."); + FFT_PLAN_T* plan=make_fft_c2c(fft_size, windowed, output, 1, benchmark); + if(benchmark) fprintf(stderr," done\n"); + if(octave) printf("setenv(\"GNUTERM\",\"X11 noraise\");y=zeros(1,%d);semilogy(y,\"ydatasource\",\"y\");\n",fft_size); + float *windowt; + windowt = precalculate_window(fft_size, window); + for(;;) + { + FEOF_CHECK; + if(every_n_samples>fft_size) + { + fread(input, sizeof(complexf), fft_size, stdin); + //skipping samples before next FFT (but fseek doesn't work for pipes) + for(int seek_remain=every_n_samples-fft_size;seek_remain>0;seek_remain-=the_bufsize) + { + fread(temp_f, sizeof(complexf), MIN_M(the_bufsize,seek_remain), stdin); + } + } + else + { + //overlapped FFT + for(int i=0;i=3) sscanf(argv[2],"%g",&add_db); - if(!sendbufsize(initialize_buffers())) return -2; + if(!sendbufsize(initialize_buffers())) return -2; - for(;;) - { - FEOF_CHECK; - fread(input_buffer, sizeof(complexf), the_bufsize, stdin); - logpower_cf((complexf*)input_buffer,output_buffer, the_bufsize, add_db); - fwrite(output_buffer, sizeof(float), the_bufsize, stdout); - TRY_YIELD; - } - } + for(;;) + { + FEOF_CHECK; + fread(input_buffer, sizeof(complexf), the_bufsize, stdin); + logpower_cf((complexf*)input_buffer,output_buffer, the_bufsize, add_db); + fwrite(output_buffer, sizeof(float), the_bufsize, stdout); + TRY_YIELD; + } + } - if(!strcmp(argv[1],"logaveragepower_cf")) - { - bigbufs=1; - if(argc<=4) return badsyntax("need required parameters (add_db, table_size, avgnumber)"); - float add_db=0; - int avgnumber=0; - int fft_size=0; - - sscanf(argv[2],"%g",&add_db); - sscanf(argv[3],"%d",&fft_size); - sscanf(argv[4],"%d",&avgnumber); - - float *input = malloc(sizeof(float)*2 * fft_size); - float *output = malloc(sizeof(float) * fft_size); + if(!strcmp(argv[1],"logaveragepower_cf")) + { + bigbufs=1; + if(argc<=4) return badsyntax("need required parameters (add_db, table_size, avgnumber)"); + float add_db=0; + int avgnumber=0; + int fft_size=0; + + sscanf(argv[2],"%g",&add_db); + sscanf(argv[3],"%d",&fft_size); + sscanf(argv[4],"%d",&avgnumber); + + float *input = malloc(sizeof(float)*2 * fft_size); + float *output = malloc(sizeof(float) * fft_size); - add_db -= 10.0*log10(avgnumber); - for(;;) - { - int i,n; - for(i = 0; i < fft_size; i++) { - output[i] = 0; - } - FEOF_CHECK; - for(n = 0; n < avgnumber; n++) { - fread (input, sizeof(float)*2, fft_size, stdin); - accumulate_power_cf((complexf*)input, output, fft_size); - } - log_ff(output, output, fft_size, add_db); - fwrite (output, sizeof(float), fft_size, stdout); - TRY_YIELD; - } - return 0; - } + add_db -= 10.0*log10(avgnumber); + for(;;) + { + int i,n; + for(i = 0; i < fft_size; i++) { + output[i] = 0; + } + FEOF_CHECK; + for(n = 0; n < avgnumber; n++) { + fread (input, sizeof(float)*2, fft_size, stdin); + accumulate_power_cf((complexf*)input, output, fft_size); + } + log_ff(output, output, fft_size, add_db); + fwrite (output, sizeof(float), fft_size, stdout); + TRY_YIELD; + } + return 0; + } - if(!strcmp(argv[1],"fft_exchange_sides_ff")) - { - if(argc<=2) return badsyntax("need required parameters (fft_size)"); - int fft_size; - sscanf(argv[2],"%d",&fft_size); - if(!getbufsize()) return -2; //dummy - sendbufsize(fft_size); - float* input_buffer_s1 = (float*)malloc(sizeof(float)*fft_size/2); - float* input_buffer_s2 = (float*)malloc(sizeof(float)*fft_size/2); - for(;;) - { - FEOF_CHECK; - fread(input_buffer_s1, sizeof(float), fft_size/2, stdin); - fread(input_buffer_s2, sizeof(float), fft_size/2, stdin); - fwrite(input_buffer_s2, sizeof(float), fft_size/2, stdout); - fwrite(input_buffer_s1, sizeof(float), fft_size/2, stdout); - TRY_YIELD; - } - } + if(!strcmp(argv[1],"fft_exchange_sides_ff")) + { + if(argc<=2) return badsyntax("need required parameters (fft_size)"); + int fft_size; + sscanf(argv[2],"%d",&fft_size); + if(!getbufsize()) return -2; //dummy + sendbufsize(fft_size); + float* input_buffer_s1 = (float*)malloc(sizeof(float)*fft_size/2); + float* input_buffer_s2 = (float*)malloc(sizeof(float)*fft_size/2); + for(;;) + { + FEOF_CHECK; + fread(input_buffer_s1, sizeof(float), fft_size/2, stdin); + fread(input_buffer_s2, sizeof(float), fft_size/2, stdin); + fwrite(input_buffer_s2, sizeof(float), fft_size/2, stdout); + fwrite(input_buffer_s1, sizeof(float), fft_size/2, stdout); + TRY_YIELD; + } + } - if(!strcmp(argv[1],"fft_one_side_ff")) - { - if(argc<=2) return badsyntax("need required parameters (fft_size)"); - int fft_size; - sscanf(argv[2],"%d",&fft_size); - if(!getbufsize()) return -2; - sendbufsize(fft_size); - float* input_buffer_s1 = (float*)malloc(sizeof(float)*fft_size/2); - float* input_buffer_s2 = (float*)malloc(sizeof(float)*fft_size/2); - for(;;) - { - FEOF_CHECK; - fread(input_buffer_s1, sizeof(float), fft_size/2, stdin); - fread(input_buffer_s2, sizeof(float), fft_size/2, stdin); - fwrite(input_buffer_s1, sizeof(float), fft_size/2, stdout); - TRY_YIELD; - } - } + if(!strcmp(argv[1],"fft_one_side_ff")) + { + if(argc<=2) return badsyntax("need required parameters (fft_size)"); + int fft_size; + sscanf(argv[2],"%d",&fft_size); + if(!getbufsize()) return -2; + sendbufsize(fft_size); + float* input_buffer_s1 = (float*)malloc(sizeof(float)*fft_size/2); + float* input_buffer_s2 = (float*)malloc(sizeof(float)*fft_size/2); + for(;;) + { + FEOF_CHECK; + fread(input_buffer_s1, sizeof(float), fft_size/2, stdin); + fread(input_buffer_s2, sizeof(float), fft_size/2, stdin); + fwrite(input_buffer_s1, sizeof(float), fft_size/2, stdout); + TRY_YIELD; + } + } #ifdef USE_IMA_ADPCM @@ -1693,1209 +1693,1209 @@ int main(int argc, char *argv[]) //so we just add data to become garbage and get skipped. //COMPRESS_FFT_PAD_N should be even. - if(!strcmp(argv[1],"compress_fft_adpcm_f_u8")) - { - if(argc<=2) return badsyntax("need required parameters (fft_size)"); - int fft_size; - sscanf(argv[2],"%d",&fft_size); - int real_data_size=fft_size+COMPRESS_FFT_PAD_N; - if(!getbufsize()) return -2; //dummy - sendbufsize(real_data_size); - float* input_buffer_cwa = (float*)malloc(sizeof(float)*real_data_size); - short* temp_buffer_cwa = (short*)malloc(sizeof(short)*real_data_size); - unsigned char* output_buffer_cwa = (unsigned char*)malloc(sizeof(unsigned char)*(real_data_size/2)); - ima_adpcm_state_t d; - d.index=d.previousValue=0; - for(;;) - { - FEOF_CHECK; - fread(input_buffer_cwa+COMPRESS_FFT_PAD_N, sizeof(float), fft_size, stdin); - for(int i=0;i=5)&&!strcmp(argv[4],"--benchmark"); - fprintf(stderr,"fft_benchmark: FFT library used: %s\n",FFT_LIBRARY_USED); + int benchmark=(argc>=5)&&!strcmp(argv[4],"--benchmark"); + fprintf(stderr,"fft_benchmark: FFT library used: %s\n",FFT_LIBRARY_USED); - complexf* input=(complexf*)fft_malloc(sizeof(complexf)*fft_size); - complexf* output=(complexf*)fft_malloc(sizeof(complexf)*fft_size); + complexf* input=(complexf*)fft_malloc(sizeof(complexf)*fft_size); + complexf* output=(complexf*)fft_malloc(sizeof(complexf)*fft_size); - //fill input with random data - srand(time(NULL)); - for(int i=0;i=6) window=firdes_get_window_from_string(argv[5]); - else fprintf(stderr,"bandpass_fir_fft_cc: window = %s\n",firdes_get_string_from_window(window)); + if(!strcmp(argv[1],"bandpass_fir_fft_cc")) //this command does not exist as a separate function + { + float low_cut; + float high_cut; + float transition_bw; + window_t window = WINDOW_DEFAULT; + int fd; + if(fd=init_fifo(argc,argv)) + { + while(!read_fifo_ctl(fd,"%g %g\n",&low_cut,&high_cut)) usleep(10000); + if(argc<=4) return badsyntax("need more required parameters (transition_bw)"); + } + else + { + if(argc<=4) return badsyntax("need required parameters (low_cut, high_cut, transition_bw)"); + sscanf(argv[2],"%g",&low_cut); + sscanf(argv[3],"%g",&high_cut); + } + sscanf(argv[4],"%g",&transition_bw); + if(argc>=6) window=firdes_get_window_from_string(argv[5]); + else fprintf(stderr,"bandpass_fir_fft_cc: window = %s\n",firdes_get_string_from_window(window)); - //calculate the FFT size and the other length parameters - int taps_length=firdes_filter_len(transition_bw); //the number of non-zero taps - int fft_size=next_pow2(taps_length); //we will have to pad the taps with zeros until the next power of 2 for FFT - //the number of padding zeros is the number of output samples we will be able to take away after every processing step, and it looks sane to check if it is large enough. - if (fft_size-taps_length<200) fft_size<<=1; - int input_size = fft_size - taps_length + 1; - int overlap_length = taps_length - 1; - fprintf(stderr,"bandpass_fir_fft_cc: (fft_size = %d) = (taps_length = %d) + (input_size = %d) - 1\n(overlap_length = %d) = taps_length - 1\n", fft_size, taps_length, input_size, overlap_length ); - if (fft_size<=2) return badsyntax("FFT size error."); + //calculate the FFT size and the other length parameters + int taps_length=firdes_filter_len(transition_bw); //the number of non-zero taps + int fft_size=next_pow2(taps_length); //we will have to pad the taps with zeros until the next power of 2 for FFT + //the number of padding zeros is the number of output samples we will be able to take away after every processing step, and it looks sane to check if it is large enough. + if (fft_size-taps_length<200) fft_size<<=1; + int input_size = fft_size - taps_length + 1; + int overlap_length = taps_length - 1; + fprintf(stderr,"bandpass_fir_fft_cc: (fft_size = %d) = (taps_length = %d) + (input_size = %d) - 1\n(overlap_length = %d) = taps_length - 1\n", fft_size, taps_length, input_size, overlap_length ); + if (fft_size<=2) return badsyntax("FFT size error."); - if(!sendbufsize(getbufsize())) return -2; + if(!sendbufsize(getbufsize())) return -2; - //prepare making the filter and doing FFT on it - complexf* taps=(complexf*)calloc(sizeof(complexf),fft_size); //initialize to zero - complexf* taps_fft=(complexf*)malloc(sizeof(complexf)*fft_size); - FFT_PLAN_T* plan_taps = make_fft_c2c(fft_size, taps, taps_fft, 1, 0); //forward, don't benchmark (we need this only once) + //prepare making the filter and doing FFT on it + complexf* taps=(complexf*)calloc(sizeof(complexf),fft_size); //initialize to zero + complexf* taps_fft=(complexf*)malloc(sizeof(complexf)*fft_size); + FFT_PLAN_T* plan_taps = make_fft_c2c(fft_size, taps, taps_fft, 1, 0); //forward, don't benchmark (we need this only once) - //make FFT plans for continously processing the input - complexf* input = fft_malloc(fft_size*sizeof(complexf)); - complexf* input_fourier = fft_malloc(fft_size*sizeof(complexf)); - FFT_PLAN_T* plan_forward = make_fft_c2c(fft_size, input, input_fourier, 1, 1); //forward, do benchmark + //make FFT plans for continously processing the input + complexf* input = fft_malloc(fft_size*sizeof(complexf)); + complexf* input_fourier = fft_malloc(fft_size*sizeof(complexf)); + FFT_PLAN_T* plan_forward = make_fft_c2c(fft_size, input, input_fourier, 1, 1); //forward, do benchmark - complexf* output_fourier = fft_malloc(fft_size*sizeof(complexf)); - complexf* output_1 = fft_malloc(fft_size*sizeof(complexf)); - complexf* output_2 = fft_malloc(fft_size*sizeof(complexf)); - //we create 2x output buffers so that one will preserve the previous overlap: - FFT_PLAN_T* plan_inverse_1 = make_fft_c2c(fft_size, output_fourier, output_1, 0, 1); //inverse, do benchmark - FFT_PLAN_T* plan_inverse_2 = make_fft_c2c(fft_size, output_fourier, output_2, 0, 1); - //we initialize this buffer to 0 as it will be taken as the overlap source for the first time: - for(int i=0;ioutput,i)=qof(plan_inverse_2->output,i)=0; + complexf* output_fourier = fft_malloc(fft_size*sizeof(complexf)); + complexf* output_1 = fft_malloc(fft_size*sizeof(complexf)); + complexf* output_2 = fft_malloc(fft_size*sizeof(complexf)); + //we create 2x output buffers so that one will preserve the previous overlap: + FFT_PLAN_T* plan_inverse_1 = make_fft_c2c(fft_size, output_fourier, output_1, 0, 1); //inverse, do benchmark + FFT_PLAN_T* plan_inverse_2 = make_fft_c2c(fft_size, output_fourier, output_2, 0, 1); + //we initialize this buffer to 0 as it will be taken as the overlap source for the first time: + for(int i=0;ioutput,i)=qof(plan_inverse_2->output,i)=0; - for(int i=input_size;ioutput + input_size; //+ fft_size - overlap_length; - apply_fir_fft_cc (plan_forward, plan_inverse, taps_fft, last_overlap, overlap_length); - int returned=fwrite(plan_inverse->output, sizeof(complexf), input_size, stdout); - if(read_fifo_ctl(fd,"%g %g\n",&low_cut,&high_cut)) break; - TRY_YIELD; - } - } + for(int odd=0;;odd=!odd) //the processing loop + { + FEOF_CHECK; + fread(input, sizeof(complexf), input_size, stdin); + FFT_PLAN_T* plan_inverse = (odd)?plan_inverse_2:plan_inverse_1; + FFT_PLAN_T* plan_contains_last_overlap = (odd)?plan_inverse_1:plan_inverse_2; //the other + complexf* last_overlap = (complexf*)plan_contains_last_overlap->output + input_size; //+ fft_size - overlap_length; + apply_fir_fft_cc (plan_forward, plan_inverse, taps_fft, last_overlap, overlap_length); + int returned=fwrite(plan_inverse->output, sizeof(complexf), input_size, stdout); + if(read_fifo_ctl(fd,"%g %g\n",&low_cut,&high_cut)) break; + TRY_YIELD; + } + } - } + } #ifdef USE_IMA_ADPCM #define IMA_ADPCM_BUFSIZE BUFSIZE - if( (!strcmp(argv[1],"encode_ima_adpcm_i16_u8"))||(!strcmp(argv[1],"encode_ima_adpcm_s16_u8")) ) - { - if(!sendbufsize(initialize_buffers()/2)) return -2; - ima_adpcm_state_t d; - d.index=d.previousValue=0; - for(;;) - { - FEOF_CHECK; - fread(buffer_i16, sizeof(short), the_bufsize, stdin); - d=encode_ima_adpcm_i16_u8(buffer_i16, buffer_u8, the_bufsize, d); - fwrite(buffer_u8, sizeof(unsigned char), the_bufsize/2, stdout); - TRY_YIELD; - } - } + if( (!strcmp(argv[1],"encode_ima_adpcm_i16_u8"))||(!strcmp(argv[1],"encode_ima_adpcm_s16_u8")) ) + { + if(!sendbufsize(initialize_buffers()/2)) return -2; + ima_adpcm_state_t d; + d.index=d.previousValue=0; + for(;;) + { + FEOF_CHECK; + fread(buffer_i16, sizeof(short), the_bufsize, stdin); + d=encode_ima_adpcm_i16_u8(buffer_i16, buffer_u8, the_bufsize, d); + fwrite(buffer_u8, sizeof(unsigned char), the_bufsize/2, stdout); + TRY_YIELD; + } + } - if( (!strcmp(argv[1],"decode_ima_adpcm_u8_i16"))||(!strcmp(argv[1],"decode_ima_adpcm_u8_s16")) ) - { - ima_adpcm_state_t d; - d.index=d.previousValue=0; - if(!sendbufsize(initialize_buffers()*2)) return -2; - for(;;) - { - FEOF_CHECK; - fread(buffer_u8, sizeof(unsigned char), the_bufsize, stdin); - d=decode_ima_adpcm_u8_i16(buffer_u8, buffer_i16, the_bufsize, d); - fwrite(buffer_i16, sizeof(short), the_bufsize*2, stdout); - TRY_YIELD; - } - } + if( (!strcmp(argv[1],"decode_ima_adpcm_u8_i16"))||(!strcmp(argv[1],"decode_ima_adpcm_u8_s16")) ) + { + ima_adpcm_state_t d; + d.index=d.previousValue=0; + if(!sendbufsize(initialize_buffers()*2)) return -2; + for(;;) + { + FEOF_CHECK; + fread(buffer_u8, sizeof(unsigned char), the_bufsize, stdin); + d=decode_ima_adpcm_u8_i16(buffer_u8, buffer_i16, the_bufsize, d); + fwrite(buffer_i16, sizeof(short), the_bufsize*2, stdout); + TRY_YIELD; + } + } #endif - if(!strcmp(argv[1],"flowcontrol")) - { - if(argc<=3) return badsyntax("need required parameters (data_rate, reads_per_seconds)"); - int data_rate; - sscanf(argv[2],"%d",&data_rate); - int reads_per_second; - sscanf(argv[3],"%d",&reads_per_second); - int flowcontrol_bufsize=ceil(1.*(double)data_rate/reads_per_second); - if(!getbufsize()) return -2; - sendbufsize(flowcontrol_bufsize); - unsigned char* flowcontrol_buffer = (unsigned char*)malloc(sizeof(unsigned char)*flowcontrol_bufsize); - int flowcontrol_sleep=floor(1000000./reads_per_second); - fprintf(stderr, "flowcontrol: flowcontrol_bufsize = %d, flowcontrol_sleep = %d\n", flowcontrol_bufsize, flowcontrol_sleep); - for(;;) - { - FEOF_CHECK; - fread(flowcontrol_buffer, sizeof(unsigned char), flowcontrol_bufsize, stdin); - fwrite(flowcontrol_buffer, sizeof(unsigned char), flowcontrol_bufsize, stdout); - usleep(flowcontrol_sleep); - TRY_YIELD; - } - } + if(!strcmp(argv[1],"flowcontrol")) + { + if(argc<=3) return badsyntax("need required parameters (data_rate, reads_per_seconds)"); + int data_rate; + sscanf(argv[2],"%d",&data_rate); + int reads_per_second; + sscanf(argv[3],"%d",&reads_per_second); + int flowcontrol_bufsize=ceil(1.*(double)data_rate/reads_per_second); + if(!getbufsize()) return -2; + sendbufsize(flowcontrol_bufsize); + unsigned char* flowcontrol_buffer = (unsigned char*)malloc(sizeof(unsigned char)*flowcontrol_bufsize); + int flowcontrol_sleep=floor(1000000./reads_per_second); + fprintf(stderr, "flowcontrol: flowcontrol_bufsize = %d, flowcontrol_sleep = %d\n", flowcontrol_bufsize, flowcontrol_sleep); + for(;;) + { + FEOF_CHECK; + fread(flowcontrol_buffer, sizeof(unsigned char), flowcontrol_bufsize, stdin); + fwrite(flowcontrol_buffer, sizeof(unsigned char), flowcontrol_bufsize, stdout); + usleep(flowcontrol_sleep); + TRY_YIELD; + } + } #if 0 - if(!strcmp(argv[1],"flowcontrol")) - { - if(argc<=3) return badsyntax("need required parameters (data_rate, reads_per_seconds)"); + if(!strcmp(argv[1],"flowcontrol")) + { + if(argc<=3) return badsyntax("need required parameters (data_rate, reads_per_seconds)"); - int data_rate; - sscanf(argv[2],"%d",&data_rate); + int data_rate; + sscanf(argv[2],"%d",&data_rate); - int reads_per_second=0; - if(strcmp(argv[3],"auto")) sscanf(argv[3],"%d",&reads_per_second); + int reads_per_second=0; + if(strcmp(argv[3],"auto")) sscanf(argv[3],"%d",&reads_per_second); - float prebuffer=2; - if(argc>4) sscanf(argv[4],"%g",&prebuffer); + float prebuffer=2; + if(argc>4) sscanf(argv[4],"%g",&prebuffer); - int thrust=10; - if(argc>5) sscanf(argv[5],"%d",&thrust); + int thrust=10; + if(argc>5) sscanf(argv[5],"%d",&thrust); - int flowcontrol_readsize, flowcontrol_bufsize, got_bufsize; + int flowcontrol_readsize, flowcontrol_bufsize, got_bufsize; - if(!(got_bufsize=getbufsize())) return -2; + if(!(got_bufsize=getbufsize())) return -2; - if(reads_per_second) - { - flowcontrol_readsize=ceil(1.*(double)data_rate/reads_per_second); - } - else - { - flowcontrol_readsize=got_bufsize; - reads_per_second=data_rate/flowcontrol_readsize; - } - flowcontrol_bufsize=flowcontrol_readsize*floor(reads_per_second*prebuffer); + if(reads_per_second) + { + flowcontrol_readsize=ceil(1.*(double)data_rate/reads_per_second); + } + else + { + flowcontrol_readsize=got_bufsize; + reads_per_second=data_rate/flowcontrol_readsize; + } + flowcontrol_bufsize=flowcontrol_readsize*floor(reads_per_second*prebuffer); - int flowcontrol_bufindex=0; - unsigned char* flowcontrol_buffer = (unsigned char*)malloc(sizeof(unsigned char)*flowcontrol_bufsize); - int flowcontrol_sleep=floor(1000000./reads_per_second); + int flowcontrol_bufindex=0; + unsigned char* flowcontrol_buffer = (unsigned char*)malloc(sizeof(unsigned char)*flowcontrol_bufsize); + int flowcontrol_sleep=floor(1000000./reads_per_second); - fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0) | O_NONBLOCK); + fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0) | O_NONBLOCK); - sendbufsize(flowcontrol_readsize); - fflush(stdout); + sendbufsize(flowcontrol_readsize); + fflush(stdout); - int flowcontrol_is_buffering = 1; - int read_return; + int flowcontrol_is_buffering = 1; + int read_return; - struct timespec start_time, end_time; + struct timespec start_time, end_time; - unsigned long long int all_bytes_written=0; - int test=0; + unsigned long long int all_bytes_written=0; + int test=0; - fprintf(stderr, "flowcontrol: flowcontrol_readsize = %d, flowcontrol_bufsize = %d, flowcontrol_sleep = %d\n", flowcontrol_readsize, flowcontrol_bufsize, flowcontrol_sleep); - for (; ;) //my friend has told me that this is like two smileys ;) - { - FEOF_CHECK; - fprintf(stderr, "r"); - read_return=read(STDIN_FILENO, flowcontrol_buffer+flowcontrol_bufindex, sizeof(unsigned char) * (flowcontrol_bufsize-flowcontrol_bufindex) ); - fprintf(stderr, "t"); - if(read_return>0) flowcontrol_bufindex+=read_return; + fprintf(stderr, "flowcontrol: flowcontrol_readsize = %d, flowcontrol_bufsize = %d, flowcontrol_sleep = %d\n", flowcontrol_readsize, flowcontrol_bufsize, flowcontrol_sleep); + for (; ;) //my friend has told me that this is like two smileys ;) + { + FEOF_CHECK; + fprintf(stderr, "r"); + read_return=read(STDIN_FILENO, flowcontrol_buffer+flowcontrol_bufindex, sizeof(unsigned char) * (flowcontrol_bufsize-flowcontrol_bufindex) ); + fprintf(stderr, "t"); + if(read_return>0) flowcontrol_bufindex+=read_return; - if(flowcontrol_is_buffering) - { - fprintf(stderr, "flowcontrol: buffering, flowcontrol_bufindex = %d\n", flowcontrol_bufindex); - if(flowcontrol_bufindex==flowcontrol_bufsize) { flowcontrol_is_buffering = 0; clock_gettime(CLOCK_MONOTONIC_RAW, &start_time); } - else if(read_return<=0) continue; - } - else { - clock_gettime(CLOCK_MONOTONIC_RAW, &end_time); - int thrust_added=0; - while( (all_bytes_written+thrust*flowcontrol_readsize) / TIME_TAKEN(start_time,end_time) < data_rate ) - { - thrust_added |= thrust++; - } - //if(!(test++%10)) fprintf(stderr, "abw=%g\n", all_bytes_written / TIME_TAKEN(start_time,end_time)); - /*if(!thrust_added && TIME_TAKEN(start_time,end_time)>50) - { - clock_gettime(CLOCK_MONOTONIC_RAW, &start_time); - all_bytes_written=0; - }*/ - while(all_bytes_written>data_rate && TIME_TAKEN(start_time,end_time)>1) - { - all_bytes_written-=data_rate; - start_time.tv_sec++; - } - do - { - //if(thrust) fprintf(stderr, "flowcontrol: %d .. thrust\n", thrust); - write(STDOUT_FILENO, flowcontrol_buffer, flowcontrol_readsize); - fflush(stdout); - //fsync(STDOUT_FILENO); - memmove(flowcontrol_buffer, flowcontrol_buffer+flowcontrol_readsize, flowcontrol_bufindex-flowcontrol_readsize); - flowcontrol_bufindex -= flowcontrol_readsize; - all_bytes_written += flowcontrol_readsize; - } while(thrust && thrust-- && flowcontrol_bufindex>=flowcontrol_readsize); - } + if(flowcontrol_is_buffering) + { + fprintf(stderr, "flowcontrol: buffering, flowcontrol_bufindex = %d\n", flowcontrol_bufindex); + if(flowcontrol_bufindex==flowcontrol_bufsize) { flowcontrol_is_buffering = 0; clock_gettime(CLOCK_MONOTONIC_RAW, &start_time); } + else if(read_return<=0) continue; + } + else { + clock_gettime(CLOCK_MONOTONIC_RAW, &end_time); + int thrust_added=0; + while( (all_bytes_written+thrust*flowcontrol_readsize) / TIME_TAKEN(start_time,end_time) < data_rate ) + { + thrust_added |= thrust++; + } + //if(!(test++%10)) fprintf(stderr, "abw=%g\n", all_bytes_written / TIME_TAKEN(start_time,end_time)); + /*if(!thrust_added && TIME_TAKEN(start_time,end_time)>50) + { + clock_gettime(CLOCK_MONOTONIC_RAW, &start_time); + all_bytes_written=0; + }*/ + while(all_bytes_written>data_rate && TIME_TAKEN(start_time,end_time)>1) + { + all_bytes_written-=data_rate; + start_time.tv_sec++; + } + do + { + //if(thrust) fprintf(stderr, "flowcontrol: %d .. thrust\n", thrust); + write(STDOUT_FILENO, flowcontrol_buffer, flowcontrol_readsize); + fflush(stdout); + //fsync(STDOUT_FILENO); + memmove(flowcontrol_buffer, flowcontrol_buffer+flowcontrol_readsize, flowcontrol_bufindex-flowcontrol_readsize); + flowcontrol_bufindex -= flowcontrol_readsize; + all_bytes_written += flowcontrol_readsize; + } while(thrust && thrust-- && flowcontrol_bufindex>=flowcontrol_readsize); + } - usleep(flowcontrol_sleep); - TRY_YIELD; - } - } + usleep(flowcontrol_sleep); + TRY_YIELD; + } + } #endif - if(!strcmp(argv[1],"through")) - { - struct timespec start_time, end_time; - if(!sendbufsize(initialize_buffers())) return -2; + if(!strcmp(argv[1],"through")) + { + struct timespec start_time, end_time; + if(!sendbufsize(initialize_buffers())) return -2; - int time_now_sec=0; - int buffer_count=0; + int time_now_sec=0; + int buffer_count=0; - unsigned char* through_buffer; - through_buffer = (unsigned char*)malloc(the_bufsize*sizeof(float)); + unsigned char* through_buffer; + through_buffer = (unsigned char*)malloc(the_bufsize*sizeof(float)); - for(;;) - { - FEOF_CHECK; - fread(through_buffer, sizeof(float), the_bufsize, stdin); + for(;;) + { + FEOF_CHECK; + fread(through_buffer, sizeof(float), the_bufsize, stdin); - if(!time_now_sec) - { - time_now_sec=1; - clock_gettime(CLOCK_MONOTONIC_RAW, &start_time); - } - else - { - clock_gettime(CLOCK_MONOTONIC_RAW, &end_time); - float timetaken; - if(time_now_sec<(timetaken=TIME_TAKEN(start_time,end_time))) - { - fprintf( stderr, "through: %lu bytes/s, buffer #%d\n", (unsigned long)floor((float)buffer_count*the_bufsize*sizeof(float)/timetaken), buffer_count ); - time_now_sec=ceil(timetaken); - } - } - fwrite(through_buffer, sizeof(float), the_bufsize, stdout); - buffer_count++; - TRY_YIELD; - } - } + if(!time_now_sec) + { + time_now_sec=1; + clock_gettime(CLOCK_MONOTONIC_RAW, &start_time); + } + else + { + clock_gettime(CLOCK_MONOTONIC_RAW, &end_time); + float timetaken; + if(time_now_sec<(timetaken=TIME_TAKEN(start_time,end_time))) + { + fprintf( stderr, "through: %lu bytes/s, buffer #%d\n", (unsigned long)floor((float)buffer_count*the_bufsize*sizeof(float)/timetaken), buffer_count ); + time_now_sec=ceil(timetaken); + } + } + fwrite(through_buffer, sizeof(float), the_bufsize, stdout); + buffer_count++; + TRY_YIELD; + } + } - if(!strcmp(argv[1],"dsb_fc")) - { - float q_value = 0; - if(argc>=3) sscanf(argv[2],"%g",&q_value); + if(!strcmp(argv[1],"dsb_fc")) + { + float q_value = 0; + if(argc>=3) sscanf(argv[2],"%g",&q_value); - if(!sendbufsize(initialize_buffers())) return -2; - for(;;) - { - FEOF_CHECK; - FREAD_R; - for(int i=0;i)"); - fprintf(stderr, "squelch_and_power_cc: initial squelch level is %g\n", squelch_level); - if((argc<=5)||((argc>5)&&(strcmp(argv[4],"--outfifo")))) return badsyntax("need required parameter (--outfifo )"); - int fd2 = open(argv[5], O_WRONLY); - if(fd2==-1) return badsyntax("error while opening --outfifo"); - int flags = fcntl(fd2, F_GETFL, 0); - fcntl(fd2, F_SETFL, flags | O_NONBLOCK); - if(argc<=6) return badsyntax("need required parameter (use_every_nth)"); - sscanf(argv[6],"%d",&decimation); - if(decimation<=0) return badsyntax("use_every_nth <= 0 is invalid"); - if(argc<=7) return badsyntax("need required parameter (report_every_nth)"); - sscanf(argv[7],"%d",&report_every_nth); - if(report_every_nth<=0) return badsyntax("report_every_nth <= 0 is invalid"); - for(;;) - { - FEOF_CHECK; - FREAD_C; //read input data - power = get_power_c((complexf*)input_buffer, the_bufsize, decimation); - if(report_cntr++>report_every_nth) - { - report_cntr=0; - power_value_buf_size=snprintf(power_value_buf,100,"%g\n",power); - write(fd2,power_value_buf,power_value_buf_size*sizeof(char)); - } - if(squelch_level==0||power>=squelch_level) - { - //fprintf(stderr,"P"); - fwrite(input_buffer, sizeof(complexf), the_bufsize, stdout); - } - else - { - //fprintf(stderr,"S"); - fwrite(zerobuf, sizeof(complexf), the_bufsize, stdout); - } - if(read_fifo_ctl(fd,"%g\n",&squelch_level)) fprintf(stderr, "squelch_and_power_cc: new squelch level is %g\n", squelch_level); - TRY_YIELD; - } - } + if(!strcmp(argv[1],"squelch_and_smeter_cc")) + { + if(!sendbufsize(initialize_buffers())) return -2; + float power; + float squelch_level; + int decimation; + int report_every_nth; + int fd; + char power_value_buf[101]; + int power_value_buf_size; + int report_cntr=0; + complexf* zerobuf = (complexf*)malloc(sizeof(complexf)*the_bufsize); + for(int i=0;i)"); + fprintf(stderr, "squelch_and_power_cc: initial squelch level is %g\n", squelch_level); + if((argc<=5)||((argc>5)&&(strcmp(argv[4],"--outfifo")))) return badsyntax("need required parameter (--outfifo )"); + int fd2 = open(argv[5], O_WRONLY); + if(fd2==-1) return badsyntax("error while opening --outfifo"); + int flags = fcntl(fd2, F_GETFL, 0); + fcntl(fd2, F_SETFL, flags | O_NONBLOCK); + if(argc<=6) return badsyntax("need required parameter (use_every_nth)"); + sscanf(argv[6],"%d",&decimation); + if(decimation<=0) return badsyntax("use_every_nth <= 0 is invalid"); + if(argc<=7) return badsyntax("need required parameter (report_every_nth)"); + sscanf(argv[7],"%d",&report_every_nth); + if(report_every_nth<=0) return badsyntax("report_every_nth <= 0 is invalid"); + for(;;) + { + FEOF_CHECK; + FREAD_C; //read input data + power = get_power_c((complexf*)input_buffer, the_bufsize, decimation); + if(report_cntr++>report_every_nth) + { + report_cntr=0; + power_value_buf_size=snprintf(power_value_buf,100,"%g\n",power); + write(fd2,power_value_buf,power_value_buf_size*sizeof(char)); + } + if(squelch_level==0||power>=squelch_level) + { + //fprintf(stderr,"P"); + fwrite(input_buffer, sizeof(complexf), the_bufsize, stdout); + } + else + { + //fprintf(stderr,"S"); + fwrite(zerobuf, sizeof(complexf), the_bufsize, stdout); + } + if(read_fifo_ctl(fd,"%g\n",&squelch_level)) fprintf(stderr, "squelch_and_power_cc: new squelch level is %g\n", squelch_level); + TRY_YIELD; + } + } - /* - ______ _ _____ _____ _____ - | ____| | | | __ \| __ \ / ____| - | |__ __ _ ___| |_| | | | | | | | - | __/ _` / __| __| | | | | | | | - | | | (_| \__ \ |_| |__| | |__| | |____ - |_| \__,_|___/\__|_____/|_____/ \_____| + /* + ______ _ _____ _____ _____ + | ____| | | | __ \| __ \ / ____| + | |__ __ _ ___| |_| | | | | | | | + | __/ _` / __| __| | | | | | | | + | | | (_| \__ \ |_| |__| | |__| | |____ + |_| \__,_|___/\__|_____/|_____/ \_____| - */ + */ - if( !strcmp(argv[1],"fastddc_fwd_cc") ) // [transition_bw [window]] - { - - int decimation; - if(argc<=2) return badsyntax("need required parameter (decimation)"); - sscanf(argv[2],"%d",&decimation); - - float transition_bw = 0.05; - if(argc>3) sscanf(argv[3],"%g",&transition_bw); + if( !strcmp(argv[1],"fastddc_fwd_cc") ) // [transition_bw [window]] + { + + int decimation; + if(argc<=2) return badsyntax("need required parameter (decimation)"); + sscanf(argv[2],"%d",&decimation); + + float transition_bw = 0.05; + if(argc>3) sscanf(argv[3],"%g",&transition_bw); - window_t window = WINDOW_DEFAULT; - if(argc>4) window=firdes_get_window_from_string(argv[4]); - else fprintf(stderr,"fastddc_fwd_cc: window = %s\n",firdes_get_string_from_window(window)); + window_t window = WINDOW_DEFAULT; + if(argc>4) window=firdes_get_window_from_string(argv[4]); + else fprintf(stderr,"fastddc_fwd_cc: window = %s\n",firdes_get_string_from_window(window)); - fastddc_t ddc; - if(fastddc_init(&ddc, transition_bw, decimation, 0)) { badsyntax("error in fastddc_init()"); return 1; } - fastddc_print(&ddc,"fastddc_fwd_cc"); + fastddc_t ddc; + if(fastddc_init(&ddc, transition_bw, decimation, 0)) { badsyntax("error in fastddc_init()"); return 1; } + fastddc_print(&ddc,"fastddc_fwd_cc"); - if(!initialize_buffers()) return -2; - sendbufsize(ddc.fft_size); + if(!initialize_buffers()) return -2; + sendbufsize(ddc.fft_size); - //make FFT plan - complexf* input = (complexf*)fft_malloc(sizeof(complexf)*ddc.fft_size); - complexf* windowed = (complexf*)fft_malloc(sizeof(complexf)*ddc.fft_size); - complexf* output = (complexf*)fft_malloc(sizeof(complexf)*ddc.fft_size); + //make FFT plan + complexf* input = (complexf*)fft_malloc(sizeof(complexf)*ddc.fft_size); + complexf* windowed = (complexf*)fft_malloc(sizeof(complexf)*ddc.fft_size); + complexf* output = (complexf*)fft_malloc(sizeof(complexf)*ddc.fft_size); - for(int i=0;i [transition_bw [window]] - { - float shift_rate; - int plusarg=0; + if( !strcmp(argv[1],"fastddc_inv_cc") ) // [transition_bw [window]] + { + float shift_rate; + int plusarg=0; - int fd; - if(fd=init_fifo(argc,argv)) - { - while(!read_fifo_ctl(fd,"%g\n",&shift_rate)) usleep(10000); - plusarg=1; - } - else - { - if(argc<=2) return badsyntax("need required parameter (rate)"); - sscanf(argv[2],"%g",&shift_rate); - } + int fd; + if(fd=init_fifo(argc,argv)) + { + while(!read_fifo_ctl(fd,"%g\n",&shift_rate)) usleep(10000); + plusarg=1; + } + else + { + if(argc<=2) return badsyntax("need required parameter (rate)"); + sscanf(argv[2],"%g",&shift_rate); + } - int decimation; - if(argc<=3+plusarg) return badsyntax("need required parameter (decimation)"); - sscanf(argv[3+plusarg],"%d",&decimation); - //fprintf(stderr, "dec=%d %d\n", decimation); + int decimation; + if(argc<=3+plusarg) return badsyntax("need required parameter (decimation)"); + sscanf(argv[3+plusarg],"%d",&decimation); + //fprintf(stderr, "dec=%d %d\n", decimation); - float transition_bw = 0.05; - if(argc>4+plusarg) sscanf(argv[4+plusarg],"%g",&transition_bw); + float transition_bw = 0.05; + if(argc>4+plusarg) sscanf(argv[4+plusarg],"%g",&transition_bw); - window_t window = WINDOW_DEFAULT; - if(argc>5+plusarg) window=firdes_get_window_from_string(argv[5+plusarg]); - else fprintf(stderr,"fastddc_apply_cc: window = %s\n",firdes_get_string_from_window(window)); + window_t window = WINDOW_DEFAULT; + if(argc>5+plusarg) window=firdes_get_window_from_string(argv[5+plusarg]); + else fprintf(stderr,"fastddc_apply_cc: window = %s\n",firdes_get_string_from_window(window)); - for(;;) - { + for(;;) + { - fastddc_t ddc; - if(fastddc_init(&ddc, transition_bw, decimation, shift_rate)) { badsyntax("error in fastddc_init()"); return 1; } - fastddc_print(&ddc,"fastddc_inv_cc"); + fastddc_t ddc; + if(fastddc_init(&ddc, transition_bw, decimation, shift_rate)) { badsyntax("error in fastddc_init()"); return 1; } + fastddc_print(&ddc,"fastddc_inv_cc"); - if(!initialize_buffers()) return -2; - sendbufsize(ddc.post_input_size/ddc.post_decimation); //TODO not exactly correct + if(!initialize_buffers()) return -2; + sendbufsize(ddc.post_input_size/ddc.post_decimation); //TODO not exactly correct - //prepare making the filter and doing FFT on it - complexf* taps=(complexf*)calloc(sizeof(complexf),ddc.fft_size); //initialize to zero - complexf* taps_fft=(complexf*)malloc(sizeof(complexf)*ddc.fft_size); - FFT_PLAN_T* plan_taps = make_fft_c2c(ddc.fft_size, taps, taps_fft, 1, 0); //forward, don't benchmark (we need this only once) + //prepare making the filter and doing FFT on it + complexf* taps=(complexf*)calloc(sizeof(complexf),ddc.fft_size); //initialize to zero + complexf* taps_fft=(complexf*)malloc(sizeof(complexf)*ddc.fft_size); + FFT_PLAN_T* plan_taps = make_fft_c2c(ddc.fft_size, taps, taps_fft, 1, 0); //forward, don't benchmark (we need this only once) - //make the filter - float filter_half_bw = 0.5/decimation; - fprintf(stderr, "fastddc_inv_cc: preparing a bandpass filter of [%g, %g] cutoff rates. Real transition bandwidth is: %g\n", (-shift_rate)-filter_half_bw, (-shift_rate)+filter_half_bw, 4.0/ddc.taps_length); - firdes_bandpass_c(taps, ddc.taps_length, (-shift_rate)-filter_half_bw, (-shift_rate)+filter_half_bw, window); - fft_execute(plan_taps); - fft_swap_sides(taps_fft,ddc.fft_size); + //make the filter + float filter_half_bw = 0.5/decimation; + fprintf(stderr, "fastddc_inv_cc: preparing a bandpass filter of [%g, %g] cutoff rates. Real transition bandwidth is: %g\n", (-shift_rate)-filter_half_bw, (-shift_rate)+filter_half_bw, 4.0/ddc.taps_length); + firdes_bandpass_c(taps, ddc.taps_length, (-shift_rate)-filter_half_bw, (-shift_rate)+filter_half_bw, window); + fft_execute(plan_taps); + fft_swap_sides(taps_fft,ddc.fft_size); - //make FFT plan - complexf* inv_input = (complexf*)fft_malloc(sizeof(complexf)*ddc.fft_inv_size); - complexf* inv_output = (complexf*)fft_malloc(sizeof(complexf)*ddc.fft_inv_size); - fprintf(stderr,"fastddc_inv_cc: benchmarking FFT..."); - FFT_PLAN_T* plan_inverse = make_fft_c2c(ddc.fft_inv_size, inv_input, inv_output, 0, 1); //inverse, do benchmark - fprintf(stderr," done\n"); - - //alloc. buffers - complexf* input = (complexf*)fft_malloc(sizeof(complexf)*ddc.fft_size); - complexf* output = (complexf*)fft_malloc(sizeof(complexf)*ddc.post_input_size); + //make FFT plan + complexf* inv_input = (complexf*)fft_malloc(sizeof(complexf)*ddc.fft_inv_size); + complexf* inv_output = (complexf*)fft_malloc(sizeof(complexf)*ddc.fft_inv_size); + fprintf(stderr,"fastddc_inv_cc: benchmarking FFT..."); + FFT_PLAN_T* plan_inverse = make_fft_c2c(ddc.fft_inv_size, inv_input, inv_output, 0, 1); //inverse, do benchmark + fprintf(stderr," done\n"); + + //alloc. buffers + complexf* input = (complexf*)fft_malloc(sizeof(complexf)*ddc.fft_size); + complexf* output = (complexf*)fft_malloc(sizeof(complexf)*ddc.post_input_size); - decimating_shift_addition_status_t shift_stat; - bzero(&shift_stat, sizeof(shift_stat)); - for(;;) - { - FEOF_CHECK; - fread(input, sizeof(complexf), ddc.fft_size, stdin); - shift_stat = fastddc_inv_cc(input, output, &ddc, plan_inverse, taps_fft, shift_stat); - fwrite(output, sizeof(complexf), shift_stat.output_size, stdout); - //fprintf(stderr, "ss os = %d\n", shift_stat.output_size); - TRY_YIELD; - if(read_fifo_ctl(fd,"%g\n",&shift_rate)) break; - } + decimating_shift_addition_status_t shift_stat; + bzero(&shift_stat, sizeof(shift_stat)); + for(;;) + { + FEOF_CHECK; + fread(input, sizeof(complexf), ddc.fft_size, stdin); + shift_stat = fastddc_inv_cc(input, output, &ddc, plan_inverse, taps_fft, shift_stat); + fwrite(output, sizeof(complexf), shift_stat.output_size, stdout); + //fprintf(stderr, "ss os = %d\n", shift_stat.output_size); + TRY_YIELD; + if(read_fifo_ctl(fd,"%g\n",&shift_rate)) break; + } - } - } + } + } - if( !strcmp(argv[1], "_fft2octave") ) - { - int fft_size; - if(argc<=2) return badsyntax("need required parameter (fft_size)"); - sscanf(argv[2],"%d",&fft_size); + if( !strcmp(argv[1], "_fft2octave") ) + { + int fft_size; + if(argc<=2) return badsyntax("need required parameter (fft_size)"); + sscanf(argv[2],"%d",&fft_size); - complexf* fft_input=(complexf*)malloc(sizeof(complexf)*fft_size); - initialize_buffers(); - if(!sendbufsize(fft_size)) return -2; + complexf* fft_input=(complexf*)malloc(sizeof(complexf)*fft_size); + initialize_buffers(); + if(!sendbufsize(fft_size)) return -2; - printf("setenv(\"GNUTERM\",\"X11 noraise\");y=zeros(1,%d);semilogy(y,\"ydatasource\",\"y\");\n",fft_size); - for(;;) - { - FEOF_CHECK; - fread(fft_input, sizeof(complexf), fft_size, stdin); - printf("fftdata=["); - //we have to swap the two parts of the array to get a valid spectrum - for(int i=fft_size/2;i initialized to 0 - unsigned char output; - if(!sendbufsize(initialize_buffers())) return -2; - unsigned char i=0; - for(;;) - { - if((output=rtty_baudot_decoder_push(&status_baudot, getchar()))) { putchar(output); fflush(stdout); } - if(i++) continue; //do the following at every 256th execution of the loop body: - FEOF_CHECK; - TRY_YIELD; - } - } + if(!strcmp(argv[1],"rtty_line_decoder_u8_u8")) + { + static rtty_baudot_decoder_t status_baudot; //created on .bss -> initialized to 0 + unsigned char output; + if(!sendbufsize(initialize_buffers())) return -2; + unsigned char i=0; + for(;;) + { + if((output=rtty_baudot_decoder_push(&status_baudot, getchar()))) { putchar(output); fflush(stdout); } + if(i++) continue; //do the following at every 256th execution of the loop body: + FEOF_CHECK; + TRY_YIELD; + } + } - if(!strcmp(argv[1],"rtty_baudot2ascii_u8_u8")) - { - unsigned char fig_mode = 0; - unsigned char output; - if(!sendbufsize(initialize_buffers())) return -2; - unsigned char i=0; - for(;;) - { - if((output=rtty_baudot_decoder_lookup(&fig_mode, getchar()))) { putchar(output); fflush(stdout); } - if(i++) continue; //do the following at every 256th execution of the loop body: - FEOF_CHECK; - TRY_YIELD; - } - } + if(!strcmp(argv[1],"rtty_baudot2ascii_u8_u8")) + { + unsigned char fig_mode = 0; + unsigned char output; + if(!sendbufsize(initialize_buffers())) return -2; + unsigned char i=0; + for(;;) + { + if((output=rtty_baudot_decoder_lookup(&fig_mode, getchar()))) { putchar(output); fflush(stdout); } + if(i++) continue; //do the following at every 256th execution of the loop body: + FEOF_CHECK; + TRY_YIELD; + } + } - if(!strcmp(argv[1],"binary_slicer_f_u8")) - { - if(!sendbufsize(initialize_buffers())) return -2; - for(;;) - { - FEOF_CHECK; - if(!FREAD_R) break; - binary_slicer_f_u8(input_buffer, (unsigned char*)output_buffer, the_bufsize); - FWRITE_U8; - TRY_YIELD; - } - return 0; - } + if(!strcmp(argv[1],"binary_slicer_f_u8")) + { + if(!sendbufsize(initialize_buffers())) return -2; + for(;;) + { + FEOF_CHECK; + if(!FREAD_R) break; + binary_slicer_f_u8(input_buffer, (unsigned char*)output_buffer, the_bufsize); + FWRITE_U8; + TRY_YIELD; + } + return 0; + } - if(!strcmp(argv[1],"serial_line_decoder_f_u8")) - { - bigbufs=1; + if(!strcmp(argv[1],"serial_line_decoder_f_u8")) + { + bigbufs=1; - serial_line_t serial; + serial_line_t serial; - if(argc<=2) return badsyntax("need required parameter (samples_per_bits)"); - sscanf(argv[2],"%f",&serial.samples_per_bits); - if(serial.samples_per_bits<1) return badsyntax("samples_per_bits should be at least 1."); - if(serial.samples_per_bits<5) fprintf(stderr, "%s: warning: this algorithm does not work well if samples_per_bits is too low. It should be at least 5.\n", argv[1]); + if(argc<=2) return badsyntax("need required parameter (samples_per_bits)"); + sscanf(argv[2],"%f",&serial.samples_per_bits); + if(serial.samples_per_bits<1) return badsyntax("samples_per_bits should be at least 1."); + if(serial.samples_per_bits<5) fprintf(stderr, "%s: warning: this algorithm does not work well if samples_per_bits is too low. It should be at least 5.\n", argv[1]); - serial.databits=8; - if(argc>3) sscanf(argv[3],"%d",&serial.databits); - if(serial.databits>8 || serial.databits<1) return badsyntax("databits should be between 1 and 8."); + serial.databits=8; + if(argc>3) sscanf(argv[3],"%d",&serial.databits); + if(serial.databits>8 || serial.databits<1) return badsyntax("databits should be between 1 and 8."); - serial.stopbits=1; - if(argc>4) sscanf(argv[4],"%f",&serial.stopbits); - if(serial.stopbits<1) return badsyntax("stopbits should be equal or above 1."); + serial.stopbits=1; + if(argc>4) sscanf(argv[4],"%f",&serial.stopbits); + if(serial.stopbits<1) return badsyntax("stopbits should be equal or above 1."); - serial.bit_sampling_width_ratio = 0.4; - serial.input_used=0; + serial.bit_sampling_width_ratio = 0.4; + serial.input_used=0; - if(!sendbufsize(initialize_buffers())) return -2; + if(!sendbufsize(initialize_buffers())) return -2; - for(;;) - { - FEOF_CHECK; - if(serial.input_used) - { - memmove(input_buffer, input_buffer+serial.input_used, sizeof(float)*(the_bufsize-serial.input_used)); - fread(input_buffer+(the_bufsize-serial.input_used), sizeof(float), serial.input_used, stdin); - } - else fread(input_buffer, sizeof(float), the_bufsize, stdin); //should happen only on the first run - serial_line_decoder_f_u8(&serial,input_buffer, (unsigned char*)output_buffer, the_bufsize); - //printf("now in | "); - if(serial.input_used==0) { fprintf(stderr, "%s: error: serial_line_decoder_f_u8() got stuck.\n", argv[1]); return -3; } - //printf("now out %d | ", serial.output_size); - fwrite(output_buffer, sizeof(unsigned char), serial.output_size, stdout); - TRY_YIELD; - } - } + for(;;) + { + FEOF_CHECK; + if(serial.input_used) + { + memmove(input_buffer, input_buffer+serial.input_used, sizeof(float)*(the_bufsize-serial.input_used)); + fread(input_buffer+(the_bufsize-serial.input_used), sizeof(float), serial.input_used, stdin); + } + else fread(input_buffer, sizeof(float), the_bufsize, stdin); //should happen only on the first run + serial_line_decoder_f_u8(&serial,input_buffer, (unsigned char*)output_buffer, the_bufsize); + //printf("now in | "); + if(serial.input_used==0) { fprintf(stderr, "%s: error: serial_line_decoder_f_u8() got stuck.\n", argv[1]); return -3; } + //printf("now out %d | ", serial.output_size); + fwrite(output_buffer, sizeof(unsigned char), serial.output_size, stdout); + TRY_YIELD; + } + } - if(!strcmp(argv[1],"pll_cc")) - { - pll_t pll; + if(!strcmp(argv[1],"pll_cc")) + { + pll_t pll; - if(argc<=2) return badsyntax("need required parameter (pll_type)"); - sscanf(argv[2],"%d",(int*)&pll.pll_type); - if(pll.pll_type == PLL_P_CONTROLLER) - { - float alpha = 0.01; - if(argc>3) sscanf(argv[3],"%f",&alpha); - pll_cc_init_p_controller(&pll, alpha); - } - else if(pll.pll_type == PLL_PI_CONTROLLER) - { - float bandwidth = 0.01, ko = 10, kd=0.1, damping_factor = 0.707; - if(argc>3) sscanf(argv[3],"%f",&bandwidth); - if(argc>4) sscanf(argv[4],"%f",&damping_factor); - if(argc>5) sscanf(argv[5],"%f",&ko); - if(argc>6) sscanf(argv[6],"%f",&kd); - pll_cc_init_pi_controller(&pll, bandwidth, ko, kd, damping_factor); - fprintf(stderr, "bw=%f damping=%f ko=%f kd=%f alpha=%f beta=%f\n", bandwidth, damping_factor, ko, kd, pll.alpha, pll.beta); - // pll.filter_taps_a[0], pll.filter_taps_a[1], pll.filter_taps_a[2], pll.filter_taps_b[0], pll.filter_taps_b[1], pll.filter_taps_b[2]); - } - else return badsyntax("invalid pll_type. Valid values are:\n\t1: PLL_P_CONTROLLER\n\t2: PLL_PI_CONTROLLER"); + if(argc<=2) return badsyntax("need required parameter (pll_type)"); + sscanf(argv[2],"%d",(int*)&pll.pll_type); + if(pll.pll_type == PLL_P_CONTROLLER) + { + float alpha = 0.01; + if(argc>3) sscanf(argv[3],"%f",&alpha); + pll_cc_init_p_controller(&pll, alpha); + } + else if(pll.pll_type == PLL_PI_CONTROLLER) + { + float bandwidth = 0.01, ko = 10, kd=0.1, damping_factor = 0.707; + if(argc>3) sscanf(argv[3],"%f",&bandwidth); + if(argc>4) sscanf(argv[4],"%f",&damping_factor); + if(argc>5) sscanf(argv[5],"%f",&ko); + if(argc>6) sscanf(argv[6],"%f",&kd); + pll_cc_init_pi_controller(&pll, bandwidth, ko, kd, damping_factor); + fprintf(stderr, "bw=%f damping=%f ko=%f kd=%f alpha=%f beta=%f\n", bandwidth, damping_factor, ko, kd, pll.alpha, pll.beta); + // pll.filter_taps_a[0], pll.filter_taps_a[1], pll.filter_taps_a[2], pll.filter_taps_b[0], pll.filter_taps_b[1], pll.filter_taps_b[2]); + } + else return badsyntax("invalid pll_type. Valid values are:\n\t1: PLL_P_CONTROLLER\n\t2: PLL_PI_CONTROLLER"); - if(!sendbufsize(initialize_buffers())) return -2; + if(!sendbufsize(initialize_buffers())) return -2; - for(;;) - { - FEOF_CHECK; - FREAD_C; - //fprintf(stderr, "| i"); - // pll_cc(&pll, (complexf*)input_buffer, output_buffer, NULL, the_bufsize); - // fwrite(output_buffer, sizeof(float), the_bufsize, stdout); - pll_cc(&pll, (complexf*)input_buffer, NULL, (complexf*)output_buffer, the_bufsize); - fwrite(output_buffer, sizeof(complexf), the_bufsize, stdout); - //fprintf(stderr, "| o"); - TRY_YIELD; - } - } + for(;;) + { + FEOF_CHECK; + FREAD_C; + //fprintf(stderr, "| i"); + // pll_cc(&pll, (complexf*)input_buffer, output_buffer, NULL, the_bufsize); + // fwrite(output_buffer, sizeof(float), the_bufsize, stdout); + pll_cc(&pll, (complexf*)input_buffer, NULL, (complexf*)output_buffer, the_bufsize); + fwrite(output_buffer, sizeof(complexf), the_bufsize, stdout); + //fprintf(stderr, "| o"); + TRY_YIELD; + } + } - if(!strcmp(argv[1],"timing_recovery_cc")) // [--add_q [--output_error | --output_indexes | --octave ]] - { - if(argc<=2) return badsyntax("need required parameter (algorithm)"); - timing_recovery_algorithm_t algorithm = timing_recovery_get_algorithm_from_string(argv[2]); - //if(algorithm == TIMING_RECOVERY_ALGORITHM_DEFAULT) - // fprintf(stderr,"#timing_recovery_cc: algorithm = %s\n",timing_recovery_get_string_from_algorithm(algorithm)); - if(argc<=3) return badsyntax("need required parameter (decimation factor)"); - int decimation; - sscanf(argv[3],"%d",&decimation); - if(decimation<=4 || decimation&3) return badsyntax("decimation factor should be a positive integer divisible by 4"); + if(!strcmp(argv[1],"timing_recovery_cc")) // [--add_q [--output_error | --output_indexes | --octave ]] + { + if(argc<=2) return badsyntax("need required parameter (algorithm)"); + timing_recovery_algorithm_t algorithm = timing_recovery_get_algorithm_from_string(argv[2]); + //if(algorithm == TIMING_RECOVERY_ALGORITHM_DEFAULT) + // fprintf(stderr,"#timing_recovery_cc: algorithm = %s\n",timing_recovery_get_string_from_algorithm(algorithm)); + if(argc<=3) return badsyntax("need required parameter (decimation factor)"); + int decimation; + sscanf(argv[3],"%d",&decimation); + if(decimation<=4 || decimation&3) return badsyntax("decimation factor should be a positive integer divisible by 4"); - int add_q = (argc>=5 && !strcmp(argv[4], "--add_q")); + int add_q = (argc>=5 && !strcmp(argv[4], "--add_q")); - int debug_n = 0; - int output_error = 0; - int output_indexes = 0; - if(argc>=7 && !strcmp(argv[5], "--octave")) debug_n = atoi(argv[6]); - if(debug_n<0) return badsyntax("debug_n should be >= 0"); + int debug_n = 0; + int output_error = 0; + int output_indexes = 0; + if(argc>=7 && !strcmp(argv[5], "--octave")) debug_n = atoi(argv[6]); + if(debug_n<0) return badsyntax("debug_n should be >= 0"); if(argc>=6 && !strcmp(argv[5], "--output_error")) output_error = 1; - float* timing_error = NULL; - if(output_error) timing_error = (float*)malloc(sizeof(float)*the_bufsize); + float* timing_error = NULL; + if(output_error) timing_error = (float*)malloc(sizeof(float)*the_bufsize); if(argc>=6 && !strcmp(argv[5], "--output_indexes")) output_indexes = 1; - unsigned* sampled_indexes = NULL; - if(output_indexes) sampled_indexes = (unsigned*)malloc(sizeof(float)*the_bufsize); + unsigned* sampled_indexes = NULL; + if(output_indexes) sampled_indexes = (unsigned*)malloc(sizeof(float)*the_bufsize); - if(!initialize_buffers()) return -2; - sendbufsize(the_bufsize/decimation); + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize/decimation); - timing_recovery_state_t state = timing_recovery_init(algorithm, decimation, add_q); + timing_recovery_state_t state = timing_recovery_init(algorithm, decimation, add_q); - int debug_i=0; - state.debug_writefiles = 1; - state.debug_force = !!debug_n; //should remove that later - FREAD_C; + int debug_i=0; + state.debug_writefiles = 1; + state.debug_force = !!debug_n; //should remove that later + FREAD_C; unsigned buffer_start_counter = 0; - for(;;) - { - FEOF_CHECK; - if(debug_n && ++debug_i%debug_n==0) timing_recovery_trigger_debug(&state, 3); - timing_recovery_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, timing_error, (int*)sampled_indexes, &state); - //fprintf(stderr, "trcc is=%d, os=%d, ip=%d\n",the_bufsize, state.output_size, state.input_processed); - if(timing_error) fwrite(timing_error, sizeof(float), state.output_size, stdout); + for(;;) + { + FEOF_CHECK; + if(debug_n && ++debug_i%debug_n==0) timing_recovery_trigger_debug(&state, 3); + timing_recovery_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, timing_error, (int*)sampled_indexes, &state); + //fprintf(stderr, "trcc is=%d, os=%d, ip=%d\n",the_bufsize, state.output_size, state.input_processed); + if(timing_error) fwrite(timing_error, sizeof(float), state.output_size, stdout); else if(sampled_indexes) { for(int i=0;i 0"); - if(argc<=3) return badsyntax("need required parameter (out_of_n_samples)"); - int out_of_n_samples = 0; - sscanf(argv[3], "%d", &out_of_n_samples); - if(out_of_n_samples4) mode2d = !strcmp(argv[4], "--2d"); - complexf* read_buf = (complexf*)malloc(sizeof(complexf)*the_bufsize); + if(!strcmp(argv[1],"octave_complex_c")) + { + if(argc<=2) return badsyntax("need required parameter (samples_to_plot)"); + int samples_to_plot = 0; + sscanf(argv[2], "%d", &samples_to_plot); + if(samples_to_plot<=0) return badsyntax("Number of samples to plot should be > 0"); + if(argc<=3) return badsyntax("need required parameter (out_of_n_samples)"); + int out_of_n_samples = 0; + sscanf(argv[3], "%d", &out_of_n_samples); + if(out_of_n_samples4) mode2d = !strcmp(argv[4], "--2d"); + complexf* read_buf = (complexf*)malloc(sizeof(complexf)*the_bufsize); - if(!sendbufsize(initialize_buffers())) return -2; - for(;;) - { - fread(read_buf, sizeof(complexf), samples_to_plot, stdin); - printf("N = %d;\nisig = [", samples_to_plot); - for(int i=0;i0;seek_remain-=samples_to_plot) - { - fread(read_buf, sizeof(complexf), MIN_M(samples_to_plot,seek_remain), stdin); - } - FEOF_CHECK; - TRY_YIELD; - } - } + if(!sendbufsize(initialize_buffers())) return -2; + for(;;) + { + fread(read_buf, sizeof(complexf), samples_to_plot, stdin); + printf("N = %d;\nisig = [", samples_to_plot); + for(int i=0;i0;seek_remain-=samples_to_plot) + { + fread(read_buf, sizeof(complexf), MIN_M(samples_to_plot,seek_remain), stdin); + } + FEOF_CHECK; + TRY_YIELD; + } + } - if(!strcmp(argv[1],"psk_modulator_u8_c")) // - { - int n_psk; - if(argc<=2) return badsyntax("need required parameter (n_psk)"); - sscanf(argv[2],"%d",&n_psk); - if(n_psk<=0 || n_psk>256) return badsyntax("n_psk should be between 1 and 256"); + if(!strcmp(argv[1],"psk_modulator_u8_c")) // + { + int n_psk; + if(argc<=2) return badsyntax("need required parameter (n_psk)"); + sscanf(argv[2],"%d",&n_psk); + if(n_psk<=0 || n_psk>256) return badsyntax("n_psk should be between 1 and 256"); - if(!initialize_buffers()) return -2; - sendbufsize(the_bufsize); + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize); - for(;;) - { - FEOF_CHECK; - fread((unsigned char*)input_buffer, sizeof(unsigned char), the_bufsize, stdin); - psk_modulator_u8_c((unsigned char*)input_buffer, (complexf*)output_buffer, the_bufsize, n_psk); - FWRITE_C; - TRY_YIELD; - } - } + for(;;) + { + FEOF_CHECK; + fread((unsigned char*)input_buffer, sizeof(unsigned char), the_bufsize, stdin); + psk_modulator_u8_c((unsigned char*)input_buffer, (complexf*)output_buffer, the_bufsize, n_psk); + FWRITE_C; + TRY_YIELD; + } + } - if(!strcmp(argv[1],"duplicate_samples_ntimes_u8_u8")) // - { - int sample_size_bytes = 0, ntimes = 0; - if(argc<=2) return badsyntax("need required parameter (sample_size_bytes)"); - sscanf(argv[2],"%d",&sample_size_bytes); - if(sample_size_bytes<=0) return badsyntax("sample_size_bytes should be >0"); - if(argc<=3) return badsyntax("need required parameter (ntimes)"); - sscanf(argv[3],"%d",&ntimes); - if(ntimes<=0) return badsyntax("ntimes should be >0"); - if(!initialize_buffers()) return -2; - sendbufsize(the_bufsize*ntimes); - unsigned char* local_input_buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize*sample_size_bytes); - unsigned char* local_output_buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize*sample_size_bytes*ntimes); - for(;;) - { - FEOF_CHECK; - fread((void*)local_input_buffer, sizeof(unsigned char), the_bufsize*sample_size_bytes, stdin); - duplicate_samples_ntimes_u8_u8(local_input_buffer, local_output_buffer, the_bufsize*sample_size_bytes, sample_size_bytes, ntimes); - fwrite((void*)local_output_buffer, sizeof(unsigned char), the_bufsize*sample_size_bytes*ntimes, stdout); - TRY_YIELD; - } - } + if(!strcmp(argv[1],"duplicate_samples_ntimes_u8_u8")) // + { + int sample_size_bytes = 0, ntimes = 0; + if(argc<=2) return badsyntax("need required parameter (sample_size_bytes)"); + sscanf(argv[2],"%d",&sample_size_bytes); + if(sample_size_bytes<=0) return badsyntax("sample_size_bytes should be >0"); + if(argc<=3) return badsyntax("need required parameter (ntimes)"); + sscanf(argv[3],"%d",&ntimes); + if(ntimes<=0) return badsyntax("ntimes should be >0"); + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize*ntimes); + unsigned char* local_input_buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize*sample_size_bytes); + unsigned char* local_output_buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize*sample_size_bytes*ntimes); + for(;;) + { + FEOF_CHECK; + fread((void*)local_input_buffer, sizeof(unsigned char), the_bufsize*sample_size_bytes, stdin); + duplicate_samples_ntimes_u8_u8(local_input_buffer, local_output_buffer, the_bufsize*sample_size_bytes, sample_size_bytes, ntimes); + fwrite((void*)local_output_buffer, sizeof(unsigned char), the_bufsize*sample_size_bytes*ntimes, stdout); + TRY_YIELD; + } + } - if(!strcmp(argv[1],"psk31_interpolate_sine_cc")) // - { - int interpolation; - if(argc<=2) return badsyntax("need required parameter (interpolation)"); - sscanf(argv[2],"%d",&interpolation); - if(interpolation<=0) return badsyntax("interpolation should be >0"); - if(!initialize_buffers()) return -2; - sendbufsize(the_bufsize*interpolation); - complexf* local_output_buffer = (complexf*)malloc(sizeof(complexf)*the_bufsize*interpolation); - complexf last_input; - iof(&last_input,0) = 0; - qof(&last_input,0) = 0; - for(;;) - { - FEOF_CHECK; - FREAD_C; - last_input = psk31_interpolate_sine_cc((complexf*)input_buffer, local_output_buffer, the_bufsize, interpolation, last_input); - fwrite((void*)local_output_buffer, sizeof(complexf), the_bufsize*interpolation, stdout); - TRY_YIELD; - } - } + if(!strcmp(argv[1],"psk31_interpolate_sine_cc")) // + { + int interpolation; + if(argc<=2) return badsyntax("need required parameter (interpolation)"); + sscanf(argv[2],"%d",&interpolation); + if(interpolation<=0) return badsyntax("interpolation should be >0"); + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize*interpolation); + complexf* local_output_buffer = (complexf*)malloc(sizeof(complexf)*the_bufsize*interpolation); + complexf last_input; + iof(&last_input,0) = 0; + qof(&last_input,0) = 0; + for(;;) + { + FEOF_CHECK; + FREAD_C; + last_input = psk31_interpolate_sine_cc((complexf*)input_buffer, local_output_buffer, the_bufsize, interpolation, last_input); + fwrite((void*)local_output_buffer, sizeof(complexf), the_bufsize*interpolation, stdout); + TRY_YIELD; + } + } - if(!strcmp(argv[1],"pack_bits_8to1_u8_u8")) - { - if(!initialize_buffers()) return -2; - sendbufsize(the_bufsize*8); - unsigned char* local_input_buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize); - unsigned char* local_output_buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize*8); - for(;;) - { - FEOF_CHECK; - fread((void*)local_input_buffer, sizeof(unsigned char), the_bufsize, stdin); - pack_bits_8to1_u8_u8(local_input_buffer, local_output_buffer, the_bufsize); - fwrite((void*)local_output_buffer, sizeof(unsigned char), the_bufsize*8, stdout); - TRY_YIELD; - } - } + if(!strcmp(argv[1],"pack_bits_8to1_u8_u8")) + { + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize*8); + unsigned char* local_input_buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize); + unsigned char* local_output_buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize*8); + for(;;) + { + FEOF_CHECK; + fread((void*)local_input_buffer, sizeof(unsigned char), the_bufsize, stdin); + pack_bits_8to1_u8_u8(local_input_buffer, local_output_buffer, the_bufsize); + fwrite((void*)local_output_buffer, sizeof(unsigned char), the_bufsize*8, stdout); + TRY_YIELD; + } + } - if(!strcmp(argv[1],"psk31_varicode_encoder_u8_u8")) - { - if(!initialize_buffers()) return -2; - sendbufsize(the_bufsize*8); - int output_max_size=the_bufsize*30; - int output_size; - int input_processed; - unsigned char* local_input_buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize); - unsigned char* local_output_buffer = (unsigned char*)malloc(sizeof(unsigned char)*output_max_size); - fread((void*)local_input_buffer, sizeof(unsigned char), the_bufsize, stdin); - for(;;) - { - psk31_varicode_encoder_u8_u8(local_input_buffer, local_output_buffer, the_bufsize, output_max_size, &input_processed, &output_size); - //fprintf(stderr, "os = %d\n", output_size); - fwrite((void*)local_output_buffer, sizeof(unsigned char), output_size, stdout); - FEOF_CHECK; - memmove(local_input_buffer, local_input_buffer+input_processed, the_bufsize-input_processed); - fread(input_buffer+the_bufsize-input_processed, sizeof(unsigned char), input_processed, stdin); - TRY_YIELD; - } - } + if(!strcmp(argv[1],"psk31_varicode_encoder_u8_u8")) + { + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize*8); + int output_max_size=the_bufsize*30; + int output_size; + int input_processed; + unsigned char* local_input_buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize); + unsigned char* local_output_buffer = (unsigned char*)malloc(sizeof(unsigned char)*output_max_size); + fread((void*)local_input_buffer, sizeof(unsigned char), the_bufsize, stdin); + for(;;) + { + psk31_varicode_encoder_u8_u8(local_input_buffer, local_output_buffer, the_bufsize, output_max_size, &input_processed, &output_size); + //fprintf(stderr, "os = %d\n", output_size); + fwrite((void*)local_output_buffer, sizeof(unsigned char), output_size, stdout); + FEOF_CHECK; + memmove(local_input_buffer, local_input_buffer+input_processed, the_bufsize-input_processed); + fread(input_buffer+the_bufsize-input_processed, sizeof(unsigned char), input_processed, stdin); + TRY_YIELD; + } + } - if(!strcmp(argv[1],"dump_u8")) - { - if(!initialize_buffers()) return -2; - sendbufsize(the_bufsize*3); - unsigned char* local_input_buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize); - for(;;) - { - FEOF_CHECK; - fread((void*)local_input_buffer, sizeof(unsigned char), the_bufsize, stdin); - for(int i=0;i - { - float samples_per_bits; - if(argc<=2) return badsyntax("need required parameter (samples_per_bits)"); - sscanf(argv[2],"%f",&samples_per_bits); - if(samples_per_bits<=0) return badsyntax("samples_per_bits should be > 0"); + if(!strcmp(argv[1],"bpsk_costas_loop_cc")) // + { + float samples_per_bits; + if(argc<=2) return badsyntax("need required parameter (samples_per_bits)"); + sscanf(argv[2],"%f",&samples_per_bits); + if(samples_per_bits<=0) return badsyntax("samples_per_bits should be > 0"); - bpsk_costas_loop_state_t state = init_bpsk_costas_loop_cc(samples_per_bits); + bpsk_costas_loop_state_t state = init_bpsk_costas_loop_cc(samples_per_bits); - if(!initialize_buffers()) return -2; - sendbufsize(the_bufsize); + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize); - for(;;) - { - FEOF_CHECK; - FREAD_C; - bpsk_costas_loop_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, &state); - FWRITE_C; - TRY_YIELD; - } - } + for(;;) + { + FEOF_CHECK; + FREAD_C; + bpsk_costas_loop_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, &state); + FWRITE_C; + TRY_YIELD; + } + } - if(!strcmp(argv[1],"simple_agc_cc")) // [reference [max_gain]] - { - float rate; - if(argc<=2) return badsyntax("need required parameter (rate)"); - sscanf(argv[2],"%f",&rate); - if(rate<=0) return badsyntax("rate should be > 0"); + if(!strcmp(argv[1],"simple_agc_cc")) // [reference [max_gain]] + { + float rate; + if(argc<=2) return badsyntax("need required parameter (rate)"); + sscanf(argv[2],"%f",&rate); + if(rate<=0) return badsyntax("rate should be > 0"); - float reference = 1.; - if(argc>3) sscanf(argv[3],"%f",&reference); - if(reference<=0) return badsyntax("reference should be > 0"); + float reference = 1.; + if(argc>3) sscanf(argv[3],"%f",&reference); + if(reference<=0) return badsyntax("reference should be > 0"); - float max_gain = 65535.; - if(argc>4) sscanf(argv[4],"%f",&max_gain); - if(max_gain<=0) return badsyntax("max_gain should be > 0"); + float max_gain = 65535.; + if(argc>4) sscanf(argv[4],"%f",&max_gain); + if(max_gain<=0) return badsyntax("max_gain should be > 0"); - float current_gain = 1.; + float current_gain = 1.; - if(!initialize_buffers()) return -2; - sendbufsize(the_bufsize); + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize); - for(;;) - { - FEOF_CHECK; - FREAD_C; - simple_agc_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, rate, reference, max_gain, ¤t_gain); - FWRITE_C; - TRY_YIELD; - } - } + for(;;) + { + FEOF_CHECK; + FREAD_C; + simple_agc_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, rate, reference, max_gain, ¤t_gain); + FWRITE_C; + TRY_YIELD; + } + } - if(!strcmp(argv[1],"firdes_resonator_c")) // [window [--octave]] - { - //Process the params - if(argc<=3) return badsyntax("need required parameters (rate, length)"); + if(!strcmp(argv[1],"firdes_resonator_c")) // [window [--octave]] + { + //Process the params + if(argc<=3) return badsyntax("need required parameters (rate, length)"); - float rate; - sscanf(argv[2],"%g",&rate); - int length; - sscanf(argv[3],"%d",&length); - if(length%2==0) return badsyntax("number of symmetric FIR filter taps should be odd"); + float rate; + sscanf(argv[2],"%g",&rate); + int length; + sscanf(argv[3],"%d",&length); + if(length%2==0) return badsyntax("number of symmetric FIR filter taps should be odd"); - window_t window = WINDOW_DEFAULT; - if(argc>=5) - { - window=firdes_get_window_from_string(argv[4]); - } - else fprintf(stderr,"firdes_resonator_c: window = %s\n",firdes_get_string_from_window(window)); + window_t window = WINDOW_DEFAULT; + if(argc>=5) + { + window=firdes_get_window_from_string(argv[4]); + } + else fprintf(stderr,"firdes_resonator_c: window = %s\n",firdes_get_string_from_window(window)); - int octave=(argc>=6 && !strcmp("--octave",argv[5])); + int octave=(argc>=6 && !strcmp("--octave",argv[5])); - complexf* taps=(complexf*)malloc(sizeof(complexf)*length); + complexf* taps=(complexf*)malloc(sizeof(complexf)*length); - //Make the filter - firdes_add_resonator_c(taps, length, rate, window, 0, 1); + //Make the filter + firdes_add_resonator_c(taps, length, rate, window, 0, 1); - //Do the output - if(octave) printf("taps=["); - for(int i=0;i - { - //rule of thumb: bw = 2/taps_length, which does not equal to transition_bw + if(!strcmp(argv[1],"resonators_fir_cc")) // + { + //rule of thumb: bw = 2/taps_length, which does not equal to transition_bw - if(argc<=2) return badsyntax("need required parameter (taps_length)"); - int taps_length; - sscanf(argv[2],"%d",&taps_length); + if(argc<=2) return badsyntax("need required parameter (taps_length)"); + int taps_length; + sscanf(argv[2],"%d",&taps_length); - int num_resonators = argc-3; - float* resonator_rate = (float*)malloc(sizeof(float)*num_resonators); - for(int i=0;i is missing."); float snr_db = 0; - sscanf(argv[2],"%f",&snr_db); + sscanf(argv[2],"%f",&snr_db); FILE* awgnfile = NULL; if(argc>=5 && !strcmp(argv[3],"--awgnfile")) { @@ -2926,8 +2926,8 @@ int main(int argc, char *argv[]) float a_signal=signal_amplitude_per_noise/(signal_amplitude_per_noise+1.0); float a_noise=1.0/(signal_amplitude_per_noise+1.0); fprintf(stderr, "csdr awgn_cc: a_signal = %f, a_noise = %f\n", a_signal, a_noise); - if(!initialize_buffers()) return -2; - sendbufsize(the_bufsize); + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize); complexf* awgn_buffer = (complexf*)malloc(sizeof(complexf)*the_bufsize); for(;;) { @@ -2968,100 +2968,119 @@ int main(int argc, char *argv[]) if(!strcmp(argv[1], "uniform_noise_f")) { FILE* urandom = init_get_random_samples_f(); - if(!initialize_buffers()) return -2; - sendbufsize(the_bufsize); + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize); for(;;) { FEOF_CHECK; get_random_samples_f(output_buffer, the_bufsize, urandom); FWRITE_R; TRY_YIELD; - } + } } if(!strcmp(argv[1], "gaussian_noise_c")) { FILE* urandom = init_get_random_samples_f(); - if(!initialize_buffers()) return -2; - sendbufsize(the_bufsize); + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize); for(;;) { FEOF_CHECK; get_random_gaussian_samples_c((complexf*)output_buffer, the_bufsize, urandom); FWRITE_C; TRY_YIELD; - } + } } - if(!strcmp(argv[1], "normalized_timing_variance_u32_f")) // [--debug] - { + if(!strcmp(argv[1], "normalized_timing_variance_u32_f")) // [--debug] + { int samples_per_symbol = 0; if(argc<=2) return badsyntax("required parameter is missing."); - sscanf(argv[2],"%d",&samples_per_symbol); + sscanf(argv[2],"%d",&samples_per_symbol); int initial_sample_offset = 0; if(argc<=3) return badsyntax("required parameter is missing."); - sscanf(argv[3],"%d",&initial_sample_offset); + sscanf(argv[3],"%d",&initial_sample_offset); int debug_print = 0; if(argc>4 && !strcmp(argv[4],"--debug")) debug_print = 1; - if(!initialize_buffers()) return -2; - sendbufsize(the_bufsize); - float* temp_buffer = (float*)malloc(sizeof(float)*the_bufsize); + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize); + float* temp_buffer = (float*)malloc(sizeof(float)*the_bufsize); for(;;) { FEOF_CHECK; - FREAD_R; //doesn't count, reads 4 bytes per sample anyway + FREAD_R; //doesn't count, reads 4 bytes per sample anyway float nv = normalized_timing_variance_u32_f((unsigned*)input_buffer, temp_buffer, the_bufsize, samples_per_symbol, initial_sample_offset, debug_print); - fwrite(&nv, sizeof(float), 1, stdout); - fprintf(stderr, "csdr normalized_timing_variance_u32_f: normalized variance = %f\n", nv); + fwrite(&nv, sizeof(float), 1, stdout); + fprintf(stderr, "csdr normalized_timing_variance_u32_f: normalized variance = %f\n", nv); TRY_YIELD; } - } + } - if(!strcmp(argv[1], "add_n_zero_samples_at_beginning_f")) // - { + if(!strcmp(argv[1], "add_n_zero_samples_at_beginning_f")) // + { int n_zero_samples = 0; if(argc<=2) return badsyntax("required parameter is missing."); - sscanf(argv[2],"%d",&n_zero_samples); - if(!sendbufsize(initialize_buffers())) return -2; + sscanf(argv[2],"%d",&n_zero_samples); + if(!sendbufsize(initialize_buffers())) return -2; float* zeros=(float*)calloc(sizeof(float),n_zero_samples); fwrite(zeros, sizeof(float), n_zero_samples, stdout); clone_(the_bufsize); } +/* + if(!strcmp(argv[1], "matched_filter_cc")) // + { + int samples_per_symbol = 0; + if(argc<=2) return badsyntax("required parameter is missing."); + sscanf(argv[2],"%d",&samples_per_symbol); + int num_taps = 0; + if(argc<=2) return badsyntax("required parameter is missing."); + sscanf(argv[2],"%d",&num_taps); + if(!sendbufsize(initialize_buffers())) return -2; + for(;;) + { + FEOF_CHECK; + FREAD_C; + FWRITE_C; + TRY_YIELD; + } + } +*/ - if(!strcmp(argv[1],"none")) - { - return 0; - } + if(!strcmp(argv[1],"none")) + { + return 0; + } - if(argv[1][0]=='?' && argv[1][1]=='?') - { - char buffer[1000]; - snprintf(buffer, 1000-1, "xdg-open https://github.com/simonyiszk/csdr/blob/master/README.md#$(csdr ?%s | head -n1 | awk '{print $1;}')", argv[1]+2); - fprintf(stderr, "csdr ??: %s\n", buffer); - system(buffer); - return 0; - } + if(argv[1][0]=='?' && argv[1][1]=='?') + { + char buffer[1000]; + snprintf(buffer, 1000-1, "xdg-open https://github.com/simonyiszk/csdr/blob/master/README.md#$(csdr ?%s | head -n1 | awk '{print $1;}')", argv[1]+2); + fprintf(stderr, "csdr ??: %s\n", buffer); + system(buffer); + return 0; + } - if(argv[1][0]=='?') - { - char buffer[1000]; - snprintf(buffer, 1000-1, "csdr 2>&1 | grep %s", argv[1]+1); - fprintf(stderr, "csdr ?: %s\n", buffer); - system(buffer); - return 0; - } + if(argv[1][0]=='?') + { + char buffer[1000]; + snprintf(buffer, 1000-1, "csdr 2>&1 | grep %s", argv[1]+1); + fprintf(stderr, "csdr ?: %s\n", buffer); + system(buffer); + return 0; + } - if(argv[1][0]=='=') - { - char buffer[100]; - snprintf(buffer, 100-1, "python -c \"import os, sys\nfrom math import *\nprint %s\"", argv[1]+1); - system(buffer); - return 0; - } + if(argv[1][0]=='=') + { + char buffer[100]; + snprintf(buffer, 100-1, "python -c \"import os, sys\nfrom math import *\nprint %s\"", argv[1]+1); + system(buffer); + return 0; + } - fprintf(stderr,"csdr: function name given in argument 1 (%s) does not exist. Possible causes:\n- You mistyped the commandline.\n- You need to update csdr to a newer version (if available).\n", argv[1]); return -1; + fprintf(stderr,"csdr: function name given in argument 1 (%s) does not exist. Possible causes:\n- You mistyped the commandline.\n- You need to update csdr to a newer version (if available).\n", argv[1]); return -1; } diff --git a/libcsdr.c b/libcsdr.c index 177a095..f2ea3e8 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -52,55 +52,55 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define MFIRDES_GWS(NAME) \ - if(!strcmp( #NAME , input )) return WINDOW_ ## NAME; + if(!strcmp( #NAME , input )) return WINDOW_ ## NAME; window_t firdes_get_window_from_string(char* input) { - MFIRDES_GWS(BOXCAR); - MFIRDES_GWS(BLACKMAN); - MFIRDES_GWS(HAMMING); - return WINDOW_DEFAULT; + MFIRDES_GWS(BOXCAR); + MFIRDES_GWS(BLACKMAN); + MFIRDES_GWS(HAMMING); + return WINDOW_DEFAULT; } #define MFIRDES_GSW(NAME) \ - if(window == WINDOW_ ## NAME) return #NAME; + if(window == WINDOW_ ## NAME) return #NAME; char* firdes_get_string_from_window(window_t window) { - MFIRDES_GSW(BOXCAR); - MFIRDES_GSW(BLACKMAN); - MFIRDES_GSW(HAMMING); - return "INVALID"; + MFIRDES_GSW(BOXCAR); + MFIRDES_GSW(BLACKMAN); + MFIRDES_GSW(HAMMING); + return "INVALID"; } float firdes_wkernel_blackman(float rate) { - //Explanation at Chapter 16 of dspguide.com, page 2 - //Blackman window has better stopband attentuation and passband ripple than Hamming, but it has slower rolloff. - rate=0.5+rate/2; - return 0.42-0.5*cos(2*PI*rate)+0.08*cos(4*PI*rate); + //Explanation at Chapter 16 of dspguide.com, page 2 + //Blackman window has better stopband attentuation and passband ripple than Hamming, but it has slower rolloff. + rate=0.5+rate/2; + return 0.42-0.5*cos(2*PI*rate)+0.08*cos(4*PI*rate); } float firdes_wkernel_hamming(float rate) { - //Explanation at Chapter 16 of dspguide.com, page 2 - //Hamming window has worse stopband attentuation and passband ripple than Blackman, but it has faster rolloff. - rate=0.5+rate/2; - return 0.54-0.46*cos(2*PI*rate); + //Explanation at Chapter 16 of dspguide.com, page 2 + //Hamming window has worse stopband attentuation and passband ripple than Blackman, but it has faster rolloff. + rate=0.5+rate/2; + return 0.54-0.46*cos(2*PI*rate); } float firdes_wkernel_boxcar(float rate) -{ //"Dummy" window kernel, do not use; an unwindowed FIR filter may have bad frequency response - return 1.0; +{ //"Dummy" window kernel, do not use; an unwindowed FIR filter may have bad frequency response + return 1.0; } float (*firdes_get_window_kernel(window_t window))(float) { - if(window==WINDOW_HAMMING) return firdes_wkernel_hamming; - else if(window==WINDOW_BLACKMAN) return firdes_wkernel_blackman; - else if(window==WINDOW_BOXCAR) return firdes_wkernel_boxcar; - else return firdes_get_window_kernel(WINDOW_DEFAULT); + if(window==WINDOW_HAMMING) return firdes_wkernel_hamming; + else if(window==WINDOW_BLACKMAN) return firdes_wkernel_blackman; + else if(window==WINDOW_BOXCAR) return firdes_wkernel_boxcar; + else return firdes_get_window_kernel(WINDOW_DEFAULT); } /* @@ -115,62 +115,62 @@ float (*firdes_get_window_kernel(window_t window))(float) */ void firdes_lowpass_f(float *output, int length, float cutoff_rate, window_t window) -{ //Generates symmetric windowed sinc FIR filter real taps - // length should be odd - // cutoff_rate is (cutoff frequency/sampling frequency) - //Explanation at Chapter 16 of dspguide.com - int middle=length/2; - float temp; - float (*window_function)(float) = firdes_get_window_kernel(window); - output[middle]=2*PI*cutoff_rate*window_function(0); - for(int i=1; i<=middle; i++) //@@firdes_lowpass_f: calculate taps - { - output[middle-i]=output[middle+i]=(sin(2*PI*cutoff_rate*i)/i)*window_function((float)i/middle); - //printf("%g %d %d %d %d | %g\n",output[middle-i],i,middle,middle+i,middle-i,sin(2*PI*cutoff_rate*i)); - } +{ //Generates symmetric windowed sinc FIR filter real taps + // length should be odd + // cutoff_rate is (cutoff frequency/sampling frequency) + //Explanation at Chapter 16 of dspguide.com + int middle=length/2; + float temp; + float (*window_function)(float) = firdes_get_window_kernel(window); + output[middle]=2*PI*cutoff_rate*window_function(0); + for(int i=1; i<=middle; i++) //@@firdes_lowpass_f: calculate taps + { + output[middle-i]=output[middle+i]=(sin(2*PI*cutoff_rate*i)/i)*window_function((float)i/middle); + //printf("%g %d %d %d %d | %g\n",output[middle-i],i,middle,middle+i,middle-i,sin(2*PI*cutoff_rate*i)); + } - //Normalize filter kernel - float sum=0; - for(int i=0;i2*PI) phase-=2*PI; //@@firdes_bandpass_c - while(phase<0) phase+=2*PI; - iof(output,i)=cosval*realtaps[i]; - qof(output,i)=sinval*realtaps[i]; - //output[i] := realtaps[i] * e^j*w - } + float phase=0, sinval, cosval; + for(int i=0; i2*PI) phase-=2*PI; //@@firdes_bandpass_c + while(phase<0) phase+=2*PI; + iof(output,i)=cosval*realtaps[i]; + qof(output,i)=sinval*realtaps[i]; + //output[i] := realtaps[i] * e^j*w + } } int firdes_filter_len(float transition_bw) { - int result=4.0/transition_bw; - if (result%2==0) result++; //number of symmetric FIR filter taps should be odd - return result; + int result=4.0/transition_bw; + if (result%2==0) result++; //number of symmetric FIR filter taps should be odd + return result; } /* @@ -185,135 +185,135 @@ int firdes_filter_len(float transition_bw) float shift_math_cc(complexf *input, complexf* output, int input_size, float rate, float starting_phase) { - rate*=2; - //Shifts the complex spectrum. Basically a complex mixer. This version uses cmath. - float phase=starting_phase; - float phase_increment=rate*PI; - float cosval, sinval; - for(int i=0;i2*PI) phase-=2*PI; //@shift_math_cc: normalize phase - while(phase<0) phase+=2*PI; - } - return phase; + rate*=2; + //Shifts the complex spectrum. Basically a complex mixer. This version uses cmath. + float phase=starting_phase; + float phase_increment=rate*PI; + float cosval, sinval; + for(int i=0;i2*PI) phase-=2*PI; //@shift_math_cc: normalize phase + while(phase<0) phase+=2*PI; + } + return phase; } shift_table_data_t shift_table_init(int table_size) { - //RTODO - shift_table_data_t output; - output.table=(float*)malloc(sizeof(float)*table_size); - output.table_size=table_size; - for(int i=0;i1)?-1:1; //in quadrant 2 and 3 - cos_sign=(quadrant&&quadrant<3)?-1:1; //in quadrant 1 and 2 - sinval=sin_sign*table_data.table[sin_index]; - cosval=cos_sign*table_data.table[cos_index]; - //we multiply two complex numbers. - //how? enter this to maxima (software) for explanation: - // (a+b*%i)*(c+d*%i), rectform; - iof(output,i)=cosval*iof(input,i)-sinval*qof(input,i); - qof(output,i)=sinval*iof(input,i)+cosval*qof(input,i); - phase+=phase_increment; - while(phase>2*PI) phase-=2*PI; //@shift_math_cc: normalize phase - while(phase<0) phase+=2*PI; - } - return phase; + //RTODO + rate*=2; + //Shifts the complex spectrum. Basically a complex mixer. This version uses a pre-built sine table. + float phase=starting_phase; + float phase_increment=rate*PI; + float cosval, sinval; + for(int i=0;i1)?-1:1; //in quadrant 2 and 3 + cos_sign=(quadrant&&quadrant<3)?-1:1; //in quadrant 1 and 2 + sinval=sin_sign*table_data.table[sin_index]; + cosval=cos_sign*table_data.table[cos_index]; + //we multiply two complex numbers. + //how? enter this to maxima (software) for explanation: + // (a+b*%i)*(c+d*%i), rectform; + iof(output,i)=cosval*iof(input,i)-sinval*qof(input,i); + qof(output,i)=sinval*iof(input,i)+cosval*qof(input,i); + phase+=phase_increment; + while(phase>2*PI) phase-=2*PI; //@shift_math_cc: normalize phase + while(phase<0) phase+=2*PI; + } + return phase; } shift_unroll_data_t shift_unroll_init(float rate, int size) { - shift_unroll_data_t output; - output.phase_increment=2*rate*PI; - output.size = size; - output.dsin=(float*)malloc(sizeof(float)*size); - output.dcos=(float*)malloc(sizeof(float)*size); - float myphase = 0; - for(int i=0;iPI) myphase-=2*PI; - while(myphase<-PI) myphase+=2*PI; - output.dsin[i]=sin(myphase); - output.dcos[i]=cos(myphase); - } - return output; + shift_unroll_data_t output; + output.phase_increment=2*rate*PI; + output.size = size; + output.dsin=(float*)malloc(sizeof(float)*size); + output.dcos=(float*)malloc(sizeof(float)*size); + float myphase = 0; + for(int i=0;iPI) myphase-=2*PI; + while(myphase<-PI) myphase+=2*PI; + output.dsin[i]=sin(myphase); + output.dcos[i]=cos(myphase); + } + return output; } float shift_unroll_cc(complexf *input, complexf* output, int input_size, shift_unroll_data_t* d, float starting_phase) { - //input_size should be multiple of 4 - //fprintf(stderr, "shift_addfast_cc: input_size = %d\n", input_size); - float cos_start=cos(starting_phase); - float sin_start=sin(starting_phase); - register float cos_val, sin_val; - for(int i=0;idcos[i] - sin_start * d->dsin[i]; - sin_val = sin_start * d->dcos[i] + cos_start * d->dsin[i]; - iof(output,i)=cos_val*iof(input,i)-sin_val*qof(input,i); - qof(output,i)=sin_val*iof(input,i)+cos_val*qof(input,i); - } - starting_phase+=input_size*d->phase_increment; - while(starting_phase>PI) starting_phase-=2*PI; - while(starting_phase<-PI) starting_phase+=2*PI; - return starting_phase; + //input_size should be multiple of 4 + //fprintf(stderr, "shift_addfast_cc: input_size = %d\n", input_size); + float cos_start=cos(starting_phase); + float sin_start=sin(starting_phase); + register float cos_val, sin_val; + for(int i=0;idcos[i] - sin_start * d->dsin[i]; + sin_val = sin_start * d->dcos[i] + cos_start * d->dsin[i]; + iof(output,i)=cos_val*iof(input,i)-sin_val*qof(input,i); + qof(output,i)=sin_val*iof(input,i)+cos_val*qof(input,i); + } + starting_phase+=input_size*d->phase_increment; + while(starting_phase>PI) starting_phase-=2*PI; + while(starting_phase<-PI) starting_phase+=2*PI; + return starting_phase; } shift_addfast_data_t shift_addfast_init(float rate) { - shift_addfast_data_t output; - output.phase_increment=2*rate*PI; - for(int i=0;i<4;i++) - { - output.dsin[i]=sin(output.phase_increment*(i+1)); - output.dcos[i]=cos(output.phase_increment*(i+1)); - } - return output; + shift_addfast_data_t output; + output.phase_increment=2*rate*PI; + for(int i=0;i<4;i++) + { + output.dsin[i]=sin(output.phase_increment*(i+1)); + output.dcos[i]=cos(output.phase_increment*(i+1)); + } + return output; } #ifdef NEON_OPTS @@ -321,76 +321,76 @@ shift_addfast_data_t shift_addfast_init(float rate) float shift_addfast_cc(complexf *input, complexf* output, int input_size, shift_addfast_data_t* d, float starting_phase) { - //input_size should be multiple of 4 - float cos_start[4], sin_start[4]; - float cos_vals[4], sin_vals[4]; - for(int i=0;i<4;i++) - { - cos_start[i] = cos(starting_phase); - sin_start[i] = sin(starting_phase); - } + //input_size should be multiple of 4 + float cos_start[4], sin_start[4]; + float cos_vals[4], sin_vals[4]; + for(int i=0;i<4;i++) + { + cos_start[i] = cos(starting_phase); + sin_start[i] = sin(starting_phase); + } - float* pdcos = d->dcos; - float* pdsin = d->dsin; - register float* pinput = (float*)input; - register float* pinput_end = (float*)(input+input_size); - register float* poutput = (float*)output; + float* pdcos = d->dcos; + float* pdsin = d->dsin; + register float* pinput = (float*)input; + register float* pinput_end = (float*)(input+input_size); + register float* poutput = (float*)output; - //Register map: - #define RDCOS "q0" //dcos, dsin - #define RDSIN "q1" - #define RCOSST "q2" //cos_start, sin_start - #define RSINST "q3" - #define RCOSV "q4" //cos_vals, sin_vals - #define RSINV "q5" - #define ROUTI "q6" //output_i, output_q - #define ROUTQ "q7" - #define RINPI "q8" //input_i, input_q - #define RINPQ "q9" - #define R3(x,y,z) x ", " y ", " z "\n\t" + //Register map: + #define RDCOS "q0" //dcos, dsin + #define RDSIN "q1" + #define RCOSST "q2" //cos_start, sin_start + #define RSINST "q3" + #define RCOSV "q4" //cos_vals, sin_vals + #define RSINV "q5" + #define ROUTI "q6" //output_i, output_q + #define ROUTQ "q7" + #define RINPI "q8" //input_i, input_q + #define RINPQ "q9" + #define R3(x,y,z) x ", " y ", " z "\n\t" - asm volatile( //(the range of q is q0-q15) - " vld1.32 {" RDCOS "}, [%[pdcos]]\n\t" - " vld1.32 {" RDSIN "}, [%[pdsin]]\n\t" - " vld1.32 {" RCOSST "}, [%[cos_start]]\n\t" - " vld1.32 {" RSINST "}, [%[sin_start]]\n\t" - "for_addfast: vld2.32 {" RINPI "-" RINPQ "}, [%[pinput]]!\n\t" //load q0 and q1 directly from the memory address stored in pinput, with interleaving (so that we get the I samples in RINPI and the Q samples in RINPQ), also increment the memory address in pinput (hence the "!" mark) + asm volatile( //(the range of q is q0-q15) + " vld1.32 {" RDCOS "}, [%[pdcos]]\n\t" + " vld1.32 {" RDSIN "}, [%[pdsin]]\n\t" + " vld1.32 {" RCOSST "}, [%[cos_start]]\n\t" + " vld1.32 {" RSINST "}, [%[sin_start]]\n\t" + "for_addfast: vld2.32 {" RINPI "-" RINPQ "}, [%[pinput]]!\n\t" //load q0 and q1 directly from the memory address stored in pinput, with interleaving (so that we get the I samples in RINPI and the Q samples in RINPQ), also increment the memory address in pinput (hence the "!" mark) - //C version: - //cos_vals[j] = cos_start * d->dcos[j] - sin_start * d->dsin[j]; - //sin_vals[j] = sin_start * d->dcos[j] + cos_start * d->dsin[j]; + //C version: + //cos_vals[j] = cos_start * d->dcos[j] - sin_start * d->dsin[j]; + //sin_vals[j] = sin_start * d->dcos[j] + cos_start * d->dsin[j]; - " vmul.f32 " R3(RCOSV, RCOSST, RDCOS) //cos_vals[i] = cos_start * d->dcos[i] - " vmls.f32 " R3(RCOSV, RSINST, RDSIN) //cos_vals[i] -= sin_start * d->dsin[i] - " vmul.f32 " R3(RSINV, RSINST, RDCOS) //sin_vals[i] = sin_start * d->dcos[i] - " vmla.f32 " R3(RSINV, RCOSST, RDSIN) //sin_vals[i] += cos_start * d->dsin[i] + " vmul.f32 " R3(RCOSV, RCOSST, RDCOS) //cos_vals[i] = cos_start * d->dcos[i] + " vmls.f32 " R3(RCOSV, RSINST, RDSIN) //cos_vals[i] -= sin_start * d->dsin[i] + " vmul.f32 " R3(RSINV, RSINST, RDCOS) //sin_vals[i] = sin_start * d->dcos[i] + " vmla.f32 " R3(RSINV, RCOSST, RDSIN) //sin_vals[i] += cos_start * d->dsin[i] - //C version: - //iof(output,4*i+j)=cos_vals[j]*iof(input,4*i+j)-sin_vals[j]*qof(input,4*i+j); - //qof(output,4*i+j)=sin_vals[j]*iof(input,4*i+j)+cos_vals[j]*qof(input,4*i+j); - " vmul.f32 " R3(ROUTI, RCOSV, RINPI) //output_i = cos_vals * input_i - " vmls.f32 " R3(ROUTI, RSINV, RINPQ) //output_i -= sin_vals * input_q - " vmul.f32 " R3(ROUTQ, RSINV, RINPI) //output_q = sin_vals * input_i - " vmla.f32 " R3(ROUTQ, RCOSV, RINPQ) //output_i += cos_vals * input_q + //C version: + //iof(output,4*i+j)=cos_vals[j]*iof(input,4*i+j)-sin_vals[j]*qof(input,4*i+j); + //qof(output,4*i+j)=sin_vals[j]*iof(input,4*i+j)+cos_vals[j]*qof(input,4*i+j); + " vmul.f32 " R3(ROUTI, RCOSV, RINPI) //output_i = cos_vals * input_i + " vmls.f32 " R3(ROUTI, RSINV, RINPQ) //output_i -= sin_vals * input_q + " vmul.f32 " R3(ROUTQ, RSINV, RINPI) //output_q = sin_vals * input_i + " vmla.f32 " R3(ROUTQ, RCOSV, RINPQ) //output_i += cos_vals * input_q - " vst2.32 {" ROUTI "-" ROUTQ "}, [%[poutput]]!\n\t" //store the outputs in memory - //" add %[poutput],%[poutput],#32\n\t" - " vdup.32 " RCOSST ", d9[1]\n\t" // cos_start[0-3] = cos_vals[3] - " vdup.32 " RSINST ", d11[1]\n\t" // sin_start[0-3] = sin_vals[3] + " vst2.32 {" ROUTI "-" ROUTQ "}, [%[poutput]]!\n\t" //store the outputs in memory + //" add %[poutput],%[poutput],#32\n\t" + " vdup.32 " RCOSST ", d9[1]\n\t" // cos_start[0-3] = cos_vals[3] + " vdup.32 " RSINST ", d11[1]\n\t" // sin_start[0-3] = sin_vals[3] - " cmp %[pinput], %[pinput_end]\n\t" //if(pinput != pinput_end) - " bcc for_addfast\n\t" // then goto for_addfast - : - [pinput]"+r"(pinput), [poutput]"+r"(poutput) //output operand list -> C variables that we will change from ASM - : - [pinput_end]"r"(pinput_end), [pdcos]"r"(pdcos), [pdsin]"r"(pdsin), [sin_start]"r"(sin_start), [cos_start]"r"(cos_start) //input operand list - : - "memory", "q0", "q1", "q2", "q4", "q5", "q6", "q7", "q8", "q9", "cc" //clobber list - ); - starting_phase+=input_size*d->phase_increment; - while(starting_phase>PI) starting_phase-=2*PI; - while(starting_phase<-PI) starting_phase+=2*PI; - return starting_phase; + " cmp %[pinput], %[pinput_end]\n\t" //if(pinput != pinput_end) + " bcc for_addfast\n\t" // then goto for_addfast + : + [pinput]"+r"(pinput), [poutput]"+r"(poutput) //output operand list -> C variables that we will change from ASM + : + [pinput_end]"r"(pinput_end), [pdcos]"r"(pdcos), [pdsin]"r"(pdsin), [sin_start]"r"(sin_start), [cos_start]"r"(cos_start) //input operand list + : + "memory", "q0", "q1", "q2", "q4", "q5", "q6", "q7", "q8", "q9", "cc" //clobber list + ); + starting_phase+=input_size*d->phase_increment; + while(starting_phase>PI) starting_phase-=2*PI; + while(starting_phase<-PI) starting_phase+=2*PI; + return starting_phase; } #else @@ -399,66 +399,66 @@ float shift_addfast_cc(complexf *input, complexf* output, int input_size, shift_ #if 1 #define SADF_L1(j) cos_vals_ ## j = cos_start * dcos_ ## j - sin_start * dsin_ ## j; \ - sin_vals_ ## j = sin_start * dcos_ ## j + cos_start * dsin_ ## j; + sin_vals_ ## j = sin_start * dcos_ ## j + cos_start * dsin_ ## j; #define SADF_L2(j) iof(output,4*i+j)=(cos_vals_ ## j)*iof(input,4*i+j)-(sin_vals_ ## j)*qof(input,4*i+j); \ - qof(output,4*i+j)=(sin_vals_ ## j)*iof(input,4*i+j)+(cos_vals_ ## j)*qof(input,4*i+j); + qof(output,4*i+j)=(sin_vals_ ## j)*iof(input,4*i+j)+(cos_vals_ ## j)*qof(input,4*i+j); float shift_addfast_cc(complexf *input, complexf* output, int input_size, shift_addfast_data_t* d, float starting_phase) { - //input_size should be multiple of 4 - //fprintf(stderr, "shift_addfast_cc: input_size = %d\n", input_size); - float cos_start=cos(starting_phase); - float sin_start=sin(starting_phase); - float register cos_vals_0, cos_vals_1, cos_vals_2, cos_vals_3, - sin_vals_0, sin_vals_1, sin_vals_2, sin_vals_3, - dsin_0 = d->dsin[0], dsin_1 = d->dsin[1], dsin_2 = d->dsin[2], dsin_3 = d->dsin[3], - dcos_0 = d->dcos[0], dcos_1 = d->dcos[1], dcos_2 = d->dcos[2], dcos_3 = d->dcos[3]; + //input_size should be multiple of 4 + //fprintf(stderr, "shift_addfast_cc: input_size = %d\n", input_size); + float cos_start=cos(starting_phase); + float sin_start=sin(starting_phase); + float register cos_vals_0, cos_vals_1, cos_vals_2, cos_vals_3, + sin_vals_0, sin_vals_1, sin_vals_2, sin_vals_3, + dsin_0 = d->dsin[0], dsin_1 = d->dsin[1], dsin_2 = d->dsin[2], dsin_3 = d->dsin[3], + dcos_0 = d->dcos[0], dcos_1 = d->dcos[1], dcos_2 = d->dcos[2], dcos_3 = d->dcos[3]; - for(int i=0;iphase_increment; - while(starting_phase>PI) starting_phase-=2*PI; - while(starting_phase<-PI) starting_phase+=2*PI; - return starting_phase; + for(int i=0;iphase_increment; + while(starting_phase>PI) starting_phase-=2*PI; + while(starting_phase<-PI) starting_phase+=2*PI; + return starting_phase; } #else float shift_addfast_cc(complexf *input, complexf* output, int input_size, shift_addfast_data_t* d, float starting_phase) { - //input_size should be multiple of 4 - //fprintf(stderr, "shift_addfast_cc: input_size = %d\n", input_size); - float cos_start=cos(starting_phase); - float sin_start=sin(starting_phase); - float cos_vals[4], sin_vals[4]; - for(int i=0;idcos[j] - sin_start * d->dsin[j]; - sin_vals[j] = sin_start * d->dcos[j] + cos_start * d->dsin[j]; - } - for(int j=0;j<4;j++) //@shift_addfast_cc - { - iof(output,4*i+j)=cos_vals[j]*iof(input,4*i+j)-sin_vals[j]*qof(input,4*i+j); - qof(output,4*i+j)=sin_vals[j]*iof(input,4*i+j)+cos_vals[j]*qof(input,4*i+j); - } - cos_start = cos_vals[3]; - sin_start = sin_vals[3]; - } - starting_phase+=input_size*d->phase_increment; - while(starting_phase>PI) starting_phase-=2*PI; - while(starting_phase<-PI) starting_phase+=2*PI; - return starting_phase; + //input_size should be multiple of 4 + //fprintf(stderr, "shift_addfast_cc: input_size = %d\n", input_size); + float cos_start=cos(starting_phase); + float sin_start=sin(starting_phase); + float cos_vals[4], sin_vals[4]; + for(int i=0;idcos[j] - sin_start * d->dsin[j]; + sin_vals[j] = sin_start * d->dcos[j] + cos_start * d->dsin[j]; + } + for(int j=0;j<4;j++) //@shift_addfast_cc + { + iof(output,4*i+j)=cos_vals[j]*iof(input,4*i+j)-sin_vals[j]*qof(input,4*i+j); + qof(output,4*i+j)=sin_vals[j]*iof(input,4*i+j)+cos_vals[j]*qof(input,4*i+j); + } + cos_start = cos_vals[3]; + sin_start = sin_vals[3]; + } + starting_phase+=input_size*d->phase_increment; + while(starting_phase>PI) starting_phase-=2*PI; + while(starting_phase<-PI) starting_phase+=2*PI; + return starting_phase; } #endif @@ -471,81 +471,81 @@ float shift_addfast_cc(complexf *input, complexf* output, int input_size, shift_ int fir_decimate_cc(complexf *input, complexf *output, int input_size, int decimation, float *taps, int taps_length) { - //Theory: http://www.dspguru.com/dsp/faqs/multirate/decimation - //It uses real taps. It returns the number of output samples actually written. - //It needs overlapping input based on its returned value: - //number of processed input samples = returned value * decimation factor - //The output buffer should be at least input_length / 3. - // i: input index | ti: tap index | oi: output index - int oi=0; - for(int i=0; iinput_size) break; - register float* pinput=(float*)&(input[i]); - register float* ptaps=taps; - register float* ptaps_end=taps+taps_length; - float quad_acciq [8]; + //Theory: http://www.dspguru.com/dsp/faqs/multirate/decimation + //It uses real taps. It returns the number of output samples actually written. + //It needs overlapping input based on its returned value: + //number of processed input samples = returned value * decimation factor + //The output buffer should be at least input_length / 3. + // i: input index | ti: tap index | oi: output index + int oi=0; + for(int i=0; iinput_size) break; + register float* pinput=(float*)&(input[i]); + register float* ptaps=taps; + register float* ptaps_end=taps+taps_length; + float quad_acciq [8]; /* -q0, q1: input signal I sample and Q sample -q2: taps +q0, q1: input signal I sample and Q sample +q2: taps q4, q5: accumulator for I branch and Q branch (will be the output) */ - asm volatile( - " veor q4, q4\n\t" - " veor q5, q5\n\t" - "for_fdccasm: vld2.32 {q0-q1}, [%[pinput]]!\n\t" //load q0 and q1 directly from the memory address stored in pinput, with interleaving (so that we get the I samples in q0 and the Q samples in q1), also increment the memory address in pinput (hence the "!" mark) //http://community.arm.com/groups/processors/blog/2010/03/17/coding-for-neon--part-1-load-and-stores - " vld1.32 {q2}, [%[ptaps]]!\n\t" - " vmla.f32 q4, q0, q2\n\t" //quad_acc_i += quad_input_i * quad_taps_1 //http://stackoverflow.com/questions/3240440/how-to-use-the-multiply-and-accumulate-intrinsics-in-arm-cortex-a8 //http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0489e/CIHEJBIE.html - " vmla.f32 q5, q1, q2\n\t" //quad_acc_q += quad_input_q * quad_taps_1 - " cmp %[ptaps], %[ptaps_end]\n\t" //if(ptaps != ptaps_end) - " bcc for_fdccasm\n\t" // then goto for_fdcasm - " vst1.32 {q4}, [%[quad_acci]]\n\t" //if the loop is finished, store the two accumulators in memory - " vst1.32 {q5}, [%[quad_accq]]\n\t" - : - [pinput]"+r"(pinput), [ptaps]"+r"(ptaps) //output operand list - : - [ptaps_end]"r"(ptaps_end), [quad_acci]"r"(quad_acciq), [quad_accq]"r"(quad_acciq+4) //input operand list - : - "memory", "q0", "q1", "q2", "q4", "q5", "cc" //clobber list - ); - //original for loops for reference: - //for(int ti=0; ti> [%d] %g \n", n, quad_acciq[n]); - iof(output,oi)=quad_acciq[0]+quad_acciq[1]+quad_acciq[2]+quad_acciq[3]; //we're still not ready, as we have to add up the contents of a quad accumulator register to get a single accumulated value - qof(output,oi)=quad_acciq[4]+quad_acciq[5]+quad_acciq[6]+quad_acciq[7]; - oi++; - } - return oi; + //for(int n=0;n<8;n++) fprintf(stderr, "\n>> [%d] %g \n", n, quad_acciq[n]); + iof(output,oi)=quad_acciq[0]+quad_acciq[1]+quad_acciq[2]+quad_acciq[3]; //we're still not ready, as we have to add up the contents of a quad accumulator register to get a single accumulated value + qof(output,oi)=quad_acciq[4]+quad_acciq[5]+quad_acciq[6]+quad_acciq[7]; + oi++; + } + return oi; } #else int fir_decimate_cc(complexf *input, complexf *output, int input_size, int decimation, float *taps, int taps_length) { - //Theory: http://www.dspguru.com/dsp/faqs/multirate/decimation - //It uses real taps. It returns the number of output samples actually written. - //It needs overlapping input based on its returned value: - //number of processed input samples = returned value * decimation factor - //The output buffer should be at least input_length / 3. - // i: input index | ti: tap index | oi: output index - int oi=0; - for(int i=0; iinput_size) break; - float acci=0; - for(int ti=0; tiinput_size) break; + float acci=0; + for(int ti=0; tiinput_size) break; - float acci=0; - int taps_halflength = taps_length/2; - for(int ti=0; tiinput_size) break; + float acci=0; + int taps_halflength = taps_length/2; + for(int ti=0; ti input_size*interpolation) break; - for(int ip=0; ip input_size*interpolation) break; + for(int ip=0; ipinput_size) break; //we can't compute the FIR filter to some input samples at the end - //fprintf(stderr,"outer loop | oi = %d | startingi = %d | taps delay = %d\n",oi,startingi,delayi); - for(int i=0; i<(taps_length-delayi)/interpolation; i++) //@rational_resampler_ff (inner loop) - { - //fprintf(stderr,"inner loop | input index = %d | tap index = %d | acc = %g\n",startingi+ii,i,acc); - acc+=input[startingi+i]*taps[delayi+i*interpolation]; - } - output[oi]=acc*interpolation; - } - rational_resampler_ff_t d; - d.input_processed=startingi; - d.output_size=oi; - d.last_taps_delay=delayi; - return d; + //Theory: http://www.dspguru.com/dsp/faqs/multirate/resampling + //oi: output index, i: tap index + int output_size=input_size*interpolation/decimation; + int oi; + int startingi, delayi; + //fprintf(stderr,"rational_resampler_ff | interpolation = %d | decimation = %d\ntaps_length = %d | input_size = %d | output_size = %d | last_taps_delay = %d\n",interpolation,decimation,taps_length,input_size,output_size,last_taps_delay); + for (oi=0; oiinput_size) break; //we can't compute the FIR filter to some input samples at the end + //fprintf(stderr,"outer loop | oi = %d | startingi = %d | taps delay = %d\n",oi,startingi,delayi); + for(int i=0; i<(taps_length-delayi)/interpolation; i++) //@rational_resampler_ff (inner loop) + { + //fprintf(stderr,"inner loop | input index = %d | tap index = %d | acc = %g\n",startingi+ii,i,acc); + acc+=input[startingi+i]*taps[delayi+i*interpolation]; + } + output[oi]=acc*interpolation; + } + rational_resampler_ff_t d; + d.input_processed=startingi; + d.output_size=oi; + d.last_taps_delay=delayi; + return d; } /* @@ -665,186 +665,186 @@ values of [oi, startingi, taps delay] in the outer loop should be: void rational_resampler_get_lowpass_f(float* output, int output_size, int interpolation, int decimation, window_t window) { - //See 4.1.6 at: http://www.dspguru.com/dsp/faqs/multirate/resampling - float cutoff_for_interpolation=1.0/interpolation; - float cutoff_for_decimation=1.0/decimation; - float cutoff = (cutoff_for_interpolationrate); - if(DEBUG_ASSERT) assert(d->rate > 1.0); - if(DEBUG_ASSERT) assert(d->where >= -d->xifirst); - int oi=0; //output index - int index_high; + //This routine can handle floating point decimation rates. + //It applies polynomial interpolation to samples that are taken into consideration from a pre-filtered input. + //The pre-filter can be switched off by applying taps=NULL. + //fprintf(stderr, "drate=%f\n", d->rate); + if(DEBUG_ASSERT) assert(d->rate > 1.0); + if(DEBUG_ASSERT) assert(d->where >= -d->xifirst); + int oi=0; //output index + int index_high; #define FD_INDEX_LOW (index_high-1) - //we optimize to calculate ceilf(where) only once every iteration, so we do it here: - for(;(index_high=ceilf(d->where))+d->num_poly_points+d->taps_lengthwhere+=d->rate) //@fractional_decimator_ff - { - //d->num_poly_points above is theoretically more than we could have here, but this makes the spectrum look good - int sxifirst = FD_INDEX_LOW + d->xifirst; - int sxilast = FD_INDEX_LOW + d->xilast; - if(d->taps) - for(int wi=0;winum_poly_points;wi++) d->filtered_buf[wi] = fir_one_pass_ff(input+FD_INDEX_LOW+wi, d->taps, d->taps_length); - else - for(int wi=0;winum_poly_points;wi++) d->filtered_buf[wi] = *(input+FD_INDEX_LOW+wi); - int id=0; - float xwhere = d->where - FD_INDEX_LOW; - for(int xi=d->xifirst;xi<=d->xilast;xi++) - { - d->coeffs_buf[id]=1; - for(int xj=d->xifirst;xj<=d->xilast;xj++) - { - if(xi!=xj) d->coeffs_buf[id] *= (xwhere-xj); - } - id++; - } - float acc = 0; - for(int i=0;inum_poly_points;i++) - { - acc += (d->coeffs_buf[i]/d->poly_precalc_denomiator[i])*d->filtered_buf[i]; //(xnom/xden)*yn - } - output[oi++]=acc; - } - d->input_processed = FD_INDEX_LOW + d->xifirst; - d->where -= d->input_processed; - d->output_size = oi; + //we optimize to calculate ceilf(where) only once every iteration, so we do it here: + for(;(index_high=ceilf(d->where))+d->num_poly_points+d->taps_lengthwhere+=d->rate) //@fractional_decimator_ff + { + //d->num_poly_points above is theoretically more than we could have here, but this makes the spectrum look good + int sxifirst = FD_INDEX_LOW + d->xifirst; + int sxilast = FD_INDEX_LOW + d->xilast; + if(d->taps) + for(int wi=0;winum_poly_points;wi++) d->filtered_buf[wi] = fir_one_pass_ff(input+FD_INDEX_LOW+wi, d->taps, d->taps_length); + else + for(int wi=0;winum_poly_points;wi++) d->filtered_buf[wi] = *(input+FD_INDEX_LOW+wi); + int id=0; + float xwhere = d->where - FD_INDEX_LOW; + for(int xi=d->xifirst;xi<=d->xilast;xi++) + { + d->coeffs_buf[id]=1; + for(int xj=d->xifirst;xj<=d->xilast;xj++) + { + if(xi!=xj) d->coeffs_buf[id] *= (xwhere-xj); + } + id++; + } + float acc = 0; + for(int i=0;inum_poly_points;i++) + { + acc += (d->coeffs_buf[i]/d->poly_precalc_denomiator[i])*d->filtered_buf[i]; //(xnom/xden)*yn + } + output[oi++]=acc; + } + d->input_processed = FD_INDEX_LOW + d->xifirst; + d->where -= d->input_processed; + d->output_size = oi; } /* * Some notes to myself on the circular buffer I wanted to implement here: - int last_input_samplewhere_shouldbe = (index_high-1)+xifirst; - int last_input_offset = last_input_samplewhere_shouldbe - d->last_input_samplewhere; - if(last_input_offset < num_poly_points) - { - //if we can move the last_input circular buffer, we move, and add the new samples at the end - d->last_inputs_startsat += last_input_offset; - d->last_inputs_startsat %= num_poly_points; - int num_copied_samples = 0; - for(int i=0; ilast_inputs_circbuf[i]= - } - d->last_input_samplewhere = d->las - } - However, I think I should just rather do a continuous big buffer. + int last_input_samplewhere_shouldbe = (index_high-1)+xifirst; + int last_input_offset = last_input_samplewhere_shouldbe - d->last_input_samplewhere; + if(last_input_offset < num_poly_points) + { + //if we can move the last_input circular buffer, we move, and add the new samples at the end + d->last_inputs_startsat += last_input_offset; + d->last_inputs_startsat %= num_poly_points; + int num_copied_samples = 0; + for(int i=0; ilast_inputs_circbuf[i]= + } + d->last_input_samplewhere = d->las + } + However, I think I should just rather do a continuous big buffer. */ void apply_fir_fft_cc(FFT_PLAN_T* plan, FFT_PLAN_T* plan_inverse, complexf* taps_fft, complexf* last_overlap, int overlap_size) { - //use the overlap & add method for filtering + //use the overlap & add method for filtering - //calculate FFT on input buffer - fft_execute(plan); + //calculate FFT on input buffer + fft_execute(plan); - //multiply the filter and the input - complexf* in = plan->output; - complexf* out = plan_inverse->input; + //multiply the filter and the input + complexf* in = plan->output; + complexf* out = plan_inverse->input; - for(int i=0;isize;i++) //@apply_fir_fft_cc: multiplication - { - iof(out,i)=iof(in,i)*iof(taps_fft,i)-qof(in,i)*qof(taps_fft,i); - qof(out,i)=iof(in,i)*qof(taps_fft,i)+qof(in,i)*iof(taps_fft,i); - } + for(int i=0;isize;i++) //@apply_fir_fft_cc: multiplication + { + iof(out,i)=iof(in,i)*iof(taps_fft,i)-qof(in,i)*qof(taps_fft,i); + qof(out,i)=iof(in,i)*qof(taps_fft,i)+qof(in,i)*iof(taps_fft,i); + } - //calculate inverse FFT on multiplied buffer - fft_execute(plan_inverse); + //calculate inverse FFT on multiplied buffer + fft_execute(plan_inverse); - //add the overlap of the previous segment - complexf* result = plan_inverse->output; + //add the overlap of the previous segment + complexf* result = plan_inverse->output; - for(int i=0;isize;i++) //@apply_fir_fft_cc: normalize by fft_size - { - iof(result,i)/=plan->size; - qof(result,i)/=plan->size; - } + for(int i=0;isize;i++) //@apply_fir_fft_cc: normalize by fft_size + { + iof(result,i)/=plan->size; + qof(result,i)/=plan->size; + } - for(int i=0;imax_iq) max_iq=abs_q; - float min_iq=abs_i; - if(abs_qmax_iq) max_iq=abs_q; + float min_iq=abs_i; + if(abs_qinput_size;i++) //@fastagc_ff: peak search - { - float val=fabs(input->buffer_input[i]); - if(val>peak_input) peak_input=val; - } + //Get the peak value of new input buffer + float peak_input=0; + for(int i=0;iinput_size;i++) //@fastagc_ff: peak search + { + float val=fabs(input->buffer_input[i]); + if(val>peak_input) peak_input=val; + } - //Determine the maximal peak out of the three blocks - float target_peak=peak_input; - if(target_peakpeak_2) target_peak=input->peak_2; - if(target_peakpeak_1) target_peak=input->peak_1; + //Determine the maximal peak out of the three blocks + float target_peak=peak_input; + if(target_peakpeak_2) target_peak=input->peak_2; + if(target_peakpeak_1) target_peak=input->peak_1; - //we change the gain linearly on the apply_block from the last_gain to target_gain. - float target_gain=input->reference/target_peak; - if(target_gain>FASTAGC_MAX_GAIN) target_gain=FASTAGC_MAX_GAIN; - //fprintf(stderr, "target_gain: %g\n",target_gain); + //we change the gain linearly on the apply_block from the last_gain to target_gain. + float target_gain=input->reference/target_peak; + if(target_gain>FASTAGC_MAX_GAIN) target_gain=FASTAGC_MAX_GAIN; + //fprintf(stderr, "target_gain: %g\n",target_gain); - for(int i=0;iinput_size;i++) //@fastagc_ff: apply gain - { - float rate=(float)i/input->input_size; - float gain=input->last_gain*(1.0-rate)+target_gain*rate; - output[i]=input->buffer_1[i]*gain; - } + for(int i=0;iinput_size;i++) //@fastagc_ff: apply gain + { + float rate=(float)i/input->input_size; + float gain=input->last_gain*(1.0-rate)+target_gain*rate; + output[i]=input->buffer_1[i]*gain; + } - //Shift the three buffers - float* temp_pointer=input->buffer_1; - input->buffer_1=input->buffer_2; - input->peak_1=input->peak_2; - input->buffer_2=input->buffer_input; - input->peak_2=peak_input; - input->buffer_input=temp_pointer; - input->last_gain=target_gain; - //fprintf(stderr,"target_gain=%g\n", target_gain); + //Shift the three buffers + float* temp_pointer=input->buffer_1; + input->buffer_1=input->buffer_2; + input->peak_1=input->peak_2; + input->buffer_2=input->buffer_input; + input->peak_2=peak_input; + input->buffer_input=temp_pointer; + input->last_gain=target_gain; + //fprintf(stderr,"target_gain=%g\n", target_gain); } /* @@ -1003,19 +1003,19 @@ void fastagc_ff(fastagc_ff_t* input, float* output) float fmdemod_atan_cf(complexf* input, float *output, int input_size, float last_phase) { - //GCC most likely won't vectorize nor atan, nor atan2. - //For more comments, look at: https://github.com/simonyiszk/minidemod/blob/master/minidemod-wfm-atan.c - float phase, dphase; - for (int i=0; iPI) dphase-=2*PI; - output[i]=dphase/PI; - last_phase=phase; - } - return last_phase; + //GCC most likely won't vectorize nor atan, nor atan2. + //For more comments, look at: https://github.com/simonyiszk/minidemod/blob/master/minidemod-wfm-atan.c + float phase, dphase; + for (int i=0; iPI) dphase-=2*PI; + output[i]=dphase/PI; + last_phase=phase; + } + return last_phase; } #define fmdemod_quadri_K 0.340447550238101026565118445432744920253753662109375 @@ -1023,56 +1023,56 @@ float fmdemod_atan_cf(complexf* input, float *output, int input_size, float last complexf fmdemod_quadri_novect_cf(complexf* input, float* output, int input_size, complexf last_sample) { - output[0]=fmdemod_quadri_K*(iof(input,0)*(qof(input,0)-last_sample.q)-qof(input,0)*(iof(input,0)-last_sample.i))/(iof(input,0)*iof(input,0)+qof(input,0)*qof(input,0)); - for (int i=1; i tau = 75e-6 - WFM transmission in EU: 50 us -> tau = 50e-6 - More info at: http://www.cliftonlaboratories.com/fm_receivers_and_de-emphasis.htm - Simulate in octave: tau=75e-6; dt=1/48000; alpha = dt/(tau+dt); freqz([alpha],[1 -(1-alpha)]) - */ - float dt = 1.0/sample_rate; - float alpha = dt/(tau+dt); - if(is_nan(last_output)) last_output=0.0; //if last_output is NaN - output[0]=alpha*input[0]+(1-alpha)*last_output; - for (int i=1;i tau = 75e-6 + WFM transmission in EU: 50 us -> tau = 50e-6 + More info at: http://www.cliftonlaboratories.com/fm_receivers_and_de-emphasis.htm + Simulate in octave: tau=75e-6; dt=1/48000; alpha = dt/(tau+dt); freqz([alpha],[1 -(1-alpha)]) + */ + float dt = 1.0/sample_rate; + float alpha = dt/(tau+dt); + if(is_nan(last_output)) last_output=0.0; //if last_output is NaN + output[0]=alpha*input[0]+(1-alpha)*last_output; + for (int i=1;ioutput[i])?-max_amplitude:output[i]; - } + for (int i=0; ioutput[i])?-max_amplitude:output[i]; + } } void gain_ff(float* input, float* output, int input_size, float gain) { - for(int i=0;iPI) phase-=2*PI; - while(phase<=-PI) phase+=2*PI; - iof(output,i)=cos(phase); - qof(output,i)=sin(phase); - } - return phase; + float phase=last_phase; + for(int i=0;iPI) phase-=2*PI; + while(phase<=-PI) phase+=2*PI; + iof(output,i)=cos(phase); + qof(output,i)=sin(phase); + } + return phase; } void fixed_amplitude_cc(complexf* input, complexf* output, int input_size, float new_amplitude) { - for(int i=0;i 0) ? new_amplitude / amplitude_now : 0; - iof(output,i)=iof(input,i)*gain; - qof(output,i)=qof(input,i)*gain; - } + //A faster solution: + float amplitude_now = sqrt(iof(input,i)*iof(input,i)+qof(input,i)*qof(input,i)); + float gain = (amplitude_now > 0) ? new_amplitude / amplitude_now : 0; + iof(output,i)=iof(input,i)*gain; + qof(output,i)=qof(input,i)*gain; + } } /* @@ -1219,97 +1219,97 @@ void fixed_amplitude_cc(complexf* input, complexf* output, int input_size, float int log2n(int x) { - int result=-1; - for(int i=0;i<31;i++) - { - if((x>>i)&1) //@@log2n - { - if (result==-1) result=i; - else return -1; - } - } - return result; + int result=-1; + for(int i=0;i<31;i++) + { + if((x>>i)&1) //@@log2n + { + if (result==-1) result=i; + else return -1; + } + } + return result; } int next_pow2(int x) { - int pow2; - //portability? (31 is the problem) - for(int i=0;i<31;i++) - { - if(x<(pow2=1< - { .code = 0b1010101111, .bitcount=10, .ascii=0x3f }, //? - { .code = 0b1010111101, .bitcount=10, .ascii=0x40 }, //@ - { .code = 0b1111101, .bitcount=7, .ascii=0x41 }, //A - { .code = 0b11101011, .bitcount=8, .ascii=0x42 }, //B - { .code = 0b10101101, .bitcount=8, .ascii=0x43 }, //C - { .code = 0b10110101, .bitcount=8, .ascii=0x44 }, //D - { .code = 0b1110111, .bitcount=7, .ascii=0x45 }, //E - { .code = 0b11011011, .bitcount=8, .ascii=0x46 }, //F - { .code = 0b11111101, .bitcount=8, .ascii=0x47 }, //G - { .code = 0b101010101, .bitcount=9, .ascii=0x48 }, //H - { .code = 0b1111111, .bitcount=7, .ascii=0x49 }, //I - { .code = 0b111111101, .bitcount=9, .ascii=0x4a }, //J - { .code = 0b101111101, .bitcount=9, .ascii=0x4b }, //K - { .code = 0b11010111, .bitcount=8, .ascii=0x4c }, //L - { .code = 0b10111011, .bitcount=8, .ascii=0x4d }, //M - { .code = 0b11011101, .bitcount=8, .ascii=0x4e }, //N - { .code = 0b10101011, .bitcount=8, .ascii=0x4f }, //O - { .code = 0b11010101, .bitcount=8, .ascii=0x50 }, //P - { .code = 0b111011101, .bitcount=9, .ascii=0x51 }, //Q - { .code = 0b10101111, .bitcount=8, .ascii=0x52 }, //R - { .code = 0b1101111, .bitcount=7, .ascii=0x53 }, //S - { .code = 0b1101101, .bitcount=7, .ascii=0x54 }, //T - { .code = 0b101010111, .bitcount=9, .ascii=0x55 }, //U - { .code = 0b110110101, .bitcount=9, .ascii=0x56 }, //V - { .code = 0b101011101, .bitcount=9, .ascii=0x57 }, //W - { .code = 0b101110101, .bitcount=9, .ascii=0x58 }, //X - { .code = 0b101111011, .bitcount=9, .ascii=0x59 }, //Y - { .code = 0b1010101101, .bitcount=10, .ascii=0x5a }, //Z - { .code = 0b111110111, .bitcount=9, .ascii=0x5b }, //[ - { .code = 0b111101111, .bitcount=9, .ascii=0x5c }, //\ - { .code = 0b111111011, .bitcount=9, .ascii=0x5d }, //] - { .code = 0b1010111111, .bitcount=10, .ascii=0x5e }, //^ - { .code = 0b101101101, .bitcount=9, .ascii=0x5f }, //_ - { .code = 0b1011011111, .bitcount=10, .ascii=0x60 }, //` - { .code = 0b1011, .bitcount=4, .ascii=0x61 }, //a - { .code = 0b1011111, .bitcount=7, .ascii=0x62 }, //b - { .code = 0b101111, .bitcount=6, .ascii=0x63 }, //c - { .code = 0b101101, .bitcount=6, .ascii=0x64 }, //d - { .code = 0b11, .bitcount=2, .ascii=0x65 }, //e - { .code = 0b111101, .bitcount=6, .ascii=0x66 }, //f - { .code = 0b1011011, .bitcount=7, .ascii=0x67 }, //g - { .code = 0b101011, .bitcount=6, .ascii=0x68 }, //h - { .code = 0b1101, .bitcount=4, .ascii=0x69 }, //i - { .code = 0b111101011, .bitcount=9, .ascii=0x6a }, //j - { .code = 0b10111111, .bitcount=8, .ascii=0x6b }, //k - { .code = 0b11011, .bitcount=5, .ascii=0x6c }, //l - { .code = 0b111011, .bitcount=6, .ascii=0x6d }, //m - { .code = 0b1111, .bitcount=4, .ascii=0x6e }, //n - { .code = 0b111, .bitcount=3, .ascii=0x6f }, //o - { .code = 0b111111, .bitcount=6, .ascii=0x70 }, //p - { .code = 0b110111111, .bitcount=9, .ascii=0x71 }, //q - { .code = 0b10101, .bitcount=5, .ascii=0x72 }, //r - { .code = 0b10111, .bitcount=5, .ascii=0x73 }, //s - { .code = 0b101, .bitcount=3, .ascii=0x74 }, //t - { .code = 0b110111, .bitcount=6, .ascii=0x75 }, //u - { .code = 0b1111011, .bitcount=7, .ascii=0x76 }, //v - { .code = 0b1101011, .bitcount=7, .ascii=0x77 }, //w - { .code = 0b11011111, .bitcount=8, .ascii=0x78 }, //x - { .code = 0b1011101, .bitcount=7, .ascii=0x79 }, //y - { .code = 0b111010101, .bitcount=9, .ascii=0x7a }, //z - { .code = 0b1010110111, .bitcount=10, .ascii=0x7b }, //{ - { .code = 0b110111011, .bitcount=9, .ascii=0x7c }, //| - { .code = 0b1010110101, .bitcount=10, .ascii=0x7d }, //} - { .code = 0b1011010111, .bitcount=10, .ascii=0x7e }, //~ - { .code = 0b1110110101, .bitcount=10, .ascii=0x7f }, //DEL + { .code = 0b1010101011, .bitcount=10, .ascii=0x00 }, //NUL, null + { .code = 0b1011011011, .bitcount=10, .ascii=0x01 }, //SOH, start of heading + { .code = 0b1011101101, .bitcount=10, .ascii=0x02 }, //STX, start of text + { .code = 0b1101110111, .bitcount=10, .ascii=0x03 }, //ETX, end of text + { .code = 0b1011101011, .bitcount=10, .ascii=0x04 }, //EOT, end of transmission + { .code = 0b1101011111, .bitcount=10, .ascii=0x05 }, //ENQ, enquiry + { .code = 0b1011101111, .bitcount=10, .ascii=0x06 }, //ACK, acknowledge + { .code = 0b1011111101, .bitcount=10, .ascii=0x07 }, //BEL, bell + { .code = 0b1011111111, .bitcount=10, .ascii=0x08 }, //BS, backspace + { .code = 0b11101111, .bitcount=8, .ascii=0x09 }, //TAB, horizontal tab + { .code = 0b11101, .bitcount=5, .ascii=0x0a }, //LF, NL line feed, new line + { .code = 0b1101101111, .bitcount=10, .ascii=0x0b }, //VT, vertical tab + { .code = 0b1011011101, .bitcount=10, .ascii=0x0c }, //FF, NP form feed, new page + { .code = 0b11111, .bitcount=5, .ascii=0x0d }, //CR, carriage return (overwrite) + { .code = 0b1101110101, .bitcount=10, .ascii=0x0e }, //SO, shift out + { .code = 0b1110101011, .bitcount=10, .ascii=0x0f }, //SI, shift in + { .code = 0b1011110111, .bitcount=10, .ascii=0x10 }, //DLE, data link escape + { .code = 0b1011110101, .bitcount=10, .ascii=0x11 }, //DC1, device control 1 + { .code = 0b1110101101, .bitcount=10, .ascii=0x12 }, //DC2, device control 2 + { .code = 0b1110101111, .bitcount=10, .ascii=0x13 }, //DC3, device control 3 + { .code = 0b1101011011, .bitcount=10, .ascii=0x14 }, //DC4, device control 4 + { .code = 0b1101101011, .bitcount=10, .ascii=0x15 }, //NAK, negative acknowledge + { .code = 0b1101101101, .bitcount=10, .ascii=0x16 }, //SYN, synchronous idle + { .code = 0b1101010111, .bitcount=10, .ascii=0x17 }, //ETB, end of trans. block + { .code = 0b1101111011, .bitcount=10, .ascii=0x18 }, //CAN, cancel + { .code = 0b1101111101, .bitcount=10, .ascii=0x19 }, //EM, end of medium + { .code = 0b1110110111, .bitcount=10, .ascii=0x1a }, //SUB, substitute + { .code = 0b1101010101, .bitcount=10, .ascii=0x1b }, //ESC, escape + { .code = 0b1101011101, .bitcount=10, .ascii=0x1c }, //FS, file separator + { .code = 0b1110111011, .bitcount=10, .ascii=0x1d }, //GS, group separator + { .code = 0b1011111011, .bitcount=10, .ascii=0x1e }, //RS, record separator + { .code = 0b1101111111, .bitcount=10, .ascii=0x1f }, //US, unit separator + { .code = 0b1, .bitcount=1, .ascii=0x20 }, //szóköz + { .code = 0b111111111, .bitcount=9, .ascii=0x21 }, //! + { .code = 0b101011111, .bitcount=9, .ascii=0x22 }, //" + { .code = 0b111110101, .bitcount=9, .ascii=0x23 }, //# + { .code = 0b111011011, .bitcount=9, .ascii=0x24 }, //$ + { .code = 0b1011010101, .bitcount=10, .ascii=0x25 }, //% + { .code = 0b1010111011, .bitcount=10, .ascii=0x26 }, //& + { .code = 0b101111111, .bitcount=9, .ascii=0x27 }, //' + { .code = 0b11111011, .bitcount=8, .ascii=0x28 }, //( + { .code = 0b11110111, .bitcount=8, .ascii=0x29 }, //) + { .code = 0b101101111, .bitcount=9, .ascii=0x2a }, //* + { .code = 0b111011111, .bitcount=9, .ascii=0x2b }, //+ + { .code = 0b1110101, .bitcount=7, .ascii=0x2c }, //, + { .code = 0b110101, .bitcount=6, .ascii=0x2d }, //- + { .code = 0b1010111, .bitcount=7, .ascii=0x2e }, //. + { .code = 0b110101111, .bitcount=9, .ascii=0x2f }, /// + { .code = 0b10110111, .bitcount=8, .ascii=0x30 }, //0 + { .code = 0b10111101, .bitcount=8, .ascii=0x31 }, //1 + { .code = 0b11101101, .bitcount=8, .ascii=0x32 }, //2 + { .code = 0b11111111, .bitcount=8, .ascii=0x33 }, //3 + { .code = 0b101110111, .bitcount=9, .ascii=0x34 }, //4 + { .code = 0b101011011, .bitcount=9, .ascii=0x35 }, //5 + { .code = 0b101101011, .bitcount=9, .ascii=0x36 }, //6 + { .code = 0b110101101, .bitcount=9, .ascii=0x37 }, //7 + { .code = 0b110101011, .bitcount=9, .ascii=0x38 }, //8 + { .code = 0b110110111, .bitcount=9, .ascii=0x39 }, //9 + { .code = 0b11110101, .bitcount=8, .ascii=0x3a }, //: + { .code = 0b110111101, .bitcount=9, .ascii=0x3b }, //; + { .code = 0b111101101, .bitcount=9, .ascii=0x3c }, //< + { .code = 0b1010101, .bitcount=7, .ascii=0x3d }, //= + { .code = 0b111010111, .bitcount=9, .ascii=0x3e }, //> + { .code = 0b1010101111, .bitcount=10, .ascii=0x3f }, //? + { .code = 0b1010111101, .bitcount=10, .ascii=0x40 }, //@ + { .code = 0b1111101, .bitcount=7, .ascii=0x41 }, //A + { .code = 0b11101011, .bitcount=8, .ascii=0x42 }, //B + { .code = 0b10101101, .bitcount=8, .ascii=0x43 }, //C + { .code = 0b10110101, .bitcount=8, .ascii=0x44 }, //D + { .code = 0b1110111, .bitcount=7, .ascii=0x45 }, //E + { .code = 0b11011011, .bitcount=8, .ascii=0x46 }, //F + { .code = 0b11111101, .bitcount=8, .ascii=0x47 }, //G + { .code = 0b101010101, .bitcount=9, .ascii=0x48 }, //H + { .code = 0b1111111, .bitcount=7, .ascii=0x49 }, //I + { .code = 0b111111101, .bitcount=9, .ascii=0x4a }, //J + { .code = 0b101111101, .bitcount=9, .ascii=0x4b }, //K + { .code = 0b11010111, .bitcount=8, .ascii=0x4c }, //L + { .code = 0b10111011, .bitcount=8, .ascii=0x4d }, //M + { .code = 0b11011101, .bitcount=8, .ascii=0x4e }, //N + { .code = 0b10101011, .bitcount=8, .ascii=0x4f }, //O + { .code = 0b11010101, .bitcount=8, .ascii=0x50 }, //P + { .code = 0b111011101, .bitcount=9, .ascii=0x51 }, //Q + { .code = 0b10101111, .bitcount=8, .ascii=0x52 }, //R + { .code = 0b1101111, .bitcount=7, .ascii=0x53 }, //S + { .code = 0b1101101, .bitcount=7, .ascii=0x54 }, //T + { .code = 0b101010111, .bitcount=9, .ascii=0x55 }, //U + { .code = 0b110110101, .bitcount=9, .ascii=0x56 }, //V + { .code = 0b101011101, .bitcount=9, .ascii=0x57 }, //W + { .code = 0b101110101, .bitcount=9, .ascii=0x58 }, //X + { .code = 0b101111011, .bitcount=9, .ascii=0x59 }, //Y + { .code = 0b1010101101, .bitcount=10, .ascii=0x5a }, //Z + { .code = 0b111110111, .bitcount=9, .ascii=0x5b }, //[ + { .code = 0b111101111, .bitcount=9, .ascii=0x5c }, //\ + { .code = 0b111111011, .bitcount=9, .ascii=0x5d }, //] + { .code = 0b1010111111, .bitcount=10, .ascii=0x5e }, //^ + { .code = 0b101101101, .bitcount=9, .ascii=0x5f }, //_ + { .code = 0b1011011111, .bitcount=10, .ascii=0x60 }, //` + { .code = 0b1011, .bitcount=4, .ascii=0x61 }, //a + { .code = 0b1011111, .bitcount=7, .ascii=0x62 }, //b + { .code = 0b101111, .bitcount=6, .ascii=0x63 }, //c + { .code = 0b101101, .bitcount=6, .ascii=0x64 }, //d + { .code = 0b11, .bitcount=2, .ascii=0x65 }, //e + { .code = 0b111101, .bitcount=6, .ascii=0x66 }, //f + { .code = 0b1011011, .bitcount=7, .ascii=0x67 }, //g + { .code = 0b101011, .bitcount=6, .ascii=0x68 }, //h + { .code = 0b1101, .bitcount=4, .ascii=0x69 }, //i + { .code = 0b111101011, .bitcount=9, .ascii=0x6a }, //j + { .code = 0b10111111, .bitcount=8, .ascii=0x6b }, //k + { .code = 0b11011, .bitcount=5, .ascii=0x6c }, //l + { .code = 0b111011, .bitcount=6, .ascii=0x6d }, //m + { .code = 0b1111, .bitcount=4, .ascii=0x6e }, //n + { .code = 0b111, .bitcount=3, .ascii=0x6f }, //o + { .code = 0b111111, .bitcount=6, .ascii=0x70 }, //p + { .code = 0b110111111, .bitcount=9, .ascii=0x71 }, //q + { .code = 0b10101, .bitcount=5, .ascii=0x72 }, //r + { .code = 0b10111, .bitcount=5, .ascii=0x73 }, //s + { .code = 0b101, .bitcount=3, .ascii=0x74 }, //t + { .code = 0b110111, .bitcount=6, .ascii=0x75 }, //u + { .code = 0b1111011, .bitcount=7, .ascii=0x76 }, //v + { .code = 0b1101011, .bitcount=7, .ascii=0x77 }, //w + { .code = 0b11011111, .bitcount=8, .ascii=0x78 }, //x + { .code = 0b1011101, .bitcount=7, .ascii=0x79 }, //y + { .code = 0b111010101, .bitcount=9, .ascii=0x7a }, //z + { .code = 0b1010110111, .bitcount=10, .ascii=0x7b }, //{ + { .code = 0b110111011, .bitcount=9, .ascii=0x7c }, //| + { .code = 0b1010110101, .bitcount=10, .ascii=0x7d }, //} + { .code = 0b1011010111, .bitcount=10, .ascii=0x7e }, //~ + { .code = 0b1110110101, .bitcount=10, .ascii=0x7f }, //DEL }; unsigned long long psk31_varicode_masklen_helper[] = { - 0b0000000000000000000000000000000000000000000000000000000000000000, - 0b0000000000000000000000000000000000000000000000000000000000000001, - 0b0000000000000000000000000000000000000000000000000000000000000011, - 0b0000000000000000000000000000000000000000000000000000000000000111, - 0b0000000000000000000000000000000000000000000000000000000000001111, - 0b0000000000000000000000000000000000000000000000000000000000011111, - 0b0000000000000000000000000000000000000000000000000000000000111111, - 0b0000000000000000000000000000000000000000000000000000000001111111, - 0b0000000000000000000000000000000000000000000000000000000011111111, - 0b0000000000000000000000000000000000000000000000000000000111111111, - 0b0000000000000000000000000000000000000000000000000000001111111111, - 0b0000000000000000000000000000000000000000000000000000011111111111, - 0b0000000000000000000000000000000000000000000000000000111111111111, - 0b0000000000000000000000000000000000000000000000000001111111111111, - 0b0000000000000000000000000000000000000000000000000011111111111111, - 0b0000000000000000000000000000000000000000000000000111111111111111, - 0b0000000000000000000000000000000000000000000000001111111111111111, - 0b0000000000000000000000000000000000000000000000011111111111111111, - 0b0000000000000000000000000000000000000000000000111111111111111111, - 0b0000000000000000000000000000000000000000000001111111111111111111, - 0b0000000000000000000000000000000000000000000011111111111111111111, - 0b0000000000000000000000000000000000000000000111111111111111111111, - 0b0000000000000000000000000000000000000000001111111111111111111111, - 0b0000000000000000000000000000000000000000011111111111111111111111, - 0b0000000000000000000000000000000000000000111111111111111111111111, - 0b0000000000000000000000000000000000000001111111111111111111111111, - 0b0000000000000000000000000000000000000011111111111111111111111111, - 0b0000000000000000000000000000000000000111111111111111111111111111, - 0b0000000000000000000000000000000000001111111111111111111111111111, - 0b0000000000000000000000000000000000011111111111111111111111111111, - 0b0000000000000000000000000000000000111111111111111111111111111111, - 0b0000000000000000000000000000000001111111111111111111111111111111, - 0b0000000000000000000000000000000011111111111111111111111111111111, - 0b0000000000000000000000000000000111111111111111111111111111111111, - 0b0000000000000000000000000000001111111111111111111111111111111111, - 0b0000000000000000000000000000011111111111111111111111111111111111, - 0b0000000000000000000000000000111111111111111111111111111111111111, - 0b0000000000000000000000000001111111111111111111111111111111111111, - 0b0000000000000000000000000011111111111111111111111111111111111111, - 0b0000000000000000000000000111111111111111111111111111111111111111, - 0b0000000000000000000000001111111111111111111111111111111111111111, - 0b0000000000000000000000011111111111111111111111111111111111111111, - 0b0000000000000000000000111111111111111111111111111111111111111111, - 0b0000000000000000000001111111111111111111111111111111111111111111, - 0b0000000000000000000011111111111111111111111111111111111111111111, - 0b0000000000000000000111111111111111111111111111111111111111111111, - 0b0000000000000000001111111111111111111111111111111111111111111111, - 0b0000000000000000011111111111111111111111111111111111111111111111, - 0b0000000000000000111111111111111111111111111111111111111111111111, - 0b0000000000000001111111111111111111111111111111111111111111111111, - 0b0000000000000011111111111111111111111111111111111111111111111111, - 0b0000000000000111111111111111111111111111111111111111111111111111, - 0b0000000000001111111111111111111111111111111111111111111111111111, - 0b0000000000011111111111111111111111111111111111111111111111111111, - 0b0000000000111111111111111111111111111111111111111111111111111111, - 0b0000000001111111111111111111111111111111111111111111111111111111, - 0b0000000011111111111111111111111111111111111111111111111111111111, - 0b0000000111111111111111111111111111111111111111111111111111111111, - 0b0000001111111111111111111111111111111111111111111111111111111111, - 0b0000011111111111111111111111111111111111111111111111111111111111, - 0b0000111111111111111111111111111111111111111111111111111111111111, - 0b0001111111111111111111111111111111111111111111111111111111111111, - 0b0011111111111111111111111111111111111111111111111111111111111111, - 0b0111111111111111111111111111111111111111111111111111111111111111 + 0b0000000000000000000000000000000000000000000000000000000000000000, + 0b0000000000000000000000000000000000000000000000000000000000000001, + 0b0000000000000000000000000000000000000000000000000000000000000011, + 0b0000000000000000000000000000000000000000000000000000000000000111, + 0b0000000000000000000000000000000000000000000000000000000000001111, + 0b0000000000000000000000000000000000000000000000000000000000011111, + 0b0000000000000000000000000000000000000000000000000000000000111111, + 0b0000000000000000000000000000000000000000000000000000000001111111, + 0b0000000000000000000000000000000000000000000000000000000011111111, + 0b0000000000000000000000000000000000000000000000000000000111111111, + 0b0000000000000000000000000000000000000000000000000000001111111111, + 0b0000000000000000000000000000000000000000000000000000011111111111, + 0b0000000000000000000000000000000000000000000000000000111111111111, + 0b0000000000000000000000000000000000000000000000000001111111111111, + 0b0000000000000000000000000000000000000000000000000011111111111111, + 0b0000000000000000000000000000000000000000000000000111111111111111, + 0b0000000000000000000000000000000000000000000000001111111111111111, + 0b0000000000000000000000000000000000000000000000011111111111111111, + 0b0000000000000000000000000000000000000000000000111111111111111111, + 0b0000000000000000000000000000000000000000000001111111111111111111, + 0b0000000000000000000000000000000000000000000011111111111111111111, + 0b0000000000000000000000000000000000000000000111111111111111111111, + 0b0000000000000000000000000000000000000000001111111111111111111111, + 0b0000000000000000000000000000000000000000011111111111111111111111, + 0b0000000000000000000000000000000000000000111111111111111111111111, + 0b0000000000000000000000000000000000000001111111111111111111111111, + 0b0000000000000000000000000000000000000011111111111111111111111111, + 0b0000000000000000000000000000000000000111111111111111111111111111, + 0b0000000000000000000000000000000000001111111111111111111111111111, + 0b0000000000000000000000000000000000011111111111111111111111111111, + 0b0000000000000000000000000000000000111111111111111111111111111111, + 0b0000000000000000000000000000000001111111111111111111111111111111, + 0b0000000000000000000000000000000011111111111111111111111111111111, + 0b0000000000000000000000000000000111111111111111111111111111111111, + 0b0000000000000000000000000000001111111111111111111111111111111111, + 0b0000000000000000000000000000011111111111111111111111111111111111, + 0b0000000000000000000000000000111111111111111111111111111111111111, + 0b0000000000000000000000000001111111111111111111111111111111111111, + 0b0000000000000000000000000011111111111111111111111111111111111111, + 0b0000000000000000000000000111111111111111111111111111111111111111, + 0b0000000000000000000000001111111111111111111111111111111111111111, + 0b0000000000000000000000011111111111111111111111111111111111111111, + 0b0000000000000000000000111111111111111111111111111111111111111111, + 0b0000000000000000000001111111111111111111111111111111111111111111, + 0b0000000000000000000011111111111111111111111111111111111111111111, + 0b0000000000000000000111111111111111111111111111111111111111111111, + 0b0000000000000000001111111111111111111111111111111111111111111111, + 0b0000000000000000011111111111111111111111111111111111111111111111, + 0b0000000000000000111111111111111111111111111111111111111111111111, + 0b0000000000000001111111111111111111111111111111111111111111111111, + 0b0000000000000011111111111111111111111111111111111111111111111111, + 0b0000000000000111111111111111111111111111111111111111111111111111, + 0b0000000000001111111111111111111111111111111111111111111111111111, + 0b0000000000011111111111111111111111111111111111111111111111111111, + 0b0000000000111111111111111111111111111111111111111111111111111111, + 0b0000000001111111111111111111111111111111111111111111111111111111, + 0b0000000011111111111111111111111111111111111111111111111111111111, + 0b0000000111111111111111111111111111111111111111111111111111111111, + 0b0000001111111111111111111111111111111111111111111111111111111111, + 0b0000011111111111111111111111111111111111111111111111111111111111, + 0b0000111111111111111111111111111111111111111111111111111111111111, + 0b0001111111111111111111111111111111111111111111111111111111111111, + 0b0011111111111111111111111111111111111111111111111111111111111111, + 0b0111111111111111111111111111111111111111111111111111111111111111 }; const int n_psk31_varicode_items = sizeof(psk31_varicode_items) / sizeof(psk31_varicode_item_t); char psk31_varicode_decoder_push(unsigned long long* status_shr, unsigned char symbol) { - *status_shr=((*status_shr)<<1)|(!!symbol); //shift new bit in shift register - //fprintf(stderr,"*status_shr = %llx\n", *status_shr); - if((*status_shr)&0xFFF==0) return 0; - for(int i=0;i>>>>>>>> %d %x %c\n", i, psk31_varicode_items[i].ascii, psk31_varicode_items[i].ascii);*/ return psk31_varicode_items[i].ascii; } + *status_shr=((*status_shr)<<1)|(!!symbol); //shift new bit in shift register + //fprintf(stderr,"*status_shr = %llx\n", *status_shr); + if((*status_shr)&0xFFF==0) return 0; + for(int i=0;i>>>>>>>> %d %x %c\n", i, psk31_varicode_items[i].ascii, psk31_varicode_items[i].ascii);*/ return psk31_varicode_items[i].ascii; } - } - return 0; + } + return 0; } void psk31_varicode_encoder_u8_u8(unsigned char* input, unsigned char* output, int input_size, int output_max_size, int* input_processed, int* output_size) { - (*output_size)=0; - for((*input_processed)=0; (*input_processed)>(current_varicode.bitcount-bi-1))&1 : 0; - (*output_size)++; - output_max_size--; - } - break; - } - } - } + (*output_size)=0; + for((*input_processed)=0; (*input_processed)>(current_varicode.bitcount-bi-1))&1 : 0; + (*output_size)++; + output_max_size--; + } + break; + } + } + } } rtty_baudot_item_t rtty_baudot_items[] = { - { .code = 0b00000, .ascii_letter=0, .ascii_figure=0 }, - { .code = 0b10000, .ascii_letter='E', .ascii_figure='3' }, - { .code = 0b01000, .ascii_letter='\n', .ascii_figure='\n' }, - { .code = 0b11000, .ascii_letter='A', .ascii_figure='-' }, - { .code = 0b00100, .ascii_letter=' ', .ascii_figure=' ' }, - { .code = 0b10100, .ascii_letter='S', .ascii_figure='\'' }, - { .code = 0b01100, .ascii_letter='I', .ascii_figure='8' }, - { .code = 0b11100, .ascii_letter='U', .ascii_figure='7' }, - { .code = 0b00010, .ascii_letter='\r', .ascii_figure='\r' }, - { .code = 0b10010, .ascii_letter='D', .ascii_figure='#' }, - { .code = 0b01010, .ascii_letter='R', .ascii_figure='4' }, - { .code = 0b11010, .ascii_letter='J', .ascii_figure='\a' }, - { .code = 0b00110, .ascii_letter='N', .ascii_figure=',' }, - { .code = 0b10110, .ascii_letter='F', .ascii_figure='@' }, - { .code = 0b01110, .ascii_letter='C', .ascii_figure=':' }, - { .code = 0b11110, .ascii_letter='K', .ascii_figure='(' }, - { .code = 0b00001, .ascii_letter='T', .ascii_figure='5' }, - { .code = 0b10001, .ascii_letter='Z', .ascii_figure='+' }, - { .code = 0b01001, .ascii_letter='L', .ascii_figure=')' }, - { .code = 0b11001, .ascii_letter='W', .ascii_figure='2' }, - { .code = 0b00101, .ascii_letter='H', .ascii_figure='$' }, - { .code = 0b10101, .ascii_letter='Y', .ascii_figure='6' }, - { .code = 0b01101, .ascii_letter='P', .ascii_figure='0' }, - { .code = 0b11101, .ascii_letter='Q', .ascii_figure='1' }, - { .code = 0b00011, .ascii_letter='O', .ascii_figure='9' }, - { .code = 0b10011, .ascii_letter='B', .ascii_figure='?' }, - { .code = 0b01011, .ascii_letter='G', .ascii_figure='*' }, - { .code = 0b00111, .ascii_letter='M', .ascii_figure='.' }, - { .code = 0b10111, .ascii_letter='X', .ascii_figure='/' }, - { .code = 0b01111, .ascii_letter='V', .ascii_figure='=' } + { .code = 0b00000, .ascii_letter=0, .ascii_figure=0 }, + { .code = 0b10000, .ascii_letter='E', .ascii_figure='3' }, + { .code = 0b01000, .ascii_letter='\n', .ascii_figure='\n' }, + { .code = 0b11000, .ascii_letter='A', .ascii_figure='-' }, + { .code = 0b00100, .ascii_letter=' ', .ascii_figure=' ' }, + { .code = 0b10100, .ascii_letter='S', .ascii_figure='\'' }, + { .code = 0b01100, .ascii_letter='I', .ascii_figure='8' }, + { .code = 0b11100, .ascii_letter='U', .ascii_figure='7' }, + { .code = 0b00010, .ascii_letter='\r', .ascii_figure='\r' }, + { .code = 0b10010, .ascii_letter='D', .ascii_figure='#' }, + { .code = 0b01010, .ascii_letter='R', .ascii_figure='4' }, + { .code = 0b11010, .ascii_letter='J', .ascii_figure='\a' }, + { .code = 0b00110, .ascii_letter='N', .ascii_figure=',' }, + { .code = 0b10110, .ascii_letter='F', .ascii_figure='@' }, + { .code = 0b01110, .ascii_letter='C', .ascii_figure=':' }, + { .code = 0b11110, .ascii_letter='K', .ascii_figure='(' }, + { .code = 0b00001, .ascii_letter='T', .ascii_figure='5' }, + { .code = 0b10001, .ascii_letter='Z', .ascii_figure='+' }, + { .code = 0b01001, .ascii_letter='L', .ascii_figure=')' }, + { .code = 0b11001, .ascii_letter='W', .ascii_figure='2' }, + { .code = 0b00101, .ascii_letter='H', .ascii_figure='$' }, + { .code = 0b10101, .ascii_letter='Y', .ascii_figure='6' }, + { .code = 0b01101, .ascii_letter='P', .ascii_figure='0' }, + { .code = 0b11101, .ascii_letter='Q', .ascii_figure='1' }, + { .code = 0b00011, .ascii_letter='O', .ascii_figure='9' }, + { .code = 0b10011, .ascii_letter='B', .ascii_figure='?' }, + { .code = 0b01011, .ascii_letter='G', .ascii_figure='*' }, + { .code = 0b00111, .ascii_letter='M', .ascii_figure='.' }, + { .code = 0b10111, .ascii_letter='X', .ascii_figure='/' }, + { .code = 0b01111, .ascii_letter='V', .ascii_figure='=' } }; const int n_rtty_baudot_items = sizeof(rtty_baudot_items) / sizeof(rtty_baudot_item_t); char rtty_baudot_decoder_lookup(unsigned char* fig_mode, unsigned char c) { - if(c==RTTY_FIGURE_MODE_SELECT_CODE) { *fig_mode=1; return 0; } - if(c==RTTY_LETTER_MODE_SELECT_CODE) { *fig_mode=0; return 0; } - for(int i=0;istate) - { - case RTTY_BAUDOT_WAITING_STOP_PULSE: - if(symbol==1) { s->state = RTTY_BAUDOT_WAITING_START_PULSE; if(s->character_received) return rtty_baudot_decoder_lookup(&s->fig_mode, s->shr&31); } - //If the character data is followed by a stop pulse, then we go on to wait for the next character. - else s->character_received = 0; - //The character should be followed by a stop pulse. If the stop pulse is missing, that is certainly an error. - //In that case, we remove forget the character we just received. - break; - case RTTY_BAUDOT_WAITING_START_PULSE: - s->character_received = 0; - if(symbol==0) { s->state = RTTY_BAUDOT_RECEIVING_DATA; s->shr = s->bit_cntr = 0; } - //Any number of high bits can come after each other, until interrupted with a low bit (start pulse) to indicate - //the beginning of a new character. If we get this start pulse, we go on to wait for the characters. We also - //clear the variables used for counting (bit_cntr) and storing (shr) the data bits. - break; - case RTTY_BAUDOT_RECEIVING_DATA: - s->shr = (s->shr<<1)|(!!symbol); - //We store 5 bits into our shift register - if(s->bit_cntr++==4) { s->state = RTTY_BAUDOT_WAITING_STOP_PULSE; s->character_received = 1; } - //If this is the 5th bit stored, then we wait for the stop pulse. - break; - default: break; - } - return 0; + //For RTTY waveforms, check this: http://www.ham.hu/radiosatvitel/szoveg/RTTY/kepek/rtty.gif + //RTTY is much like an UART data transfer with 1 start bit, 5 data bits and 1 stop bit. + //The start pulse and stop pulse are used for synchronization. + symbol=!!symbol; //We want symbol to be 0 or 1. + switch(s->state) + { + case RTTY_BAUDOT_WAITING_STOP_PULSE: + if(symbol==1) { s->state = RTTY_BAUDOT_WAITING_START_PULSE; if(s->character_received) return rtty_baudot_decoder_lookup(&s->fig_mode, s->shr&31); } + //If the character data is followed by a stop pulse, then we go on to wait for the next character. + else s->character_received = 0; + //The character should be followed by a stop pulse. If the stop pulse is missing, that is certainly an error. + //In that case, we remove forget the character we just received. + break; + case RTTY_BAUDOT_WAITING_START_PULSE: + s->character_received = 0; + if(symbol==0) { s->state = RTTY_BAUDOT_RECEIVING_DATA; s->shr = s->bit_cntr = 0; } + //Any number of high bits can come after each other, until interrupted with a low bit (start pulse) to indicate + //the beginning of a new character. If we get this start pulse, we go on to wait for the characters. We also + //clear the variables used for counting (bit_cntr) and storing (shr) the data bits. + break; + case RTTY_BAUDOT_RECEIVING_DATA: + s->shr = (s->shr<<1)|(!!symbol); + //We store 5 bits into our shift register + if(s->bit_cntr++==4) { s->state = RTTY_BAUDOT_WAITING_STOP_PULSE; s->character_received = 1; } + //If this is the 5th bit stored, then we wait for the stop pulse. + break; + default: break; + } + return 0; } #define DEBUG_SERIAL_LINE_DECODER 0 //What has not been checked: // behaviour on 1.5 stop bits -// check all exit conditions +// check all exit conditions void serial_line_decoder_f_u8(serial_line_t* s, float* input, unsigned char* output, int input_size) { - static int abs_samples_helper = 0; - abs_samples_helper += s->input_used; - int iabs_samples_helper = abs_samples_helper; - s->output_size = 0; - s->input_used = 0; - short* output_s = (short*)output; - unsigned* output_u = (unsigned*)output; - for(;;) - { - //we find the start bit (first negative edge on the line) - int startbit_start = -1; - int i; - for(i=1;i 0) { startbit_start=i; break; } + static int abs_samples_helper = 0; + abs_samples_helper += s->input_used; + int iabs_samples_helper = abs_samples_helper; + s->output_size = 0; + s->input_used = 0; + short* output_s = (short*)output; + unsigned* output_u = (unsigned*)output; + for(;;) + { + //we find the start bit (first negative edge on the line) + int startbit_start = -1; + int i; + for(i=1;i 0) { startbit_start=i; break; } - if(startbit_start == -1) { s->input_used += i; DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:startbit_not_found (+%d)\n", s->input_used); return; } - DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:startbit_found at %d (%d)\n", startbit_start, iabs_samples_helper + startbit_start); + if(startbit_start == -1) { s->input_used += i; DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:startbit_not_found (+%d)\n", s->input_used); return; } + DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:startbit_found at %d (%d)\n", startbit_start, iabs_samples_helper + startbit_start); - //If the stop bit would be too far so that we reached the end of the buffer, then we return failed. - //The caller can rearrange the buffer so that the whole character fits into it. - float all_bits = 1 + s->databits + s->stopbits; - DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:all_bits = %f\n", all_bits); - if(startbit_start + s->samples_per_bits * all_bits >= input_size) { s->input_used += MAX_M(0,startbit_start-2); DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:return_stopbit_too_far (+%d)\n", s->input_used); return; } + //If the stop bit would be too far so that we reached the end of the buffer, then we return failed. + //The caller can rearrange the buffer so that the whole character fits into it. + float all_bits = 1 + s->databits + s->stopbits; + DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:all_bits = %f\n", all_bits); + if(startbit_start + s->samples_per_bits * all_bits >= input_size) { s->input_used += MAX_M(0,startbit_start-2); DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:return_stopbit_too_far (+%d)\n", s->input_used); return; } - //We do the actual sampling. - int di; //databit counter - unsigned shr = 0; - for(di=0; di < s->databits; di++) - { - int databit_start = startbit_start + (1+di+(0.5*(1-s->bit_sampling_width_ratio))) * s->samples_per_bits; - int databit_end = startbit_start + (1+di+(0.5*(1+s->bit_sampling_width_ratio))) * s->samples_per_bits; - DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:databit_start = %d (%d)\n", databit_start, iabs_samples_helper+databit_start); - DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:databit_end = %d (%d)\n", databit_end, iabs_samples_helper+databit_end); - float databit_acc = 0; - for(i=databit_start;i0)); - shr=(shr<<1)|!!(databit_acc>0); - } - DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:shr = 0x%x, %d\n", shr, shr); + //We do the actual sampling. + int di; //databit counter + unsigned shr = 0; + for(di=0; di < s->databits; di++) + { + int databit_start = startbit_start + (1+di+(0.5*(1-s->bit_sampling_width_ratio))) * s->samples_per_bits; + int databit_end = startbit_start + (1+di+(0.5*(1+s->bit_sampling_width_ratio))) * s->samples_per_bits; + DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:databit_start = %d (%d)\n", databit_start, iabs_samples_helper+databit_start); + DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:databit_end = %d (%d)\n", databit_end, iabs_samples_helper+databit_end); + float databit_acc = 0; + for(i=databit_start;i0)); + shr=(shr<<1)|!!(databit_acc>0); + } + DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:shr = 0x%x, %d\n", shr, shr); - //We check if the stopbit is correct. - int stopbit_start = startbit_start + (1+s->databits) * s->samples_per_bits + (s->stopbits * 0.5 * (1-s->bit_sampling_width_ratio)) * s->samples_per_bits; - int stopbit_end = startbit_start + (1+s->databits) * s->samples_per_bits + (s->stopbits * 0.5 * (1+s->bit_sampling_width_ratio)) * s->samples_per_bits; - DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:stopbit_start = %d (%d)\n", stopbit_start, iabs_samples_helper+stopbit_start); - DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:stopbit_end = %d (%d)\n", stopbit_end, iabs_samples_helper+stopbit_end); - float stopbit_acc = 0; - for(i=stopbit_start;iinput_used += MIN_M(startbit_start + 1, input_size); DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:return_stopbit_faulty (+%d)\n", s->input_used); return; } - DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:stopbit_found\n"); + //We check if the stopbit is correct. + int stopbit_start = startbit_start + (1+s->databits) * s->samples_per_bits + (s->stopbits * 0.5 * (1-s->bit_sampling_width_ratio)) * s->samples_per_bits; + int stopbit_end = startbit_start + (1+s->databits) * s->samples_per_bits + (s->stopbits * 0.5 * (1+s->bit_sampling_width_ratio)) * s->samples_per_bits; + DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:stopbit_start = %d (%d)\n", stopbit_start, iabs_samples_helper+stopbit_start); + DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:stopbit_end = %d (%d)\n", stopbit_end, iabs_samples_helper+stopbit_end); + float stopbit_acc = 0; + for(i=stopbit_start;iinput_used += MIN_M(startbit_start + 1, input_size); DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:return_stopbit_faulty (+%d)\n", s->input_used); return; } + DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:stopbit_found\n"); - //we write the output sample - if(s->databits <= 8) output[s->output_size] = shr; - else if(s->databits <= 16) output_s[s->output_size] = shr; - else output_u[s->output_size] = shr; - s->output_size++; + //we write the output sample + if(s->databits <= 8) output[s->output_size] = shr; + else if(s->databits <= 16) output_s[s->output_size] = shr; + else output_u[s->output_size] = shr; + s->output_size++; - int samples_used_up_now = MIN_M(startbit_start + all_bits * s->samples_per_bits, input_size); - s->input_used += samples_used_up_now; - input += samples_used_up_now; - input_size -= samples_used_up_now; - iabs_samples_helper += samples_used_up_now; - if(!input_size) { DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:return_no_more_input (+%d)\n", s->input_used); return; } - } - DEBUG_SERIAL_LINE_DECODER && fprintf(stderr, "sld: >> output_size = %d (+%d)\n", s->output_size, s->input_used); + int samples_used_up_now = MIN_M(startbit_start + all_bits * s->samples_per_bits, input_size); + s->input_used += samples_used_up_now; + input += samples_used_up_now; + input_size -= samples_used_up_now; + iabs_samples_helper += samples_used_up_now; + if(!input_size) { DEBUG_SERIAL_LINE_DECODER && fprintf(stderr,"sld:return_no_more_input (+%d)\n", s->input_used); return; } + } + DEBUG_SERIAL_LINE_DECODER && fprintf(stderr, "sld: >> output_size = %d (+%d)\n", s->output_size, s->input_used); } void binary_slicer_f_u8(float* input, unsigned char* output, int input_size) { - for(int i=0;i 0; + for(int i=0;i 0; } void psk_modulator_u8_c(unsigned char* input, complexf* output, int input_size, int n_psk) { - //outputs one complex sample per input symbol - float phase_increment = (2*M_PI)/n_psk; - for(int i=0;i>bi)&1; + for(int i=0; i>bi)&1; } unsigned char differential_codec(unsigned char* input, unsigned char* output, int input_size, int encode, unsigned char state) { - if(!encode) - for(int i=0;ialpha = (damping_factor*2*bandwidth_omega)/(ko*kd); - float sampling_rate = 1; //the bandwidth is normalized to the sampling rate - p->beta = (bandwidth_omega*bandwidth_omega)/(sampling_rate*ko*kd); - p->iir_temp = p->dphase = p->output_phase = 0; + //kd: detector gain + //ko: VCO gain + float bandwidth_omega = 2*M_PI*bandwidth; + p->alpha = (damping_factor*2*bandwidth_omega)/(ko*kd); + float sampling_rate = 1; //the bandwidth is normalized to the sampling rate + p->beta = (bandwidth_omega*bandwidth_omega)/(sampling_rate*ko*kd); + p->iir_temp = p->dphase = p->output_phase = 0; } void pll_cc_init_p_controller(pll_t* p, float alpha) { - p->alpha = alpha; - p->dphase=p->output_phase=0; + p->alpha = alpha; + p->dphase=p->output_phase=0; } void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nco, int input_size) { - for(int i=0;ioutput_phase += p->dphase; - while(p->output_phase>PI) p->output_phase-=2*PI; - while(p->output_phase<-PI) p->output_phase+=2*PI; - complexf current_nco; - iof(¤t_nco,0) = sin(p->output_phase); - qof(¤t_nco,0) = cos(p->output_phase); - if(output_nco) output_nco[i] = current_nco; //we don't output anything if it is a NULL pointer + for(int i=0;ioutput_phase += p->dphase; + while(p->output_phase>PI) p->output_phase-=2*PI; + while(p->output_phase<-PI) p->output_phase+=2*PI; + complexf current_nco; + iof(¤t_nco,0) = sin(p->output_phase); + qof(¤t_nco,0) = cos(p->output_phase); + if(output_nco) output_nco[i] = current_nco; //we don't output anything if it is a NULL pointer - //accurate phase detector: calculating error from phase offset - float input_phase = atan2(iof(input,i),qof(input,i)); - float new_dphase = input_phase - p->output_phase; - while(new_dphase>PI) new_dphase-=2*PI; - while(new_dphase<-PI) new_dphase+=2*PI; + //accurate phase detector: calculating error from phase offset + float input_phase = atan2(iof(input,i),qof(input,i)); + float new_dphase = input_phase - p->output_phase; + while(new_dphase>PI) new_dphase-=2*PI; + while(new_dphase<-PI) new_dphase+=2*PI; - //modeling analog phase detector, which would be abs(input[i] * current_nco) if we had a real output signal, but what if we have complex signals? - //qof(¤t_nco,0)=-qof(¤t_nco,0); //calculate conjugate - //complexf multiply_result; - //cmult(&multiply_result, &input[i], ¤t_nco); - //output_nco[i] = multiply_result; - //float new_dphase = absof(&multiply_result,0); + //modeling analog phase detector, which would be abs(input[i] * current_nco) if we had a real output signal, but what if we have complex signals? + //qof(¤t_nco,0)=-qof(¤t_nco,0); //calculate conjugate + //complexf multiply_result; + //cmult(&multiply_result, &input[i], ¤t_nco); + //output_nco[i] = multiply_result; + //float new_dphase = absof(&multiply_result,0); - if(p->pll_type == PLL_PI_CONTROLLER) - { - p->dphase = new_dphase * p->alpha + p->iir_temp; - p->iir_temp += new_dphase * p->beta; + if(p->pll_type == PLL_PI_CONTROLLER) + { + p->dphase = new_dphase * p->alpha + p->iir_temp; + p->iir_temp += new_dphase * p->beta; - while(p->dphase>PI) p->dphase-=2*PI; //won't need this one - while(p->dphase<-PI) p->dphase+=2*PI; - } - else if(p->pll_type == PLL_P_CONTROLLER) - { - p->dphase = new_dphase * p->alpha; - } - else return; - if(output_dphase) output_dphase[i] = -p->dphase; - //if(output_dphase) output_dphase[i] = new_dphase/10; - } + while(p->dphase>PI) p->dphase-=2*PI; //won't need this one + while(p->dphase<-PI) p->dphase+=2*PI; + } + else if(p->pll_type == PLL_P_CONTROLLER) + { + p->dphase = new_dphase * p->alpha; + } + else return; + if(output_dphase) output_dphase[i] = -p->dphase; + //if(output_dphase) output_dphase[i] = new_dphase/10; + } } void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error, int index, int correction_offset, int writefiles, int points_size, ...) { - static int figure_output_counter = 0; - int* points_z = (int*)malloc(sizeof(int)*points_size); - int* points_color = (int*)malloc(sizeof(int)*points_size); - va_list vl; - va_start(vl,points_size); - for(int i=0;idebug_phase=debug_phase; + state->debug_phase=debug_phase; } #define MTIMINGR_HDEBUG 0 void timing_recovery_cc(complexf* input, complexf* output, int input_size, float* timing_error, int* sampled_indexes, timing_recovery_state_t* state) { - //We always assume that the input starts at center of the first symbol cross before the first symbol. - //Last time we consumed that much from the input samples that it is there. - int correction_offset = state->last_correction_offset; - int current_bitstart_index = 0; - int num_samples_bit = state->decimation_rate; - int num_samples_halfbit = state->decimation_rate / 2; - int num_samples_quarterbit = state->decimation_rate / 4; - int num_samples_earlylate_wing = num_samples_bit * state->earlylate_ratio; - int debug_i = state->debug_count; - float error; - int el_point_left_index, el_point_right_index, el_point_mid_index; - int si = 0; - if(state->debug_force) fprintf(stderr, "disp(\"begin timing_recovery_cc\");\n"); - if(MTIMINGR_HDEBUG) fprintf(stderr, "timing_recovery_cc started, nsb = %d, nshb = %d, nsqb = %d\n", num_samples_bit, num_samples_halfbit, num_samples_quarterbit); - { - for(;;) - { - //the MathWorks style algorithm has correction_offset. - //correction_offset = 0; - if(current_bitstart_index + num_samples_halfbit * 3 >= input_size) break; - if(MTIMINGR_HDEBUG) fprintf(stderr, "current_bitstart_index = %d, input_size = %d, correction_offset(prev) = %d\n", - current_bitstart_index, input_size, correction_offset); - - if(correction_offset<=-num_samples_quarterbit*0.9 || correction_offset>=0.9*num_samples_quarterbit) - { - if(MTIMINGR_HDEBUG) fprintf(stderr, "correction_offset = %d, reset to 0!\n", correction_offset); - correction_offset = 0; - } - //should check if the sign of the correction_offset (or disabling it) has an effect on the EVM. - //it is also a possibility to disable multiplying with the magnitude - if(state->algorithm == TIMING_RECOVERY_ALGORITHM_EARLYLATE) - { - //bitstart index should be at symbol edge, maximum effect point is at current_bitstart_index + num_samples_halfbit - el_point_right_index = current_bitstart_index + num_samples_earlylate_wing * 3; - el_point_left_index = current_bitstart_index + num_samples_earlylate_wing * 1 - correction_offset; - el_point_mid_index = current_bitstart_index + num_samples_halfbit; + //We always assume that the input starts at center of the first symbol cross before the first symbol. + //Last time we consumed that much from the input samples that it is there. + int correction_offset = state->last_correction_offset; + int current_bitstart_index = 0; + int num_samples_bit = state->decimation_rate; + int num_samples_halfbit = state->decimation_rate / 2; + int num_samples_quarterbit = state->decimation_rate / 4; + int num_samples_earlylate_wing = num_samples_bit * state->earlylate_ratio; + int debug_i = state->debug_count; + float error; + int el_point_left_index, el_point_right_index, el_point_mid_index; + int si = 0; + if(state->debug_force) fprintf(stderr, "disp(\"begin timing_recovery_cc\");\n"); + if(MTIMINGR_HDEBUG) fprintf(stderr, "timing_recovery_cc started, nsb = %d, nshb = %d, nsqb = %d\n", num_samples_bit, num_samples_halfbit, num_samples_quarterbit); + { + for(;;) + { + //the MathWorks style algorithm has correction_offset. + //correction_offset = 0; + if(current_bitstart_index + num_samples_halfbit * 3 >= input_size) break; + if(MTIMINGR_HDEBUG) fprintf(stderr, "current_bitstart_index = %d, input_size = %d, correction_offset(prev) = %d\n", + current_bitstart_index, input_size, correction_offset); + + if(correction_offset<=-num_samples_quarterbit*0.9 || correction_offset>=0.9*num_samples_quarterbit) + { + if(MTIMINGR_HDEBUG) fprintf(stderr, "correction_offset = %d, reset to 0!\n", correction_offset); + correction_offset = 0; + } + //should check if the sign of the correction_offset (or disabling it) has an effect on the EVM. + //it is also a possibility to disable multiplying with the magnitude + if(state->algorithm == TIMING_RECOVERY_ALGORITHM_EARLYLATE) + { + //bitstart index should be at symbol edge, maximum effect point is at current_bitstart_index + num_samples_halfbit + el_point_right_index = current_bitstart_index + num_samples_earlylate_wing * 3; + el_point_left_index = current_bitstart_index + num_samples_earlylate_wing * 1 - correction_offset; + el_point_mid_index = current_bitstart_index + num_samples_halfbit; if(sampled_indexes) sampled_indexes[si]=el_point_mid_index; - output[si++] = input[el_point_mid_index]; - } - else if(state->algorithm == TIMING_RECOVERY_ALGORITHM_GARDNER) - { - //maximum effect point is at current_bitstart_index - el_point_right_index = current_bitstart_index + num_samples_halfbit * 3; - el_point_left_index = current_bitstart_index + num_samples_halfbit * 1; - el_point_mid_index = current_bitstart_index + num_samples_halfbit * 2; + output[si++] = input[el_point_mid_index]; + } + else if(state->algorithm == TIMING_RECOVERY_ALGORITHM_GARDNER) + { + //maximum effect point is at current_bitstart_index + el_point_right_index = current_bitstart_index + num_samples_halfbit * 3; + el_point_left_index = current_bitstart_index + num_samples_halfbit * 1; + el_point_mid_index = current_bitstart_index + num_samples_halfbit * 2; if(sampled_indexes) sampled_indexes[si]=el_point_left_index; - output[si++] = input[el_point_left_index]; - } - else break; + output[si++] = input[el_point_left_index]; + } + else break; - error = ( iof(input, el_point_right_index) - iof(input, el_point_left_index) ) * iof(input, el_point_mid_index); - if(state->use_q) - { - error += ( qof(input, el_point_right_index) - qof(input, el_point_left_index)) * qof(input, el_point_mid_index); - error /= 2; - } - //Original correction method: this version can only move a single sample in any direction - //current_bitstart_index += num_samples_halfbit * 2 + (error)?((error<0)?1:-1):0; + error = ( iof(input, el_point_right_index) - iof(input, el_point_left_index) ) * iof(input, el_point_mid_index); + if(state->use_q) + { + error += ( qof(input, el_point_right_index) - qof(input, el_point_left_index)) * qof(input, el_point_mid_index); + error /= 2; + } + //Original correction method: this version can only move a single sample in any direction + //current_bitstart_index += num_samples_halfbit * 2 + (error)?((error<0)?1:-1):0; if(timing_error) timing_error[si-1]=error; //it is not written if NULL - - if(error>2) error=2; - if(error<-2) error=-2; - if( state->debug_force || (state->debug_phase >= si && debug_i) ) - { - debug_i--; - if(!debug_i) state->debug_phase = -1; - octave_plot_point_on_cplxsig(input+current_bitstart_index, state->decimation_rate*2, - error, - current_bitstart_index, - correction_offset, - state->debug_writefiles, - 3, - el_point_left_index - current_bitstart_index, 'r', - el_point_right_index - current_bitstart_index, 'r', - el_point_mid_index - current_bitstart_index, 'r', - 0); - } - int error_sign = (state->algorithm == TIMING_RECOVERY_ALGORITHM_GARDNER) ? -1 : 1; - correction_offset = num_samples_halfbit * error_sign * (error/2); - current_bitstart_index += num_samples_bit + correction_offset; - if(si>=input_size) - { - if(MTIMINGR_HDEBUG) fprintf(stderr, "oops_out_of_si!\n"); - break; - } - } - } - state->input_processed = current_bitstart_index; - state->output_size = si; - state->last_correction_offset = correction_offset; + + if(error>2) error=2; + if(error<-2) error=-2; + if( state->debug_force || (state->debug_phase >= si && debug_i) ) + { + debug_i--; + if(!debug_i) state->debug_phase = -1; + octave_plot_point_on_cplxsig(input+current_bitstart_index, state->decimation_rate*2, + error, + current_bitstart_index, + correction_offset, + state->debug_writefiles, + 3, + el_point_left_index - current_bitstart_index, 'r', + el_point_right_index - current_bitstart_index, 'r', + el_point_mid_index - current_bitstart_index, 'r', + 0); + } + int error_sign = (state->algorithm == TIMING_RECOVERY_ALGORITHM_GARDNER) ? -1 : 1; + correction_offset = num_samples_halfbit * error_sign * (error/2); + current_bitstart_index += num_samples_bit + correction_offset; + if(si>=input_size) + { + if(MTIMINGR_HDEBUG) fprintf(stderr, "oops_out_of_si!\n"); + break; + } + } + } + state->input_processed = current_bitstart_index; + state->output_size = si; + state->last_correction_offset = correction_offset; } #define MTIMINGR_GAS(NAME) \ - if(!strcmp( #NAME , input )) return TIMING_RECOVERY_ALGORITHM_ ## NAME; + if(!strcmp( #NAME , input )) return TIMING_RECOVERY_ALGORITHM_ ## NAME; timing_recovery_algorithm_t timing_recovery_get_algorithm_from_string(char* input) { - MTIMINGR_GAS(GARDNER); - MTIMINGR_GAS(EARLYLATE); - return TIMING_RECOVERY_ALGORITHM_DEFAULT; + MTIMINGR_GAS(GARDNER); + MTIMINGR_GAS(EARLYLATE); + return TIMING_RECOVERY_ALGORITHM_DEFAULT; } #define MTIMINGR_GSA(NAME) \ - if(algorithm == TIMING_RECOVERY_ALGORITHM_ ## NAME) return #NAME; + if(algorithm == TIMING_RECOVERY_ALGORITHM_ ## NAME) return #NAME; char* timing_recovery_get_string_from_algorithm(timing_recovery_algorithm_t algorithm) { - MTIMINGR_GSA(GARDNER); - MTIMINGR_GSA(EARLYLATE); - return "INVALID"; + MTIMINGR_GSA(GARDNER); + MTIMINGR_GSA(EARLYLATE); + return "INVALID"; } bpsk_costas_loop_state_t init_bpsk_costas_loop_cc(float samples_per_bits) { - bpsk_costas_loop_state_t state; - state.vco_phase = 0; - state.last_vco_phase_addition = 0; - float virtual_sampling_rate = 10000; - float virtual_data_rate = virtual_sampling_rate / samples_per_bits; - fprintf(stderr, "virtual_sampling_rate = %g, virtual_data_rate = %g\n", virtual_sampling_rate, virtual_data_rate); - float rc_filter_cutoff = virtual_data_rate * 2; //this is so far the best - float rc_filter_rc = 1/(2*M_PI*rc_filter_cutoff); //as of Equation 24 in Feigin - float virtual_sampling_dt = 1.0/virtual_sampling_rate; - fprintf(stderr, "rc_filter_cutoff = %g, rc_filter_rc = %g, virtual_sampling_dt = %g\n", - rc_filter_cutoff, rc_filter_rc, virtual_sampling_dt); - state.rc_filter_alpha = virtual_sampling_dt/(rc_filter_rc+virtual_sampling_dt); //https://en.wikipedia.org/wiki/Low-pass_filter - float rc_filter_omega_cutoff = 2*M_PI*rc_filter_cutoff; - state.vco_phase_addition_multiplier = 8*rc_filter_omega_cutoff / (virtual_sampling_rate); //as of Equation 25 in Feigin, assuming input signal amplitude of 1 (to 1V) and (state.vco_phase_addition_multiplier*), a value in radians, will be added to the vco_phase directly. - fprintf(stderr, "rc_filter_alpha = %g, rc_filter_omega_cutoff = %g, vco_phase_addition_multiplier = %g\n", - state.rc_filter_alpha, rc_filter_omega_cutoff, state.vco_phase_addition_multiplier); - return state; + bpsk_costas_loop_state_t state; + state.vco_phase = 0; + state.last_vco_phase_addition = 0; + float virtual_sampling_rate = 10000; + float virtual_data_rate = virtual_sampling_rate / samples_per_bits; + fprintf(stderr, "virtual_sampling_rate = %g, virtual_data_rate = %g\n", virtual_sampling_rate, virtual_data_rate); + float rc_filter_cutoff = virtual_data_rate * 2; //this is so far the best + float rc_filter_rc = 1/(2*M_PI*rc_filter_cutoff); //as of Equation 24 in Feigin + float virtual_sampling_dt = 1.0/virtual_sampling_rate; + fprintf(stderr, "rc_filter_cutoff = %g, rc_filter_rc = %g, virtual_sampling_dt = %g\n", + rc_filter_cutoff, rc_filter_rc, virtual_sampling_dt); + state.rc_filter_alpha = virtual_sampling_dt/(rc_filter_rc+virtual_sampling_dt); //https://en.wikipedia.org/wiki/Low-pass_filter + float rc_filter_omega_cutoff = 2*M_PI*rc_filter_cutoff; + state.vco_phase_addition_multiplier = 8*rc_filter_omega_cutoff / (virtual_sampling_rate); //as of Equation 25 in Feigin, assuming input signal amplitude of 1 (to 1V) and (state.vco_phase_addition_multiplier*), a value in radians, will be added to the vco_phase directly. + fprintf(stderr, "rc_filter_alpha = %g, rc_filter_omega_cutoff = %g, vco_phase_addition_multiplier = %g\n", + state.rc_filter_alpha, rc_filter_omega_cutoff, state.vco_phase_addition_multiplier); + return state; } void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, bpsk_costas_loop_state_t* state) { - int debug = 0; - if(debug) fprintf(stderr, "costas:\n"); - for(int i=0;ivco_phase; - if(debug) fprintf(stderr, "%g | %g\n", input_and_vco_mixed_phase, input_phase), debug--; - complexf input_and_vco_mixed_sample; - e_powj(&input_and_vco_mixed_sample, input_and_vco_mixed_phase); - - complexf vco_sample; - e_powj(&vco_sample, -state->vco_phase); - //cmult(&input_and_vco_mixed_sample, &input[i], &vco_sample);//if this is enabled, the real input sample is used, not the amplitude normalized + int debug = 0; + if(debug) fprintf(stderr, "costas:\n"); + for(int i=0;ivco_phase; + if(debug) fprintf(stderr, "%g | %g\n", input_and_vco_mixed_phase, input_phase), debug--; + complexf input_and_vco_mixed_sample; + e_powj(&input_and_vco_mixed_sample, input_and_vco_mixed_phase); + + complexf vco_sample; + e_powj(&vco_sample, -state->vco_phase); + //cmult(&input_and_vco_mixed_sample, &input[i], &vco_sample);//if this is enabled, the real input sample is used, not the amplitude normalized - float loop_output_i = - input_and_vco_mixed_sample.i * state->rc_filter_alpha + state->last_lpfi_output * (1-state->rc_filter_alpha); - float loop_output_q = - input_and_vco_mixed_sample.q * state->rc_filter_alpha + state->last_lpfq_output * (1-state->rc_filter_alpha); - //loop_output_i = input_and_vco_mixed_sample.i; - //loop_output_q = input_and_vco_mixed_sample.q; - state->last_lpfi_output = loop_output_i; - state->last_lpfq_output = loop_output_q; - float vco_phase_addition = loop_output_i * loop_output_q * state->vco_phase_addition_multiplier; - //vco_phase_addition = vco_phase_addition * state->rc_filter_alpha + state->last_vco_phase_addition * (1-state->rc_filter_alpha); - //state->last_vco_phase_addition = vco_phase_addition; - state->vco_phase += vco_phase_addition; - while(state->vco_phase>PI) state->vco_phase-=2*PI; - while(state->vco_phase<-PI) state->vco_phase+=2*PI; - cmult(&output[i], &input[i], &vco_sample); - } + float loop_output_i = + input_and_vco_mixed_sample.i * state->rc_filter_alpha + state->last_lpfi_output * (1-state->rc_filter_alpha); + float loop_output_q = + input_and_vco_mixed_sample.q * state->rc_filter_alpha + state->last_lpfq_output * (1-state->rc_filter_alpha); + //loop_output_i = input_and_vco_mixed_sample.i; + //loop_output_q = input_and_vco_mixed_sample.q; + state->last_lpfi_output = loop_output_i; + state->last_lpfq_output = loop_output_q; + float vco_phase_addition = loop_output_i * loop_output_q * state->vco_phase_addition_multiplier; + //vco_phase_addition = vco_phase_addition * state->rc_filter_alpha + state->last_vco_phase_addition * (1-state->rc_filter_alpha); + //state->last_vco_phase_addition = vco_phase_addition; + state->vco_phase += vco_phase_addition; + while(state->vco_phase>PI) state->vco_phase-=2*PI; + while(state->vco_phase<-PI) state->vco_phase+=2*PI; + cmult(&output[i], &input[i], &vco_sample); + } } void simple_agc_cc(complexf* input, complexf* output, int input_size, float rate, float reference, float max_gain, float* current_gain) { - float rate_1minus=1-rate; - int debugn = 0; - for(int i=0;imax_gain) ideal_gain = max_gain; - if(ideal_gain<=0) ideal_gain = 0; - //*current_gain += (ideal_gain-(*current_gain))*rate; - *current_gain = (ideal_gain-(*current_gain))*rate + (*current_gain); //*rate_1minus; - //if(debugn<100) fprintf(stderr, "cgain: %g\n", *current_gain), debugn++; - output[i].i=(*current_gain)*input[i].i; - output[i].q=(*current_gain)*input[i].q; - } + float rate_1minus=1-rate; + int debugn = 0; + for(int i=0;imax_gain) ideal_gain = max_gain; + if(ideal_gain<=0) ideal_gain = 0; + //*current_gain += (ideal_gain-(*current_gain))*rate; + *current_gain = (ideal_gain-(*current_gain))*rate + (*current_gain); //*rate_1minus; + //if(debugn<100) fprintf(stderr, "cgain: %g\n", *current_gain), debugn++; + output[i].i=(*current_gain)*input[i].i; + output[i].q=(*current_gain)*input[i].q; + } } void firdes_add_resonator_c(complexf* output, int length, float rate, window_t window, int add, int normalize) { - //add=0: malloc output previously - //add=1: calloc output previously - complexf* taps = (complexf*)malloc(sizeof(complexf)*length); - int middle=length/2; - float phase = 0, phase_addition = -rate*M_PI*2; - float (*window_function)(float) = firdes_get_window_kernel(window); - for(int i=0; i2*M_PI) phase-=2*M_PI; - while(phase<0) phase+=2*M_PI; - } + //add=0: malloc output previously + //add=1: calloc output previously + complexf* taps = (complexf*)malloc(sizeof(complexf)*length); + int middle=length/2; + float phase = 0, phase_addition = -rate*M_PI*2; + float (*window_function)(float) = firdes_get_window_kernel(window); + for(int i=0; i2*M_PI) phase-=2*M_PI; + while(phase<0) phase+=2*M_PI; + } - //Normalize filter kernel - if(add) - for(int i=0;isamples_per_symbol/2) sinearest++; unsigned socorrect = initial_sample_offset+(sinearest*samples_per_symbol); //the sample offset which input[i] should have been, in order to sample at the maximum effect point int sodiff = abs(socorrect-input[i]); - float ndiff = (float)sodiff/samples_per_symbol; + float ndiff = (float)sodiff/samples_per_symbol; ndiff_rad[i] = ndiff*PI; - ndiff_rad_mean = ndiff_rad_mean*(((float)i)/(i+1))+(ndiff_rad[i]/(i+1)); - if(debug_print) fprintf(stderr, "input[%d] = %u, sinearest = %u, socorrect = %u, sodiff = %u, ndiff = %f, ndiff_rad[i] = %f, ndiff_rad_mean = %f\n", i, input[i], sinearest, socorrect, sodiff, ndiff, ndiff_rad[i], ndiff_rad_mean); + ndiff_rad_mean = ndiff_rad_mean*(((float)i)/(i+1))+(ndiff_rad[i]/(i+1)); + if(debug_print) fprintf(stderr, "input[%d] = %u, sinearest = %u, socorrect = %u, sodiff = %u, ndiff = %f, ndiff_rad[i] = %f, ndiff_rad_mean = %f\n", i, input[i], sinearest, socorrect, sodiff, ndiff, ndiff_rad[i], ndiff_rad_mean); } - fprintf(stderr, "ndiff_rad_mean = %f\n", ndiff_rad_mean); + fprintf(stderr, "ndiff_rad_mean = %f\n", ndiff_rad_mean); float result = 0; - for(int i=0;i convert_u8_f + for(int i=0;i convert_u8_f } void convert_f_s8(float* input, signed char* output, int input_size) { - for(int i=0;i1.0) input[i]=1.0; - if(input[i]<-1.0) input[i]=-1.0; - }*/ - for(int i=0;i1.0) input[i]=1.0; + if(input[i]<-1.0) input[i]=-1.0; + }*/ + for(int i=0;i>8); - unsigned char* ptemp=(unsigned char*)&temp; - output[k++]=*ptemp; - output[k++]=*(ptemp+1); - output[k++]=*(ptemp+2); - } - else for(int i=0;i>8); - unsigned char* ptemp=(unsigned char*)&temp; - output[k++]=*(ptemp+2); - output[k++]=*(ptemp+1); - output[k++]=*ptemp; - } + int k=0; + if(bigendian) for(int i=0;i>8); + unsigned char* ptemp=(unsigned char*)&temp; + output[k++]=*ptemp; + output[k++]=*(ptemp+1); + output[k++]=*(ptemp+2); + } + else for(int i=0;i>8); + unsigned char* ptemp=(unsigned char*)&temp; + output[k++]=*(ptemp+2); + output[k++]=*(ptemp+1); + output[k++]=*ptemp; + } } void convert_s24_f(unsigned char* input, float* output, int input_size, int bigendian) { - int k=0; - if(bigendian) for(int i=0;i Date: Sun, 30 Apr 2017 17:51:35 +0200 Subject: [PATCH 088/111] Added matched filter --- csdr.c | 70 +++++++++++++++++++++++++++++++++------ libcsdr.c | 99 +++++++++++++++++++++++++++++++++++++++++++------------ libcsdr.h | 14 ++++++++ 3 files changed, 152 insertions(+), 31 deletions(-) diff --git a/csdr.c b/csdr.c index 52f1c66..0c415ee 100755 --- a/csdr.c +++ b/csdr.c @@ -3030,26 +3030,76 @@ int main(int argc, char *argv[]) fwrite(zeros, sizeof(float), n_zero_samples, stdout); clone_(the_bufsize); } -/* - if(!strcmp(argv[1], "matched_filter_cc")) // + + int matched_filter_which = 0; + if( + (!strcmp(argv[1], "firdes_matched_filter_f") && (matched_filter_which = 1)) || + (!strcmp(argv[1], "matched_filter_cc") && (matched_filter_which = 2)) + ) //(RRC | COSINE ) { + if(argc<=2) return badsyntax("required parameter is missing."); + matched_filter_type_t type = matched_filter_get_type_from_string(argv[2]); int samples_per_symbol = 0; - if(argc<=2) return badsyntax("required parameter is missing."); - sscanf(argv[2],"%d",&samples_per_symbol); + + if(argc<=3) return badsyntax("required parameter is missing."); + sscanf(argv[3],"%d",&samples_per_symbol); + int num_taps = 0; - if(argc<=2) return badsyntax("required parameter is missing."); - sscanf(argv[2],"%d",&num_taps); + if(argc<=4 && type!=MATCHED_FILTER_COSINE) + return badsyntax("required parameter is missing."); + sscanf(argv[4],"%d",&num_taps); + + float beta = 0; + if(argc<=5 && type==MATCHED_FILTER_RRC) + return badsyntax("required parameter is missing."); + sscanf(argv[5],"%f",&beta); + + if(type==MATCHED_FILTER_COSINE) num_taps = (2*samples_per_symbol)+1; + float* taps = (float*)malloc(sizeof(float)*num_taps); + switch(type) + { + case MATCHED_FILTER_RRC: + firdes_rrc_f(taps, num_taps, samples_per_symbol, beta); + break; + case MATCHED_FILTER_COSINE: + firdes_cosine_f(taps, num_taps, samples_per_symbol); + break; + } + + if(!sendbufsize(initialize_buffers())) return -2; + + if(matched_filter_which==1) + { + for(int i=0;i + { + int n_symbols = 0; + if(argc<=2) return badsyntax("required parameter is missing."); + sscanf(argv[2],"%d",&n_symbols); if(!sendbufsize(initialize_buffers())) return -2; for(;;) { FEOF_CHECK; - FREAD_C; - - FWRITE_C; + if(!FREAD_R) break; + generic_slicer_f_u8(input_buffer, (unsigned char*)output_buffer, the_bufsize, n_symbols); + FWRITE_U8; TRY_YIELD; } + return 0; } -*/ if(!strcmp(argv[1],"none")) { diff --git a/libcsdr.c b/libcsdr.c index f2ea3e8..89e4b10 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -1721,6 +1721,33 @@ void serial_line_decoder_f_u8(serial_line_t* s, float* input, unsigned char* out DEBUG_SERIAL_LINE_DECODER && fprintf(stderr, "sld: >> output_size = %d (+%d)\n", s->output_size, s->input_used); } +void generic_slicer_f_u8(float* input, unsigned char* output, int input_size, int n_symbols) +{ + float symbol_distance = 2.0/(n_symbols+1); + for(int i=0;i=symbol_low_limit) output[i]=j; + break; + } + else + { + if(input[i]>=symbol_low_limit && input[i] 0; @@ -2169,6 +2196,24 @@ int apply_fir_cc(complexf* input, complexf* output, int input_size, complexf* ta return i; } + +int apply_real_fir_cc(complexf* input, complexf* output, int input_size, float* taps, int taps_length) +{ + int i; + for(i=0; i1); - iof(output, i)=(1/0.82)*iof(output, i); - qof(output, i)=(1/0.82)*qof(output, i); - } -} -*/ - - int deinit_get_random_samples_f(FILE* status) { return fclose(status); } +int firdes_cosine_f(float* taps, int taps_length, int samples_per_symbol) +{ + //needs a taps_length 2 × samples_per_symbol + 1 + int middle_i=taps_length/2; + for(int i=0;i Date: Sun, 30 Apr 2017 22:23:21 +0200 Subject: [PATCH 089/111] Working RRC filter design --- csdr.c | 21 +++++++++++++-------- libcsdr.c | 8 ++++---- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/csdr.c b/csdr.c index 0c415ee..5cc9f15 100755 --- a/csdr.c +++ b/csdr.c @@ -3039,22 +3039,26 @@ int main(int argc, char *argv[]) { if(argc<=2) return badsyntax("required parameter is missing."); matched_filter_type_t type = matched_filter_get_type_from_string(argv[2]); - int samples_per_symbol = 0; + int samples_per_symbol = 0; if(argc<=3) return badsyntax("required parameter is missing."); sscanf(argv[3],"%d",&samples_per_symbol); int num_taps = 0; - if(argc<=4 && type!=MATCHED_FILTER_COSINE) - return badsyntax("required parameter is missing."); - sscanf(argv[4],"%d",&num_taps); + if(type!=MATCHED_FILTER_COSINE) + { + if(argc<=4) return badsyntax("required parameter is missing."); + sscanf(argv[4],"%d",&num_taps); + } + else num_taps = (2*samples_per_symbol)+1; float beta = 0; - if(argc<=5 && type==MATCHED_FILTER_RRC) - return badsyntax("required parameter is missing."); - sscanf(argv[5],"%f",&beta); + if(type==MATCHED_FILTER_RRC) + { + if(argc<=5) return badsyntax("required parameter is missing."); + sscanf(argv[5],"%f",&beta); + } - if(type==MATCHED_FILTER_COSINE) num_taps = (2*samples_per_symbol)+1; float* taps = (float*)malloc(sizeof(float)*num_taps); switch(type) { @@ -3065,6 +3069,7 @@ int main(int argc, char *argv[]) firdes_cosine_f(taps, num_taps, samples_per_symbol); break; } + //fprintf(stderr, "beta = %f, num_taps = %d, samples_per_symbol = %d\n", beta, num_taps, samples_per_symbol); if(!sendbufsize(initialize_buffers())) return -2; diff --git a/libcsdr.c b/libcsdr.c index 89e4b10..ced77c1 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -2371,13 +2371,13 @@ int firdes_rrc_f(float* taps, int taps_length, int samples_per_symbol, float bet { //needs an odd taps_length int middle_i=taps_length/2; - taps[middle_i]=(1/samples_per_symbol)*(1+beta*(4/PI-1)); - for(int i=1;i Date: Mon, 1 May 2017 13:09:42 +0200 Subject: [PATCH 090/111] Added plain_interpolate_cc --- csdr.c | 22 ++++++++++++++++++++++ libcsdr.c | 10 ++++++++++ libcsdr.h | 1 + 3 files changed, 33 insertions(+) diff --git a/csdr.c b/csdr.c index 5cc9f15..feff244 100755 --- a/csdr.c +++ b/csdr.c @@ -143,7 +143,11 @@ char usage[]= " gaussian_noise_c\n" " awgn_cc [--snrshow]\n" " pack_bits_8to1_u8_u8\n" +" firdes_matched_filter_f (RRC | COSINE )\n" +" matched_filter_cc (RRC | COSINE )\n" " add_n_zero_samples_at_beginning_f \n" +" generic_slicer_f_u8 \n" +" plain_interpolate_cc \n" " ?\n" " =\n" " \n" @@ -3106,6 +3110,24 @@ int main(int argc, char *argv[]) return 0; } + if(!strcmp(argv[1], "plain_interpolate_cc")) // + { + int interpolation = 0; + if(argc<=2) return badsyntax("required parameter is missing."); + sscanf(argv[2],"%d",&interpolation); + if(!sendbufsize(interpolation*initialize_buffers())) return -2; + complexf* plainint_output_buffer = (complexf*)malloc(sizeof(complexf)*the_bufsize*interpolation); + for(;;) + { + FEOF_CHECK; + FREAD_C; + plain_interpolate_cc((complexf*)input_buffer, plainint_output_buffer, the_bufsize, interpolation); + fwrite(plainint_output_buffer, sizeof(float)*2, the_bufsize*interpolation, stdout); + TRY_YIELD; + } + return 0; + } + if(!strcmp(argv[1],"none")) { return 0; diff --git a/libcsdr.c b/libcsdr.c index ced77c1..15a147b 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -2383,6 +2383,15 @@ int firdes_rrc_f(float* taps, int taps_length, int samples_per_symbol, float bet } } +void plain_interpolate_cc(complexf* input, complexf* output, int input_size, int interpolation) +{ + for(int i=0;i Date: Tue, 2 May 2017 18:37:54 +0200 Subject: [PATCH 091/111] Made new bpsk_costas_loop_cc, added add_const_cc, added new parameters to timing_recvery_cc --- Makefile | 2 + csdr.c | 77 ++- grc_tests/test_bpsk_costas_loop.grc | 756 ++++++---------------------- libcsdr.c | 94 +++- libcsdr.h | 23 +- 5 files changed, 302 insertions(+), 650 deletions(-) diff --git a/Makefile b/Makefile index dfe3df2..905bf3a 100644 --- a/Makefile +++ b/Makefile @@ -98,3 +98,5 @@ emcc-beautify: bash -c 'type js-beautify >/dev/null 2>&1; if [ $$? -eq 0 ]; then js-beautify sdr.js/sdr.js >sdr.js/sdr.js.beautiful; mv sdr.js/sdr.js.beautiful sdr.js/sdr.js; fi' codequality: @bash -c 'if [ `cat csdr.c | grep badsyntax | grep -v return | wc -l` -ne 1 ]; then echo "error at code quality check: badsyntax() used in csdr.c without return."; exit 1; else exit 0; fi' +v: + vim csdr.c libcsdr.c diff --git a/csdr.c b/csdr.c index feff244..2951d8f 100755 --- a/csdr.c +++ b/csdr.c @@ -124,7 +124,7 @@ char usage[]= " rtty_baudot2ascii_u8_u8\n" " serial_line_decoder_u8_u8\n" " octave_complex_c \n" -" timing_recovery_cc [--add_q [--output_error | --output_indexes | --octave ]] \n" +" timing_recovery_cc [mu [--add_q [--output_error | --output_indexes | --octave ]]] \n" " psk31_varicode_encoder_u8_u8\n" " psk31_varicode_decoder_u8_u8\n" " differential_encoder_u8_u8\n" @@ -133,7 +133,7 @@ char usage[]= " psk_modulator_u8_c \n" " psk31_interpolate_sine_cc \n" " duplicate_samples_ntimes_u8_u8 \n" -" bpsk_costas_loop_cc \n" +" bpsk_costas_loop_cc [--dd | --decision_directed]\n" " binary_slicer_f_u8\n" " simple_agc_cc [reference [max_gain]]\n" " firdes_resonator_c [window [--octave]]\n" @@ -148,6 +148,7 @@ char usage[]= " add_n_zero_samples_at_beginning_f \n" " generic_slicer_f_u8 \n" " plain_interpolate_cc \n" +" add_const_cc \n" " ?\n" " =\n" " \n" @@ -396,7 +397,7 @@ int main(int argc, char *argv[]) clone_(the_bufsize); //After sending the buffer size out, just copy stdin to stdout } - if(!strcmp(argv[1],"clone")) + if(!strcmp(argv[1],"clone") || !strcmp(argv[1],"REM")) { if(!sendbufsize(initialize_buffers())) return -2; clone_(the_bufsize); @@ -2525,7 +2526,7 @@ int main(int argc, char *argv[]) } } - if(!strcmp(argv[1],"timing_recovery_cc")) // [--add_q [--output_error | --output_indexes | --octave ]] + if(!strcmp(argv[1],"timing_recovery_cc")) // [loop_gain [max_error [--add_q] [--output_error | --output_indexes | --octave ]]] { if(argc<=2) return badsyntax("need required parameter (algorithm)"); timing_recovery_algorithm_t algorithm = timing_recovery_get_algorithm_from_string(argv[2]); @@ -2536,26 +2537,32 @@ int main(int argc, char *argv[]) sscanf(argv[3],"%d",&decimation); if(decimation<=4 || decimation&3) return badsyntax("decimation factor should be a positive integer divisible by 4"); - int add_q = (argc>=5 && !strcmp(argv[4], "--add_q")); + float loop_gain = 0.5; + if(argc>4) sscanf(argv[4],"%f",&loop_gain); + + float max_error = 2; + if(argc>5) sscanf(argv[5],"%f",&max_error); + + int add_q = !!(argc>=7 && !strcmp(argv[6], "--add_q")); int debug_n = 0; int output_error = 0; int output_indexes = 0; - if(argc>=7 && !strcmp(argv[5], "--octave")) debug_n = atoi(argv[6]); + if(argc+add_q>=8 && !strcmp(argv[6+add_q], "--octave")) debug_n = atoi(argv[7+add_q]); if(debug_n<0) return badsyntax("debug_n should be >= 0"); - if(argc>=6 && !strcmp(argv[5], "--output_error")) output_error = 1; + if(argc>=(8+add_q) && !strcmp(argv[7+add_q], "--output_error")) output_error = 1; float* timing_error = NULL; if(output_error) timing_error = (float*)malloc(sizeof(float)*the_bufsize); - if(argc>=6 && !strcmp(argv[5], "--output_indexes")) output_indexes = 1; + if(argc>=(8+add_q) && !strcmp(argv[7+add_q], "--output_indexes")) output_indexes = 1; unsigned* sampled_indexes = NULL; if(output_indexes) sampled_indexes = (unsigned*)malloc(sizeof(float)*the_bufsize); if(!initialize_buffers()) return -2; sendbufsize(the_bufsize/decimation); - timing_recovery_state_t state = timing_recovery_init(algorithm, decimation, add_q); + timing_recovery_state_t state = timing_recovery_init(algorithm, decimation, add_q, loop_gain, max_error); int debug_i=0; state.debug_writefiles = 1; @@ -2756,14 +2763,24 @@ int main(int argc, char *argv[]) } } - if(!strcmp(argv[1],"bpsk_costas_loop_cc")) // + if(!strcmp(argv[1],"bpsk_costas_loop_cc")) // [--dd | --decision_directed] { - float samples_per_bits; - if(argc<=2) return badsyntax("need required parameter (samples_per_bits)"); - sscanf(argv[2],"%f",&samples_per_bits); - if(samples_per_bits<=0) return badsyntax("samples_per_bits should be > 0"); + float loop_bandwidth; + if(argc<=2) return badsyntax("need required parameter (loop_bandwidth)"); + sscanf(argv[2],"%f",&loop_bandwidth); - bpsk_costas_loop_state_t state = init_bpsk_costas_loop_cc(samples_per_bits); + float damping_factor; + if(argc<=3) return badsyntax("need required parameter (damping_factor)"); + sscanf(argv[3],"%f",&damping_factor); + + float gain; + if(argc<=4) return badsyntax("need required parameter (gain)"); + sscanf(argv[4],"%f",&gain); + + int decision_directed = !!(argc>5 && (!strcmp(argv[5], "--dd") || !strcmp(argv[5], "--decision_directed"))); + + bpsk_costas_loop_state_t state; + init_bpsk_costas_loop_cc(&state, decision_directed, damping_factor, loop_bandwidth, gain); if(!initialize_buffers()) return -2; sendbufsize(the_bufsize); @@ -3083,13 +3100,17 @@ int main(int argc, char *argv[]) return 0; } + int output_size=0; + FREAD_C; for(;;) { FEOF_CHECK; - FREAD_C; - apply_real_fir_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, taps, num_taps); - FWRITE_C; + output_size = apply_real_fir_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, taps, num_taps); + fwrite(output_buffer, sizeof(complexf), output_size, stdout); + //fprintf(stderr, "os = %d, is = %d, num_taps = %d\n", output_size, the_bufsize, num_taps); TRY_YIELD; + memmove((complexf*)input_buffer,((complexf*)input_buffer)+output_size,(the_bufsize-output_size)*sizeof(complexf)); + fread(((complexf*)input_buffer)+(the_bufsize-output_size), sizeof(complexf), output_size, stdin); } } @@ -3128,6 +3149,26 @@ int main(int argc, char *argv[]) return 0; } + if(!strcmp(argv[1], "add_const_cc")) // + { + complexf x; + if(argc<=2) return badsyntax("required parameter is missing."); + sscanf(argv[2],"%f",&iofv(x)); + if(argc<=2) return badsyntax("required parameter is missing."); + sscanf(argv[2],"%f",&qofv(x)); + + if(!sendbufsize(initialize_buffers())) return -2; + for(;;) + { + FEOF_CHECK; + FREAD_C; + add_const_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, x); + FWRITE_C; + TRY_YIELD; + } + return 0; + } + if(!strcmp(argv[1],"none")) { return 0; diff --git a/grc_tests/test_bpsk_costas_loop.grc b/grc_tests/test_bpsk_costas_loop.grc index 9d2262e..0abca69 100644 --- a/grc_tests/test_bpsk_costas_loop.grc +++ b/grc_tests/test_bpsk_costas_loop.grc @@ -89,7 +89,7 @@ _coordinate - (480, 3) + (416, 3) _rotation @@ -207,7 +207,7 @@ _coordinate - (712, 571) + (32, 275) _rotation @@ -235,7 +235,7 @@ notebook - nb, 1 + num_steps @@ -270,7 +270,54 @@ value - 2**18 + 2**13 + + + + analog_const_source_x + + alias + + + + comment + + + + const + 0 + + + affinity + + + + _enabled + True + + + _coordinate + (288, 203) + + + _rotation + 0 + + + id + analog_const_source_x_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + float @@ -293,7 +340,7 @@ _coordinate - (16, 187) + (40, 147) _rotation @@ -325,7 +372,7 @@ type - byte + int repeat @@ -333,7 +380,7 @@ - blocks_complex_to_float + blocks_add_const_vxx alias @@ -343,51 +390,8 @@ - affinity - - - - _enabled - 0 - - - _coordinate - (960, 265) - - - _rotation - 0 - - - id - blocks_complex_to_float_0 - - - maxoutbuf - 0 - - - minoutbuf - 0 - - - vlen - 1 - - - - blocks_interleave - - alias - - - - blocksize - 1 - - - comment - + const + -1 affinity @@ -395,11 +399,11 @@ _enabled - 0 + True _coordinate - (1168, 265) + (336, 131) _rotation @@ -407,7 +411,7 @@ id - blocks_interleave_0 + blocks_add_const_vxx_0 type @@ -421,17 +425,13 @@ minoutbuf 0 - - num_streams - 2 - vlen 1 - blocks_multiply_const_vxx + blocks_float_to_complex alias @@ -440,10 +440,6 @@ comment - - const - amplitude - affinity @@ -454,7 +450,7 @@ _coordinate - (496, 155) + (496, 161) _rotation @@ -462,11 +458,7 @@ id - blocks_multiply_const_vxx_0 - - - type - complex + blocks_float_to_complex_0 maxoutbuf @@ -481,6 +473,53 @@ 1 + + blocks_int_to_float + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (200, 131) + + + _rotation + 0 + + + id + blocks_int_to_float_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + scale + 0.5 + + + vlen + 1 + + blocks_throttle @@ -501,7 +540,7 @@ _coordinate - (488, 211) + (496, 355) _rotation @@ -556,7 +595,7 @@ _coordinate - (928, 537) + (864, 345) _rotation @@ -587,73 +626,6 @@ False - - digital_psk_mod - - alias - - - - comment - - - - affinity - - - - differential - True - - - _enabled - True - - - excess_bw - 0.35 - - - _coordinate - (208, 179) - - - _rotation - 0 - - - mod_code - "none" - - - id - digital_psk_mod_0 - - - log - False - - - maxoutbuf - 0 - - - minoutbuf - 0 - - - constellation_points - 2 - - - samples_per_symbol - 2 - - - verbose - False - - freq_xlating_fir_filter_xxx @@ -662,7 +634,7 @@ center_freq - -freq_add + freq_add comment @@ -678,11 +650,11 @@ _enabled - 1 + True _coordinate - (688, 251) + (232, 331) _rotation @@ -713,41 +685,6 @@ ccc - - ha5kfu_execproc_sink_f - - alias - - - - commandline - zsh -c \"csdr timing_recovery_cc GARDNER 16 --add_q --octave 1 1>/dev/null 2> >(octave -i)\" - - - comment - - - - affinity - - - - _enabled - 0 - - - _coordinate - (976, 379) - - - _rotation - 0 - - - id - ha5kfu_execproc_sink_f_0 - - ha5kfu_execproc_xx @@ -756,7 +693,7 @@ commandline - csdr bpsk_costas_loop_cc 16 + csdr bpsk_costas_loop_cc $(csdr =2*pi/100) 0.707 1 comment @@ -772,7 +709,7 @@ _coordinate - (128, 411) + (840, 163) _rotation @@ -795,286 +732,6 @@ cc - - ha5kfu_execproc_xx - - alias - - - - commandline - csdr timing_recovery_cc GARDNER 16 --add_q | csdr fir_interpolate_cc 8 - - - comment - - - - affinity - - - - _enabled - 0 - - - _coordinate - (400, 411) - - - _rotation - 0 - - - id - ha5kfu_execproc_xx_0_0 - - - maxoutbuf - 0 - - - minoutbuf - 0 - - - type - cc - - - - notebook - - alias - - - - comment - - - - _enabled - True - - - _coordinate - (16, 83) - - - _rotation - 0 - - - grid_pos - - - - id - nb - - - labels - ['1', '2'] - - - notebook - - - - style - wx.NB_TOP - - - - wxgui_fftsink2 - - avg_alpha - 0 - - - average - False - - - baseband_freq - 0 - - - alias - - - - comment - - - - affinity - - - - _enabled - 0 - - - fft_size - 1024 - - - freqvar - None - - - _coordinate - (960, 59) - - - _rotation - 0 - - - grid_pos - - - - id - wxgui_fftsink2_0 - - - notebook - - - - peak_hold - False - - - ref_level - 0 - - - ref_scale - 2.0 - - - fft_rate - 15 - - - samp_rate - samp_rate - - - title - FFT Plot - - - type - complex - - - win_size - - - - win - None - - - y_divs - 10 - - - y_per_div - 10 - - - - wxgui_scopesink2 - - ac_couple - False - - - alias - - - - comment - - - - affinity - - - - _enabled - 0 - - - _coordinate - (632, 379) - - - _rotation - 0 - - - grid_pos - - - - id - wxgui_scopesink2_0 - - - notebook - - - - num_inputs - 1 - - - samp_rate - (samp_rate/256)*8 - - - t_scale - 0 - - - title - After timing recovery - - - trig_mode - wxgui.TRIG_MODE_AUTO - - - type - complex - - - v_offset - 0 - - - v_scale - 0 - - - win_size - - - - xy_mode - True - - - y_axis_label - Counts - - wxgui_scopesink2 @@ -1099,7 +756,7 @@ _coordinate - (432, 507) + (1104, 123) _rotation @@ -1115,7 +772,7 @@ notebook - nb, 0 + num_inputs @@ -1123,7 +780,7 @@ samp_rate - (samp_rate/256)*8 + samp_rate t_scale @@ -1131,7 +788,7 @@ title - BPSK modulated signal after Costas Loop + After Costas Loop (csdr) trig_mode @@ -1186,7 +843,7 @@ _coordinate - (1112, 491) + (1112, 299) _rotation @@ -1200,93 +857,6 @@ id wxgui_scopesink2_0_0_0 - - notebook - nb, 1 - - - num_inputs - 1 - - - samp_rate - (samp_rate/256)*8 - - - t_scale - 0 - - - title - After Costas Loop - - - trig_mode - wxgui.TRIG_MODE_AUTO - - - type - complex - - - v_offset - 0 - - - v_scale - 0 - - - win_size - - - - xy_mode - True - - - y_axis_label - Counts - - - - wxgui_scopesink2 - - ac_couple - False - - - alias - - - - comment - - - - affinity - - - - _enabled - True - - - _coordinate - (688, 11) - - - _rotation - 0 - - - grid_pos - - - - id - wxgui_scopesink2_0_1 - notebook @@ -1305,7 +875,7 @@ title - BPSK modulated signal with frequency offset + After Costas Loop (GNU Radio) trig_mode @@ -1329,7 +899,7 @@ xy_mode - False + True y_axis_label @@ -1337,38 +907,44 @@ - analog_random_source_x_0 - digital_psk_mod_0 + analog_const_source_x_0 + blocks_float_to_complex_0 0 - 0 - - - blocks_complex_to_float_0 - blocks_interleave_0 - 1 1 - blocks_complex_to_float_0 - blocks_interleave_0 + analog_random_source_x_0 + blocks_int_to_float_0 0 0 - blocks_interleave_0 - ha5kfu_execproc_sink_f_0 + blocks_add_const_vxx_0 + blocks_float_to_complex_0 0 0 - blocks_multiply_const_vxx_0 - blocks_throttle_0 + blocks_float_to_complex_0 + freq_xlating_fir_filter_xxx_0 + 0 + 0 + + + blocks_int_to_float_0 + blocks_add_const_vxx_0 0 0 blocks_throttle_0 - freq_xlating_fir_filter_xxx_0 + digital_costas_loop_cc_0 + 0 + 0 + + + blocks_throttle_0 + ha5kfu_execproc_xx_0 0 0 @@ -1378,45 +954,9 @@ 0 0 - - digital_psk_mod_0 - blocks_multiply_const_vxx_0 - 0 - 0 - freq_xlating_fir_filter_xxx_0 - blocks_complex_to_float_0 - 0 - 0 - - - freq_xlating_fir_filter_xxx_0 - digital_costas_loop_cc_0 - 0 - 0 - - - freq_xlating_fir_filter_xxx_0 - ha5kfu_execproc_xx_0 - 0 - 0 - - - freq_xlating_fir_filter_xxx_0 - wxgui_fftsink2_0 - 0 - 0 - - - freq_xlating_fir_filter_xxx_0 - wxgui_scopesink2_0_1 - 0 - 0 - - - ha5kfu_execproc_xx_0 - ha5kfu_execproc_xx_0_0 + blocks_throttle_0 0 0 @@ -1426,10 +966,4 @@ 0 0 - - ha5kfu_execproc_xx_0_0 - wxgui_scopesink2_0 - 0 - 0 - diff --git a/libcsdr.c b/libcsdr.c index 15a147b..d06bb5d 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -114,6 +114,16 @@ float (*firdes_get_window_kernel(window_t window))(float) |___/ */ +void normalize_fir_f(float* input, float* output, int length) +{ + //Normalize filter kernel + float sum=0; + for(int i=0;i2) error=2; - if(error<-2) error=-2; + if(error>state->max_error) error=state->max_error; + if(error<-state->max_error) error=-state->max_error; if( state->debug_force || (state->debug_phase >= si && debug_i) ) { debug_i--; @@ -2033,7 +2035,7 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, float 0); } int error_sign = (state->algorithm == TIMING_RECOVERY_ALGORITHM_GARDNER) ? -1 : 1; - correction_offset = num_samples_halfbit * error_sign * (error/2); + correction_offset = num_samples_halfbit * error_sign * error * state->loop_gain; current_bitstart_index += num_samples_bit + correction_offset; if(si>=input_size) { @@ -2067,6 +2069,45 @@ char* timing_recovery_get_string_from_algorithm(timing_recovery_algorithm_t algo return "INVALID"; } +void init_bpsk_costas_loop_cc(bpsk_costas_loop_state_t* s, int decision_directed, float damping_factor, float bandwidth, float gain) +{ + float bandwidth_omega = 2*M_PI*bandwidth; + s->alpha = (damping_factor*2*bandwidth_omega)/gain; + float sampling_rate = 1; //the bandwidth is normalized to the sampling rate + s->beta = (bandwidth_omega*bandwidth_omega)/(sampling_rate*gain); + s->iir_temp = s->dphase = s->nco_phase = 0; +} + +void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, bpsk_costas_loop_state_t* s) +{ + for(int i=0;inco_phase); + cmult(&output[i], &input[i], &nco_sample); + float error = 0; + if(s->decision_directed) + { + float output_phase = atan2(qof(output,i),iof(output,i)); + if (fabs(output_phase)PI) error -= 2*PI; + } + } + else error = iof(output,i)*qof(output,i); + s->dphase = error * s->alpha + s->iir_temp; + s->iir_temp += error * s->beta; + + //step NCO + s->nco_phase += s->dphase; + while(s->nco_phase>2*PI) s->nco_phase-=2*PI; + } +} + +#if 0 bpsk_costas_loop_state_t init_bpsk_costas_loop_cc(float samples_per_bits) { bpsk_costas_loop_state_t state; @@ -2088,7 +2129,7 @@ bpsk_costas_loop_state_t init_bpsk_costas_loop_cc(float samples_per_bits) return state; } -void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, bpsk_costas_loop_state_t* state) +void bpsk_costas_loop_c1mc(complexf* input, complexf* output, int input_size, bpsk_costas_loop_state_t* state) { int debug = 0; if(debug) fprintf(stderr, "costas:\n"); @@ -2122,6 +2163,8 @@ void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, bpsk } } +#endif + void simple_agc_cc(complexf* input, complexf* output, int input_size, float rate, float reference, float max_gain, float* current_gain) { float rate_1minus=1-rate; @@ -2205,8 +2248,8 @@ int apply_real_fir_cc(complexf* input, complexf* output, int input_size, float* float acci = 0, accq = 0; for(int ti=0;ti Date: Tue, 2 May 2017 19:23:05 +0200 Subject: [PATCH 092/111] Working bpsk_costas_loop_cc --- csdr.c | 1 + grc_tests/test_bpsk_costas_loop.grc | 6 +++--- libcsdr.c | 2 ++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/csdr.c b/csdr.c index 2951d8f..3a78c2b 100755 --- a/csdr.c +++ b/csdr.c @@ -2778,6 +2778,7 @@ int main(int argc, char *argv[]) sscanf(argv[4],"%f",&gain); int decision_directed = !!(argc>5 && (!strcmp(argv[5], "--dd") || !strcmp(argv[5], "--decision_directed"))); + if(decision_directed) fprintf(stderr, "csdr bpsk_costas_loop_cc: decision directed mode\n"); bpsk_costas_loop_state_t state; init_bpsk_costas_loop_cc(&state, decision_directed, damping_factor, loop_bandwidth, gain); diff --git a/grc_tests/test_bpsk_costas_loop.grc b/grc_tests/test_bpsk_costas_loop.grc index 0abca69..b8d1183 100644 --- a/grc_tests/test_bpsk_costas_loop.grc +++ b/grc_tests/test_bpsk_costas_loop.grc @@ -140,7 +140,7 @@ value - 0 + 10 _enabled @@ -180,7 +180,7 @@ num_steps - 100 + 1000 style @@ -693,7 +693,7 @@ commandline - csdr bpsk_costas_loop_cc $(csdr =2*pi/100) 0.707 1 + csdr bpsk_costas_loop_cc $(csdr =2*pi/100) 0.707 300 --dd 2>/tmp/cout comment diff --git a/libcsdr.c b/libcsdr.c index d06bb5d..436c589 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -2100,10 +2100,12 @@ void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, bpsk else error = iof(output,i)*qof(output,i); s->dphase = error * s->alpha + s->iir_temp; s->iir_temp += error * s->beta; + fprintf(stderr, " error = %f, dphase = %f, nco_phase = %f\n", error, s->dphase, s->nco_phase); //step NCO s->nco_phase += s->dphase; while(s->nco_phase>2*PI) s->nco_phase-=2*PI; + while(s->nco_phase<=0) s->nco_phase+=2*PI; } } From ac8e1b61b4ab35ab0290633d7c7f875fbb23df1c Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Tue, 2 May 2017 19:31:29 +0200 Subject: [PATCH 093/111] bpsk_costas_loop_cc now locks to +1+0j and -1+0j --- grc_tests/test_bpsk_costas_loop.grc | 2 +- libcsdr.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/grc_tests/test_bpsk_costas_loop.grc b/grc_tests/test_bpsk_costas_loop.grc index b8d1183..bb240e3 100644 --- a/grc_tests/test_bpsk_costas_loop.grc +++ b/grc_tests/test_bpsk_costas_loop.grc @@ -693,7 +693,7 @@ commandline - csdr bpsk_costas_loop_cc $(csdr =2*pi/100) 0.707 300 --dd 2>/tmp/cout + csdr bpsk_costas_loop_cc $(csdr =2*pi/100) 0.707 5 2>/tmp/cout comment diff --git a/libcsdr.c b/libcsdr.c index 436c589..5cb67d7 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -2083,7 +2083,7 @@ void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, bpsk for(int i=0;inco_phase); + e_powj(&nco_sample, s->nco_phase); cmult(&output[i], &input[i], &nco_sample); float error = 0; if(s->decision_directed) From d526744d0c236c29fbcf3750f98019abb76af07a Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Fri, 5 May 2017 11:34:40 +0200 Subject: [PATCH 094/111] Added "csdr tee" and unified how csdr messages start --- csdr.c | 173 ++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 117 insertions(+), 56 deletions(-) diff --git a/csdr.c b/csdr.c index d893364..78764e5 100755 --- a/csdr.c +++ b/csdr.c @@ -152,6 +152,7 @@ char usage[]= " generic_slicer_f_u8 \n" " plain_interpolate_cc \n" " add_const_cc \n" +" tee [buffers]\n" " ?\n" " =\n" " \n" @@ -175,10 +176,22 @@ int bigbufs = 0; #define TRY_YIELD fflush(stdout);sched_yield() //unsigned yield_counter=0; +char **argv_global; +int argc_global; + +int errhead() +{ + fprintf(stderr, "%s%s%s: ", argv_global[0], ((argc_global>=2)?" ":""), ((argc_global>=2)?argv_global[1]:"")); +} + int badsyntax(char* why) { if(why==0) fprintf(stderr, "%s", usage); - else fprintf(stderr, "csdr: %s\n\n", why); + else + { + errhead(); + fprintf(stderr, "%s\n", why); + } return -1; } @@ -186,8 +199,8 @@ int clipdetect_ff(float* input, int input_size) { for(int i=0;i1.0) { fprintf(stderr, "csdr clipdetect_ff: Signal value above 1.0!\n"); return 1; } + if(input[i]<-1.0) { errhead(); fprintf(stderr, "Signal value below -1.0!\n"); return -1; } + if(input[i]>1.0) { errhead(); fprintf(stderr, "Signal value above 1.0!\n"); return 1; } } return 0; } @@ -220,7 +233,7 @@ int init_fifo(int argc, char *argv[]) { if(!strcmp(argv[2],"--fifo")) { - fprintf(stderr,"csdr: fifo control mode on\n"); + errhead(); fprintf(stderr,"fifo control mode on\n"); int fd = open(argv[3], O_RDONLY); int flags = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, flags | O_NONBLOCK); @@ -237,7 +250,8 @@ int init_fifo(int argc, char *argv[]) //This is implemented in ddcd, check there to see how to do it! int fd; if(sscanf(argv[3], "%d",&fd)<=0) return 0; - fprintf(stderr,"csdr: fd control mode on, fd=%d\n", fd); + errhead(); + fprintf(stderr,"fd control mode on, fd=%d\n", fd); int flags = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, flags | O_NONBLOCK); return fd; @@ -309,7 +323,7 @@ float *output_buffer; short *buffer_i16; float *temp_f; int the_bufsize = 0; -char **argv_global; + #define UNITROUND_UNIT 4 @@ -324,7 +338,7 @@ int initialize_buffers() { if(!(the_bufsize=getbufsize())) return 0; the_bufsize=unitround(the_bufsize); - if(env_csdr_print_bufsizes) fprintf(stderr,"%s %s: buffer size set to %d\n",argv_global[0], argv_global[1], the_bufsize); + if(env_csdr_print_bufsizes) { errhead(); fprintf(stderr,"buffer size set to %d\n", the_bufsize); } input_buffer = (float*) malloc(the_bufsize*sizeof(float) * 2); //need the 2× because we might also put complex floats into it output_buffer = (float*) malloc(the_bufsize*sizeof(float) * 2); buffer_u8 = (unsigned char*)malloc(the_bufsize*sizeof(unsigned char)); @@ -347,7 +361,7 @@ int sendbufsize(int size) //The first word is a preamble, "csdr". //If the next csdr process detects it, sets the buffer size according to the second word if(!env_csdr_dynamic_bufsize_on) return env_csdr_fixed_bufsize; - if(env_csdr_print_bufsizes) fprintf(stderr,"%s %s: next process proposed input buffer size is %d\n",argv_global[0], argv_global[1], size); + if(env_csdr_print_bufsizes) { errhead(); fprintf(stderr,"next process proposed input buffer size is %d\n", size); } int send_first[2]; memcpy((char*)send_first, SETBUF_PREAMBLE, 4*sizeof(char)); send_first[1] = size; @@ -384,6 +398,7 @@ int main(int argc, char *argv[]) { parse_env(); argv_global=argv; + argc_global=argc; if(argc<=1) return badsyntax(0); if(!strcmp(argv[1],"--help")) return badsyntax(0); @@ -466,7 +481,7 @@ int main(int argc, char *argv[]) if(fifo_actual_buffer_rd_pos==fifo_buffer_size) { fifo_actual_buffer_rd_pos = 0; //rewrite same buffer - if(!fifo_overrun_shown) { fifo_overrun_shown=1; fprintf(stderr, "fifo: circular buffer full, dropping samples\n"); } + if(!fifo_overrun_shown) { fifo_overrun_shown=1; errhead(); fprintf(stderr, "circular buffer full, dropping samples\n"); } } } } @@ -486,7 +501,7 @@ int main(int argc, char *argv[]) } } - if(fifo_error&&errno!=11) { fprintf(stderr,"fifo: fifo_error (%d)", errno); return -1; } + if(fifo_error&&errno!=11) { errhead(); fprintf(stderr,"fifo_error (%d)", errno); return -1; } } return -1; @@ -696,7 +711,8 @@ int main(int argc, char *argv[]) if(argc>3) sscanf(argv[3],"%d",&table_size); if(!sendbufsize(initialize_buffers())) return -2; shift_table_data_t table_data=shift_table_init(table_size); - fprintf(stderr,"shift_table_cc: LUT initialized\n"); + errhead(); + fprintf(stderr,"LUT initialized\n"); for(;;) { FEOF_CHECK; @@ -730,7 +746,8 @@ int main(int argc, char *argv[]) for(;;) { shift_addfast_data_t data=shift_addfast_init(rate); - fprintf(stderr,"shift_addfast_cc: reinitialized to %g\n",rate); + errhead(); + fprintf(stderr,"reinitialized to %g\n",rate); int remain, current_size; float* ibufptr; float* obufptr; @@ -780,7 +797,8 @@ int main(int argc, char *argv[]) for(;;) { shift_unroll_data_t data=shift_unroll_init(rate, 1024); - fprintf(stderr,"shift_unroll_cc: reinitialized to %g\n",rate); + errhead(); + fprintf(stderr,"reinitialized to %g\n",rate); int remain, current_size; float* ibufptr; float* obufptr; @@ -856,7 +874,8 @@ int main(int argc, char *argv[]) for(;;) { shift_addition_data_t data=shift_addition_init(rate); - fprintf(stderr,"shift_addition_cc: reinitialized to %g\n",rate); + errhead(); + fprintf(stderr,"reinitialized to %g\n",rate); int remain, current_size; float* ibufptr; float* obufptr; @@ -978,7 +997,7 @@ int main(int argc, char *argv[]) sscanf(argv[2],"%d",&sample_rate); float tau; sscanf(argv[3],"%g",&tau); - fprintf(stderr,"deemphasis_wfm_ff: tau = %g, sample_rate = %d\n",tau,sample_rate); + errhead(); fprintf(stderr,"tau = %g, sample_rate = %d\n",tau,sample_rate); float last_output=0; for(;;) { @@ -1006,7 +1025,7 @@ int main(int argc, char *argv[]) break; } } - if(nan_detect) fprintf(stderr, "detect_nan_f: NaN detected!\n"); + if(nan_detect) { errhead(); fprintf(stderr, "NaN detected!\n"); } fwrite(input_buffer, sizeof(float), the_bufsize, stdout); TRY_YIELD; } @@ -1103,14 +1122,14 @@ int main(int argc, char *argv[]) float *taps; #define NEON_ALIGNMENT (4*4*2) #ifdef NEON_OPTS - fprintf(stderr,"taps_length = %d\n", taps_length); + errhead(); fprintf(stderr,"taps_length = %d\n", taps_length); padded_taps_length = taps_length+(NEON_ALIGNMENT/4)-1 - ((taps_length+(NEON_ALIGNMENT/4)-1)%(NEON_ALIGNMENT/4)); - fprintf(stderr,"padded_taps_length = %d\n", padded_taps_length); + errhead(); fprintf(stderr,"padded_taps_length = %d\n", padded_taps_length); taps = (float*) (float*)malloc((padded_taps_length+NEON_ALIGNMENT)*sizeof(float)); - fprintf(stderr,"taps = %x\n", taps); + errhead(); fprintf(stderr,"taps = %x\n", taps); taps = (float*)((((unsigned)taps)+NEON_ALIGNMENT-1) & ~(NEON_ALIGNMENT-1)); - fprintf(stderr,"taps = %x\n", taps); + errhead(); fprintf(stderr,"NEON aligned taps = %x\n", taps); for(int i=0;i 0); while (env_csdr_fixed_big_bufsize < taps_length*2) env_csdr_fixed_big_bufsize*=2; //temporary fix for buffer size if [transition_bw] is low @@ -1224,7 +1243,7 @@ int main(int argc, char *argv[]) { window=firdes_get_window_from_string(argv[4]); } - else fprintf(stderr,"firdes_lowpass_f: window = %s\n",firdes_get_string_from_window(window)); + else { errhead(); fprintf(stderr,"window = %s\n",firdes_get_string_from_window(window)); } int octave=(argc>=6 && !strcmp("--octave",argv[5])); @@ -1263,7 +1282,7 @@ int main(int argc, char *argv[]) { window=firdes_get_window_from_string(argv[5]); } - else fprintf(stderr,"firdes_bandpass_c: window = %s\n",firdes_get_string_from_window(window)); + else { errhead(); fprintf(stderr,"window = %s\n",firdes_get_string_from_window(window));} int octave=(argc>=7 && !strcmp("--octave",argv[6])); @@ -1385,9 +1404,9 @@ int main(int argc, char *argv[]) { window=firdes_get_window_from_string(argv[5]); } - else fprintf(stderr,"rational_resampler_ff: window = %s\n",firdes_get_string_from_window(window)); + else { errhead(); fprintf(stderr,"window = %s\n",firdes_get_string_from_window(window)); } - if(suboptimal) fprintf(stderr,"note: suboptimal rational resampler chosen.\n"); + if(suboptimal) { errhead(); fprintf(stderr,"note: suboptimal rational resampler chosen.\n"); } if(!initialize_buffers()) return -2; @@ -1440,7 +1459,7 @@ int main(int argc, char *argv[]) { if(!strcmp(argv[4], "--prefilter")) { - fprintf(stderr, "fractional_decimator_ff: using prefilter with default values\n"); + errhead(); fprintf(stderr, "using prefilter with default values\n"); use_prefilter = 1; } else @@ -1449,7 +1468,7 @@ int main(int argc, char *argv[]) if(argc>=6) window = firdes_get_window_from_string(argv[5]); } } - fprintf(stderr,"fractional_decimator_ff: use_prefilter = %d, num_poly_points = %d, transition_bw = %g, window = %s\n", + errhead(); fprintf(stderr,"use_prefilter = %d, num_poly_points = %d, transition_bw = %g, window = %s\n", use_prefilter, num_poly_points, transition_bw, firdes_get_string_from_window(window)); if(!initialize_buffers()) return -2; @@ -1463,12 +1482,12 @@ int main(int argc, char *argv[]) if(use_prefilter) { taps_length = firdes_filter_len(transition_bw); - fprintf(stderr,"fractional_decimator_ff: taps_length = %d\n",taps_length); + errhead(); fprintf(stderr,"taps_length = %d\n",taps_length); taps = (float*)malloc(sizeof(float)*taps_length); firdes_lowpass_f(taps, taps_length, 0.5/(rate-transition_bw), window); //0.6 const to compensate rolloff //for(int=0;i=5)&&!strcmp(argv[4],"--benchmark"); - fprintf(stderr,"fft_benchmark: FFT library used: %s\n",FFT_LIBRARY_USED); + errhead(); fprintf(stderr,"FFT library used: %s\n",FFT_LIBRARY_USED); complexf* input=(complexf*)fft_malloc(sizeof(complexf)*fft_size); complexf* output=(complexf*)fft_malloc(sizeof(complexf)*fft_size); @@ -1750,7 +1769,7 @@ int main(int argc, char *argv[]) } //initialize FFT library, and measure time - fprintf(stderr,"fft_benchmark: initializing... "); + errhead(); fprintf(stderr,"initializing... "); struct timespec start_time, end_time; clock_gettime(CLOCK_MONOTONIC_RAW, &start_time); FFT_PLAN_T* plan=make_fft_c2c(fft_size,input,output,1,benchmark); @@ -1762,7 +1781,7 @@ int main(int argc, char *argv[]) for(int i=0;i=6) window=firdes_get_window_from_string(argv[5]); - else fprintf(stderr,"bandpass_fir_fft_cc: window = %s\n",firdes_get_string_from_window(window)); + else { errhead(); fprintf(stderr,"window = %s\n",firdes_get_string_from_window(window)); } //calculate the FFT size and the other length parameters int taps_length=firdes_filter_len(transition_bw); //the number of non-zero taps @@ -1795,7 +1814,7 @@ int main(int argc, char *argv[]) if (fft_size-taps_length<200) fft_size<<=1; int input_size = fft_size - taps_length + 1; int overlap_length = taps_length - 1; - fprintf(stderr,"bandpass_fir_fft_cc: (fft_size = %d) = (taps_length = %d) + (input_size = %d) - 1\n(overlap_length = %d) = taps_length - 1\n", fft_size, taps_length, input_size, overlap_length ); + errhead(); fprintf(stderr,"(fft_size = %d) = (taps_length = %d) + (input_size = %d) - 1\n(overlap_length = %d) = taps_length - 1\n", fft_size, taps_length, input_size, overlap_length ); if (fft_size<=2) return badsyntax("FFT size error."); if(!sendbufsize(getbufsize())) return -2; @@ -1824,7 +1843,7 @@ int main(int argc, char *argv[]) for(;;) { //make the filter - fprintf(stderr,"bandpass_fir_fft_cc: filter initialized, low_cut = %g, high_cut = %g\n",low_cut,high_cut); + errhead(); fprintf(stderr,"filter initialized, low_cut = %g, high_cut = %g\n",low_cut,high_cut); firdes_bandpass_c(taps, taps_length, low_cut, high_cut, window); fft_execute(plan_taps); @@ -1890,7 +1909,7 @@ int main(int argc, char *argv[]) sendbufsize(flowcontrol_bufsize); unsigned char* flowcontrol_buffer = (unsigned char*)malloc(sizeof(unsigned char)*flowcontrol_bufsize); int flowcontrol_sleep=floor(1000000./reads_per_second); - fprintf(stderr, "flowcontrol: flowcontrol_bufsize = %d, flowcontrol_sleep = %d\n", flowcontrol_bufsize, flowcontrol_sleep); + errhead(); fprintf(stderr, "flowcontrol_bufsize = %d, flowcontrol_sleep = %d\n", flowcontrol_bufsize, flowcontrol_sleep); for(;;) { FEOF_CHECK; @@ -2163,7 +2182,7 @@ int main(int argc, char *argv[]) for(int i=0;i)"); - fprintf(stderr, "squelch_and_power_cc: initial squelch level is %g\n", squelch_level); + errhead(); fprintf(stderr, "initial squelch level is %g\n", squelch_level); if((argc<=5)||((argc>5)&&(strcmp(argv[4],"--outfifo")))) return badsyntax("need required parameter (--outfifo )"); int fd2 = open(argv[5], O_WRONLY); if(fd2==-1) return badsyntax("error while opening --outfifo"); @@ -2196,7 +2215,7 @@ int main(int argc, char *argv[]) //fprintf(stderr,"S"); fwrite(zerobuf, sizeof(complexf), the_bufsize, stdout); } - if(read_fifo_ctl(fd,"%g\n",&squelch_level)) fprintf(stderr, "squelch_and_power_cc: new squelch level is %g\n", squelch_level); + if(read_fifo_ctl(fd,"%g\n",&squelch_level)) { errhead(); fprintf(stderr, "new squelch level is %g\n", squelch_level); } TRY_YIELD; } } @@ -2223,7 +2242,7 @@ int main(int argc, char *argv[]) window_t window = WINDOW_DEFAULT; if(argc>4) window=firdes_get_window_from_string(argv[4]); - else fprintf(stderr,"fastddc_fwd_cc: window = %s\n",firdes_get_string_from_window(window)); + else { errhead(); fprintf(stderr,"window = %s\n",firdes_get_string_from_window(window)); } fastddc_t ddc; if(fastddc_init(&ddc, transition_bw, decimation, 0)) { badsyntax("error in fastddc_init()"); return 1; } @@ -2240,7 +2259,7 @@ int main(int argc, char *argv[]) for(int i=0;i5+plusarg) window=firdes_get_window_from_string(argv[5+plusarg]); - else fprintf(stderr,"fastddc_apply_cc: window = %s\n",firdes_get_string_from_window(window)); + else { errhead(); fprintf(stderr,"window = %s\n",firdes_get_string_from_window(window)); } for(;;) { @@ -2304,7 +2323,7 @@ int main(int argc, char *argv[]) //make the filter float filter_half_bw = 0.5/decimation; - fprintf(stderr, "fastddc_inv_cc: preparing a bandpass filter of [%g, %g] cutoff rates. Real transition bandwidth is: %g\n", (-shift_rate)-filter_half_bw, (-shift_rate)+filter_half_bw, 4.0/ddc.taps_length); + errhead(); fprintf(stderr, "preparing a bandpass filter of [%g, %g] cutoff rates. Real transition bandwidth is: %g\n", (-shift_rate)-filter_half_bw, (-shift_rate)+filter_half_bw, 4.0/ddc.taps_length); firdes_bandpass_c(taps, ddc.taps_length, (-shift_rate)-filter_half_bw, (-shift_rate)+filter_half_bw, window); fft_execute(plan_taps); fft_swap_sides(taps_fft,ddc.fft_size); @@ -2312,7 +2331,7 @@ int main(int argc, char *argv[]) //make FFT plan complexf* inv_input = (complexf*)fft_malloc(sizeof(complexf)*ddc.fft_inv_size); complexf* inv_output = (complexf*)fft_malloc(sizeof(complexf)*ddc.fft_inv_size); - fprintf(stderr,"fastddc_inv_cc: benchmarking FFT..."); + errhead(); fprintf(stderr,"benchmarking FFT..."); FFT_PLAN_T* plan_inverse = make_fft_c2c(ddc.fft_inv_size, inv_input, inv_output, 0, 1); //inverse, do benchmark fprintf(stderr," done\n"); @@ -2481,7 +2500,7 @@ int main(int argc, char *argv[]) else fread(input_buffer, sizeof(float), the_bufsize, stdin); //should happen only on the first run serial_line_decoder_f_u8(&serial,input_buffer, (unsigned char*)output_buffer, the_bufsize); //printf("now in | "); - if(serial.input_used==0) { fprintf(stderr, "%s: error: serial_line_decoder_f_u8() got stuck.\n", argv[1]); return -3; } + if(serial.input_used==0) { errhead(); fprintf(stderr, "error: serial_line_decoder_f_u8() got stuck.\n"); return -3; } //printf("now out %d | ", serial.output_size); fwrite(output_buffer, sizeof(unsigned char), serial.output_size, stdout); TRY_YIELD; @@ -2508,7 +2527,7 @@ int main(int argc, char *argv[]) if(argc>5) sscanf(argv[5],"%f",&ko); if(argc>6) sscanf(argv[6],"%f",&kd); pll_cc_init_pi_controller(&pll, bandwidth, ko, kd, damping_factor); - fprintf(stderr, "bw=%f damping=%f ko=%f kd=%f alpha=%f beta=%f\n", bandwidth, damping_factor, ko, kd, pll.alpha, pll.beta); + errhead(); fprintf(stderr, "bw=%f damping=%f ko=%f kd=%f alpha=%f beta=%f\n", bandwidth, damping_factor, ko, kd, pll.alpha, pll.beta); // pll.filter_taps_a[0], pll.filter_taps_a[1], pll.filter_taps_a[2], pll.filter_taps_b[0], pll.filter_taps_b[1], pll.filter_taps_b[2]); } else return badsyntax("invalid pll_type. Valid values are:\n\t1: PLL_P_CONTROLLER\n\t2: PLL_PI_CONTROLLER"); @@ -2781,7 +2800,7 @@ int main(int argc, char *argv[]) sscanf(argv[4],"%f",&gain); int decision_directed = !!(argc>5 && (!strcmp(argv[5], "--dd") || !strcmp(argv[5], "--decision_directed"))); - if(decision_directed) fprintf(stderr, "csdr bpsk_costas_loop_cc: decision directed mode\n"); + if(decision_directed) { errhead(); fprintf(stderr, "decision directed mode\n"); } bpsk_costas_loop_state_t state; init_bpsk_costas_loop_cc(&state, decision_directed, damping_factor, loop_bandwidth, gain); @@ -2845,7 +2864,7 @@ int main(int argc, char *argv[]) { window=firdes_get_window_from_string(argv[4]); } - else fprintf(stderr,"firdes_resonator_c: window = %s\n",firdes_get_string_from_window(window)); + else { errhead(); fprintf(stderr,"window = %s\n",firdes_get_string_from_window(window)); } int octave=(argc>=6 && !strcmp("--octave",argv[5])); @@ -2950,7 +2969,7 @@ int main(int argc, char *argv[]) float signal_amplitude_per_noise = pow(10,snr_db/20); float a_signal=signal_amplitude_per_noise/(signal_amplitude_per_noise+1.0); float a_noise=1.0/(signal_amplitude_per_noise+1.0); - fprintf(stderr, "csdr awgn_cc: a_signal = %f, a_noise = %f\n", a_signal, a_noise); + errhead(); fprintf(stderr, "a_signal = %f, a_noise = %f\n", a_signal, a_noise); if(!initialize_buffers()) return -2; sendbufsize(the_bufsize); complexf* awgn_buffer = (complexf*)malloc(sizeof(complexf)*the_bufsize); @@ -2982,7 +3001,7 @@ int main(int argc, char *argv[]) float power_signal = total_logpower_cf((complexf*)input_buffer, the_bufsize); float power_noise = total_logpower_cf(awgn_buffer, the_bufsize); //fprintf(stderr, "csdr awgn_cc: after gain_ff, power_signal = %f dB, power_noise = %f dB\n", power_signal, power_noise); - fprintf(stderr, "csdr awgn_cc: SNR = %f dB\n", power_signal - power_noise); + errhead(); fprintf(stderr, "SNR = %f dB\n", power_signal - power_noise); } add_ff(input_buffer, (float*)awgn_buffer, (float*)output_buffer, the_bufsize*2); FWRITE_C; @@ -3040,7 +3059,7 @@ int main(int argc, char *argv[]) FREAD_R; //doesn't count, reads 4 bytes per sample anyway float nv = normalized_timing_variance_u32_f((unsigned*)input_buffer, temp_buffer, the_bufsize, samples_per_symbol, initial_sample_offset, debug_print); fwrite(&nv, sizeof(float), 1, stdout); - fprintf(stderr, "csdr normalized_timing_variance_u32_f: normalized variance = %f\n", nv); + errhead(); fprintf(stderr, "normalized variance = %f\n", nv); TRY_YIELD; } } @@ -3173,6 +3192,48 @@ int main(int argc, char *argv[]) return 0; } + if(!strcmp(argv[1], "tee")) // [buffers] + { + if(argc<=2) return badsyntax("required parameter is missing."); + FILE* teefile = fopen(argv[2],"w"); + if(!teefile) return badsyntax(" cannot be opened!"); + errhead(); fprintf(stderr, "file opened: %s\n", argv[2]); + int num_buffers=100; + if(argc>3) sscanf(argv[3], "%d", &num_buffers); + if(num_buffers<=0) return badsyntax("num_buffers should be > 0"); + SET_NONBLOCK(fileno(teefile)); + if(!sendbufsize(initialize_buffers())) return -2; + unsigned char* async_tee_buffers = malloc(sizeof(unsigned char)*the_bufsize*num_buffers); + int current_buffer_read_cntr = 0; + int current_buffer_write_cntr = 0; + int current_byte_write_cntr = 0; + for(;;) + { + FEOF_CHECK; + fread(async_tee_buffers+(the_bufsize*current_buffer_read_cntr), sizeof(unsigned char), the_bufsize, stdin); + fwrite(async_tee_buffers+(the_bufsize*current_buffer_read_cntr++), sizeof(unsigned char), the_bufsize, stdout); + if(current_buffer_read_cntr>=num_buffers) current_buffer_read_cntr = 0; + if(current_buffer_read_cntr==current_buffer_write_cntr) { errhead(); fprintf(stderr, "circular buffer overflow (read pointer gone past write pointer)\n"); } + //errhead(); fprintf(stderr, "new fwrites\n"); + while(current_buffer_write_cntr!=current_buffer_read_cntr) + { + int result = fwrite(async_tee_buffers+(the_bufsize*current_buffer_write_cntr)+current_byte_write_cntr, sizeof(unsigned char), the_bufsize-current_byte_write_cntr, teefile); + if(!result) { errhead(); fprintf(stderr, "\t fwrite tee zero, next turn\n"); break; } + current_byte_write_cntr += result; + //errhead(); fprintf(stderr, "\tfwrite tee, current_byte_write_cntr = %d, current_buffer_write_cntr = %d, current_buffer_read_cntr = %d\n", + // current_byte_write_cntr, current_buffer_write_cntr, current_buffer_read_cntr); + if(current_byte_write_cntr >= the_bufsize) + { + current_byte_write_cntr = 0; + current_buffer_write_cntr++; + if(current_buffer_write_cntr>=num_buffers) current_buffer_write_cntr = 0; + } + } + TRY_YIELD; + } + return 0; + } + if(!strcmp(argv[1],"shift_addition_fc")) { bigbufs=1; @@ -3195,7 +3256,7 @@ int main(int argc, char *argv[]) for(;;) { shift_addition_data_t data=shift_addition_init(rate); - fprintf(stderr,"shift_addition_fc: reinitialized to %g\n",rate); + errhead(); fprintf(stderr,"reinitialized to %g\n",rate); int remain, current_size; float* ibufptr; float* obufptr; @@ -3261,7 +3322,7 @@ int main(int argc, char *argv[]) float* input=(float*)fft_malloc(sizeof(float)*fft_in_size); float* windowed=(float*)fft_malloc(sizeof(float)*fft_in_size); complexf* output=(complexf*)fft_malloc(sizeof(complexf)*fft_out_size); - if(benchmark) fprintf(stderr,"fft_cc: benchmarking..."); + if(benchmark) { errhead(); fprintf(stderr,"benchmarking..."); } FFT_PLAN_T* plan=make_fft_r2c(fft_in_size, windowed, output, benchmark); if(benchmark) fprintf(stderr," done\n"); //if(octave) printf("setenv(\"GNUTERM\",\"X11 noraise\");y=zeros(1,%d);semilogy(y,\"ydatasource\",\"y\");\n",fft_size); // TODO From b749e789250c1a7c5b43bdd5e22e3e6aa4265a80 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Fri, 5 May 2017 12:06:28 +0200 Subject: [PATCH 095/111] Added psk31_sigmodel.m --- grc_tests/psk31_sigmodel.m | 50 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100755 grc_tests/psk31_sigmodel.m diff --git a/grc_tests/psk31_sigmodel.m b/grc_tests/psk31_sigmodel.m new file mode 100755 index 0000000..0739b66 --- /dev/null +++ b/grc_tests/psk31_sigmodel.m @@ -0,0 +1,50 @@ +#!/usr/bin/octave + +global Tb=20 + +function g=gbb(t) %impulse response of pulse shaping filter + global Tb + g=t; + for i = 1:size(t)(2) + if (t(i)>1*Tb || t(i)<=-1*Tb) + g(i) = 0; + else + g(i) = 0.5+cos((t(i)/(Tb*1))*pi)/2; %this is not RRC, rather a sinusoidal pulse shape + end + end +end + +function [toreturny, plotrange]=y(s) + global Tb + slen=size(s)(2) + plotrange=(-3*Tb):(slen+2)*Tb-1; + plotlen=size(plotrange)(2) + toreturny=zeros(1,plotlen); + for i=1:slen %sum of (symbol[i] * filter impulse response) for all symbols + toreturny+=s(i)*gbb(plotrange.-(i-1)*Tb); + end +end + +function fmtplot(h) + FN = findall(h,'-property','FontName'); + set(FN,'FontName','/usr/share/fonts/truetype/ttf-dejavu/DejaVuSerifCondensed.ttf'); + set(FN,'FontName','times'); + FS = findall(h,'-property','FontSize'); + set(FS,'FontSize',18); + set(FS,'FontSize',18); +end + +h=figure(1); +subplot(2, 1, 1); +plot(y([1]), 'linewidth', 2) +title(sprintf("Impulse response of pulse shaping filter\n(1 symbol = %d samples)", Tb)) +xlabel('t [1/Ts]') +ylabel('h(t)') + +subplot(2, 1, 2); +plot(y([1 1 -1 -1 1 1 1 -1 1 -1 1 1]), 'linewidth', 2) +title("Baseband signal for modulator input\nbit sequence: 110011101011") %assuming that differential encoding has already been performed +xlabel('t [1/Ts]') +ylabel('s(t)') +fmtplot(h); +pause From dbaa973354cab5e862c217ed9c4bb25ad16c5d85 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 7 May 2017 23:46:37 +0200 Subject: [PATCH 096/111] grc hangs from too much info on stderr --- libcsdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcsdr.c b/libcsdr.c index 981c7b5..8fa53ee 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -2107,7 +2107,7 @@ void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, bpsk else error = iof(output,i)*qof(output,i); s->dphase = error * s->alpha + s->iir_temp; s->iir_temp += error * s->beta; - fprintf(stderr, " error = %f, dphase = %f, nco_phase = %f\n", error, s->dphase, s->nco_phase); + //fprintf(stderr, " error = %f, dphase = %f, nco_phase = %f\n", error, s->dphase, s->nco_phase); //step NCO s->nco_phase += s->dphase; From 2450ed3439f46bc5f642ee3e97543ca5bd04ec64 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Thu, 11 May 2017 16:04:55 +0200 Subject: [PATCH 097/111] Renamed some functions, e.g. reso->peak, matched filter -> pulse shaping filter --- csdr.c | 47 ++++++++++--------- ..._resonators_fir.grc => test_peaks_fir.grc} | 6 +-- 2 files changed, 27 insertions(+), 26 deletions(-) rename grc_tests/{test_resonators_fir.grc => test_peaks_fir.grc} (99%) diff --git a/csdr.c b/csdr.c index 78764e5..a707f18 100755 --- a/csdr.c +++ b/csdr.c @@ -125,7 +125,7 @@ char usage[]= " invert_u8_u8\n" " rtty_line_decoder_u8_u8\n" " rtty_baudot2ascii_u8_u8\n" -" serial_line_decoder_u8_u8\n" +" serial_line_decoder_f_u8 [databits [stopbits]]\n" " octave_complex_c \n" " timing_recovery_cc [mu [--add_q [--output_error | --output_indexes | --octave ]]] \n" " psk31_varicode_encoder_u8_u8\n" @@ -139,20 +139,21 @@ char usage[]= " bpsk_costas_loop_cc [--dd | --decision_directed]\n" " binary_slicer_f_u8\n" " simple_agc_cc [reference [max_gain]]\n" -" firdes_resonator_c [window [--octave]]\n" -" resonators_fir_cc [resonator_rate × N]\n" +" firdes_peak_c [window [--octave]]\n" +" peaks_fir_cc [peak_rate × N]\n" " repeat_u8 \n" " uniform_noise_f\n" " gaussian_noise_c\n" " awgn_cc [--snrshow]\n" " pack_bits_8to1_u8_u8\n" -" firdes_matched_filter_f (RRC | COSINE )\n" -" matched_filter_cc (RRC | COSINE )\n" +" firdes_pulse_shaping_filter_f (RRC | COSINE )\n" +" pulse_shaping_filter_cc (RRC | COSINE )\n" " add_n_zero_samples_at_beginning_f \n" " generic_slicer_f_u8 \n" -" plain_interpolate_cc \n" +" plain_interpolate_cc \n" " add_const_cc \n" " tee [buffers]\n" +" pll_cc (1 [alpha] |2 [bandwidth [damping_factor [ko [kd]]]])\n" " ?\n" " =\n" " \n" @@ -2465,7 +2466,7 @@ int main(int argc, char *argv[]) return 0; } - if(!strcmp(argv[1],"serial_line_decoder_f_u8")) + if(!strcmp(argv[1],"serial_line_decoder_f_u8")) // [databits [stopbits]] { bigbufs=1; @@ -2848,7 +2849,7 @@ int main(int argc, char *argv[]) } } - if(!strcmp(argv[1],"firdes_resonator_c")) // [window [--octave]] + if(!strcmp(argv[1],"firdes_peak_c")) // [window [--octave]] { //Process the params if(argc<=3) return badsyntax("need required parameters (rate, length)"); @@ -2891,7 +2892,7 @@ int main(int argc, char *argv[]) return 0; } - if(!strcmp(argv[1],"resonators_fir_cc")) // + if(!strcmp(argv[1],"peaks_fir_cc")) // { //rule of thumb: bw = 2/taps_length, which does not equal to transition_bw @@ -2899,12 +2900,12 @@ int main(int argc, char *argv[]) int taps_length; sscanf(argv[2],"%d",&taps_length); - int num_resonators = argc-3; - float* resonator_rate = (float*)malloc(sizeof(float)*num_resonators); - for(int i=0;i | COSINE ) { - if(argc<=2) return badsyntax("required parameter is missing."); + if(argc<=2) return badsyntax("required parameter is missing."); matched_filter_type_t type = matched_filter_get_type_from_string(argv[2]); int samples_per_symbol = 0; @@ -3117,7 +3118,7 @@ int main(int argc, char *argv[]) if(!sendbufsize(initialize_buffers())) return -2; - if(matched_filter_which==1) + if(pulse_shaping_filter_which==1) { for(int i=0;i value - 100e3 + 1e3 @@ -344,7 +344,7 @@ samples_per_second - samp_rate + samp_rate*10 type @@ -363,7 +363,7 @@ commandline - csdr resonators_fir_cc 101 -0.2 -0.1 0 0.1 0.2 + csdr peaks_fir_cc 101 -0.2 -0.1 0 0.1 0.2 comment From 2a3c2102507c41f0363870fc601787039dfe5e66 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 14 May 2017 17:37:54 +0200 Subject: [PATCH 098/111] Working on the Costas loop --- csdr.c | 42 ++++++++++++++++++++++------- grc_tests/test_bpsk_costas_loop.grc | 4 +-- libcsdr.c | 27 +++++++++++-------- libcsdr.h | 4 +-- 4 files changed, 52 insertions(+), 25 deletions(-) diff --git a/csdr.c b/csdr.c index a707f18..6925cbd 100755 --- a/csdr.c +++ b/csdr.c @@ -136,7 +136,7 @@ char usage[]= " psk_modulator_u8_c \n" " psk31_interpolate_sine_cc \n" " duplicate_samples_ntimes_u8_u8 \n" -" bpsk_costas_loop_cc [--dd | --decision_directed]\n" +" bpsk_costas_loop_cc [--dd | --decision_directed] [--output_error | --output_dphase | --output_nco | --octave]\n" " binary_slicer_f_u8\n" " simple_agc_cc [reference [max_gain]]\n" " firdes_peak_c [window [--octave]]\n" @@ -2786,7 +2786,7 @@ int main(int argc, char *argv[]) } } - if(!strcmp(argv[1],"bpsk_costas_loop_cc")) // [--dd | --decision_directed] + if(!strcmp(argv[1],"bpsk_costas_loop_cc")) // [--dd | --decision_directed] [--output_error | --output_dphase | --output_nco | --octave] { float loop_bandwidth; if(argc<=2) return badsyntax("need required parameter (loop_bandwidth)"); @@ -2796,25 +2796,47 @@ int main(int argc, char *argv[]) if(argc<=3) return badsyntax("need required parameter (damping_factor)"); sscanf(argv[3],"%f",&damping_factor); - float gain; - if(argc<=4) return badsyntax("need required parameter (gain)"); - sscanf(argv[4],"%f",&gain); + int decision_directed = !!(argc>4 && (!strcmp(argv[4], "--dd") || !strcmp(argv[5], "--decision_directed"))); - int decision_directed = !!(argc>5 && (!strcmp(argv[5], "--dd") || !strcmp(argv[5], "--decision_directed"))); - if(decision_directed) { errhead(); fprintf(stderr, "decision directed mode\n"); } + int output_error = !!(argc>4+decision_directed && (!strcmp(argv[4+decision_directed], "--output_error"))); + int output_dphase = !output_error & !!(argc>4+decision_directed && (!strcmp(argv[4+decision_directed], "--output_dphase"))); + int output_nco = !output_dphase & !!(argc>4+decision_directed && (!strcmp(argv[4+decision_directed], "--output_nco"))); + int octave = !output_nco & !!(argc>4+decision_directed && (!strcmp(argv[4+decision_directed], "--octave"))); + + if(decision_directed && !octave) { errhead(); fprintf(stderr, "decision directed mode\n"); } bpsk_costas_loop_state_t state; - init_bpsk_costas_loop_cc(&state, decision_directed, damping_factor, loop_bandwidth, gain); + init_bpsk_costas_loop_cc(&state, decision_directed, damping_factor, loop_bandwidth); if(!initialize_buffers()) return -2; sendbufsize(the_bufsize); + float* buffer_output_error = (!(octave || output_error)) ? NULL : (float*)malloc(sizeof(float)*the_bufsize); + float* buffer_output_dphase = (!(octave || output_dphase)) ? NULL : (float*)malloc(sizeof(float)*the_bufsize); + complexf* buffer_output_nco = (!(octave || output_nco)) ? NULL : (complexf*)malloc(sizeof(complexf)*the_bufsize); + + if(octave) fprintf(stderr, "error=[]; dphase=[]; nco=[];\n"); for(;;) { FEOF_CHECK; FREAD_C; - bpsk_costas_loop_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, &state); - FWRITE_C; + bpsk_costas_loop_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, + buffer_output_error, buffer_output_dphase, buffer_output_nco, + &state); + if(output_error) fwrite(buffer_output_error, sizeof(float), the_bufsize, stdout); + else if(output_dphase) fwrite(buffer_output_dphase, sizeof(float), the_bufsize, stdout); + else if(output_nco) fwrite(buffer_output_nco, sizeof(complexf), the_bufsize, stdout); + else if(octave) + { + fprintf(stderr, "error=[error "); + for(int i=0; i value - 2**13 + 2**12 @@ -693,7 +693,7 @@ commandline - csdr bpsk_costas_loop_cc $(csdr =2*pi/100) 0.707 5 2>/tmp/cout + csdr bpsk_costas_loop_cc 0.01 0.707 --dd --octave 2>/home/pcfl/Asztal/szakdoga/dipterv1/costaslog comment diff --git a/libcsdr.c b/libcsdr.c index 8fa53ee..5a0a600 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -2076,21 +2076,23 @@ char* timing_recovery_get_string_from_algorithm(timing_recovery_algorithm_t algo return "INVALID"; } -void init_bpsk_costas_loop_cc(bpsk_costas_loop_state_t* s, int decision_directed, float damping_factor, float bandwidth, float gain) +void init_bpsk_costas_loop_cc(bpsk_costas_loop_state_t* s, int decision_directed, float damping_factor, float bandwidth) { - float bandwidth_omega = 2*M_PI*bandwidth; - s->alpha = (damping_factor*2*bandwidth_omega)/gain; - float sampling_rate = 1; //the bandwidth is normalized to the sampling rate - s->beta = (bandwidth_omega*bandwidth_omega)/(sampling_rate*gain); + //based on: http://gnuradio.squarespace.com/blog/2011/8/13/control-loop-gain-values.html + float bandwidth_omega = 2*M_PI*bandwidth; //so that the bandwidth should be around 0.01 by default (2pi/100), and the damping_factor should be default 0.707 + float denomiator = 1+2*damping_factor*bandwidth_omega+bandwidth_omega*bandwidth_omega; + s->alpha = (4*damping_factor*bandwidth_omega)/denomiator; + s->beta = (4*bandwidth_omega*bandwidth_omega)/denomiator; s->iir_temp = s->dphase = s->nco_phase = 0; } -void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, bpsk_costas_loop_state_t* s) +void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, float* output_error, float* output_dphase, complexf* output_nco, bpsk_costas_loop_state_t* s) { for(int i=0;inco_phase); + e_powj(&nco_sample, -s->nco_phase); + if(output_nco) output_nco[i]=nco_sample; cmult(&output[i], &input[i], &nco_sample); float error = 0; if(s->decision_directed) @@ -2104,10 +2106,14 @@ void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, bpsk while(error>PI) error -= 2*PI; } } - else error = iof(output,i)*qof(output,i); + else error = PI*iof(output,i)*qof(output,i); + if(output_error) output_error[i]=error; s->dphase = error * s->alpha + s->iir_temp; - s->iir_temp += error * s->beta; - //fprintf(stderr, " error = %f, dphase = %f, nco_phase = %f\n", error, s->dphase, s->nco_phase); + s->iir_temp += error * s->beta; //iir_temp could be named current_freq. See Tom Rondeau's article for better understanding. + if(s->dphase>PI) s->dphase=PI; + if(s->dphase<-PI) s->dphase=-PI; + if(output_dphase) output_dphase[i]=s->dphase; + //fprintf(stderr, " error = %f; dphase = %f; nco_phase = %f;\n", error, s->dphase, s->nco_phase); //step NCO s->nco_phase += s->dphase; @@ -2171,7 +2177,6 @@ void bpsk_costas_loop_c1mc(complexf* input, complexf* output, int input_size, bp cmult(&output[i], &input[i], &vco_sample); } } - #endif void simple_agc_cc(complexf* input, complexf* output, int input_size, float rate, float reference, float max_gain, float* current_gain) diff --git a/libcsdr.h b/libcsdr.h index 38c2cfc..ff5810e 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -375,7 +375,8 @@ typedef struct bpsk_costas_loop_state_s } bpsk_costas_loop_state_t; void plain_interpolate_cc(complexf* input, complexf* output, int input_size, int interpolation); -void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, bpsk_costas_loop_state_t* state); +void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, float* output_error, float* output_dphase, complexf* output_nco, bpsk_costas_loop_state_t* s); +void init_bpsk_costas_loop_cc(bpsk_costas_loop_state_t* s, int decision_directed, float damping_factor, float bandwidth); void simple_agc_cc(complexf* input, complexf* output, int input_size, float rate, float reference, float max_gain, float* current_gain); void firdes_add_resonator_c(complexf* output, int length, float rate, window_t window, int add, int normalize); @@ -405,5 +406,4 @@ int apply_real_fir_cc(complexf* input, complexf* output, int input_size, float* void generic_slicer_f_u8(float* input, unsigned char* output, int input_size, int n_symbols); void plain_interpolate_cc(complexf* input, complexf* output, int input_size, int interpolation);; void normalize_fir_f(float* input, float* output, int length); -void init_bpsk_costas_loop_cc(bpsk_costas_loop_state_t* s, int decision_directed, float damping_factor, float bandwidth, float gain); float* add_const_cc(complexf* input, complexf* output, int input_size, complexf x); From 7718eda15b9499255f15c04f6bd219e32ff36af0 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 14 May 2017 22:01:36 +0200 Subject: [PATCH 099/111] costas loop --octave changed to --output_combined --- csdr.c | 52 ++++++++++++++++++----------- grc_tests/test_bpsk_costas_loop.grc | 2 +- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/csdr.c b/csdr.c index 6925cbd..98ce304 100755 --- a/csdr.c +++ b/csdr.c @@ -136,7 +136,7 @@ char usage[]= " psk_modulator_u8_c \n" " psk31_interpolate_sine_cc \n" " duplicate_samples_ntimes_u8_u8 \n" -" bpsk_costas_loop_cc [--dd | --decision_directed] [--output_error | --output_dphase | --output_nco | --octave]\n" +" bpsk_costas_loop_cc // [--dd | --decision_directed] [--output_error | --output_dphase | --output_nco | --output_combined ]\n" " binary_slicer_f_u8\n" " simple_agc_cc [reference [max_gain]]\n" " firdes_peak_c [window [--octave]]\n" @@ -2786,7 +2786,7 @@ int main(int argc, char *argv[]) } } - if(!strcmp(argv[1],"bpsk_costas_loop_cc")) // [--dd | --decision_directed] [--output_error | --output_dphase | --output_nco | --octave] + if(!strcmp(argv[1],"bpsk_costas_loop_cc")) // [--dd | --decision_directed] [--output_error | --output_dphase | --output_nco | --output_combined ] { float loop_bandwidth; if(argc<=2) return badsyntax("need required parameter (loop_bandwidth)"); @@ -2797,13 +2797,13 @@ int main(int argc, char *argv[]) sscanf(argv[3],"%f",&damping_factor); int decision_directed = !!(argc>4 && (!strcmp(argv[4], "--dd") || !strcmp(argv[5], "--decision_directed"))); + if(decision_directed) { errhead(); fprintf(stderr, "decision directed mode\n"); } - int output_error = !!(argc>4+decision_directed && (!strcmp(argv[4+decision_directed], "--output_error"))); - int output_dphase = !output_error & !!(argc>4+decision_directed && (!strcmp(argv[4+decision_directed], "--output_dphase"))); - int output_nco = !output_dphase & !!(argc>4+decision_directed && (!strcmp(argv[4+decision_directed], "--output_nco"))); - int octave = !output_nco & !!(argc>4+decision_directed && (!strcmp(argv[4+decision_directed], "--octave"))); + int output_error = !!(argc>4+decision_directed && (!strcmp(argv[4+decision_directed], "--output_error"))); + int output_dphase = !output_error & !!(argc>4+decision_directed && (!strcmp(argv[4+decision_directed], "--output_dphase"))); + int output_nco = !output_dphase & !!(argc>4+decision_directed && (!strcmp(argv[4+decision_directed], "--output_nco"))); + int output_combined = !output_nco & !!(argc>4+decision_directed && (!strcmp(argv[4+decision_directed], "--output_combined"))); - if(decision_directed && !octave) { errhead(); fprintf(stderr, "decision directed mode\n"); } bpsk_costas_loop_state_t state; init_bpsk_costas_loop_cc(&state, decision_directed, damping_factor, loop_bandwidth); @@ -2811,11 +2811,21 @@ int main(int argc, char *argv[]) if(!initialize_buffers()) return -2; sendbufsize(the_bufsize); - float* buffer_output_error = (!(octave || output_error)) ? NULL : (float*)malloc(sizeof(float)*the_bufsize); - float* buffer_output_dphase = (!(octave || output_dphase)) ? NULL : (float*)malloc(sizeof(float)*the_bufsize); - complexf* buffer_output_nco = (!(octave || output_nco)) ? NULL : (complexf*)malloc(sizeof(complexf)*the_bufsize); + float* buffer_output_error = (!(output_combined || output_error)) ? NULL : (float*)malloc(sizeof(float)*the_bufsize); + float* buffer_output_dphase = (!(output_combined || output_dphase)) ? NULL : (float*)malloc(sizeof(float)*the_bufsize); + complexf* buffer_output_nco = (!(output_combined || output_nco)) ? NULL : (complexf*)malloc(sizeof(complexf)*the_bufsize); + + FILE* file_output_error = NULL; + FILE* file_output_dphase = NULL; + FILE* file_output_nco = NULL; + if(!(argc>4+decision_directed+3)) { errhead(); return badsyntax("need required parameters after --output_combined: "); } + if(output_combined) + { + file_output_error = fopen(argv[4+decision_directed+1], "w"); + file_output_dphase = fopen(argv[4+decision_directed+2], "w"); + file_output_nco = fopen(argv[4+decision_directed+3], "w"); + } - if(octave) fprintf(stderr, "error=[]; dphase=[]; nco=[];\n"); for(;;) { FEOF_CHECK; @@ -2826,19 +2836,21 @@ int main(int argc, char *argv[]) if(output_error) fwrite(buffer_output_error, sizeof(float), the_bufsize, stdout); else if(output_dphase) fwrite(buffer_output_dphase, sizeof(float), the_bufsize, stdout); else if(output_nco) fwrite(buffer_output_nco, sizeof(complexf), the_bufsize, stdout); - else if(octave) + else { - fprintf(stderr, "error=[error "); - for(int i=0; i [reference [max_gain]] diff --git a/grc_tests/test_bpsk_costas_loop.grc b/grc_tests/test_bpsk_costas_loop.grc index 7cbad16..2aacc7f 100644 --- a/grc_tests/test_bpsk_costas_loop.grc +++ b/grc_tests/test_bpsk_costas_loop.grc @@ -693,7 +693,7 @@ commandline - csdr bpsk_costas_loop_cc 0.01 0.707 --dd --octave 2>/home/pcfl/Asztal/szakdoga/dipterv1/costaslog + tee /s/costas_input | csdr bpsk_costas_loop_cc 0.01 0.707 --dd --output_combined /s/costas_error /s/costas_dphase /s/costas_nco | tee /s/costas_output comment From fe46aba98d43b14c0d2158f3d613cf268c386335 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 14 May 2017 23:39:11 +0200 Subject: [PATCH 100/111] Costas loop looks working again --- csdr.c | 1 + grc_tests/test_bpsk_costas_loop.grc | 2 +- grc_tests/test_bpsk_costas_loop_convertwavs.sh | 9 +++++++++ libcsdr.c | 7 ++++--- 4 files changed, 15 insertions(+), 4 deletions(-) create mode 100755 grc_tests/test_bpsk_costas_loop_convertwavs.sh diff --git a/csdr.c b/csdr.c index 98ce304..c1e4b59 100755 --- a/csdr.c +++ b/csdr.c @@ -2807,6 +2807,7 @@ int main(int argc, char *argv[]) bpsk_costas_loop_state_t state; init_bpsk_costas_loop_cc(&state, decision_directed, damping_factor, loop_bandwidth); + errhead(); fprintf(stderr, "alpha = %f, beta = %f\n", state.alpha, state.beta); if(!initialize_buffers()) return -2; sendbufsize(the_bufsize); diff --git a/grc_tests/test_bpsk_costas_loop.grc b/grc_tests/test_bpsk_costas_loop.grc index 2aacc7f..6a6ec5d 100644 --- a/grc_tests/test_bpsk_costas_loop.grc +++ b/grc_tests/test_bpsk_costas_loop.grc @@ -693,7 +693,7 @@ commandline - tee /s/costas_input | csdr bpsk_costas_loop_cc 0.01 0.707 --dd --output_combined /s/costas_error /s/costas_dphase /s/costas_nco | tee /s/costas_output + tee /s/costas_input | csdr bpsk_costas_loop_cc 0.1 0.707 --output_combined /s/costas_error /s/costas_dphase /s/costas_nco | tee /s/costas_output comment diff --git a/grc_tests/test_bpsk_costas_loop_convertwavs.sh b/grc_tests/test_bpsk_costas_loop_convertwavs.sh new file mode 100755 index 0000000..d7c08f0 --- /dev/null +++ b/grc_tests/test_bpsk_costas_loop_convertwavs.sh @@ -0,0 +1,9 @@ +#!/bin/bash +sox -r 48k -t f32 -c 2 /s/costas_nco -t wav -e floating-point /s/costas_nco.wav +sox -r 48k -t f32 -c 1 /s/costas_error -t wav -e floating-point /s/costas_error.wav +sox -r 48k -t f32 -c 1 /s/costas_dphase -t wav -e floating-point /s/costas_dphase.wav +sox -r 48k -t f32 -c 2 /s/costas_input -t wav -e floating-point /s/costas_input.wav +sox -r 48k -t f32 -c 2 /s/costas_output -t wav -e floating-point /s/costas_output.wav + + + diff --git a/libcsdr.c b/libcsdr.c index 5a0a600..bc3eef5 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -2078,8 +2078,9 @@ char* timing_recovery_get_string_from_algorithm(timing_recovery_algorithm_t algo void init_bpsk_costas_loop_cc(bpsk_costas_loop_state_t* s, int decision_directed, float damping_factor, float bandwidth) { + //fprintf(stderr, "init_bpsk_costas_loop_cc: bandwidth = %f, damping_factor = %f\n", bandwidth, damping_factor); //based on: http://gnuradio.squarespace.com/blog/2011/8/13/control-loop-gain-values.html - float bandwidth_omega = 2*M_PI*bandwidth; //so that the bandwidth should be around 0.01 by default (2pi/100), and the damping_factor should be default 0.707 + float bandwidth_omega = 2*PI*bandwidth; //so that the bandwidth should be around 0.01 by default (2pi/100), and the damping_factor should be default 0.707 float denomiator = 1+2*damping_factor*bandwidth_omega+bandwidth_omega*bandwidth_omega; s->alpha = (4*damping_factor*bandwidth_omega)/denomiator; s->beta = (4*bandwidth_omega*bandwidth_omega)/denomiator; @@ -2091,9 +2092,9 @@ void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, floa for(int i=0;inco_phase); - if(output_nco) output_nco[i]=nco_sample; + e_powj(&nco_sample, s->nco_phase); cmult(&output[i], &input[i], &nco_sample); + if(output_nco) output_nco[i]=nco_sample; float error = 0; if(s->decision_directed) { From 50528abd718c8d5a61d34487c21f84371315e371 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Mon, 15 May 2017 21:35:58 +0200 Subject: [PATCH 101/111] Fixed CLI for timing recovery, added max_dphase for Costas --- csdr.c | 31 +- grc_tests/test_bpsk31_parts.grc | 473 +++++++++++++++++++++++++++- grc_tests/test_bpsk_costas_loop.grc | 79 ++++- libcsdr.c | 56 ++-- libcsdr.h | 11 +- 5 files changed, 587 insertions(+), 63 deletions(-) diff --git a/csdr.c b/csdr.c index c1e4b59..e04bae0 100755 --- a/csdr.c +++ b/csdr.c @@ -127,7 +127,7 @@ char usage[]= " rtty_baudot2ascii_u8_u8\n" " serial_line_decoder_f_u8 [databits [stopbits]]\n" " octave_complex_c \n" -" timing_recovery_cc [mu [--add_q [--output_error | --output_indexes | --octave ]]] \n" +" timing_recovery_cc [mu [--add_q [--output_error | --output_indexes | --octave | --octave_save ]]] \n" " psk31_varicode_encoder_u8_u8\n" " psk31_varicode_decoder_u8_u8\n" " differential_encoder_u8_u8\n" @@ -136,7 +136,7 @@ char usage[]= " psk_modulator_u8_c \n" " psk31_interpolate_sine_cc \n" " duplicate_samples_ntimes_u8_u8 \n" -" bpsk_costas_loop_cc // [--dd | --decision_directed] [--output_error | --output_dphase | --output_nco | --output_combined ]\n" +" bpsk_costas_loop_cc [--dd | --decision_directed] [--output_error | --output_dphase | --output_nco | --output_combined ]\n" " binary_slicer_f_u8\n" " simple_agc_cc [reference [max_gain]]\n" " firdes_peak_c [window [--octave]]\n" @@ -2549,7 +2549,7 @@ int main(int argc, char *argv[]) } } - if(!strcmp(argv[1],"timing_recovery_cc")) // [loop_gain [max_error [--add_q] [--output_error | --output_indexes | --octave ]]] + if(!strcmp(argv[1],"timing_recovery_cc")) // [mu [max_error [--add_q [--output_error | --output_indexes | --octave | --octave_save ]]]] \n" { if(argc<=2) return badsyntax("need required parameter (algorithm)"); timing_recovery_algorithm_t algorithm = timing_recovery_get_algorithm_from_string(argv[2]); @@ -2568,11 +2568,22 @@ int main(int argc, char *argv[]) int add_q = !!(argc>=7 && !strcmp(argv[6], "--add_q")); - int debug_n = 0; + int debug_every_nth = -1; int output_error = 0; int output_indexes = 0; - if(argc+add_q>=8 && !strcmp(argv[6+add_q], "--octave")) debug_n = atoi(argv[7+add_q]); - if(debug_n<0) return badsyntax("debug_n should be >= 0"); + int octave_save = 0; + char* octave_save_path = NULL; + if(argc>=8+add_q && (!strcmp(argv[6+add_q], "--octave") || (octave_save = !strcmp(argv[6+add_q], "--octave_save")))) + { + debug_every_nth = atoi(argv[7+add_q]); + if(debug_every_nth<0) return badsyntax("debug_every_nth should be >= 0"); + } + if(octave_save) + { + if(argc>=9+add_q) octave_save_path = argv[8+add_q]; + else octave_save_path = "figs"; + } + if(debug_every_nth<0) { errhead(); fprintf(stderr, "--add_q mode on\n"); } if(argc>=(8+add_q) && !strcmp(argv[7+add_q], "--output_error")) output_error = 1; float* timing_error = NULL; @@ -2585,17 +2596,13 @@ int main(int argc, char *argv[]) if(!initialize_buffers()) return -2; sendbufsize(the_bufsize/decimation); - timing_recovery_state_t state = timing_recovery_init(algorithm, decimation, add_q, loop_gain, max_error); + timing_recovery_state_t state = timing_recovery_init(algorithm, decimation, add_q, loop_gain, max_error, debug_every_nth, octave_save_path); - int debug_i=0; - state.debug_writefiles = 1; - state.debug_force = !!debug_n; //should remove that later FREAD_C; unsigned buffer_start_counter = 0; for(;;) { FEOF_CHECK; - if(debug_n && ++debug_i%debug_n==0) timing_recovery_trigger_debug(&state, 3); timing_recovery_cc((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, timing_error, (int*)sampled_indexes, &state); //fprintf(stderr, "trcc is=%d, os=%d, ip=%d\n",the_bufsize, state.output_size, state.input_processed); if(timing_error) fwrite(timing_error, sizeof(float), state.output_size, stdout); @@ -2819,9 +2826,9 @@ int main(int argc, char *argv[]) FILE* file_output_error = NULL; FILE* file_output_dphase = NULL; FILE* file_output_nco = NULL; - if(!(argc>4+decision_directed+3)) { errhead(); return badsyntax("need required parameters after --output_combined: "); } if(output_combined) { + if(!(argc>4+decision_directed+3)) { return badsyntax("need required parameters after --output_combined: "); } file_output_error = fopen(argv[4+decision_directed+1], "w"); file_output_dphase = fopen(argv[4+decision_directed+2], "w"); file_output_nco = fopen(argv[4+decision_directed+3], "w"); diff --git a/grc_tests/test_bpsk31_parts.grc b/grc_tests/test_bpsk31_parts.grc index ac3ad4d..6218910 100644 --- a/grc_tests/test_bpsk31_parts.grc +++ b/grc_tests/test_bpsk31_parts.grc @@ -257,7 +257,7 @@ commandline - csdr dsb_fc | csdr shift_addition_cc $(csdr =-2000./48e3) | csdr fir_decimate_cc 32 | csdr simple_agc_cc 0.0001 0.5 + csdr dsb_fc | csdr shift_addition_cc $(csdr =-2000./48e3) | csdr fir_decimate_cc 32 comment @@ -304,7 +304,7 @@ commandline - csdr bpsk_costas_loop_cc 48 + csdr bpsk_costas_loop_cc 0.05 0.707 comment @@ -316,7 +316,7 @@ _enabled - True + 0 _coordinate @@ -363,7 +363,7 @@ _enabled - 1 + 0 _coordinate @@ -390,6 +390,53 @@ cc + + ha5kfu_execproc_xx + + alias + + + + commandline + csdr bandpass_fir_fft_cc $(csdr '=-(31.25)/1.5e3') $(csdr '=(31.25)/1.5e3') $(csdr '=31.25/1.5e3') | csdr simple_agc_cc 0.0001 0.5 + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (568, 643) + + + _rotation + 0 + + + id + ha5kfu_execproc_xx_0_1 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + cc + + notebook @@ -422,7 +469,7 @@ labels - ['tab1', 'tab2', 'tab3', 'tab4'] + ['tab1', 'channel', 'tab3', 'tab4','bpf'] notebook @@ -667,7 +714,7 @@ _enabled - True + 0 fft_size @@ -742,6 +789,109 @@ 10 + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + 1 + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (832, 563) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_0_1_0 + + + notebook + nb, 4 + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate/32 + + + title + FFT Plot + + + type + complex + + + win_size + + + + win + window.hamming + + + y_divs + 10 + + + y_per_div + 10 + + wxgui_scopesink2 @@ -762,7 +912,7 @@ _enabled - True + 0 _coordinate @@ -849,7 +999,7 @@ _enabled - 1 + 0 _coordinate @@ -916,6 +1066,283 @@ Counts + + wxgui_scopesink2 + + ac_couple + False + + + alias + + + + comment + + + + affinity + + + + _enabled + 0 + + + _coordinate + (832, 787) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_scopesink2_0_0_0 + + + notebook + nb,4 + + + num_inputs + 1 + + + samp_rate + samp_rate/32 + + + t_scale + 0 + + + title + Scope Plot + + + trig_mode + wxgui.TRIG_MODE_AUTO + + + type + complex + + + v_offset + 0 + + + v_scale + 0 + + + win_size + + + + xy_mode + False + + + y_axis_label + Counts + + + + wxgui_waterfallsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + dynamic_range + 100 + + + _enabled + True + + + fft_rate + 15 + + + fft_size + 512 + + + freqvar + None + + + _coordinate + (840, 907) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_waterfallsink2_0 + + + notebook + nb,4 + + + ref_scale + 2.0 + + + ref_level + 0 + + + samp_rate + samp_rate/32 + + + title + Waterfall Plot + + + type + complex + + + win_size + + + + win + None + + + + wxgui_waterfallsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + dynamic_range + 100 + + + _enabled + True + + + fft_rate + 15 + + + fft_size + 512 + + + freqvar + None + + + _coordinate + (1120, 43) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_waterfallsink2_0_0 + + + notebook + nb,1 + + + ref_scale + 2.0 + + + ref_level + 0 + + + samp_rate + samp_rate/32 + + + title + Waterfall Plot + + + type + complex + + + win_size + + + + win + None + + audio_source_0 ha5kfu_execproc_xx_0 @@ -946,12 +1373,24 @@ 0 0 + + blocks_float_to_complex_0 + ha5kfu_execproc_xx_0_1 + 0 + 0 + blocks_float_to_complex_0 wxgui_fftsink2_0 0 0 + + blocks_float_to_complex_0 + wxgui_waterfallsink2_0_0 + 0 + 0 + ha5kfu_execproc_xx_0 blocks_deinterleave_0 @@ -982,4 +1421,22 @@ 0 0 + + ha5kfu_execproc_xx_0_1 + wxgui_fftsink2_0_1_0 + 0 + 0 + + + ha5kfu_execproc_xx_0_1 + wxgui_scopesink2_0_0_0 + 0 + 0 + + + ha5kfu_execproc_xx_0_1 + wxgui_waterfallsink2_0 + 0 + 0 + diff --git a/grc_tests/test_bpsk_costas_loop.grc b/grc_tests/test_bpsk_costas_loop.grc index 6a6ec5d..a42452c 100644 --- a/grc_tests/test_bpsk_costas_loop.grc +++ b/grc_tests/test_bpsk_costas_loop.grc @@ -293,7 +293,7 @@ _enabled - True + 0 _coordinate @@ -336,7 +336,7 @@ _enabled - True + 0 _coordinate @@ -399,7 +399,7 @@ _enabled - True + 0 _coordinate @@ -446,7 +446,7 @@ _enabled - True + 0 _coordinate @@ -489,7 +489,7 @@ _enabled - True + 0 _coordinate @@ -575,6 +575,65 @@ 1 + + blocks_vector_source_x + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (32, 443) + + + _rotation + 0 + + + id + blocks_vector_source_x_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + complex + + + repeat + True + + + tags + [] + + + vlen + 1 + + + vector + (1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1) + + digital_costas_loop_cc @@ -650,7 +709,7 @@ _enabled - True + 1 _coordinate @@ -693,7 +752,7 @@ commandline - tee /s/costas_input | csdr bpsk_costas_loop_cc 0.1 0.707 --output_combined /s/costas_error /s/costas_dphase /s/costas_nco | tee /s/costas_output + tee /s/costas_input | CSDR_FIXED_BUFSIZE=1 csdr bpsk_costas_loop_cc 0.1 0.707 --dd --output_combined /s/costas_error /s/costas_dphase /s/costas_nco | tee /s/costas_output comment @@ -948,6 +1007,12 @@ 0 0 + + blocks_vector_source_x_0 + freq_xlating_fir_filter_xxx_0 + 0 + 0 + digital_costas_loop_cc_0 wxgui_scopesink2_0_0_0 diff --git a/libcsdr.c b/libcsdr.c index bc3eef5..234a946 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -1894,7 +1894,7 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nc } } -void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error, int index, int correction_offset, int writefiles, int points_size, ...) +void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error, int index, int correction_offset, char* writefiles_path, int points_size, ...) { static int figure_output_counter = 0; int* points_z = (int*)malloc(sizeof(int)*points_size); @@ -1906,7 +1906,7 @@ void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error points_z[i] = va_arg(vl, int); points_color[i] = va_arg(vl, int); } - if(writefiles && !figure_output_counter) fprintf(stderr, "cf=figure();\n"); + if(writefiles_path && !figure_output_counter) fprintf(stderr, "cf=figure();\n"); fprintf(stderr, "N = %d;\nisig = [", signal_size); for(int i=0;i=0 to_return.last_correction_offset = 0; to_return.earlylate_ratio = 0.25; //0..0.5 + to_return.debug_writefiles_path = debug_writefiles_path; return to_return; } -void timing_recovery_trigger_debug(timing_recovery_state_t* state, int debug_phase) -{ - state->debug_phase=debug_phase; -} - #define MTIMINGR_HDEBUG 0 void timing_recovery_cc(complexf* input, complexf* output, int input_size, float* timing_error, int* sampled_indexes, timing_recovery_state_t* state) @@ -1971,11 +1964,10 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, float int num_samples_halfbit = state->decimation_rate / 2; int num_samples_quarterbit = state->decimation_rate / 4; int num_samples_earlylate_wing = num_samples_bit * state->earlylate_ratio; - int debug_i = state->debug_count; float error; int el_point_left_index, el_point_right_index, el_point_mid_index; int si = 0; - if(state->debug_force) fprintf(stderr, "disp(\"begin timing_recovery_cc\");\n"); + if(state->debug_every_nth>=0) fprintf(stderr, "disp(\"begin timing_recovery_cc\");\n"); if(MTIMINGR_HDEBUG) fprintf(stderr, "timing_recovery_cc started, nsb = %d, nshb = %d, nsqb = %d\n", num_samples_bit, num_samples_halfbit, num_samples_quarterbit); { for(;;) @@ -2026,20 +2018,23 @@ void timing_recovery_cc(complexf* input, complexf* output, int input_size, float if(error>state->max_error) error=state->max_error; if(error<-state->max_error) error=-state->max_error; - if( state->debug_force || (state->debug_phase >= si && debug_i) ) + if(state->debug_every_nth>=0) { - debug_i--; - if(!debug_i) state->debug_phase = -1; - octave_plot_point_on_cplxsig(input+current_bitstart_index, state->decimation_rate*2, - error, - current_bitstart_index, - correction_offset, - state->debug_writefiles, - 3, - el_point_left_index - current_bitstart_index, 'r', - el_point_right_index - current_bitstart_index, 'r', - el_point_mid_index - current_bitstart_index, 'r', - 0); + if(state->debug_every_nth==0 || state->debug_phase==0) + { + state->debug_phase = state->debug_every_nth; + octave_plot_point_on_cplxsig(input+current_bitstart_index, state->decimation_rate*2, + error, + current_bitstart_index, + correction_offset, + state->debug_writefiles_path, + 3, + el_point_left_index - current_bitstart_index, 'r', + el_point_right_index - current_bitstart_index, 'r', + el_point_mid_index - current_bitstart_index, 'r', + 0); + } + else state->debug_phase--; } int error_sign = (state->algorithm == TIMING_RECOVERY_ALGORITHM_GARDNER) ? -1 : 1; correction_offset = num_samples_halfbit * error_sign * error * state->loop_gain; @@ -2085,6 +2080,7 @@ void init_bpsk_costas_loop_cc(bpsk_costas_loop_state_t* s, int decision_directed s->alpha = (4*damping_factor*bandwidth_omega)/denomiator; s->beta = (4*bandwidth_omega*bandwidth_omega)/denomiator; s->iir_temp = s->dphase = s->nco_phase = 0; + s->dphase_max=0.9*PI; //if it reached PI or -PI then it might actually hang and not come back } void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, float* output_error, float* output_dphase, complexf* output_nco, bpsk_costas_loop_state_t* s) @@ -2111,8 +2107,8 @@ void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, floa if(output_error) output_error[i]=error; s->dphase = error * s->alpha + s->iir_temp; s->iir_temp += error * s->beta; //iir_temp could be named current_freq. See Tom Rondeau's article for better understanding. - if(s->dphase>PI) s->dphase=PI; - if(s->dphase<-PI) s->dphase=-PI; + if(s->dphase>s->dphase_max) s->dphase=s->dphase_max; + if(s->dphase<-s->dphase_max) s->dphase=-s->dphase_max; if(output_dphase) output_dphase[i]=s->dphase; //fprintf(stderr, " error = %f; dphase = %f; nco_phase = %f;\n", error, s->dphase, s->nco_phase); diff --git a/libcsdr.h b/libcsdr.h index ff5810e..503d036 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -327,21 +327,19 @@ typedef struct timing_recovery_state_s int input_processed; int use_q; //use both I and Q for calculating the error int debug_phase; - int debug_count; - int debug_force; - int debug_writefiles; + int debug_every_nth; + char* debug_writefiles_path; int last_correction_offset; float earlylate_ratio; float loop_gain; float max_error; } timing_recovery_state_t; -timing_recovery_state_t timing_recovery_init(timing_recovery_algorithm_t algorithm, int decimation_rate, int use_q, float loop_gain, float max_error); +timing_recovery_state_t timing_recovery_init(timing_recovery_algorithm_t algorithm, int decimation_rate, int use_q, float loop_gain, float max_error, int debug_every_nth, char* debug_writefiles_path); void timing_recovery_cc(complexf* input, complexf* output, int input_size, float* timing_error, int* sampled_indexes, timing_recovery_state_t* state); timing_recovery_algorithm_t timing_recovery_get_algorithm_from_string(char* input); char* timing_recovery_get_string_from_algorithm(timing_recovery_algorithm_t algorithm); -void timing_recovery_trigger_debug(timing_recovery_state_t* state, int debug_phase); -void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error, int index, int correction_offset, int writefiles, int points_size, ...); +void octave_plot_point_on_cplxsig(complexf* signal, int signal_size, float error, int index, int correction_offset, char* writefiles_path, int points_size, ...); void psk_modulator_u8_c(unsigned char* input, complexf* output, int input_size, int n_psk); void duplicate_samples_ntimes_u8_u8(unsigned char* input, unsigned char* output, int input_size_bytes, int sample_size_bytes, int ntimes); complexf psk31_interpolate_sine_cc(complexf* input, complexf* output, int input_size, int interpolation, complexf last_input); @@ -372,6 +370,7 @@ typedef struct bpsk_costas_loop_state_s float iir_temp; float dphase; float nco_phase; + float dphase_max; } bpsk_costas_loop_state_t; void plain_interpolate_cc(complexf* input, complexf* output, int input_size, int interpolation); From c6d5287d820535a9165e6726acd582cffe0ab625 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Mon, 15 May 2017 23:07:26 +0200 Subject: [PATCH 102/111] Fixed timing_recovery_cc docs and tedvar graph generator --- csdr.c | 6 +++--- grc_tests/bpsk31_tedvar.m | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/csdr.c b/csdr.c index e04bae0..ad1d30d 100755 --- a/csdr.c +++ b/csdr.c @@ -127,7 +127,7 @@ char usage[]= " rtty_baudot2ascii_u8_u8\n" " serial_line_decoder_f_u8 [databits [stopbits]]\n" " octave_complex_c \n" -" timing_recovery_cc [mu [--add_q [--output_error | --output_indexes | --octave | --octave_save ]]] \n" +" timing_recovery_cc [mu [max_error [--add_q [--output_error | --output_indexes | --octave | --octave_save ]]]] \n" " psk31_varicode_encoder_u8_u8\n" " psk31_varicode_decoder_u8_u8\n" " differential_encoder_u8_u8\n" @@ -2585,11 +2585,11 @@ int main(int argc, char *argv[]) } if(debug_every_nth<0) { errhead(); fprintf(stderr, "--add_q mode on\n"); } - if(argc>=(8+add_q) && !strcmp(argv[7+add_q], "--output_error")) output_error = 1; + if(argc>=(7+add_q) && !strcmp(argv[6+add_q], "--output_error")) output_error = 1; float* timing_error = NULL; if(output_error) timing_error = (float*)malloc(sizeof(float)*the_bufsize); - if(argc>=(8+add_q) && !strcmp(argv[7+add_q], "--output_indexes")) output_indexes = 1; + if(argc>=(7+add_q) && !strcmp(argv[6+add_q], "--output_indexes")) output_indexes = 1; unsigned* sampled_indexes = NULL; if(output_indexes) sampled_indexes = (unsigned*)malloc(sizeof(float)*the_bufsize); diff --git a/grc_tests/bpsk31_tedvar.m b/grc_tests/bpsk31_tedvar.m index af43a8f..5a65e7a 100755 --- a/grc_tests/bpsk31_tedvar.m +++ b/grc_tests/bpsk31_tedvar.m @@ -49,7 +49,7 @@ end function variance=run_var(snr, which_ted) disp('ran a command') - out_vect=shrun(sprintf('cat /tmp/psk31-raw-data | csdr awgn_cc %d --awgnfile /tmp/psk31-gaussian-noise | csdr timing_recovery_cc %s 256 --add_q --output_indexes | CSDR_FIXED_BUFSIZE=1048576 csdr normalized_timing_variance_u32_f 256 85', snr, which_ted), 'float32', 1); + out_vect=shrun(sprintf('cat /tmp/psk31-raw-data | csdr awgn_cc %d --awgnfile /tmp/psk31-gaussian-noise | csdr timing_recovery_cc %s 256 0.5 2 --add_q --output_indexes | CSDR_FIXED_BUFSIZE=1048576 csdr normalized_timing_variance_u32_f 256 85', snr, which_ted), 'float32', 1); disp('run_var output:'); out_vect' variance=out_vect(1); From 117ee8e3a86fce6705d0746a886c4a764b280a3b Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Tue, 16 May 2017 17:02:55 +0200 Subject: [PATCH 103/111] I've actually seen this version doing as well as Fldigi in a simulation --- grc_tests/bpsk31_tedvar.m | 4 ++-- grc_tests/test_bpsk_costas_loop_convertwavs.sh | 4 ++-- libcsdr.c | 11 ++++++----- libcsdr.h | 2 +- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/grc_tests/bpsk31_tedvar.m b/grc_tests/bpsk31_tedvar.m index 5a65e7a..74aad13 100755 --- a/grc_tests/bpsk31_tedvar.m +++ b/grc_tests/bpsk31_tedvar.m @@ -49,7 +49,7 @@ end function variance=run_var(snr, which_ted) disp('ran a command') - out_vect=shrun(sprintf('cat /tmp/psk31-raw-data | csdr awgn_cc %d --awgnfile /tmp/psk31-gaussian-noise | csdr timing_recovery_cc %s 256 0.5 2 --add_q --output_indexes | CSDR_FIXED_BUFSIZE=1048576 csdr normalized_timing_variance_u32_f 256 85', snr, which_ted), 'float32', 1); + out_vect=shrun(sprintf('cat /tmp/psk31-raw-data | csdr awgn_cc %d --awgnfile /tmp/psk31-gaussian-noise | csdr bandpass_fir_fft_cc $(csdr "=-31.25/8e3") $(csdr "=31.25/8e3") $(csdr "=31.25/8e3") | csdr simple_agc_cc 0.0001 0.5 | csdr timing_recovery_cc %s 256 0.5 2 --add_q --output_indexes | CSDR_FIXED_BUFSIZE=1048576 csdr normalized_timing_variance_u32_f 256 85', snr, which_ted), 'float32', 1); disp('run_var output:'); out_vect' variance=out_vect(1); @@ -77,7 +77,7 @@ function fmtplot(h) ylabel('Phase error variance [rad^2]'); end -snrs=-5:5:30 +snrs=-15:5:20 %snrs=[10] error_values_gardner=mkvarplot('GARDNER',snrs); %{ diff --git a/grc_tests/test_bpsk_costas_loop_convertwavs.sh b/grc_tests/test_bpsk_costas_loop_convertwavs.sh index d7c08f0..d146ee8 100755 --- a/grc_tests/test_bpsk_costas_loop_convertwavs.sh +++ b/grc_tests/test_bpsk_costas_loop_convertwavs.sh @@ -1,9 +1,9 @@ #!/bin/bash sox -r 48k -t f32 -c 2 /s/costas_nco -t wav -e floating-point /s/costas_nco.wav sox -r 48k -t f32 -c 1 /s/costas_error -t wav -e floating-point /s/costas_error.wav -sox -r 48k -t f32 -c 1 /s/costas_dphase -t wav -e floating-point /s/costas_dphase.wav +sox -r 48k -t f32 -c 1 /s/costas_dphase -t wav -e floating-point --norm=-6 /s/costas_dphase.wav sox -r 48k -t f32 -c 2 /s/costas_input -t wav -e floating-point /s/costas_input.wav sox -r 48k -t f32 -c 2 /s/costas_output -t wav -e floating-point /s/costas_output.wav - +ls -al /s/costas_nco.wav /s/costas_error.wav /s/costas_dphase.wav /s/costas_output.wav /s/costas_input.wav diff --git a/libcsdr.c b/libcsdr.c index 234a946..d4803d8 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -2077,10 +2077,11 @@ void init_bpsk_costas_loop_cc(bpsk_costas_loop_state_t* s, int decision_directed //based on: http://gnuradio.squarespace.com/blog/2011/8/13/control-loop-gain-values.html float bandwidth_omega = 2*PI*bandwidth; //so that the bandwidth should be around 0.01 by default (2pi/100), and the damping_factor should be default 0.707 float denomiator = 1+2*damping_factor*bandwidth_omega+bandwidth_omega*bandwidth_omega; + fprintf(stderr, "damp = %f, bw = %f, bwomega = %f\n", damping_factor, bandwidth, bandwidth_omega); s->alpha = (4*damping_factor*bandwidth_omega)/denomiator; s->beta = (4*bandwidth_omega*bandwidth_omega)/denomiator; - s->iir_temp = s->dphase = s->nco_phase = 0; - s->dphase_max=0.9*PI; //if it reached PI or -PI then it might actually hang and not come back + s->current_freq = s->dphase = s->nco_phase = 0; + s->dphase_max=bandwidth*PI; //this has been determined by experiment: if dphase is out of [-dphase_max; dphase_max] it might actually hang and not come back } void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, float* output_error, float* output_dphase, complexf* output_nco, bpsk_costas_loop_state_t* s) @@ -2105,8 +2106,8 @@ void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, floa } else error = PI*iof(output,i)*qof(output,i); if(output_error) output_error[i]=error; - s->dphase = error * s->alpha + s->iir_temp; - s->iir_temp += error * s->beta; //iir_temp could be named current_freq. See Tom Rondeau's article for better understanding. + s->current_freq += error * s->beta; + s->dphase = error * s->alpha + s->current_freq; if(s->dphase>s->dphase_max) s->dphase=s->dphase_max; if(s->dphase<-s->dphase_max) s->dphase=-s->dphase_max; if(output_dphase) output_dphase[i]=s->dphase; @@ -2187,7 +2188,7 @@ void simple_agc_cc(complexf* input, complexf* output, int input_size, float rate if(ideal_gain>max_gain) ideal_gain = max_gain; if(ideal_gain<=0) ideal_gain = 0; //*current_gain += (ideal_gain-(*current_gain))*rate; - *current_gain = (ideal_gain-(*current_gain))*rate + (*current_gain); //*rate_1minus; + *current_gain = (ideal_gain-(*current_gain))*rate + (*current_gain)*rate_1minus; //if(debugn<100) fprintf(stderr, "cgain: %g\n", *current_gain), debugn++; output[i].i=(*current_gain)*input[i].i; output[i].q=(*current_gain)*input[i].q; diff --git a/libcsdr.h b/libcsdr.h index 503d036..37e5576 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -367,7 +367,7 @@ typedef struct bpsk_costas_loop_state_s float alpha; float beta; int decision_directed; - float iir_temp; + float current_freq; float dphase; float nco_phase; float dphase_max; From f9a6535e108a10170569bc1b5ac981382f84128d Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Thu, 18 May 2017 23:43:40 +0200 Subject: [PATCH 104/111] Edited Makefile Changed functionality of pack_bits_8to1_u8_u8 Added pack_bits_1to8_u8_u8, pattern_search_u8_u8, dbpsk_decoder_c_u8, bfsk_demod_cf --- Makefile | 3 + README.md | 12 +- csdr.c | 173 +++++++++++++++++- grc_tests/psk31_sigmodel.m | 32 +++- .../test_bpsk_costas_loop_convertwavs.sh | 1 + libcsdr.c | 64 ++++++- libcsdr.h | 8 +- 7 files changed, 271 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index 905bf3a..a82a63e 100644 --- a/Makefile +++ b/Makefile @@ -42,6 +42,7 @@ PARAMS_MISC = -Wno-unused-result #DEBUG_ON = 0 #debug is always on by now (anyway it could be compiled with `make DEBUG_ON=1`) #PARAMS_DEBUG = $(if $(DEBUG_ON),-g,) FFTW_PACKAGE = fftw-3.3.3 +PARSEVECT ?= yes .PHONY: clean-vect clean codequality all: codequality csdr nmux @@ -51,7 +52,9 @@ libcsdr.so: fft_fftw.c fft_rpi.c libcsdr_wrapper.c libcsdr.c libcsdr_gpl.c fastd @echo rm -f dumpvect*.vect gcc -std=gnu99 $(PARAMS_LOOPVECT) $(PARAMS_SIMD) $(LIBSOURCES) $(PARAMS_LIBS) $(PARAMS_MISC) -fpic -shared -o libcsdr.so +ifeq ($(PARSEVECT),yes) -./parsevect dumpvect*.vect +endif csdr: csdr.c libcsdr.so gcc -std=gnu99 $(PARAMS_LOOPVECT) $(PARAMS_SIMD) csdr.c $(PARAMS_LIBS) -L. -lcsdr $(PARAMS_MISC) -o csdr ddcd: ddcd.cpp libcsdr.so ddcd.h diff --git a/README.md b/README.md index c133c91..1bdc57e 100755 --- a/README.md +++ b/README.md @@ -832,7 +832,7 @@ For this input, the output of `psk31_varicode_encoder_u8_u8` will be the followi Syntax: - csdr repeat_u8 [resonator_rate × N]\n" + csdr repeat_u8 It repeatedly outputs a set of data bytes (given with decimal numbers). @@ -871,6 +871,16 @@ Syntax: csdr pack_bits_8to1_u8_u8 +TODO + +---- + +### [pack_bits_1to8_u8_u8](#pack_bits_1to8_u8_u8) + +Syntax: + + csdr pack_bits_1to8_u8_u8 + It serializes the bytes on the input: it outputs each bit of the input byte as a single byte valued 0x00 or 0x01, starting from the lowest bit and going to the highest bit. The output is 8 times as large in size as the input. diff --git a/csdr.c b/csdr.c index ad1d30d..58edba7 100755 --- a/csdr.c +++ b/csdr.c @@ -146,6 +146,7 @@ char usage[]= " gaussian_noise_c\n" " awgn_cc [--snrshow]\n" " pack_bits_8to1_u8_u8\n" +" pack_bits_1to8_u8_u8\n" " firdes_pulse_shaping_filter_f (RRC | COSINE )\n" " pulse_shaping_filter_cc (RRC | COSINE )\n" " add_n_zero_samples_at_beginning_f \n" @@ -154,6 +155,9 @@ char usage[]= " add_const_cc \n" " tee [buffers]\n" " pll_cc (1 [alpha] |2 [bandwidth [damping_factor [ko [kd]]]])\n" +" pattern_search_u8_u8 \n" +" dbpsk_decoder_c_u8\n" +" bfsk_demod_cf \n" " ?\n" " =\n" " \n" @@ -2723,7 +2727,7 @@ int main(int argc, char *argv[]) } } - if(!strcmp(argv[1],"pack_bits_8to1_u8_u8")) + if(!strcmp(argv[1],"pack_bits_1to8_u8_u8")) { if(!initialize_buffers()) return -2; sendbufsize(the_bufsize*8); @@ -2733,12 +2737,27 @@ int main(int argc, char *argv[]) { FEOF_CHECK; fread((void*)local_input_buffer, sizeof(unsigned char), the_bufsize, stdin); - pack_bits_8to1_u8_u8(local_input_buffer, local_output_buffer, the_bufsize); + pack_bits_1to8_u8_u8(local_input_buffer, local_output_buffer, the_bufsize); fwrite((void*)local_output_buffer, sizeof(unsigned char), the_bufsize*8, stdout); TRY_YIELD; } } + if(!strcmp(argv[1],"pack_bits_8to1_u8_u8")) + { + if(!initialize_buffers()) return -2; + sendbufsize(1); + char local_input_buffer[8]; + for(;;) + { + FEOF_CHECK; + fread((void*)local_input_buffer, sizeof(unsigned char), 8, stdin); + unsigned char c = pack_bits_8to1_u8_u8(local_input_buffer); + fwrite(&c, sizeof(unsigned char), 1, stdout); + TRY_YIELD; + } + } + if(!strcmp(argv[1],"psk31_varicode_encoder_u8_u8")) { if(!initialize_buffers()) return -2; @@ -2914,7 +2933,7 @@ int main(int argc, char *argv[]) complexf* taps=(complexf*)malloc(sizeof(complexf)*length); //Make the filter - firdes_add_resonator_c(taps, length, rate, window, 0, 1); + firdes_add_peak_c(taps, length, rate, window, 0, 1); //Do the output if(octave) printf("taps=["); @@ -2960,7 +2979,7 @@ int main(int argc, char *argv[]) for(int i=0; i + { + float frequency_shift = 0; + if(argc<=2) return badsyntax("required parameter is missing."); + sscanf(argv[2],"%f",&frequency_shift); + + int filter_length = 0; + if(argc<=3) return badsyntax("required parameter is missing."); + sscanf(argv[3],"%d",&filter_length); + + complexf* mark_filter = (complexf*)malloc(sizeof(complexf)*filter_length); + complexf* space_filter = (complexf*)malloc(sizeof(complexf)*filter_length); + firdes_add_peak_c(mark_filter, filter_length, frequency_shift/2, WINDOW_DEFAULT, 0, 1); + firdes_add_peak_c(space_filter, filter_length, -frequency_shift/2, WINDOW_DEFAULT, 0, 1); + + if(!sendbufsize(initialize_buffers())) return -2; + + int input_skip=0; + int output_size=0; + FREAD_C; + for(;;) + { + FEOF_CHECK; + output_size=bfsk_demod_cf((complexf*)input_buffer, output_buffer, the_bufsize, mark_filter, space_filter, filter_length); + fwrite(output_buffer, sizeof(float), output_size, stdout); + TRY_YIELD; + memmove((complexf*)input_buffer,((complexf*)input_buffer)+output_size,(the_bufsize-output_size)*sizeof(complexf)); + fread(((complexf*)input_buffer)+(the_bufsize-output_size), sizeof(complexf), output_size, stdin); + } + return 0; + } + if(!strcmp(argv[1], "add_const_cc")) // { complexf x; @@ -3411,6 +3477,105 @@ int main(int argc, char *argv[]) TRY_YIELD; } } +/* + if(!strcmp(argv[1],"syncword_search")) + { + if(argc<3) return badsyntax("need required parameter (syncword)"); + unsigned long syncword=0UL; + int syncword_length=strlen(argv[2]); + for(int i=0; i='0') cval = c-'0'; + if(c<='f'&&c>='a') cval = c-'a'+10; + syncword|=cval; + } + errhead(); fprintf("syncword = 0x%0x, syncword_length=%d\n", syncword, syncword_length); + if(argc<4) return badsyntax("need required parameter (bits_after)"); + int bits_after = 0; + sscanf(argv[3], &bits_after); + if(bits_after<0) return badsyntax("bits_after should be >0"); + unsigned char* syncword_bits = malloc(sizeof(unsigned char)*syncword_length*4); + int k=0; + for(int i=0;i>j + } + } + malloc + + } +*/ + if(!strcmp(argv[1],"pattern_search_u8_u8")) // + { + if(argc<3) return badsyntax("need required parameter (values_after)"); + int values_after = 0; + sscanf(argv[2], "%d", &values_after); + if(argc<4) return badsyntax("need required parameter (pattern_values × N)"); + int pattern_values_length = argc-3; + unsigned* pattern_values = (unsigned*)malloc(sizeof(unsigned)*pattern_values_length); + for(int i=0;i=pattern_values_length) input_index=0; + int match=1; + //fprintf(stderr, "ov1: "); + //for(int i=0;i>bi)&1; } + +unsigned char pack_bits_8to1_u8_u8(unsigned char* input) +{ + unsigned char output; + for(int i=0;i<8;i++) + { + output<<=1; + output|=!!input[i]; + } + return output; +} unsigned char differential_codec(unsigned char* input, unsigned char* output, int input_size, int encode, unsigned char state) { if(!encode) @@ -2081,7 +2092,8 @@ void init_bpsk_costas_loop_cc(bpsk_costas_loop_state_t* s, int decision_directed s->alpha = (4*damping_factor*bandwidth_omega)/denomiator; s->beta = (4*bandwidth_omega*bandwidth_omega)/denomiator; s->current_freq = s->dphase = s->nco_phase = 0; - s->dphase_max=bandwidth*PI; //this has been determined by experiment: if dphase is out of [-dphase_max; dphase_max] it might actually hang and not come back + s->dphase_max=bandwidth_omega; //this has been determined by experiment: if dphase is out of [-dphase_max; dphase_max] it might actually hang and not come back + s->dphase_max_reset_to_zero=0; } void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, float* output_error, float* output_dphase, complexf* output_nco, bpsk_costas_loop_state_t* s) @@ -2106,10 +2118,10 @@ void bpsk_costas_loop_cc(complexf* input, complexf* output, int input_size, floa } else error = PI*iof(output,i)*qof(output,i); if(output_error) output_error[i]=error; - s->current_freq += error * s->beta; + s->current_freq += error * s->beta; s->dphase = error * s->alpha + s->current_freq; - if(s->dphase>s->dphase_max) s->dphase=s->dphase_max; - if(s->dphase<-s->dphase_max) s->dphase=-s->dphase_max; + if(s->dphase>s->dphase_max) s->dphase = (s->dphase_max_reset_to_zero) ? 0 : s->dphase_max; + if(s->dphase<-s->dphase_max) s->dphase = (s->dphase_max_reset_to_zero) ? 0 : -s->dphase_max; if(output_dphase) output_dphase[i]=s->dphase; //fprintf(stderr, " error = %f; dphase = %f; nco_phase = %f;\n", error, s->dphase, s->nco_phase); @@ -2195,7 +2207,7 @@ void simple_agc_cc(complexf* input, complexf* output, int input_size, float rate } } -void firdes_add_resonator_c(complexf* output, int length, float rate, window_t window, int add, int normalize) +void firdes_add_peak_c(complexf* output, int length, float rate, window_t window, int add, int normalize) { //add=0: malloc output previously //add=1: calloc output previously @@ -2203,7 +2215,7 @@ void firdes_add_resonator_c(complexf* output, int length, float rate, window_t w int middle=length/2; float phase = 0, phase_addition = -rate*M_PI*2; float (*window_function)(float) = firdes_get_window_kernel(window); - for(int i=0; i=PI) dphase-=2*PI; + if( (dphase>(PI/2)) || (dphase<(-PI/2)) ) output[i]=0; + else output[i]=1; + last_input = input[i]; + } +} + +int bfsk_demod_cf(complexf* input, float* output, int input_size, complexf* mark_filter, complexf* space_filter, int taps_length) +{ + complexf acc_space, acc_mark; + for(int i=0; i Date: Fri, 19 May 2017 14:55:11 +0200 Subject: [PATCH 105/111] Some modifications to the S-curve --- csdr.c | 1 + grc_tests/bpsk31_scurve.m | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/csdr.c b/csdr.c index 58edba7..60b1a98 100755 --- a/csdr.c +++ b/csdr.c @@ -2592,6 +2592,7 @@ int main(int argc, char *argv[]) if(argc>=(7+add_q) && !strcmp(argv[6+add_q], "--output_error")) output_error = 1; float* timing_error = NULL; if(output_error) timing_error = (float*)malloc(sizeof(float)*the_bufsize); + errhead(); fprintf(stderr, "--output_error mode\n"); if(argc>=(7+add_q) && !strcmp(argv[6+add_q], "--output_indexes")) output_indexes = 1; unsigned* sampled_indexes = NULL; diff --git a/grc_tests/bpsk31_scurve.m b/grc_tests/bpsk31_scurve.m index a1cfac2..b17fd24 100755 --- a/grc_tests/bpsk31_scurve.m +++ b/grc_tests/bpsk31_scurve.m @@ -46,20 +46,22 @@ function fmtplot(h) ylabel('Error value (TED output)'); end -skips_gardner=0:256 +skips_gardner=0:16:256 error_values_gardner=mkscurve('GARDNER',skips_gardner); -skips_earlylate=0:256 +skips_earlylate=0:16:256 error_values_earlylate=mkscurve('EARLYLATE',skips_earlylate); %graphics_toolkit("gnuplot") h=figure(1); -plot(skips_gardner, error_values_gardner, 'linewidth', 2); +plot((skips_gardner-128)/256, -error_values_gardner, 'linewidth', 2); title('S-curve for Gardner TED'); fmtplot(h) +grid on pause -plot(skips_earlylate, error_values_earlylate, 'linewidth', 2); +plot((skips_earlylate-128)/256, error_values_earlylate, 'linewidth', 2); title('S-curve for early-late TED'); fmtplot(h) +grid on pause From ee5b54643931b93aadae9a609476527ee62ff6f9 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sat, 20 May 2017 21:02:18 +0200 Subject: [PATCH 106/111] Fixed generic slicer, etc. --- csdr.c | 9 ++++++--- grc_tests/bpsk31_tedvar.m | 30 ++++++++++-------------------- libcsdr.c | 25 +++++++++++++++++-------- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/csdr.c b/csdr.c index 60b1a98..0d2d0cb 100755 --- a/csdr.c +++ b/csdr.c @@ -144,7 +144,7 @@ char usage[]= " repeat_u8 \n" " uniform_noise_f\n" " gaussian_noise_c\n" -" awgn_cc [--snrshow]\n" +" awgn_cc [--awgnfile ] [--snrshow]\n" " pack_bits_8to1_u8_u8\n" " pack_bits_1to8_u8_u8\n" " firdes_pulse_shaping_filter_f (RRC | COSINE )\n" @@ -158,7 +158,9 @@ char usage[]= " pattern_search_u8_u8 \n" " dbpsk_decoder_c_u8\n" " bfsk_demod_cf \n" +" normalized_timing_variance_u32_f [--debug]\n" " ?\n" +" ??\n" " =\n" " \n" ; @@ -2592,11 +2594,12 @@ int main(int argc, char *argv[]) if(argc>=(7+add_q) && !strcmp(argv[6+add_q], "--output_error")) output_error = 1; float* timing_error = NULL; if(output_error) timing_error = (float*)malloc(sizeof(float)*the_bufsize); - errhead(); fprintf(stderr, "--output_error mode\n"); + if(output_error) { errhead(); fprintf(stderr, "--output_error mode\n"); } if(argc>=(7+add_q) && !strcmp(argv[6+add_q], "--output_indexes")) output_indexes = 1; unsigned* sampled_indexes = NULL; if(output_indexes) sampled_indexes = (unsigned*)malloc(sizeof(float)*the_bufsize); + if(output_indexes) { errhead(); fprintf(stderr, "--output_indexes mode\n"); } if(!initialize_buffers()) return -2; sendbufsize(the_bufsize/decimation); @@ -3595,7 +3598,7 @@ int main(int argc, char *argv[]) if(argv[1][0]=='?') { char buffer[1000]; - snprintf(buffer, 1000-1, "csdr 2>&1 | grep %s", argv[1]+1); + snprintf(buffer, 1000-1, "csdr 2>&1 | grep -i %s", argv[1]+1); fprintf(stderr, "csdr ?: %s\n", buffer); system(buffer); return 0; diff --git a/grc_tests/bpsk31_tedvar.m b/grc_tests/bpsk31_tedvar.m index 74aad13..765dc3d 100755 --- a/grc_tests/bpsk31_tedvar.m +++ b/grc_tests/bpsk31_tedvar.m @@ -15,11 +15,13 @@ function y=inarg(x) y=0; end +bpfcmd="csdr bandpass_fir_fft_cc $(csdr \"=-31.25/8e3\") $(csdr \"=31.25/8e3\") $(csdr \"=31.25/8e3\") | "; + if !inarg('--nogen') fwrite(stdout, "===========================================\nGenerating baseband signal from random data\n===========================================\n"); - system('cat /dev/urandom | csdr pack_bits_8to1_u8_u8 | csdr psk_modulator_u8_c 2 | csdr gain_ff 0.25 | csdr psk31_interpolate_sine_cc 256 | csdr add_n_zero_samples_at_beginning_f 170 | pv -ps 2g | dd iflag=fullblock bs=128M count=16 of=/tmp/psk31-raw-data'); + system(["cat /dev/urandom | csdr pack_bits_8to1_u8_u8 | csdr psk_modulator_u8_c 2 | csdr gain_ff 0.25 | csdr psk31_interpolate_sine_cc 256 | " bpfcmd "csdr add_n_zero_samples_at_beginning_f 170 | pv -ps 2g | dd iflag=fullblock bs=128M count=16 of=/tmp/psk31-raw-data"]); fwrite(stdout, "===========================================\nGenerating Gaussian white noise for agwn_cc\n===========================================\n"); - system('csdr gaussian_noise_c | pv -ps 256m | dd of=/tmp/psk31-gaussian-noise iflag=fullblock bs=256M count=1'); + system(["csdr gaussian_noise_c | " bpfcmd "pv -ps 256m | dd of=/tmp/psk31-gaussian-noise iflag=fullblock bs=256M count=1"]); end if inarg('--onlygen') exit(0) @@ -49,7 +51,7 @@ end function variance=run_var(snr, which_ted) disp('ran a command') - out_vect=shrun(sprintf('cat /tmp/psk31-raw-data | csdr awgn_cc %d --awgnfile /tmp/psk31-gaussian-noise | csdr bandpass_fir_fft_cc $(csdr "=-31.25/8e3") $(csdr "=31.25/8e3") $(csdr "=31.25/8e3") | csdr simple_agc_cc 0.0001 0.5 | csdr timing_recovery_cc %s 256 0.5 2 --add_q --output_indexes | CSDR_FIXED_BUFSIZE=1048576 csdr normalized_timing_variance_u32_f 256 85', snr, which_ted), 'float32', 1); + out_vect=shrun(sprintf('cat /tmp/psk31-raw-data | csdr awgn_cc %d --awgnfile /tmp/psk31-gaussian-noise | csdr simple_agc_cc 0.0001 0.5 | csdr timing_recovery_cc %s 256 0.5 2 --add_q --output_indexes | CSDR_FIXED_BUFSIZE=1048576 csdr normalized_timing_variance_u32_f 256 85', snr, which_ted), 'float32', 1); disp('run_var output:'); out_vect' variance=out_vect(1); @@ -77,33 +79,21 @@ function fmtplot(h) ylabel('Phase error variance [rad^2]'); end -snrs=-15:5:20 +%snrs=-10:5:10 +snrs=-10:5:25 %snrs=[10] -error_values_gardner=mkvarplot('GARDNER',snrs); -%{ -snrs_earlylate=0:256 -error_values_earlylate=mkvarplot('EARLYLATE',snrs_earlylate); -%} +error_values=mkvarplot('EARLYLATE',snrs); %graphics_toolkit("gnuplot") h=figure(1); -ebn0=snrs-13.26-10*log10(1/256.) -%13.56 dB is the difference between the real (measured) SNR and the number input to awgn_cc. -%This is because agwn_cc assumes a signal with 0dB power at te input, while our BPSK31 baseband signal is of -13.26 dB. +ebn0=snrs+9.7 -semilogy(ebn0, error_values_gardner, 'linewidth', 2); +semilogy(ebn0, error_values, 'linewidth', 2); title('Estimation variance'); fmtplot(h) pause -%{ -semilogy(snrs_earlylate, error_values_earlylate, 'linewidth', 2); -title('S-curve for early-late TED'); -fmtplot(h) -pause -%} - if !inarg('--nogen') system('rm /tmp/psk31-raw-data /tmp/psk31-gaussian-noise'); end diff --git a/libcsdr.c b/libcsdr.c index 2058cf1..1eb91b3 100755 --- a/libcsdr.c +++ b/libcsdr.c @@ -1730,27 +1730,36 @@ void serial_line_decoder_f_u8(serial_line_t* s, float* input, unsigned char* out void generic_slicer_f_u8(float* input, unsigned char* output, int input_size, int n_symbols) { - float symbol_distance = 2.0/(n_symbols+1); + float symbol_distance = 2.0/(n_symbols-1); for(int i=0;i=symbol_low_limit) output[i]=j; - break; + if(input[i]>=symbol_low_limit) + { + output[i]=j; + break; + } } else { - if(input[i]>=symbol_low_limit && input[i]=symbol_low_limit && input[i] Date: Wed, 14 Jun 2017 11:57:32 +0200 Subject: [PATCH 107/111] Updated README and added bpsk31_ber.py --- README.md | 24 ++++++++++++------- grc_tests/bpsk31_ber.py | 53 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 9 deletions(-) create mode 100755 grc_tests/bpsk31_ber.py diff --git a/README.md b/README.md index 1bdc57e..c0997c7 100755 --- a/README.md +++ b/README.md @@ -1,14 +1,20 @@ -libcsdr -======= +CSDR +==== + +`csdr` is a command line tool to carry out DSP tasks for Software Defined Radio. + +It can be used to build simple signal processing flow graphs, right from the command line. + +The included `libcsdr` library contains the DSP functions that `csdr` makes use of. It was designed to use auto-vectorization available in `gcc`, and also has some functions optimized with inline assembly for ARM NEON to achieve some speedup by taking advantage of SIMD command sets available in today's CPUs. -*libcsdr* is a set of simple DSP routines for Software Defined Radio. -It is mostly useful for AM/FM/SSB demodulation and spectrum display. Feel free to use it in your projects. Most of the code is available under the permissive BSD license, with some optional parts under GPL. For additional details, see licensing. -- The package comes with a command-line tool `csdr`, which lets you build DSP processing chains by shell pipes. -- The code of *libcsdr* was intended to be easy to follow. -- *libcsdr* was designed to use auto-vectorization available in *gcc*. It means that it can achieve some speedup by taking advantage of SIMD command sets available in today's CPUs (e.g. SSE on x86 and NEON on ARM). +`csdr` has already been used to build: + +- AM/FM/SSB/CW demodulators, BPSK31 decoder and waterfall display in [OpenWebRX](https://github.com/simonyiszk/openwebrx), +- AM/FM/SSB modulators in [qtcsdr](https://github.com/ha7ilm/qtcsdr) that can also be used standalone with [rpitx](https://github.com/ha7ilm/rpitx-app-note), +- a decoder for FSK transmissions sent with the CC1111 wireless MCU, and also a standalone RTTY demodulator. How to compile -------------- @@ -22,11 +28,11 @@ If you compile on ARM, please edit the Makefile and tailor `PARAMS_NEON` for you To run the examples, you will also need rtl_sdr from Osmocom, and the following packages (at least on Debian): `mplayer octave gnuplot gnuplot-x11` -If you compile *fftw3* from sources for use with *libcsdr*, you need to configure it with 32-bit float support enabled: +If you compile `fftw3` from sources for use with `libcsdr`, you need to configure it with 32-bit float support enabled: ./configure --enable-float -(This is for *fftw3*, not *libcsdr*. You do not need to run the configure script before compiling *libcsdr*.) +(This is for `fftw3`, not `libcsdr`. You do not need to run the configure script before compiling `libcsdr`.) Credits ------- diff --git a/grc_tests/bpsk31_ber.py b/grc_tests/bpsk31_ber.py new file mode 100755 index 0000000..dbfa9d6 --- /dev/null +++ b/grc_tests/bpsk31_ber.py @@ -0,0 +1,53 @@ +#!/usr/bin/python + +import os, time, signal +from subprocess import * +#https://bugs.python.org/issue1652 + +def p(x): + global printcmds + if printcmds: print x + return check_output(x, shell=True) + +printcmds=True + + +def genfiles(snr): + cmd="""(while true; do echo -n 'CQ CQ CQ DE HA7ILM HA7ILM HA7ILM PSE K '; done) | \ +csdr psk31_varicode_encoder_u8_u8 | \ +tee /s/bpsk31_testin | \ +csdr differential_encoder_u8_u8 | \ +csdr psk_modulator_u8_c 2 | \ +csdr psk31_interpolate_sine_cc 256 | \ +csdr awgn_cc %d | \ +csdr timing_recovery_cc GARDNER 256 0.5 2 --add_q | \ +csdr dbpsk_decoder_c_u8 | \ +dd bs=1024 count=10 of=/s/bpsk31_testout +"""%snr + signal.signal(signal.SIGPIPE, signal.SIG_DFL) + if printcmds: print cmd + os.system(cmd) + +def getminsize(): + return min(os.path.getsize("/s/bpsk31_testout"), os.path.getsize("/s/bpsk31_testin")) + +def mkdiff(shift): + if shift==0: + return int(p("cmp -l /s/bpsk31_testin /s/bpsk31_testout | wc -l")) + elif shift<0: + return int(p("(dd if=/dev/zero bs=%d count=1; cat /s/bpsk31_testin)>/s/bpsk31_testin0; cmp -l /s/bpsk31_testin0 /s/bpsk31_testout | wc -l"%-shift)) + elif shift>0: + return int(p("(dd if=/dev/zero bs=%d count=1; cat /s/bpsk31_testout)>/s/bpsk31_testout0; cmp -l /s/bpsk31_testin /s/bpsk31_testout0 | wc -l"%shift)) + + +lf=open("/s/output_results","w") + +for snr in range(0,20,2): + genfiles(snr) + num_totalbits=getminsize() + num_errors=None + for shift in range(-5,5): + curr_num_errors = mkdiff(shift) + if not num_errors or (num_errors and num_errors > curr_num_errors): + num_errors = curr_num_errors + lf.write("%d; %d; %d; %d\n" %(snr, num_errors, num_totalbits, num_errors/float(num_totalbits))) From d8b47f6ad2eb6663a80e906434542ddde68ec0e4 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 25 Jun 2017 12:22:43 +0200 Subject: [PATCH 108/111] Added test_m_fsk.grc --- grc_tests/test_m_fsk.grc | 816 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 816 insertions(+) create mode 100644 grc_tests/test_m_fsk.grc diff --git a/grc_tests/test_m_fsk.grc b/grc_tests/test_m_fsk.grc new file mode 100644 index 0000000..a7ea06e --- /dev/null +++ b/grc_tests/test_m_fsk.grc @@ -0,0 +1,816 @@ + + + + Sat Oct 31 16:06:38 2015 + + options + + author + + + + window_size + 1280*2, 1024*4 + + + category + Custom + + + comment + + + + description + + + + _enabled + True + + + _coordinate + (8, 11) + + + _rotation + 0 + + + generate_options + wx_gui + + + id + top_block + + + max_nouts + 0 + + + realtime_scheduling + + + + run_options + prompt + + + run + True + + + thread_safe_setters + + + + title + + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (272, 11) + + + _rotation + 0 + + + id + interp + + + value + 1024*4 + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (176, 11) + + + _rotation + 0 + + + id + samp_rate + + + value + 2**16 + + + + blocks_complex_to_float + + alias + + + + comment + + + + affinity + + + + _enabled + 1 + + + _coordinate + (656, 65) + + + _rotation + 0 + + + id + blocks_complex_to_float_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + vlen + 1 + + + + blocks_interleave + + alias + + + + blocksize + 1 + + + comment + + + + affinity + + + + _enabled + 1 + + + _coordinate + (904, 65) + + + _rotation + 0 + + + id + blocks_interleave_0 + + + type + float + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + num_streams + 2 + + + vlen + 1 + + + + blocks_throttle + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (496, 155) + + + _rotation + 0 + + + id + blocks_throttle_0 + + + ignoretag + True + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + samples_per_second + samp_rate + + + type + complex + + + vlen + 1 + + + + blocks_vco_c + + amplitude + 1 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (248, 139) + + + _rotation + 0 + + + id + blocks_vco_c_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + samp_rate + samp_rate + + + sensitivity + samp_rate*0.9 + + + + blocks_vector_source_x + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (8, 139) + + + _rotation + 0 + + + id + blocks_vector_source_x_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + float + + + repeat + True + + + tags + [] + + + vlen + 1 + + + vector + [2]*interp+[-2]*interp+[0.333*2]*interp+[-0.333*2]*interp + + + + ha5kfu_execproc_sink_f + + alias + + + + commandline + csdr fmdemod_quadri_cf | csdr dsb_fc | csdr fir_decimate_cc 40 | csdr timing_recovery_cc GARDNER 100 0.5 2 --add_q | CSDR_FIXED_BUFSIZE=64 csdr realpart_cf | CSDR_FIXED_BUFSIZE=64 csdr gain_ff 2.5 | CSDR_FIXED_BUFSIZE=64 csdr generic_slicer_f_u8 4 > /s/mfsksymbols + + + comment + + + + affinity + + + + _enabled + 1 + + + _coordinate + (1040, 75) + + + _rotation + 0 + + + id + ha5kfu_execproc_sink_f_0 + + + + ha5kfu_execproc_xx + + alias + + + + commandline + csdr fmdemod_quadri_cf | csdr dsb_fc | csdr bandpass_fir_fft_cc -0.1 0.1 0.001 | csdr timing_recovery_cc GARDNER 1024 0.5 2 --add_q | csdr realpart_cf | csdr generic_slicer_f_u8 4 > /s/sliced + + + comment + + + + affinity + + + + _enabled + 0 + + + _coordinate + (528, 467) + + + _rotation + 0 + + + id + ha5kfu_execproc_xx_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + cc + + + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (1040, 115) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_0 + + + notebook + + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate + + + title + FFT Plot + + + type + complex + + + win_size + + + + win + None + + + y_divs + 10 + + + y_per_div + 10 + + + + wxgui_scopesink2 + + ac_couple + False + + + alias + + + + comment + + + + affinity + + + + _enabled + 0 + + + _coordinate + (864, 443) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_scopesink2_0 + + + notebook + + + + num_inputs + 1 + + + samp_rate + samp_rate + + + t_scale + 0 + + + title + Scope Plot + + + trig_mode + wxgui.TRIG_MODE_AUTO + + + type + complex + + + v_offset + 0 + + + v_scale + 0 + + + win_size + + + + xy_mode + False + + + y_axis_label + Counts + + + + wxgui_waterfallsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + dynamic_range + 100 + + + _enabled + True + + + fft_rate + 15 + + + fft_size + 512 + + + freqvar + None + + + _coordinate + (864, 251) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_waterfallsink2_0 + + + notebook + + + + ref_scale + 2.0 + + + ref_level + 0 + + + samp_rate + samp_rate + + + title + Waterfall Plot + + + type + complex + + + win_size + + + + win + None + + + + blocks_complex_to_float_0 + blocks_interleave_0 + 1 + 1 + + + blocks_complex_to_float_0 + blocks_interleave_0 + 0 + 0 + + + blocks_interleave_0 + ha5kfu_execproc_sink_f_0 + 0 + 0 + + + blocks_throttle_0 + blocks_complex_to_float_0 + 0 + 0 + + + blocks_throttle_0 + ha5kfu_execproc_xx_0 + 0 + 0 + + + blocks_throttle_0 + wxgui_fftsink2_0 + 0 + 0 + + + blocks_throttle_0 + wxgui_waterfallsink2_0 + 0 + 0 + + + blocks_vco_c_0 + blocks_throttle_0 + 0 + 0 + + + blocks_vector_source_x_0 + blocks_vco_c_0 + 0 + 0 + + + ha5kfu_execproc_xx_0 + wxgui_scopesink2_0 + 0 + 0 + + From 7825fc5d0fc1de632681ad48d57193651fb90eff Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Thu, 6 Jul 2017 19:17:58 +0200 Subject: [PATCH 109/111] Added a lot of docs --- Makefile | 7 +- README.md | 409 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ csdr.c | 19 ++- 3 files changed, 432 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index a82a63e..da3b5fb 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ PARAMS_MISC = -Wno-unused-result FFTW_PACKAGE = fftw-3.3.3 PARSEVECT ?= yes -.PHONY: clean-vect clean codequality +.PHONY: clean-vect clean codequality checkdocs v all: codequality csdr nmux libcsdr.so: fft_fftw.c fft_rpi.c libcsdr_wrapper.c libcsdr.c libcsdr_gpl.c fastddc.c fastddc.h fft_fftw.h fft_rpi.h ima_adpcm.h libcsdr_gpl.h libcsdr.h predefined.h @echo NOTE: you may have to manually edit Makefile to optimize for your CPU \(especially if you compile on ARM, please edit PARAMS_NEON\). @@ -101,5 +101,10 @@ emcc-beautify: bash -c 'type js-beautify >/dev/null 2>&1; if [ $$? -eq 0 ]; then js-beautify sdr.js/sdr.js >sdr.js/sdr.js.beautiful; mv sdr.js/sdr.js.beautiful sdr.js/sdr.js; fi' codequality: @bash -c 'if [ `cat csdr.c | grep badsyntax | grep -v return | wc -l` -ne 1 ]; then echo "error at code quality check: badsyntax() used in csdr.c without return."; exit 1; else exit 0; fi' +checkdocs: + @cat csdr.c | grep strcmp | egrep 'argv\[1\]' | awk -F'"' '$$0=$$2' > /tmp/csdr-list-of-functions + @cat /tmp/csdr-list-of-functions | xargs -I{} bash -c 'if ! cat csdr.c | grep \"\ \ \ \ {} >/dev/null ; then echo "warning: \"{}\" is in csdr.c code, but not in usage string"; fi' + @cat /tmp/csdr-list-of-functions | xargs -I{} bash -c 'if ! cat README.md | grep {} >/dev/null ; then echo "warning: \"{}\" is in csdr.c code, but not in README.md"; fi' + @rm /tmp/csdr-list-of-functions v: vim csdr.c libcsdr.c diff --git a/README.md b/README.md index c0997c7..4d2f4f5 100755 --- a/README.md +++ b/README.md @@ -140,12 +140,15 @@ The following commands are available: - `csdr convert_f_s8` - `csdr convert_s16_f` - `csdr convert_f_s16` +- `csdr convert_s24_f [--bigendian]` +- `csdr convert_f_s24 [--bigendian]` How to interpret: `csdr convert__` You can use these commands on complex streams, too, as they are only interleaved values (I,Q,I,Q,I,Q... coming after each other). > Note: The the functions with `i16` in their names have been renamed, but still work (e.g. `csdr convert_f_i16`). + ### csdr commands `csdr` should be considered as a reference implementation on using `libcsdr`. For additional details on how to use the library, check `csdr.c` and `libcsdr.c`. @@ -381,6 +384,16 @@ It cannot be used as a channelizer by itself, use `fir_decimate_cc` instead. ---- +### [shift_addition_fc](#shift_addition_fc) + +Syntax: + + csdr shift_addition_fc + +It converts the real input signal to complex, and then shifts it in the frequency domain by `rate`. + +---- + ### [dcblock_ff](#dcblock_ff) Syntax: @@ -641,6 +654,20 @@ FFTW can be faster if we let it optimalize a while before starting the first tra ---- +### [fft_fc](#fft_fc) + +Syntax: + + csdr fft_fc [--benchmark] + +It works similarly to fft_cc, but on real input samples. + +For real FFT, the `fft_out_size` parameter is the number of output complex bins instead of the actual FFT size. + +Number of input samples used for each FFT is `2 × fft_out_size`. This makes it easier to replace `fft_cc` by `fft_fc` in some applications. + +---- + ### [fft_benchmark](#fft_benchmark) Syntax: @@ -929,6 +956,388 @@ When the function is executed, it furst writes `` 32-bit floatin ---- +### [fft_one_side_ff](#fft_one_side_ff) + +Syntax: + + csdr fft_one_side_ff + +If the frequency domain signal spans between frequencies -fs/2 to fs/2, this function removes the part from -fs/2 to DC. This can be useful if the FFT of a real signal has been taken (so that the spectrum is mirrored to DC). + +---- + +### [logaveragepower_cf](#logaveragepower_cf) + +Syntax: + + csdr logaveragepower_cf + +It works like logpower_cf , but it calculates the average of every `avgnumber` FFTs. + +---- + +### [mono2stereo_s16](#mono2stereo_s16) + +Syntax: + + csdr mono2stereo_s16 + +It duplicates each 16-bit integer input sample. + +---- + +### [psk31_varicode_decoder_u8_u8](#psk31_varicode_decoder_u8_u8) + +Syntax: + + csdr psk31_varicode_decoder_u8_u8 + +It expects symbols encoded as 0x00 and 0x01 bytes on the input, and extracts Varicode characters from them. + +---- + +### [_fft2octave](#_fft2octave) + +Syntax: + + csdr _fft2octave + +It is used for plotting FFT data with a GNU Octave session, piping its output to `octave -i`. + +---- + +### [invert_u8_u8](#invert_u8_u8) + +Syntax: + + csdr invert_u8_u8 + +It maps + +* each 0x00 to 0x01, +* each 0x01 to 0x00. + +---- + +### [rtty_baudot2ascii_u8_u8](#rtty_baudot2ascii_u8_u8) + +Syntax: + + csdr rtty_baudot2ascii_u8_u8 + +This function awaits baudot code characters on its input (ranging from 0b00000000 to 0b00011111), and converts them into ASCII characters. It has an internal state to switch between letters and figures. + +---- + +### [binary_slicer_f_u8](#binary_slicer_f_u8) + +Syntax: + + csdr binary_slicer_f_u8 + +* If the input sample is below or equals to 0.0, it outputs a 0x00. +* If the input sample is above 0.0, it outputs a 0x01. + +---- + +### [serial_line_decoder_f_u8](#serial_line_decoder_f_u8) + +Syntax: + + csdr serial_line_decoder_f_u8 [databits [stopbits]] + +It decodes bits from a sampled serial line. It does so by finding the appropriate start and stop bits, and extracts the data bits in between. + +---- + +### [pll_cc](#pll_cc) + +Syntax: + + csdr pll_cc (1 [alpha] |2 [bandwidth [damping_factor [ko [kd]]]]) + +It implements a PLL that can lock onto a sinusoidal input signal. + +The first parameter corresponds to the order of the PLL loop filter (first or second order), others are parameters of the loop filter. + +---- + +### [timing_recovery_cc](#timing_recovery_cc) + +Syntax: + + csdr timing_recovery_cc [mu [max_error [--add_q [--output_error | --output_indexes | --octave | --octave_save ]]]] + +It implements non-data aided timing recovery (Gardner and early-late gate algorithms). + +[More information](http://openwebrx.org/msc-thesis.pdf#page=34) (section 4.4 from page 34) + +---- + +### [octave_complex_c](#octave_complex_c) + +Syntax: + + csdr octave_complex_c [--2d] + +It generates octave commands to plot a complex time domain signal. Its output can be piped into `octave -i`. It plots every `samples_to_plot` samples `out_of_n_samples`. + +---- + +### [psk_modulator_u8_c](#psk_modulator_u8_c) + +Syntax: + + csdr psk_modulator_u8_c + +It generates an N-PSK modulated signal from the input symbols. + +As an example, for `n_psk`=4, it will translate: + +* any 0x00 byte on the input into 1+0j on the output, +* any 0x01 byte on the input into 0+1j on the output, +* any 0x02 byte on the input into -1+0j on the output, +* any 0x03 byte on the input into 0-1j on the output. + +---- + +### [duplicate_samples_ntimes_u8_u8](#duplicate_samples_ntimes_u8_u8) + +Syntax: + + csdr duplicate_samples_ntimes_u8_u8 + +It duplicates each sample of `sample_size_bytes` the given `ntimes` times. + +---- + +### [psk31_interpolate_sine_cc](#psk31_interpolate_sine_cc) + +Syntax: + + csdr psk31_interpolate_sine_cc + +The input to this function is one complex sample per symbol, the output is `interpolation` samples per symbol, interpolated using a cosine envelope (which is used for PSK31). + +---- + +### [differential_encoder_u8_u8](#differential_encoder_u8_u8) + +Syntax: + + csdr differential_encoder_u8_u8 + +It can be used while generating e.g. differential BPSK modulation. + +* If the input is 0x01, the output remains the same as the last output. +* If the input is 0x00, the output changes from 0x00 to 0x01, or 0x01 to 0x00. + +---- + +### [differential_decoder_u8_u8](#differential_decoder_u8_u8) + +Syntax: + + csdr differential_decoder_u8_u8 + +It can be used while demodulating e.g. differential BPSK modulation. The following table show the logic function it performs: + +| Last input | Current input | Output | +| ---------- | ------------- | ------ | +| 0x00 | 0x00 | 0x01 | +| 0x00 | 0x01 | 0x00 | +| 0x01 | 0x00 | 0x00 | +| 0x01 | 0x01 | 0x01 | + +---- + +### [bpsk_costas_loop_cc](#bpsk_costas_loop_cc) + +Syntax: + + csdr bpsk_costas_loop_cc [--dd | --decision_directed] [--output_error | --output_dphase | --output_nco | --output_combined ] + +It implements a Costas loop for BPSK signals. + +[More information](http://openwebrx.org/msc-thesis.pdf#page=55) (section 5.4 from page 55) + +---- + +### [simple_agc_cc](#simple_agc_cc) + +Syntax: + + csdr simple_agc_cc [reference [max_gain]] + +It is an automatic gain control function with a single pole IIR loop filter. + +- `reference` is the reference level for the AGC. It tries to keep the amplitude of the output signal close to that. +- AGC won't increase the gain over `max_gain`. +- `rate` is the parameter of the loop filter. + +The block diagram of this function follows: + +![simple_agc_cc block diagram](https://raw.githubusercontent.com/wiki/simonyiszk/csdr/simple-agc-dataflow.png) + +---- + +### [peaks_fir_cc](#peaks_fir_cc) + +Syntax: + + csdr peaks_fir_cc + +It applies a peak filter to the input signal. The peak filter is a very narrow bandpass filter, the opposite of a notch filter. The higher the `taps_length` is, the sharper the filter frequency transfer function is. + +`peak_rate` is the center of the passband, in proportion to the sampling rate. + +---- + +### [firdes_peak_c](#firdes_peak_c) + +Syntax: + + csdr firdes_peak_c [window [--octave]] + +It designs a FIR peak filter, and writes the taps to the output. More about this filter at peaks_fir_cc. + +This command also supports GNU Octave-friendly output that can be piped into the Octave interpreter `octave -i`. + +---- + +### [normalized_timing_variance_u32_f](#normalized_timing_variance_u32_f) + +Syntax: + + csdr normalized_timing_variance_u32_f [--debug] + +It calculates the normalized timing variance. It works on the sample indexes output from the `timing_recovery_cc` function. + +---- + +### [pulse_shaping_filter_cc](#pulse_shaping_filter_cc) + +Syntax: + + csdr pulse_shaping_filter_cc (RRC | COSINE ) + +It runs a pulse shaping FIR filter on the signal. + +* `RRC` stands for Root-Raised-Cosine filter, a design parameter of which is `beta`. +* The `COSINE` filter is the one used for BPSK31. +* `samples_per_symbol` is the number of input samples per symbol. +* `num_taps` is the filter length. + +---- + +### [firdes_pulse_shaping_filter_f](#firdes_pulse_shaping_filter_f) + +Syntax: + + csdr firdes_pulse_shaping_filter_f (RRC | COSINE ) + +It designs a pulse shaping filter, and outputs the taps. It has the same parameters as `pulse_shaping_filter_cc`. + +---- + +### [generic_slicer_f_u8](#generic_slicer_f_u8) + +Syntax: + + csdr generic_slicer_f_u8 + +It decides which symbol the sample corresponds to, where the highest symbol corresponds to 1.0, and the lowest symbol corresponds to -1.0. + +As an example, if N=3, the 3 symbols to choose from are: -1, 0, 1. The algorithm will output: + +* 0x00 for any input sample between -infinity and -0.5. +* 0x01 for any input sample between -0.5 and 0.5. +* 0x02 for any input sample between 0.5 and infinity. + +---- + +### [plain_interpolate_cc](#plain_interpolate_cc) + +Syntax: + + csdr plain_interpolate_cc + +It interpolates the signal by writing `interpolation - 1` zero samples between each input sample. You need to run an anti-aliasing filter on its output. + +---- + +### [dbpsk_decoder_c_u8](#dbpsk_decoder_c_u8) + +Syntax: + + csdr dbpsk_decoder_c_u8 + +It implements a differential BPSK demodulator, with the following data flow: + +![DBPSK dataflow](https://raw.githubusercontent.com/wiki/simonyiszk/csdr/dbpsk-dataflow.png) + +The output is 0x00 or 0x01. + +---- + +### [bfsk_demod_cf](#bfsk_demod_cf) + +Syntax: + + csdr bfsk_demod_cf + +It implements a 2-FSK demodulator, with the following data flow: + +![BFSK dataflow](https://raw.githubusercontent.com/wiki/simonyiszk/csdr/bfsk-dataflow.png) + +You can calculate the expected frequencies of the two tones on the input by the following formulas: `+(spacing/sampling_rate)` and `-(spacing/sampling_rate)`. + +Filter length is the length of the peak filters (FIR) applied to the input för each tone. + +---- + +### [add_const_cc](#add_const_cc) + +Syntax: + + csdr add_const_cc + +It adds a constant value of `i+q*j` to each input sample. + +---- + +### [pattern_search_u8_u8](#pattern_search_u8_u8) + +Syntax: + + csdr pattern_search_u8_u8 + +It can be used for preamble search. It looks for a given sequence of N bytes (``) in the input data, and if the sequence is found, it reads the following `` bytes and outputs them. The `` parameter is read as unsigned integers. + +---- + +### [tee](#tee) + +Syntax: + + csdr tee [buffers] + +Similarly to the `tee` command, it reads data from the standard input, and writes it to both a file and the standard output. + +Unlike `tee`, if it fails to flush the data to the file, it still flushes it to the standard output. This allows us to have less glitches / better response time if we use this as a way to put branches in the data flow. Example: + + mkfifo /tmp/csdr_fifo + rtl_sdr - | csdr tee /tmp/csdr_fifo | csdr dump_u8 + cat /tmp/csdr_fifo | csdr convert_u8_f | csdr dump_f + +How the data flow looks like: + + rtl_sdr --> tee --> dump_u8 + | + \/ + convert_u8_f --> dump_f + + ### [?](#search_the_function_list) Syntax: diff --git a/csdr.c b/csdr.c index 0d2d0cb..27dbf6d 100755 --- a/csdr.c +++ b/csdr.c @@ -126,7 +126,7 @@ char usage[]= " rtty_line_decoder_u8_u8\n" " rtty_baudot2ascii_u8_u8\n" " serial_line_decoder_f_u8 [databits [stopbits]]\n" -" octave_complex_c \n" +" octave_complex_c [--2d]\n" " timing_recovery_cc [mu [max_error [--add_q [--output_error | --output_indexes | --octave | --octave_save ]]]] \n" " psk31_varicode_encoder_u8_u8\n" " psk31_varicode_decoder_u8_u8\n" @@ -162,6 +162,21 @@ char usage[]= " ?\n" " ??\n" " =\n" +" shift_addfast_cc #only if system supports NEON \n" +" shift_unroll_cc \n" +" logaveragepower_cf \n" +" fft_one_side_ff \n" +" convert_f_samplerf \n" +" add_dcoffset_cc\n" +" fastddc_fwd_cc [transition_bw [window]]\n" +" fastddc_inv_cc [transition_bw [window]]\n" +" _fft2octave \n" +" convert_f_i16 #deprecated, use instead: convert_f_s16\n" +" convert_i16_f #deprecated, use instead: convert_s16_f\n" +" floatdump_f #deprecated, use instead: dump_f\n" +" mono2stereo_i16 #deprecated, use instead: mono2stereo_s16\n" +" decode_ima_adpcm_u8_i16 #deprecated, use instead: decode_ima_adpcm_u8_s16\n" +" encode_ima_adpcm_i16_u8 #deprecated, use instead: encode_ima_adpcm_i16_u8\n" " \n" ; @@ -1648,7 +1663,7 @@ int main(int argc, char *argv[]) if(!strcmp(argv[1],"logaveragepower_cf")) { bigbufs=1; - if(argc<=4) return badsyntax("need required parameters (add_db, table_size, avgnumber)"); + if(argc<=4) return badsyntax("need required parameters (add_db, fft_size, avgnumber)"); float add_db=0; int avgnumber=0; int fft_size=0; From 146bb6e3830f15028e4710a45758d760b1c65b88 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Fri, 7 Jul 2017 13:10:30 +0200 Subject: [PATCH 110/111] README --- README.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4d2f4f5..c3f611e 100755 --- a/README.md +++ b/README.md @@ -12,9 +12,14 @@ Most of the code is available under the permissive BSD license, with some option `csdr` has already been used to build: -- AM/FM/SSB/CW demodulators, BPSK31 decoder and waterfall display in [OpenWebRX](https://github.com/simonyiszk/openwebrx), -- AM/FM/SSB modulators in [qtcsdr](https://github.com/ha7ilm/qtcsdr) that can also be used standalone with [rpitx](https://github.com/ha7ilm/rpitx-app-note), -- a decoder for FSK transmissions sent with the CC1111 wireless MCU, and also a standalone RTTY demodulator. +- AM, FM, SSB, CW and BPSK31 demodulators and waterfall display in [OpenWebRX](https://github.com/simonyiszk/openwebrx), +- AM, FM, SSB modulators in [qtcsdr](https://github.com/ha7ilm/qtcsdr) that can also be used standalone with [rpitx](https://github.com/ha7ilm/rpitx-app-note), +- a demodulator for FSK transmissions sent with the CC1111 wireless MCU, and also a standalone RTTY demodulator. + +This animation shows the Gardner timing recovery algorithm in `csdr` locking on a baseband BPSK signal: + +![Gardner](https://raw.githubusercontent.com/wiki/simonyiszk/csdr/gardner.gif) + How to compile -------------- From 32c7e3b52c31b105fdcc03eda06fdc912eac619d Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Fri, 7 Jul 2017 13:19:57 +0200 Subject: [PATCH 111/111] README.md --- README.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/README.md b/README.md index c3f611e..3ffb1c6 100755 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ This animation shows the Gardner timing recovery algorithm in `csdr` locking on ![Gardner](https://raw.githubusercontent.com/wiki/simonyiszk/csdr/gardner.gif) +(The symbol is sampled at the left red dot. The algorithm moves the middle dot as close to the symbol transition center, as possible.) How to compile -------------- @@ -696,12 +697,6 @@ Calculates `10*log10(i^2+q^2)+add_db` for the input complex samples. It is usefu ### [encode_ima_adpcm_i16_u8](#encode_ima_adpcm_i16_u8) -Syntax: - ----- - -### [csdr](#csdr) - Syntax: csdr csdr encode_ima_adpcm_i16_u8