Working PSK31 generator

This commit is contained in:
ha7ilm 2017-03-27 13:44:01 +02:00
parent c23693e885
commit d3a7c6e12b
4 changed files with 103 additions and 16 deletions

View file

@ -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 <data_rate> <reads_per_second>
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 <rate>
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 `<squel
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
It encodes ASCII characters into varicode for PSK31 transmission. It puts a `00` sequence between the varicode characters (which acts as a separator).
For the Varicode character set, see: http://www.arrl.org/psk31-spec
For example, `aaa` means the bit sequence `101100101100101100`.
For this input, the output of `psk31_varicode_encoder_u8_u8` will be the following bytes (in hexadecimal):
```
01 00 01 01 00 00 01 00
01 01 00 00 01 00 01 01
00 00
```
#### 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.

41
csdr.c Normal file → Executable file
View file

@ -73,7 +73,7 @@ char usage[]=
" none\n"
" yes_f <to_repeat> [buf_times]\n"
" detect_nan_ff\n"
" floatdump_f\n"
" dump_f\n"
" flowcontrol <data_rate> <reads_per_second> [prebuffer_sec] [thrust]\n"
" shift_math_cc <rate>\n"
" shift_math_cc --fifo <fifo_path>\n"
@ -124,6 +124,14 @@ char usage[]=
" serial_line_decoder_sy_u8\n"
" octave_complex_c <samples_to_plot> <out_of_n_samples>\n"
" timing_recovery_cc <algorithm> <decimation> [--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_psk>\n"
" psk31_interpolate_sine_cc\n"
" duplicate_samples_ntimes_u8_u8 <sample_size_bytes> <ntimes>\n"
" ?<search_the_function_list>\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_samples<samples_to_plot) badsyntax("out_of_n_samples should be < samples_to_plot");
int mode2d = 0;
if(argc>4) 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<samples_to_plot;i++) printf("%f ", iof(read_buf, i));
printf("];\nqsig = [");
for(int i=0;i<samples_to_plot;i++) printf("%f ", qof(read_buf, i));
printf("];\nzsig = [0:N-1];\nplot3(isig,zsig,qsig);\n");
printf("];\nzsig = [0:N-1];\n");
if(mode2d) printf("subplot(2,1,1);\nplot(zsig,isig);\nsubplot(2,1,2);\nplot(zsig,qsig);\n");
else printf("plot3(isig,zsig,qsig);\n");
//printf("xlim([-1 1]);\nzlim([-1 1]);\n");
fflush(stdout);
//if(fseek(stdin, (out_of_n_samples - samples_to_plot)*sizeof(complexf), SEEK_CUR)<0) { perror("fseek error"); return -3; } //this cannot be used on stdin
@ -2450,11 +2462,13 @@ int main(int argc, char *argv[])
if(!strcmp(argv[1],"duplicate_samples_ntimes_u8_u8")) //<sample_size_bytes> <ntimes>
{
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;

View file

@ -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<input_size; *input_processed++)
(*output_size)=0;
for((*input_processed)=0; (*input_processed)<input_size; (*input_processed)++)
{
//fprintf(stderr, "ii = %d, input_size = %d, output_max_size = %d\n", *input_processed, input_size, output_max_size);
for(int ci=0; ci<n_psk31_varicode_items; ci++) //ci: character index
{
psk31_varicode_item_t current_varicode = psk31_varicode_items[ci];
if(input[*input_processed]==current_varicode.ascii)
{
if(output_max_size<current_varicode.bitcount) return;
for(int bi=0; bi<current_varicode.bitcount; bi++) //bi: bit index
//fprintf(stderr, "ci = %d\n", ci);
if(output_max_size<current_varicode.bitcount+2) return;
for(int bi=0; bi<current_varicode.bitcount+2; bi++) //bi: bit index
{
output[*output_size]=(psk31_varicode_items[ci].code>>(current_varicode.bitcount-bi-1))&1;
*output_size++;
//fprintf(stderr, "bi = %d\n", bi);
output[*output_size] = (bi<current_varicode.bitcount) ? (psk31_varicode_items[ci].code>>(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<input_size;i++)
{
float out_phase=((2*M_PI)/n_psk)*input[i];
float out_phase=phase_increment*input[i];
iof(output,i)=cos(out_phase);
qof(output,i)=sin(out_phase);
}
@ -1617,14 +1621,18 @@ void duplicate_samples_ntimes_u8_u8(unsigned char* input, unsigned char* output,
complexf psk31_interpolate_sine_cc(complexf* input, complexf* output, int input_size, int interpolation, complexf last_input)
{
int oi=0; //output index
for(int i=0;i<input_size;i++)
{
for(int j=0; j<interpolation; j++)
{
float rate = (1+sin(-(M_PI/2)+M_PI*((j+1)/(float)interpolation)))/2;
iof(output,i)=iof(input,i) * rate + iof(&last_input,0) * (1-rate);
qof(output,i)=qof(input,i) * rate + qof(&last_input,0) * (1-rate);
last_input = output[i];
iof(output,oi)=iof(input,i) * rate + iof(&last_input,0) * (1-rate);
qof(output,oi)=qof(input,i) * rate + qof(&last_input,0) * (1-rate);
oi++;
}
last_input = input[i];
}
return last_input;
}
@ -1635,6 +1643,21 @@ void pack_bits_8to1_u8_u8(unsigned char* input, unsigned char* output, int input
*(output++)=(input[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<input_size;i++)
{
output[i] = input[i] == state;
state = input[i];
}
else
for(int i=0;i<input_size;i++)
{
if(!input[i]) state=!state;
output[i] = state;
}
}
/*
_____ _ _______ _ _ _____

View file

@ -322,3 +322,4 @@ void duplicate_samples_ntimes_u8_u8(unsigned char* input, unsigned char* output,
complexf psk31_interpolate_sine_cc(complexf* input, complexf* output, int input_size, int interpolation, complexf last_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);