From cfd9ef1fb7a51628caf045ad7815d53b5d6e2ca5 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Sun, 14 Feb 2016 19:16:07 +0100 Subject: [PATCH] i16 -> s16 at even more places, README improvements, env_csdr_fixed_big_bufsize fix. --- README.md | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- csdr.c | 20 ++++++++---- 2 files changed, 105 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 883e0da..7bc5cf2 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ Data types are noted as it follows: - `f` is `float` (single percision) - `c` is `complexf` (two single precision floating point values in a struct) - `u8` is `unsigned char` of 1 byte/8 bits (e. g. the output of `rtl_sdr` is of `u8`) -- `i16` is `signed short` of 2 bytes/16 bits (e. g. sound card input is usually `i16`) +- `s16` is `signed short` of 2 bytes/16 bits (e. g. sound card input is usually `s16`) Functions usually end as: @@ -124,12 +124,14 @@ The following commands are available: - `csdr convert_f_u8` - `csdr convert_s8_f` - `csdr convert_f_s8` -- `csdr convert_i16_f` -- `csdr convert_f_i16` +- `csdr convert_s16_f` +- `csdr convert_f_s16` 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`. @@ -157,6 +159,10 @@ It multiplies all samples by `gain`. It copies the input to the output. + through + +It copies the input to the output, while also displaying the speed of the data going through it. + none The `csdr` process just exits with 0. @@ -349,6 +355,38 @@ The actual number of padding samples can be determined by running `cat csdr.c | 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] + +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 + +It adds a DC offset to the complex signal: `i_output = 0.5 + i_input / 2, q_output = q_input / 2` + + 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 + +It generates a complex FM modulated output from a real input signal. + + 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. + + setbuf + +See the [buffer sizes](#buffer_sizes) section. + #### 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. @@ -371,6 +409,56 @@ 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` +#### Buffer sizes + +`csdr` has three modes of determining the buffer sizes, which can be chosen by the appropriate environment variables: +* default: 16k or 1k buffer is chosen based on function, +* dynamic buffer size determination: input buffer size is recommended by the previous process, output buffer size is determined by the process, +* fixed buffer sizes. + +`csdr` uses two buffer sizes by **default**. +* For operations handling the full-bandwidth I/Q data from the receiver, a buffer size of 16384 samples is used. +* For operations handling only a selected channel, a buffer size of 1024 samples is used (see `env_csdr_fixed_bufsize` in the code). + +`csdr` now has an experimental feature called **dynamic buffer size determination**, which is switched on by issuing `export CSDR_DYNAMIC_BUFSIZE_ON=1` in the shell before running `csdr`. If it is enabled: +* All `csdr` processes in a DSP chain acquire their recommended input buffer size from the previous `csdr` process. This information is in the first 8 bytes of the input stream. +* Each process can decide whether to use this or choose another input buffer size (if that's more practical). +* Every process sends out its output buffer size to the next process. Then it startss processing data. +* The DSP chain should start with a `csdr setbuf ` process, which only copies data from the input to the output, but also sends out the given buffer size information to the next process. +* The 8 information included in the beginning of the stream is: + * a preamble of the bytes 'C','S','D','R' (4 bytes), + * the buffer size stored as `int` (4 bytes). +* This size always counts as samples, as we expect that the user takes care of connecting the functions with right data types to each other. + +> I added this feature while researching how to decrease the latency of a DSP chain consisting of several multirate algorithms. +> For example, a `csdr fir_decimate_cc 10` would use an input buffer of 10240, and an output buffer of 1024. The next process in the chain, `csdr bandpass_fir_fft_cc` would automatically adjust to it, using a buffer of 1024 for both input and output. +> In contrast to original expectations, using dynamic buffer sizes didn't decrease the latency much. + +If dynamic buffer size determination is disabled, you can still set a **fixed buffer size** with `export CSDR_FIXED_BUFSIZE=`. + +For debug purposes, buffer sizes of all processes can be printed using `export CSDR_PRINT_BUFSIZES=1`. + +If you add your own functions to `csdr`, you have to initialize the buffers before doing the processing. Buffer size will be stored in the global variable `the_bufsize`. + +Example of initialization if the process generates N output samples for N input samples: + + if(!sendbufsize(initialize_buffers())) return -2; + +Example of initalization if the process generates N/D output samples for N input samples: + + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize/D); + +Example of initialization if the process allocates memory for itself, and it doesn't want to use the global buffers: + + getbufsize(); //dummy + sendbufsize(my_own_bufsize); + +Example of initialization if the process always works with a fixed output size, regardless of the input: + + if(!initialize_buffers()) return -2; + sendbufsize(fft_size); + #### Testbench `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. diff --git a/csdr.c b/csdr.c index 287c48e..affcc4c 100644 --- a/csdr.c +++ b/csdr.c @@ -95,9 +95,17 @@ char usage[]= " logpower_cf [add_db]\n" " fft_benchmark [--benchmark]\n" " bandpass_fir_fft_cc [window]\n" -" encode_ima_adpcm_i16_u8\n" -" decode_ima_adpcm_u8_i16\n" +" encode_ima_adpcm_s16_u8\n" +" decode_ima_adpcm_u8_s16\n" " compress_fft_adpcm_f_u8 \n" +" flowcontrol \n" +" through\n" +" dsb_fc [q_value]\n" +" convert_f_samperf \n" +" fmmod_fc\n" +" fixed_amplitude_cc \n" +" monos2stereo_s16\n" +" setbuf \n" " fft_exchange_sides_ff \n" " \n" ; @@ -288,7 +296,7 @@ int parse_env() envtmp=getenv("CSDR_FIXED_BUFSIZE"); if(envtmp) { - env_csdr_fixed_bufsize = atoi(envtmp); + env_csdr_fixed_big_bufsize = env_csdr_fixed_bufsize = atoi(envtmp); } } envtmp=getenv("CSDR_PRINT_BUFSIZES"); @@ -1372,7 +1380,7 @@ int main(int argc, char *argv[]) #ifdef USE_IMA_ADPCM #define IMA_ADPCM_BUFSIZE BUFSIZE - if(!strcmp(argv[1],"encode_ima_adpcm_i16_u8")) + 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; @@ -1387,7 +1395,7 @@ int main(int argc, char *argv[]) } } - if(!strcmp(argv[1],"decode_ima_adpcm_u8_i16")) + 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; @@ -1655,7 +1663,7 @@ int main(int argc, char *argv[]) } } - if(!strcmp(argv[1],"mono2stereo_i16")) + if((!strcmp(argv[1],"mono2stereo_i16"))||(!strcmp(argv[1],"mono2stereo_s16"))) { if(!sendbufsize(initialize_buffers())) return -2; float last_phase = 0;