i16 -> s16 at even more places, README improvements, env_csdr_fixed_big_bufsize fix.

This commit is contained in:
ha7ilm 2016-02-14 19:16:07 +01:00
parent 26d10e6df8
commit cfd9ef1fb7
2 changed files with 105 additions and 9 deletions

View file

@ -109,7 +109,7 @@ Data types are noted as it follows:
- `f` is `float` (single percision) - `f` is `float` (single percision)
- `c` is `complexf` (two single precision floating point values in a struct) - `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`) - `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: Functions usually end as:
@ -124,12 +124,14 @@ The following commands are available:
- `csdr convert_f_u8` - `csdr convert_f_u8`
- `csdr convert_s8_f` - `csdr convert_s8_f`
- `csdr convert_f_s8` - `csdr convert_f_s8`
- `csdr convert_i16_f` - `csdr convert_s16_f`
- `csdr convert_f_i16` - `csdr convert_f_s16`
How to interpret: `csdr convert_<src>_<dst>` How to interpret: `csdr convert_<src>_<dst>`
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). 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 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`. `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. 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 none
The `csdr` process just exits with 0. 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`. 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 <wait_for_this_sample>
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 `<wait_for_this_sample>` 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 <new_amplitude>
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 <buffer_size>
See the [buffer sizes](#buffer_sizes) section.
#### Control via pipes #### 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. 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` 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 <buffer_size>` 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=<buffer_size>`.
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 #### Testbench
`csdr` was tested with GNU Radio Companion flowgraphs. These flowgraphs are available under the directory `grc_tests`, and they require the <a href="https://github.com/simonyiszk/gr-ha5kfu">gr-ha5kfu</a> set of blocks for GNU Radio. `csdr` was tested with GNU Radio Companion flowgraphs. These flowgraphs are available under the directory `grc_tests`, and they require the <a href="https://github.com/simonyiszk/gr-ha5kfu">gr-ha5kfu</a> set of blocks for GNU Radio.

20
csdr.c
View file

@ -95,9 +95,17 @@ char usage[]=
" logpower_cf [add_db]\n" " logpower_cf [add_db]\n"
" fft_benchmark <fft_size> <fft_cycles> [--benchmark]\n" " fft_benchmark <fft_size> <fft_cycles> [--benchmark]\n"
" bandpass_fir_fft_cc <low_cut> <high_cut> <transition_bw> [window]\n" " bandpass_fir_fft_cc <low_cut> <high_cut> <transition_bw> [window]\n"
" encode_ima_adpcm_i16_u8\n" " encode_ima_adpcm_s16_u8\n"
" decode_ima_adpcm_u8_i16\n" " decode_ima_adpcm_u8_s16\n"
" compress_fft_adpcm_f_u8 <fft_size>\n" " compress_fft_adpcm_f_u8 <fft_size>\n"
" flowcontrol <data_rate> <reads_per_second>\n"
" through\n"
" dsb_fc [q_value]\n"
" convert_f_samperf <wait_for_this_sample> \n"
" fmmod_fc\n"
" fixed_amplitude_cc <new_amplitude>\n"
" monos2stereo_s16\n"
" setbuf <buffer_size>\n"
" fft_exchange_sides_ff <fft_size>\n" " fft_exchange_sides_ff <fft_size>\n"
" \n" " \n"
; ;
@ -288,7 +296,7 @@ int parse_env()
envtmp=getenv("CSDR_FIXED_BUFSIZE"); envtmp=getenv("CSDR_FIXED_BUFSIZE");
if(envtmp) if(envtmp)
{ {
env_csdr_fixed_bufsize = atoi(envtmp); env_csdr_fixed_big_bufsize = env_csdr_fixed_bufsize = atoi(envtmp);
} }
} }
envtmp=getenv("CSDR_PRINT_BUFSIZES"); envtmp=getenv("CSDR_PRINT_BUFSIZES");
@ -1372,7 +1380,7 @@ int main(int argc, char *argv[])
#ifdef USE_IMA_ADPCM #ifdef USE_IMA_ADPCM
#define IMA_ADPCM_BUFSIZE BUFSIZE #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; if(!sendbufsize(initialize_buffers()/2)) return -2;
ima_adpcm_state_t d; 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; ima_adpcm_state_t d;
d.index=d.previousValue=0; 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; if(!sendbufsize(initialize_buffers())) return -2;
float last_phase = 0; float last_phase = 0;