Merged origin/master into nmux
This commit is contained in:
commit
3246e20864
6 changed files with 736 additions and 311 deletions
4
Makefile
4
Makefile
|
@ -29,7 +29,7 @@
|
|||
LIBSOURCES = fft_fftw.c libcsdr_wrapper.c
|
||||
#SOURCES = csdr.c $(LIBSOURCES)
|
||||
cpufeature = $(if $(findstring $(1),$(shell cat /proc/cpuinfo)),$(2))
|
||||
PARAMS_SSE = $(call cpufeature,sse,-msse) $(call cpufeature,sse2,-msse2) $(call cpufeature,sse3,-msse3) $(call cpufeature,sse4,-msse4) $(call cpufeature,sse4_1,-msse4.1) $(call cpufeature,sse4_2,-msse4.2) -mfpmath=sse
|
||||
PARAMS_SSE = $(call cpufeature,sse,-msse) $(call cpufeature,sse2,-msse2) $(call cpufeature,sse3,-msse3) $(call cpufeature,sse4a,-msse4a) $(call cpufeature,sse4_1,-msse4.1) $(call cpufeature,sse4_2,-msse4.2 -msse4) -mfpmath=sse
|
||||
PARAMS_NEON = -mfloat-abi=hard -march=armv7-a -mtune=cortex-a8 -mfpu=neon -mvectorize-with-neon-quad -funsafe-math-optimizations -Wformat=0 -DNEON_OPTS
|
||||
#tnx Jan Szumiec for the Raspberry Pi support
|
||||
PARAMS_RASPI = -mfloat-abi=hard -mcpu=arm1176jzf-s -mfpu=vfp -funsafe-math-optimizations -Wformat=0
|
||||
|
@ -92,7 +92,7 @@ emcc-get-deps:
|
|||
emmake make; \
|
||||
emmake make install
|
||||
emcc:
|
||||
emcc -O3 -Isdr.js/$(FFTW_PACKAGE)/api -Lsdr.js/$(FFTW_PACKAGE)/emscripten-lib -o sdr.js/sdrjs-compiled.js fft_fftw.c libcsdr_wrapper.c -DLIBCSDR_GPL -DUSE_IMA_ADPCM -DUSE_FFTW -lfftw3f -s EXPORTED_FUNCTIONS="`python sdr.js/exported_functions.py`"
|
||||
emcc -O3 -Isdr.js/$(FFTW_PACKAGE)/api -Lsdr.js/$(FFTW_PACKAGE)/emscripten-lib -o sdr.js/sdrjs-compiled.js fft_fftw.c libcsdr_wrapper.c -s TOTAL_MEMORY=67108864 -DLIBCSDR_GPL -DUSE_IMA_ADPCM -DUSE_FFTW -lfftw3f -s EXPORTED_FUNCTIONS="`python sdr.js/exported_functions.py`"
|
||||
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'
|
||||
|
|
118
README.md
118
README.md
|
@ -12,14 +12,22 @@ Most of the code is available under the permissive BSD license, with some option
|
|||
|
||||
How to compile
|
||||
--------------
|
||||
The project was only tested on Linux. It has the following dependencies: `libfftw3-dev`
|
||||
|
||||
make
|
||||
sudo make install
|
||||
|
||||
The project was only tested on Linux. It has the following dependencies: `libfftw3-dev`
|
||||
|
||||
If you compile on ARM, please edit the Makefile and tailor `PARAMS_NEON` for your CPU.
|
||||
|
||||
To run the examples, you will also need <a href="http://sdr.osmocom.org/trac/wiki/rtl-sdr">rtl_sdr</a> 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:
|
||||
|
||||
./configure --enable-float
|
||||
|
||||
(This is for *fftw3*, not *libcsdr*. You do not need to run the configure script before compiling *libcsdr*.)
|
||||
|
||||
Credits
|
||||
-------
|
||||
The library was written by Andras Retzler, HA7ILM <<randras@sdr.hu>>.
|
||||
|
@ -31,7 +39,7 @@ Usage by example
|
|||
|
||||
### Demodulate WFM
|
||||
|
||||
rtl_sdr -s 240000 -f 89500000 -g 20 - | csdr convert_u8_f | csdr fmdemod_quadri_cf | csdr fractional_decimator_ff 5 | csdr deemphasis_wfm_ff 48000 50e-6 | csdr convert_f_i16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
|
||||
rtl_sdr -s 240000 -f 89500000 -g 20 - | csdr convert_u8_f | csdr fmdemod_quadri_cf | csdr fractional_decimator_ff 5 | csdr deemphasis_wfm_ff 48000 50e-6 | csdr convert_f_s16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
|
||||
|
||||
- Baseband I/Q signal is coming from an RTL-SDR USB dongle, with a center frequency of `-f 104300000` Hz, a sampling rate of `-s 240000` samples per second.
|
||||
- The `rtl_sdr` tool outputs an unsigned 8-bit I/Q signal (one byte of I sample and one byte of Q coming after each other), but `libcsdr` DSP routines internally use floating point data type, so we convert the data stream of `unsigned char` to `float` by `csdr convert_u8_f`.
|
||||
|
@ -43,7 +51,7 @@ Usage by example
|
|||
|
||||
### Demodulate WFM: advanced
|
||||
|
||||
rtl_sdr -s 2400000 -f 89300000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc -0.085 | csdr fir_decimate_cc 10 0.05 HAMMING | csdr fmdemod_quadri_cf | csdr fractional_decimator_ff 5 | csdr deemphasis_wfm_ff 48000 50e-6 | csdr convert_f_i16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
|
||||
rtl_sdr -s 2400000 -f 89300000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc -0.085 | csdr fir_decimate_cc 10 0.05 HAMMING | csdr fmdemod_quadri_cf | csdr fractional_decimator_ff 5 | csdr deemphasis_wfm_ff 48000 50e-6 | csdr convert_f_s16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
|
||||
|
||||
- We want to listen to one radio station, but input signal contains multiple stations, and its bandwidth is too large for sending it directly to the FM demodulator.
|
||||
- We shift the signal to the center frequency of the station we want to receive: `-0.085*2400000 = -204000`, so basically we will listen to the radio station centered at 89504000 Hz.
|
||||
|
@ -64,7 +72,7 @@ The first parameter is the frequency in MHz, and the second optional parameter i
|
|||
|
||||
### Demodulate NFM
|
||||
|
||||
rtl_sdr -s 2400000 -f 145000000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc `python -c "print float(145000000-145350000)/2400000"` | csdr fir_decimate_cc 50 0.005 HAMMING | csdr fmdemod_quadri_cf | csdr limit_ff | csdr deemphasis_nfm_ff 48000 | csdr fastagc_ff | csdr convert_f_i16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
|
||||
rtl_sdr -s 2400000 -f 145000000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc `python -c "print float(145000000-145350000)/2400000"` | csdr fir_decimate_cc 50 0.005 HAMMING | csdr fmdemod_quadri_cf | csdr limit_ff | csdr deemphasis_nfm_ff 48000 | csdr fastagc_ff | csdr convert_f_s16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
|
||||
|
||||
- Note that the decimation factor is higher (we want to select a ~25 kHz channel).
|
||||
- Also there is a python hack to calculate the relative shift offset. The real receiver frequency is `145350000` Hz.
|
||||
|
@ -72,7 +80,7 @@ The first parameter is the frequency in MHz, and the second optional parameter i
|
|||
|
||||
### Demodulate AM
|
||||
|
||||
rtl_sdr -s 2400000 -f 145000000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc `python -c "print float(145000000-144400000)/2400000"` | csdr fir_decimate_cc 50 0.005 HAMMING | csdr amdemod_cf | csdr fastdcblock_ff | csdr agc_ff | csdr limit_ff | csdr convert_f_i16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
|
||||
rtl_sdr -s 2400000 -f 145000000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc `python -c "print float(145000000-144400000)/2400000"` | csdr fir_decimate_cc 50 0.005 HAMMING | csdr amdemod_cf | csdr fastdcblock_ff | csdr agc_ff | csdr limit_ff | csdr convert_f_s16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
|
||||
|
||||
- `amdemod_cf` is used as demodulator.
|
||||
- `agc_ff` should be used for AM and SSB.
|
||||
|
@ -87,7 +95,7 @@ The first parameter is the frequency in MHz, and the second optional parameter i
|
|||
|
||||
### Demodulate SSB
|
||||
|
||||
rtl_sdr -s 2400000 -f 145000000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc `python -c "print float(145000000-144400000)/2400000"` | csdr fir_decimate_cc 50 0.005 HAMMING | csdr bandpass_fir_fft_cc 0 0.1 0.05 | csdr realpart_cf | csdr agc_ff | csdr limit_ff | csdr convert_f_i16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
|
||||
rtl_sdr -s 2400000 -f 145000000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc `python -c "print float(145000000-144400000)/2400000"` | csdr fir_decimate_cc 50 0.005 HAMMING | csdr bandpass_fir_fft_cc 0 0.1 0.05 | csdr realpart_cf | csdr agc_ff | csdr limit_ff | csdr convert_f_s16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
|
||||
|
||||
- It is a modified Weaver-demodulator. The complex FIR filter removes the lower sideband and lets only the upper pass (USB). If you want to demodulate LSB, change `bandpass_fir_fft_cc 0 0.05` to `bandpass_fir_fft_cc -0.05 0`.
|
||||
|
||||
|
@ -109,7 +117,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 +132,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_<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).
|
||||
|
||||
> 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 +167,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.
|
||||
|
@ -363,11 +377,45 @@ 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 <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>
|
||||
|
||||
If the environment variable `CSDR_DYNAMIC_BUFSIZE_ON` is set to 1, then you can use this command to set the input buffer size for the next `csdr` process in the chain.
|
||||
See the [buffer sizes](#buffer_sizes) section.
|
||||
|
||||
squelch_and_smeter_cc --fifo <squelch_fifo> --outfifo <smeter_fifo> <use_every_nth> <report_every_nth>
|
||||
|
||||
This is a controllable squelch, which reads the squelch level input from `<squelch_fifo>` and writes the power level output to `<smeter_fifo>`. Both input and output are in the format of `%g\n`. While calculating the power level, it takes only every `<use_every_nth>` sample into consideration. It writes the S-meter value for every `<report_every_nth>` buffer to `<smeter_fifo>`. 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 <buffer_size> <number_of_buffers>
|
||||
|
||||
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.
|
||||
|
||||
#### Control via pipes
|
||||
|
||||
|
@ -391,6 +439,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* can choose from two different buffer sizes by **default**.
|
||||
* For operations handling the full-bandwidth I/Q data from the receiver, a buffer size of 16384 samples is used (see `env_csdr_fixed_big_bufsize` in the code).
|
||||
* 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 bytes of 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.<br />
|
||||
> 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.<br />
|
||||
> 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
|
||||
|
||||
`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.
|
||||
|
|
276
csdr.c
276
csdr.c
|
@ -49,6 +49,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <sched.h>
|
||||
#include <math.h>
|
||||
#include <strings.h>
|
||||
#include <errno.h>
|
||||
#include "fastddc.h"
|
||||
|
||||
char usage[]=
|
||||
|
@ -60,8 +61,10 @@ char usage[]=
|
|||
" convert_f_u8\n"
|
||||
" convert_s8_f\n"
|
||||
" convert_f_s8\n"
|
||||
" convert_f_i16\n"
|
||||
" convert_i16_f\n"
|
||||
" convert_f_s16\n"
|
||||
" convert_s16_f\n"
|
||||
" convert_f_s24 [--bigendian]\n"
|
||||
" convert_s24_f [--bigendian]\n"
|
||||
" realpart_cf\n"
|
||||
" clipdetect_ff\n"
|
||||
" limit_ff [max_amplitude]\n"
|
||||
|
@ -73,7 +76,9 @@ char usage[]=
|
|||
" floatdump_f\n"
|
||||
" flowcontrol <data_rate> <reads_per_second> [prebuffer_sec] [thrust]\n"
|
||||
" shift_math_cc <rate>\n"
|
||||
" shift_math_cc --fifo <fifo_path>\n"
|
||||
" shift_addition_cc <rate>\n"
|
||||
" shift_addition_cc --fifo <fifo_path>\n"
|
||||
" shift_addition_cc_test\n"
|
||||
" shift_table_cc <rate> [table_size]\n"
|
||||
" decimating_shift_addition_cc <rate> [decimation]\n"
|
||||
|
@ -97,10 +102,21 @@ char usage[]=
|
|||
" logpower_cf [add_db]\n"
|
||||
" fft_benchmark <fft_size> <fft_cycles> [--benchmark]\n"
|
||||
" bandpass_fir_fft_cc <low_cut> <high_cut> <transition_bw> [window]\n"
|
||||
" encode_ima_adpcm_i16_u8\n"
|
||||
" decode_ima_adpcm_u8_i16\n"
|
||||
" bandpass_fir_fft_cc --fifo <fifo_path> <transition_bw> [window]\n"
|
||||
" encode_ima_adpcm_s16_u8\n"
|
||||
" decode_ima_adpcm_u8_s16\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"
|
||||
" squelch_and_smeter_cc --fifo <squelch_fifo> --outfifo <smeter_fifo> <use_every_nth> <report_every_nth>\n"
|
||||
" fifo <buffer_size> <number_of_buffers>\n"
|
||||
" \n"
|
||||
;
|
||||
|
||||
|
@ -306,7 +322,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");
|
||||
|
@ -341,6 +357,94 @@ int main(int argc, char *argv[])
|
|||
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;
|
||||
|
||||
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<fifo_num_buffers;i++) fifo_buffers[i]=(char*)malloc(sizeof(char)*fifo_buffer_size);
|
||||
|
||||
SET_NONBLOCK(STDIN_FILENO);
|
||||
SET_NONBLOCK(STDOUT_FILENO);
|
||||
|
||||
fd_set read_fds;
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(STDIN_FILENO, &read_fds);
|
||||
fd_set write_fds;
|
||||
FD_ZERO(&write_fds);
|
||||
FD_SET(STDOUT_FILENO, &write_fds);
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
if(fifo_error&&errno!=11) { fprintf(stderr,"fifo: fifo_error (%d)", errno); return -1; }
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
if(!strcmp(argv[1],"convert_u8_f"))
|
||||
{
|
||||
|
@ -368,27 +472,29 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
if(!strcmp(argv[1],"convert_s8_f"))
|
||||
{
|
||||
if(!sendbufsize(initialize_buffers())) return -2;
|
||||
for(;;)
|
||||
{
|
||||
FEOF_CHECK;
|
||||
fread(buffer_s8, sizeof(signed char), BUFSIZE, stdin);
|
||||
convert_s8_f(buffer_s8, output_buffer, BUFSIZE);
|
||||
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, buffer_s8, BUFSIZE);
|
||||
fwrite(buffer_s8, sizeof(signed char), BUFSIZE, stdout);
|
||||
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"))
|
||||
if((!strcmp(argv[1],"convert_f_i16")) || (!strcmp(argv[1],"convert_f_s16")))
|
||||
{
|
||||
if(!sendbufsize(initialize_buffers())) return -2;
|
||||
for(;;)
|
||||
|
@ -400,7 +506,7 @@ int main(int argc, char *argv[])
|
|||
TRY_YIELD;
|
||||
}
|
||||
}
|
||||
if(!strcmp(argv[1],"convert_i16_f")) //not tested
|
||||
if((!strcmp(argv[1],"convert_i16_f")) || (!strcmp(argv[1],"convert_s16_f")))
|
||||
{
|
||||
if(!sendbufsize(initialize_buffers())) return -2;
|
||||
for(;;)
|
||||
|
@ -412,6 +518,34 @@ int main(int argc, char *argv[])
|
|||
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;
|
||||
|
@ -906,11 +1040,15 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
int taps_length=firdes_filter_len(transition_bw);
|
||||
fprintf(stderr,"fir_decimate_cc: taps_length = %d\n",taps_length);
|
||||
|
||||
int padded_taps_length = taps_length;
|
||||
float *taps;
|
||||
|
@ -1255,6 +1393,8 @@ int main(int argc, char *argv[])
|
|||
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;
|
||||
|
@ -1273,7 +1413,8 @@ int main(int argc, char *argv[])
|
|||
for(int i=0;i<fft_size-every_n_samples;i++) input[i]=input[i+every_n_samples];
|
||||
fread(input+fft_size-every_n_samples, sizeof(complexf), every_n_samples, stdin);
|
||||
}
|
||||
apply_window_c(input,windowed,fft_size,window);
|
||||
//apply_window_c(input,windowed,fft_size,window);
|
||||
apply_precalculated_window_c(input,windowed,fft_size,windowt);
|
||||
fft_execute(plan);
|
||||
if(octave)
|
||||
{
|
||||
|
@ -1309,6 +1450,40 @@ 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)");
|
||||
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;
|
||||
}
|
||||
|
||||
if(!strcmp(argv[1],"fft_exchange_sides_ff"))
|
||||
{
|
||||
if(argc<=2) return badsyntax("need required parameters (fft_size)");
|
||||
|
@ -1409,7 +1584,6 @@ int main(int argc, char *argv[])
|
|||
float high_cut;
|
||||
float transition_bw;
|
||||
window_t window = WINDOW_DEFAULT;
|
||||
|
||||
int fd;
|
||||
if(fd=init_fifo(argc,argv))
|
||||
{
|
||||
|
@ -1485,7 +1659,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;
|
||||
|
@ -1500,7 +1674,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;
|
||||
|
@ -1515,7 +1689,7 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
|
||||
if(!strcmp(argv[1],"flowcontrol"))
|
||||
{
|
||||
if(argc<=3) return badsyntax("need required parameters (data_rate, reads_per_seconds)");
|
||||
|
@ -1537,9 +1711,9 @@ int main(int argc, char *argv[])
|
|||
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)");
|
||||
|
@ -1638,6 +1812,7 @@ int main(int argc, char *argv[])
|
|||
TRY_YIELD;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!strcmp(argv[1],"through"))
|
||||
{
|
||||
|
@ -1767,7 +1942,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;
|
||||
|
@ -1785,6 +1960,59 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
}
|
||||
|
||||
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<the_bufsize*2;i++) *(((float*)zerobuf)+i)=0;
|
||||
if(fd=init_fifo(argc,argv)) while(!read_fifo_ctl(fd,"%g\n",&squelch_level)) usleep(10000);
|
||||
else return badsyntax("need required parameter (--fifo <fifo>)");
|
||||
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 <fifo>)");
|
||||
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") ) //<decimation> [transition_bw [window]]
|
||||
{
|
||||
|
||||
|
@ -1942,9 +2170,5 @@ int main(int argc, char *argv[])
|
|||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
|
108
libcsdr.c
108
libcsdr.c
|
@ -941,7 +941,7 @@ complexf fmdemod_quadri_cf(complexf* input, float* output, int input_size, float
|
|||
}
|
||||
for (int i=0; i<input_size; i++) //@fmdemod_quadri_cf: output division
|
||||
{
|
||||
output[i]=fmdemod_quadri_K*output[i]/temp[i];
|
||||
output[i]=(temp[i])?fmdemod_quadri_K*output[i]/temp[i]:0;
|
||||
}
|
||||
|
||||
return input[input_size-1];
|
||||
|
@ -1018,6 +1018,26 @@ void gain_ff(float* input, float* output, int input_size, float gain)
|
|||
for(int i=0;i<input_size;i++) output[i]=gain*input[i]; //@gain_ff
|
||||
}
|
||||
|
||||
float get_power_f(float* input, int input_size, int decimation)
|
||||
{
|
||||
float acc = 0;
|
||||
for(int i=0;i<input_size;i+=decimation)
|
||||
{
|
||||
acc += (input[i]*input[i])/input_size;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
float get_power_c(complexf* input, int input_size, int decimation)
|
||||
{
|
||||
float acc = 0;
|
||||
for(int i=0;i<input_size;i+=decimation)
|
||||
{
|
||||
acc += (iof(input,i)*iof(input,i)+qof(input,i)*qof(input,i))/input_size;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
/*
|
||||
__ __ _ _ _
|
||||
| \/ | | | | | | |
|
||||
|
@ -1110,6 +1130,29 @@ void apply_window_c(complexf* input, complexf* output, int size, window_t window
|
|||
}
|
||||
}
|
||||
|
||||
float *precalculate_window(int size, window_t window)
|
||||
{
|
||||
float (*window_function)(float)=firdes_get_window_kernel(window);
|
||||
float *windowt;
|
||||
windowt = malloc(sizeof(float) * size);
|
||||
for(int i=0;i<size;i++) //@precalculate_window
|
||||
{
|
||||
float rate=(float)i/(size-1);
|
||||
windowt[i] = window_function(2.0*rate+1.0);
|
||||
}
|
||||
return windowt;
|
||||
}
|
||||
|
||||
void apply_precalculated_window_c(complexf* input, complexf* output, int size, float *windowt)
|
||||
{
|
||||
for(int i=0;i<size;i++) //@apply_precalculated_window_c
|
||||
{
|
||||
iof(output,i)=iof(input,i)*windowt[i];
|
||||
qof(output,i)=qof(input,i)*windowt[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void apply_window_f(float* input, float* output, int size, window_t window)
|
||||
{
|
||||
float (*window_function)(float)=firdes_get_window_kernel(window);
|
||||
|
@ -1129,6 +1172,19 @@ void logpower_cf(complexf* input, float* output, int size, float add_db)
|
|||
for(int i=0;i<size;i++) output[i]=10*output[i]+add_db; //@logpower_cf: pass 3
|
||||
}
|
||||
|
||||
void accumulate_power_cf(complexf* input, float* output, int size)
|
||||
{
|
||||
for(int i=0;i<size;i++) output[i] += iof(input,i)*iof(input,i) + qof(input,i)*qof(input,i); //@logpower_cf: pass 1
|
||||
|
||||
}
|
||||
|
||||
void log_ff(float* input, float* output, int size, float add_db) {
|
||||
for(int i=0;i<size;i++) output[i]=log10(input[i]); //@logpower_cf: pass 2
|
||||
|
||||
for(int i=0;i<size;i++) output[i]=10*output[i]+add_db; //@logpower_cf: pass 3
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
_____ _ _
|
||||
| __ \ | | (_)
|
||||
|
@ -1149,9 +1205,9 @@ void convert_s8_f(signed char* input, float* output, int input_size)
|
|||
for(int i=0;i<input_size;i++) output[i]=((float)input[i])/SCHAR_MAX; //@convert_s8_f
|
||||
}
|
||||
|
||||
void convert_i16_f(short* input, float* output, int input_size)
|
||||
void convert_s16_f(short* input, float* output, int input_size)
|
||||
{
|
||||
for(int i=0;i<input_size;i++) output[i]=(float)input[i]/SHRT_MAX; //@convert_i16_f
|
||||
for(int i=0;i<input_size;i++) output[i]=(float)input[i]/SHRT_MAX; //@convert_s16_f
|
||||
}
|
||||
|
||||
void convert_f_u8(float* input, unsigned char* output, int input_size)
|
||||
|
@ -1166,16 +1222,56 @@ void convert_f_s8(float* input, signed char* output, int input_size)
|
|||
for(int i=0;i<input_size;i++) output[i]=input[i]*SCHAR_MAX; //@convert_f_s8
|
||||
}
|
||||
|
||||
void convert_f_i16(float* input, short* output, int input_size)
|
||||
void convert_f_s16(float* input, short* output, int input_size)
|
||||
{
|
||||
/*for(int i=0;i<input_size;i++)
|
||||
{
|
||||
if(input[i]>1.0) input[i]=1.0;
|
||||
if(input[i]<-1.0) input[i]=-1.0;
|
||||
}*/
|
||||
for(int i=0;i<input_size;i++) output[i]=input[i]*SHRT_MAX; //@convert_f_i16
|
||||
for(int i=0;i<input_size;i++) output[i]=input[i]*SHRT_MAX; //@convert_f_s16
|
||||
}
|
||||
|
||||
void convert_i16_f(short* input, float* output, int input_size) { convert_s16_f(input, output, input_size); }
|
||||
void convert_f_i16(float* input, short* output, int input_size) { convert_f_s16(input, output, input_size); }
|
||||
|
||||
void convert_f_s24(float* input, unsigned char* output, int input_size, int bigendian)
|
||||
{
|
||||
int k=0;
|
||||
if(bigendian) for(int i=0;i<input_size;i++)
|
||||
{
|
||||
int temp=input[i]*(INT_MAX>>8);
|
||||
unsigned char* ptemp=(unsigned char*)&temp;
|
||||
output[k++]=*ptemp;
|
||||
output[k++]=*(ptemp+1);
|
||||
output[k++]=*(ptemp+2);
|
||||
}
|
||||
else for(int i=0;i<input_size;i++)
|
||||
{
|
||||
int temp=input[i]*(INT_MAX>>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<input_size*3;i+=3)
|
||||
{
|
||||
int temp=(input[i+2]<<24)|(input[i+1]<<16)|(input[i]<<8);
|
||||
output[k++]=temp/(float)(INT_MAX-256);
|
||||
}
|
||||
else for(int i=0;i<input_size*3;i+=3)
|
||||
{
|
||||
int temp=(input[i+2]<<8)|(input[i+1]<<16)|(input[i]<<24);
|
||||
output[k++]=temp/(float)(INT_MAX-256);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int trivial_vectorize()
|
||||
{
|
||||
//this function is trivial to vectorize and should pass on both NEON and SSE
|
||||
|
@ -1186,5 +1282,3 @@ int trivial_vectorize()
|
|||
}
|
||||
return c[0];
|
||||
}
|
||||
|
||||
|
||||
|
|
11
libcsdr.h
11
libcsdr.h
|
@ -137,9 +137,13 @@ typedef struct rational_resampler_ff_s
|
|||
rational_resampler_ff_t rational_resampler_ff(float *input, float *output, int input_size, int interpolation, int decimation, float *taps, int taps_length, int last_taps_delay);
|
||||
void rational_resampler_get_lowpass_f(float* output, int output_size, int interpolation, int decimation, window_t window);
|
||||
|
||||
float *precalculate_window(int size, window_t window);
|
||||
void apply_window_c(complexf* input, complexf* output, int size, window_t window);
|
||||
void apply_precalculated_window_c(complexf* input, complexf* output, int size, float *windowt);
|
||||
void apply_window_f(float* input, float* output, int size, window_t window);
|
||||
void logpower_cf(complexf* input, float* output, int size, float add_db);
|
||||
void accumulate_power_cf(complexf* input, float* output, int size);
|
||||
void log_ff(float* input, float* output, int size, float add_db);
|
||||
|
||||
typedef struct fractional_decimator_ff_s
|
||||
{
|
||||
|
@ -182,6 +186,8 @@ int log2n(int x);
|
|||
int next_pow2(int x);
|
||||
void apply_fir_fft_cc(FFT_PLAN_T* plan, FFT_PLAN_T* plan_inverse, complexf* taps_fft, complexf* last_overlap, int overlap_size);
|
||||
void gain_ff(float* input, float* output, int input_size, float gain);
|
||||
float get_power_f(float* input, int input_size, int decimation);
|
||||
float get_power_c(complexf* input, int input_size, int decimation);
|
||||
|
||||
void add_dcoffset_cc(complexf* input, complexf* output, int input_size);
|
||||
float fmmod_fc(float* input, complexf* output, int input_size, float last_phase);
|
||||
|
@ -191,7 +197,12 @@ void convert_u8_f(unsigned char* input, float* output, int input_size);
|
|||
void convert_f_u8(float* input, unsigned char* output, int input_size);
|
||||
void convert_s8_f(signed char* input, float* output, int input_size);
|
||||
void convert_f_s8(float* input, signed char* output, int input_size);
|
||||
void convert_f_s16(float* input, short* output, int input_size);
|
||||
void convert_s16_f(short* input, float* output, int input_size);
|
||||
void convert_f_i16(float* input, short* output, int input_size);
|
||||
void convert_i16_f(short* input, float* output, int input_size);
|
||||
void convert_f_s24(float* input, unsigned char* output, int input_size, int bigendian);
|
||||
void convert_s24_f(unsigned char* input, float* output, int input_size, int bigendian);
|
||||
|
||||
|
||||
int is_nan(float f);
|
||||
|
|
|
@ -219,10 +219,9 @@ float agc_ff(float* input, float* output, int input_size, float reference, float
|
|||
}
|
||||
gain=gain+dgain;
|
||||
//fprintf(stderr,"g=%f dg=%f\n",gain,dgain);
|
||||
|
||||
}
|
||||
if(gain>max_gain) gain=max_gain; //We also have to limit our gain, it can't be infinity.
|
||||
if(gain<0) gain=0;
|
||||
}
|
||||
//output[i]=gain*input[i]; //Here we do the actual scaling of the samples.
|
||||
//Here we do the actual scaling of the samples, but we run an IIR filter on the gain values:
|
||||
output[i]=(gain=gain+last_gain-gain_filter_alpha*last_gain)*input[i]; //dc-pass-filter: freqz([1 -1],[1 -0.99]) y[i]=x[i]+y[i-1]-alpha*x[i-1]
|
||||
|
@ -234,4 +233,3 @@ float agc_ff(float* input, float* output, int input_size, float reference, float
|
|||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in a new issue