diff --git a/.gitignore b/.gitignore index 73f4345..3aad0c2 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,5 @@ ddcd *.so tags dumpvect.*.vect -grc_tests/top_block.py *.swp +grc_tests/top_block.py diff --git a/Makefile b/Makefile index 047630c..4db95f1 100644 --- a/Makefile +++ b/Makefile @@ -44,9 +44,10 @@ PARAMS_MISC = -Wno-unused-result FFTW_PACKAGE = fftw-3.3.3 PREFIX ?= /usr SOVERSION = 0.15 +PARSEVECT ?= yes -.PHONY: clean-vect clean -all: csdr nmux +.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\). @echo Auto-detected optimization parameters: $(PARAMS_SIMD) @@ -54,7 +55,9 @@ libcsdr.so: fft_fftw.c fft_rpi.c libcsdr_wrapper.c libcsdr.c libcsdr_gpl.c fastd rm -f dumpvect*.vect gcc -std=gnu99 $(PARAMS_LOOPVECT) $(PARAMS_SIMD) $(LIBSOURCES) $(PARAMS_LIBS) $(PARAMS_MISC) -fpic -shared -Wl,-soname,libcsdr.so.$(SOVERSION) -o libcsdr.so.$(SOVERSION) @ln -fs libcsdr.so.$(SOVERSION) 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 @@ -99,3 +102,12 @@ 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' +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 old mode 100644 new mode 100755 index dbc3f45..3ffb1c6 --- a/README.md +++ b/README.md @@ -1,20 +1,32 @@ -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 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) + +(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 -------------- - make - sudo make install + make + sudo make install The project was only tested on Linux. It has the following dependencies: `libfftw3-dev` @@ -22,11 +34,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 + ./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 ------- @@ -39,7 +51,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_s16 | 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`. @@ -51,7 +63,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_s16 | 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. @@ -60,19 +72,19 @@ Usage by example Sample rates look like this: - 2.4 Msps 240 ksps 48 ksps - I/Q source ------------> FIR decimation ------------> FM demod -> frac. decimation ---------> deemphasis -> sound card + 2.4 Msps 240 ksps 48 ksps + I/Q source ------------> FIR decimation ------------> FM demod -> frac. decimation ---------> deemphasis -> sound card *Note:* there is an example shell script that does this for you (without the unnecessary shift operation). If you just want to listen to FM radio, type: - csdr-fm 89.5 20 + csdr-fm 89.5 20 The first parameter is the frequency in MHz, and the second optional parameter is the RTL-SDR tuner gain in dB. ### 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_s16 | 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. @@ -80,14 +92,14 @@ 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_s16 | 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. ### Design FIR band-pass filter (with complex taps) - csdr firdes_bandpass_c 0 0.5 59 HAMMING --octave | octave -i + csdr firdes_bandpass_c 0 0.5 59 HAMMING --octave | octave -i - ...and then plot its frequency response with octave. (You can close octave window by issuing Ctrl-C in the terminal window.) - It will design a filter that lets only the positive frequencies pass (low cut is 0, high cut is 0.5 - these are relative to the sampling rate). @@ -95,13 +107,13 @@ 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_s16 | 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`. ### Draw FFT - rtl_sdr -s 2400000 -f 104300000 -g 20 - | csdr convert_u8_f | csdr fft_cc 1024 1200000 HAMMING --octave | octave -i > /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. @@ -134,98 +146,229 @@ 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 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) + +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 +---- -It copies the input to the output, while also displaying the speed of the data going through it. +### [through](#through) - none +Syntax: + + csdr through + +It copies the input to the output, while also displaying the data rate going through it. + +---- + +### [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 +---- + +### [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. - floatdump_f +---- -It prints any floating point input samples. -The format string used is `"%g "`. +### [dump_f](#dump_f) - flowcontrol +Syntax: + + csdr dump_f + +It prints all floating point input samples as text. + +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` + +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) + +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`. + `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. +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`. @@ -233,86 +376,210 @@ 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 +---- + +### [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: + + 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`. + +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](#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 [num_poly_points ( [transition_bw [window]] | --prefilter )] +---- + +### [fractional_decimator_ff](#fractional_decimator_ff) + +Syntax: + + csdr fractional_decimator_ff [num_poly_points ( [transition_bw [window]] | --prefilter )] It can decimate by a floating point ratio. @@ -323,17 +590,37 @@ It can filter the signal with an anti-aliasing FIR filter before applying the La * passing only the `transition_bw`, or both the `transition_bw` and the `window` parameters of the filter, * using the `--prefilter` switch after `num_poly_points` to switch this filter on with the default parameters. - bandpass_fir_fft_cc [window] +---- + +### [old_fractional_decimator_ff](#old_fractional_decimator_ff) + +Syntax: + + 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`. + +(It uses linear interpolation, and its filter cuts at 59% of the passband.) + +---- + +### [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`. - old_fractional_decimator_ff [num_poly_points [transition_bw [window]]] +---- -This is the deprecated, old version of `fractional_decimator_ff` (only uses linear interpolation, its filter cuts at 59% of the passband). +### [agc_ff](#agc_ff) - agc_ff [hang_time [reference [attack_rate [decay_rate [max_gain [attack_wait [filter_alpha]]]]]]] +Syntax: + + csdr agc_ff [hang_time [reference [attack_rate [decay_rate [max_gain [attack_wait [filter_alpha]]]]]]] It is an automatic gain control function. @@ -347,11 +634,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. @@ -359,92 +658,749 @@ 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_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: + + 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 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. - 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. - 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) + +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). + +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 +``` + +---- + +### [repeat_u8](#repeat_u8) + +Syntax: + + csdr repeat_u8 + +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 +``` + +---- + +### [uniform_noise_f](#uniform_noise_f) + +Syntax: + + csdr uniform_noise_f + +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. + +---- + +### [pack_bits_8to1_u8_u8](#pack_bits_8to1_u8_u8) + +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. + +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: + + 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. + +---- + +### [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. + +---- + +### [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: + + 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.') + +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. - 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` @@ -502,7 +1458,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*. @@ -512,19 +1468,19 @@ 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) +## [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. @@ -533,7 +1489,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. diff --git a/csdr.c b/csdr.c old mode 100644 new mode 100755 index aea07b0..27dbf6d --- 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 @@ -51,6 +51,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include "fastddc.h" +#include char usage[]= "csdr - a simple commandline tool for Software Defined Radio receiver DSP.\n\n" @@ -73,8 +74,7 @@ char usage[]= " none\n" " yes_f [buf_times]\n" " detect_nan_ff\n" -" floatdump_f\n" -" flowcontrol [prebuffer_sec] [thrust]\n" +" dump_f\n" " shift_math_cc \n" " shift_math_cc --fifo \n" " shift_addition_cc \n" @@ -94,6 +94,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" @@ -116,11 +117,66 @@ 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" +" invert_u8_u8\n" +" rtty_line_decoder_u8_u8\n" +" rtty_baudot2ascii_u8_u8\n" +" serial_line_decoder_f_u8 [databits [stopbits]]\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" +" 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" +" 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" +" peaks_fir_cc [peak_rate × N]\n" +" repeat_u8 \n" +" uniform_noise_f\n" +" gaussian_noise_c\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" +" pulse_shaping_filter_cc (RRC | COSINE )\n" +" add_n_zero_samples_at_beginning_f \n" +" generic_slicer_f_u8 \n" +" plain_interpolate_cc \n" +" 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" +" normalized_timing_variance_u32_f [--debug]\n" +" ?\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" ; @@ -139,76 +195,91 @@ 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 fflush(stdout); sched_yield() +#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); - return -1; + if(why==0) fprintf(stderr, "%s", usage); + else + { + errhead(); + fprintf(stderr, "%s\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) { errhead(); fprintf(stderr, "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_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")) + { + 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); + 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; + 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; + } + } + return 0; } @@ -217,38 +288,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]; } @@ -274,1438 +345,1393 @@ float *output_buffer; short *buffer_i16; float *temp_f; int the_bufsize = 0; -char **argv_global; -#define UNITROUND_UNIT 128 + +#define UNITROUND_UNIT 4 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); - return the_bufsize; + if(!(the_bufsize=getbufsize())) return 0; + the_bufsize=unitround(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)); + 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) { - //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) { 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; + 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; + argc_global=argc; + 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") || !strcmp(argv[1],"REM")) + { + 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; errhead(); fprintf(stderr, "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) { errhead(); fprintf(stderr,"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); + errhead(); + fprintf(stderr,"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); + errhead(); + fprintf(stderr,"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); + errhead(); + fprintf(stderr,"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); + errhead(); + fprintf(stderr,"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_fc")) - { - bigbufs=1; - - 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); - } - - if(!sendbufsize(initialize_buffers())) return -2; - for(;;) - { - shift_addition_data_t data=shift_addition_init(rate); - fprintf(stderr,"shift_addition_fc: reinitialized to %g\n",rate); - int remain, current_size; - float* ibufptr; - float* obufptr; - for(;;) - { - FEOF_CHECK; - if(!FREAD_R) break; - remain=the_bufsize; - ibufptr=input_buffer; - obufptr=output_buffer; - while(remain) - { - current_size=(remain>1024)?1024:remain; - starting_phase=shift_addition_fc(ibufptr, (complexf*)obufptr, current_size, data, starting_phase); - ibufptr+=current_size; - 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); + errhead(); fprintf(stderr,"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); + int factor; + sscanf(argv[2],"%d",&factor); - 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)); + float transition_bw = 0.05; + if(argc>=4) sscanf(argv[3],"%g",&transition_bw); - int taps_length=firdes_filter_len(transition_bw); - fprintf(stderr,"fir_decimate_cc: taps_length = %d\n",taps_length); + 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)); - 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); + int taps_length=firdes_filter_len(transition_bw); + fprintf(stderr,"fir_decimate_cc: taps_length = %d\n",taps_length); - if(!initialize_buffers()) return -2; - sendbufsize(the_bufsize/factor); + 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 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); + 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)); + 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); - taps = (float*)((((unsigned)taps)+NEON_ALIGNMENT-1) & ~(NEON_ALIGNMENT-1)); - fprintf(stderr,"taps = %x\n", taps); - for(int i=0;i=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 factor; + sscanf(argv[2],"%d",&factor); + assert(factor >= 1); - int octave=(argc>=6 && !strcmp("--octave",argv[5])); + float transition_bw = 0.05; + if(argc>=4) sscanf(argv[3],"%g",&transition_bw); + assert(transition_bw >= 0 && transition_bw < 1.); - float* taps=(float*)malloc(sizeof(float)*length); + window_t window = WINDOW_DEFAULT; + if(argc>=5) + { + window=firdes_get_window_from_string(argv[4]); + } + else {errhead(); fprintf(stderr,"window = %s\n",firdes_get_string_from_window(window));} - //Make the filter - firdes_lowpass_f(taps,length,cutoff_rate,window); + int taps_length=firdes_filter_len(transition_bw); + errhead(); fprintf(stderr,"taps_length = %d\n",taps_length); + assert(taps_length > 0); - //Do the output - if(octave) printf("taps=["); - for(int i=0;i 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; + 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)); + } + } - //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],"firdes_bandpass_c")) - { - //Process the params - if(argc<=4) return badsyntax("need required parameters (low_cut, high_cut, length)"); - float low_cut; - sscanf(argv[2],"%g",&low_cut); - float high_cut; - sscanf(argv[3],"%g",&high_cut); - int length; - sscanf(argv[4],"%d",&length); - if(length%2==0) return badsyntax("number of symmetric FIR filter taps should be odd"); + /*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)"); - 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)); + float cutoff_rate; + sscanf(argv[2],"%g",&cutoff_rate); - int octave=(argc>=7 && !strcmp("--octave",argv[6])); + int length; + sscanf(argv[3],"%d",&length); + if(length%2==0) return badsyntax("number of symmetric FIR filter taps should be odd"); - complexf* taps=(complexf*)malloc(sizeof(complexf)*length); + window_t window = WINDOW_DEFAULT; + if(argc>=5) + { + window=firdes_get_window_from_string(argv[4]); + } + else { errhead(); fprintf(stderr,"window = %s\n",firdes_get_string_from_window(window)); } - //Make the filter - firdes_bandpass_c(taps, length, low_cut, high_cut, window); + int octave=(argc>=6 && !strcmp("--octave",argv[5])); - //Do the output - if(octave) printf("taps=["); - for(int i=0;i=6) + { + window=firdes_get_window_from_string(argv[5]); + } + else { errhead(); fprintf(stderr,"window = %s\n",firdes_get_string_from_window(window));} + + int octave=(argc>=7 && !strcmp("--octave",argv[6])); + + complexf* taps=(complexf*)malloc(sizeof(complexf)*length); + + //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 { 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; + 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")) + { + errhead(); fprintf(stderr, "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]); + } + } + 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; - 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 { errhead(); fprintf(stderr,"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;ifft_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(!strcmp(argv[1],"fft_fc")) - { - /* - For real FFT, the parameter is the number of output complex bins - instead of the actual FFT size. - Number of input samples used for each FFT is twice the given parameter. - This makes it easier to replace fft_cc by fft_fc in some applications. */ - if(argc<=3) return badsyntax("need required parameters (fft_out_size, out_of_every_n_samples)"); - int fft_in_size=0, fft_out_size=0; - sscanf(argv[2],"%d",&fft_out_size); - if(log2n(fft_out_size)==-1) return badsyntax("fft_out_size should be power of 2"); - fft_in_size = 2*fft_out_size; - 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(!sendbufsize(initialize_buffers())) return -2; - if(!initialize_buffers()) return -2; - sendbufsize(fft_out_size); + 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; + } + } - //make FFT plan - 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..."); - 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 - float *windowt; - windowt = precalculate_window(fft_in_size, window); - for(;;) - { - FEOF_CHECK; - if(every_n_samples>fft_in_size) - { - fread(input, sizeof(float), fft_in_size, stdin); - //skipping samples before next FFT (but fseek doesn't work for pipes) - for(int seek_remain=every_n_samples-fft_in_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(!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(!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; - } - } - - 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)"); - 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; + } + } #ifdef USE_IMA_ADPCM @@ -1716,662 +1742,1890 @@ 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"); + 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); + 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 { 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 - 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; + 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; + 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); + errhead(); fprintf(stderr, "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 %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)"); + 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"); + 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)) { errhead(); fprintf(stderr, "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); + /* + ______ _ _____ _____ _____ + | ____| | | | __ \| __ \ / ____| + | |__ __ _ ___| |_| | | | | | | | + | __/ _` / __| __| | | | | | | | + | | | (_| \__ \ |_| |__| | |__| | |____ + |_| \__,_|___/\__|_____/|_____/ \_____| - 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)); + */ + + 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); - fastddc_t ddc; - if(fastddc_init(&ddc, transition_bw, decimation, 0)) { badsyntax("error in fastddc_init()"); return 1; } - fastddc_print(&ddc,"fastddc_fwd_cc"); + window_t window = WINDOW_DEFAULT; + if(argc>4) window=firdes_get_window_from_string(argv[4]); + else { errhead(); fprintf(stderr,"window = %s\n",firdes_get_string_from_window(window)); } - if(!initialize_buffers()) return -2; - sendbufsize(ddc.fft_size); + fastddc_t ddc; + if(fastddc_init(&ddc, transition_bw, decimation, 0)) { badsyntax("error in fastddc_init()"); return 1; } + fastddc_print(&ddc,"fastddc_fwd_cc"); - //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); + if(!initialize_buffers()) return -2; + sendbufsize(ddc.fft_size); - for(int i=0;i [transition_bw [window]] - { - float shift_rate; - int plusarg=0; + for(;;) + { + FEOF_CHECK; + //overlapped FFT + for(int i=0;i [transition_bw [window]] + { + float shift_rate; + int plusarg=0; - 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 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); + } - float transition_bw = 0.05; - if(argc>4+plusarg) sscanf(argv[4+plusarg],"%g",&transition_bw); + 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); - 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)); + float transition_bw = 0.05; + if(argc>4+plusarg) sscanf(argv[4+plusarg],"%g",&transition_bw); - for(;;) - { + window_t window = WINDOW_DEFAULT; + if(argc>5+plusarg) window=firdes_get_window_from_string(argv[5+plusarg]); + else { errhead(); fprintf(stderr,"window = %s\n",firdes_get_string_from_window(window)); } - 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"); + for(;;) + { - if(!initialize_buffers()) return -2; - sendbufsize(ddc.post_input_size/ddc.post_decimation); //TODO not exactly correct + 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"); - //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) + if(!initialize_buffers()) return -2; + sendbufsize(ddc.post_input_size/ddc.post_decimation); //TODO not exactly correct - //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); + //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 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 the filter + float filter_half_bw = 0.5/decimation; + 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); - 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; - } + //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); + 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"); + + //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; + } - 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; + if( !strcmp(argv[1], "_fft2octave") ) + { + int fft_size; + if(argc<=2) return badsyntax("need required parameter (fft_size)"); + sscanf(argv[2],"%d",&fft_size); - 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_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")) // [databits [stopbits]] + { + 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, "%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.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; + + 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) { 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; + } + } + + 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); + 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"); + + 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; + } + } + + 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]); + //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"); + + 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_every_nth = -1; + int output_error = 0; + int output_indexes = 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>=(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(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); + + timing_recovery_state_t state = timing_recovery_init(algorithm, decimation, add_q, loop_gain, max_error, debug_every_nth, octave_save_path); + + FREAD_C; + unsigned buffer_start_counter = 0; + for(;;) + { + FEOF_CHECK; + 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(!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(!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 = 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],"pack_bits_1to8_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_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; + 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 [--dd | --decision_directed] [--output_error | --output_dphase | --output_nco | --output_combined ] + { + float loop_bandwidth; + if(argc<=2) return badsyntax("need required parameter (loop_bandwidth)"); + sscanf(argv[2],"%f",&loop_bandwidth); + + float damping_factor; + if(argc<=3) return badsyntax("need required parameter (damping_factor)"); + 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 output_combined = !output_nco & !!(argc>4+decision_directed && (!strcmp(argv[4+decision_directed], "--output_combined"))); + + + 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); + + 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(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"); + } + + for(;;) + { + FEOF_CHECK; + FREAD_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(output_combined) + { + fwrite(buffer_output_error, sizeof(float), the_bufsize, file_output_error); + fwrite(buffer_output_dphase, sizeof(float), the_bufsize, file_output_dphase); + fwrite(buffer_output_nco, sizeof(complexf), the_bufsize, file_output_nco); + } + FWRITE_C; + } + TRY_YIELD; + } + fclose(file_output_error); + fclose(file_output_dphase); + fclose(file_output_nco); + } + + 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 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.; + + 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],"firdes_peak_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 { errhead(); fprintf(stderr,"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_add_peak_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(argc<=2) return badsyntax("need required parameter (taps_length)"); + int taps_length; + sscanf(argv[2],"%d",&taps_length); + + int num_peaks = argc-3; + float* peak_rate = (float*)malloc(sizeof(float)*num_peaks); + for(int i=0;i 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+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); + 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); + for(;;) + { + FEOF_CHECK; + FREAD_C; + //get_awgn_samples_f((float*)awgn_buffer, the_bufsize*2, 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 [--debug] + { + int samples_per_symbol = 0; + if(argc<=2) return badsyntax("required parameter is missing."); + 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); + + 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); + 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, debug_print); + fwrite(&nv, sizeof(float), 1, stdout); + errhead(); fprintf(stderr, "normalized variance = %f\n", nv); + TRY_YIELD; + } + } + + 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; + float* zeros=(float*)calloc(sizeof(float),n_zero_samples); + fwrite(zeros, sizeof(float), n_zero_samples, stdout); + clone_(the_bufsize); + } + + int pulse_shaping_filter_which = 0; + if( + (!strcmp(argv[1], "firdes_pulse_shaping_filter_f") && (pulse_shaping_filter_which = 1)) || + (!strcmp(argv[1], "pulse_shaping_filter_cc") && (pulse_shaping_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<=3) return badsyntax("required parameter is missing."); + sscanf(argv[3],"%d",&samples_per_symbol); + + int num_taps = 0; + 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(type==MATCHED_FILTER_RRC) + { + if(argc<=5) return badsyntax("required parameter is missing."); + sscanf(argv[5],"%f",&beta); + } + + 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; + } + //fprintf(stderr, "beta = %f, num_taps = %d, samples_per_symbol = %d\n", beta, num_taps, samples_per_symbol); + + if(!sendbufsize(initialize_buffers())) return -2; + + if(pulse_shaping_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; + 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], "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], "dbpsk_decoder_c_u8")) + { + if(!sendbufsize(initialize_buffers())) return -2; + unsigned char* local_output_buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize); + for(;;) + { + FEOF_CHECK; + FREAD_C; + dbpsk_decoder_c_u8((complexf*)input_buffer, local_output_buffer, the_bufsize); + fwrite(local_output_buffer, sizeof(unsigned char), the_bufsize, stdout); + TRY_YIELD; + } + return 0; + } + + if(!strcmp(argv[1], "bfsk_demod_cf")) // + { + 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; + 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], "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; + + 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); + } + + if(!sendbufsize(initialize_buffers())) return -2; + for(;;) + { + shift_addition_data_t data=shift_addition_init(rate); + errhead(); fprintf(stderr,"reinitialized to %g\n",rate); + int remain, current_size; + float* ibufptr; + float* obufptr; + for(;;) + { + FEOF_CHECK; + if(!FREAD_R) break; + remain=the_bufsize; + ibufptr=input_buffer; + obufptr=output_buffer; + while(remain) + { + current_size=(remain>1024)?1024:remain; + starting_phase=shift_addition_fc(ibufptr, (complexf*)obufptr, current_size, data, starting_phase); + ibufptr+=current_size; + 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],"fft_fc")) + { + /* + For real FFT, the parameter is the number of output complex bins + instead of the actual FFT size. + Number of input samples used for each FFT is twice the given parameter. + This makes it easier to replace fft_cc by fft_fc in some applications. */ + if(argc<=3) return badsyntax("need required parameters (fft_out_size, out_of_every_n_samples)"); + int fft_in_size=0, fft_out_size=0; + sscanf(argv[2],"%d",&fft_out_size); + if(log2n(fft_out_size)==-1) return badsyntax("fft_out_size should be power of 2"); + fft_in_size = 2*fft_out_size; + 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_out_size); + + //make FFT plan + 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) { 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 + float *windowt; + windowt = precalculate_window(fft_in_size, window); + for(;;) + { + FEOF_CHECK; + if(every_n_samples>fft_in_size) + { + fread(input, sizeof(float), fft_in_size, stdin); + //skipping samples before next FFT (but fseek doesn't work for pipes) + for(int seek_remain=every_n_samples-fft_in_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='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&1 | grep -i %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; + } + + 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/grc_tests/bpsk31_baseband_sample_complex_8000_sps_010101.raw b/grc_tests/bpsk31_baseband_sample_complex_8000_sps_010101.raw new file mode 100644 index 0000000..91b4ab1 Binary files /dev/null and b/grc_tests/bpsk31_baseband_sample_complex_8000_sps_010101.raw differ 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))) diff --git a/grc_tests/bpsk31_scurve.m b/grc_tests/bpsk31_scurve.m new file mode 100755 index 0000000..b17fd24 --- /dev/null +++ b/grc_tests/bpsk31_scurve.m @@ -0,0 +1,67 @@ +#!/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); + fclose(pin); + fclose(pout); +end + +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 + +function error_values=mkscurve(which_ted, skips) + error_values=[] + for skip=skips + error_values=[error_values run_tr(skip, 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 + +skips_gardner=0:16:256 +error_values_gardner=mkscurve('GARDNER',skips_gardner); +skips_earlylate=0:16:256 +error_values_earlylate=mkscurve('EARLYLATE',skips_earlylate); + +%graphics_toolkit("gnuplot") +h=figure(1); + +plot((skips_gardner-128)/256, -error_values_gardner, 'linewidth', 2); +title('S-curve for Gardner TED'); +fmtplot(h) +grid on +pause + +plot((skips_earlylate-128)/256, error_values_earlylate, 'linewidth', 2); +title('S-curve for early-late TED'); +fmtplot(h) +grid on +pause diff --git a/grc_tests/bpsk31_tedvar.m b/grc_tests/bpsk31_tedvar.m new file mode 100755 index 0000000..765dc3d --- /dev/null +++ b/grc_tests/bpsk31_tedvar.m @@ -0,0 +1,99 @@ +#!/usr/bin/octave + +%you need to first install the parallel and struct packages: +%pkg install -forge struct +%pkg install -forge parallel +pkg load parallel + +function y=inarg(x) + for i=1:length(argv()) + if strcmp(argv(){i},x) + y=1; + return + end + end + 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 | " 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 | " bpfcmd "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; + output=[]; + cmd + [pin, pout, pid]=popen2('bash',{'-c', cmd}); + %fclose(pin); + do + sleep(0.3) + fwrite(stdout,'.'); + %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 --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); +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('E_b/N_0 [dB]'); + ylabel('Phase error variance [rad^2]'); +end + +%snrs=-10:5:10 +snrs=-10:5:25 +%snrs=[10] +error_values=mkvarplot('EARLYLATE',snrs); + +%graphics_toolkit("gnuplot") +h=figure(1); + +ebn0=snrs+9.7 + +semilogy(ebn0, error_values, 'linewidth', 2); +title('Estimation variance'); +fmtplot(h) +pause + +if !inarg('--nogen') + system('rm /tmp/psk31-raw-data /tmp/psk31-gaussian-noise'); +end diff --git a/grc_tests/psk31_sigmodel.m b/grc_tests/psk31_sigmodel.m new file mode 100755 index 0000000..06e3fbb --- /dev/null +++ b/grc_tests/psk31_sigmodel.m @@ -0,0 +1,70 @@ +#!/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 + +global padding=[-2 2]; + +function [toreturny, plotrange]=y(s) + global Tb + global padding + slen=size(s)(2) + plotrange=((padding(1)-1)*Tb):(slen+padding(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 + plotrange=plotrange/Tb +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); +[a b]=y([1]); +plot(b, a, 'linewidth', 2) +title(sprintf("Impulse response of pulse shaping filter")) +xlabel('t/Ts') +ylabel('h(t)') + +subplot(2, 1, 2); +[a b]=y([1 1 -1 -1 1 1 1 -1 1 -1 1 1]); +plot(b, a, 'linewidth', 2) +title("Baseband signal for modulator input\nbit sequence: 110011101011") %assuming that differential encoding has already been performed +xlabel('t/Ts') +ylabel('s(t)') +xbounds = xlim; +set(gca,'XTick',xbounds(1):xbounds(2)); +fmtplot(h); +pause +exit + +%fourier analisys of baseband signal +h2=figure(2); +padding=[-1 1] +plot(y([1])) +h3=figure(3); +fftvals=abs(fft(y([1]))); +sizefftvals=size(fftvals)(2) +fftvals=[fftvals(sizefftvals/2:sizefftvals) fftvals(2:sizefftvals/2)] +plot(fftvals, "-") +pause 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/grc_tests/test_bpsk31_parts.grc b/grc_tests/test_bpsk31_parts.grc new file mode 100644 index 0000000..6218910 --- /dev/null +++ b/grc_tests/test_bpsk31_parts.grc @@ -0,0 +1,1442 @@ + + + + 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 0.05 0.707 + + + comment + + + + affinity + + + + _enabled + 0 + + + _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 + 0 + + + _coordinate + (608, 299) + + + _rotation + 0 + + + id + ha5kfu_execproc_xx_0_0_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + 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 + + alias + + + + comment + + + + _enabled + True + + + _coordinate + (400, 40) + + + _rotation + 0 + + + grid_pos + + + + id + nb + + + labels + ['tab1', 'channel', 'tab3', 'tab4','bpf'] + + + 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 + 0 + + + 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_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 + + ac_couple + False + + + alias + + + + comment + + + + affinity + + + + _enabled + 0 + + + _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 + 0 + + + _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 + + + + 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 + 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 + 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 + 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 + + + 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_bpsk31_to_octave.grc b/grc_tests/test_bpsk31_to_octave.grc new file mode 100644 index 0000000..f83a0d5 --- /dev/null +++ b/grc_tests/test_bpsk31_to_octave.grc @@ -0,0 +1,675 @@ + + + + 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_bpsk_costas_loop.grc b/grc_tests/test_bpsk_costas_loop.grc new file mode 100644 index 0000000..a42452c --- /dev/null +++ b/grc_tests/test_bpsk_costas_loop.grc @@ -0,0 +1,1034 @@ + + + + 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 + 1 + + + _enabled + True + + + _coordinate + (416, 3) + + + _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 + 10 + + + _enabled + True + + + _coordinate + (288, 11) + + + _rotation + 0 + + + grid_pos + + + + id + freq_add + + + label + + + + max + samp_rate*0.5 + + + min + -samp_rate*0.5 + + + notebook + + + + num_steps + 1000 + + + style + wx.SL_HORIZONTAL + + + + variable_slider + + comment + + + + converver + float_converter + + + value + 0.3 + + + _enabled + True + + + _coordinate + (32, 275) + + + _rotation + 0 + + + grid_pos + + + + id + loop_bw + + + label + + + + max + 0.5 + + + min + 0 + + + notebook + + + + num_steps + 100 + + + style + wx.SL_HORIZONTAL + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (176, 11) + + + _rotation + 0 + + + id + samp_rate + + + value + 2**12 + + + + analog_const_source_x + + alias + + + + comment + + + + const + 0 + + + affinity + + + + _enabled + 0 + + + _coordinate + (288, 203) + + + _rotation + 0 + + + id + analog_const_source_x_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + float + + + + analog_random_source_x + + alias + + + + comment + + + + affinity + + + + _enabled + 0 + + + _coordinate + (40, 147) + + + _rotation + 0 + + + id + analog_random_source_x_0 + + + maxoutbuf + 0 + + + max + 2 + + + minoutbuf + 0 + + + min + 0 + + + num_samps + 1000 + + + type + int + + + repeat + True + + + + blocks_add_const_vxx + + alias + + + + comment + + + + const + -1 + + + affinity + + + + _enabled + 0 + + + _coordinate + (336, 131) + + + _rotation + 0 + + + id + blocks_add_const_vxx_0 + + + type + float + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + vlen + 1 + + + + blocks_float_to_complex + + alias + + + + comment + + + + affinity + + + + _enabled + 0 + + + _coordinate + (496, 161) + + + _rotation + 0 + + + id + blocks_float_to_complex_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + vlen + 1 + + + + blocks_int_to_float + + alias + + + + comment + + + + affinity + + + + _enabled + 0 + + + _coordinate + (200, 131) + + + _rotation + 0 + + + id + blocks_int_to_float_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + scale + 0.5 + + + vlen + 1 + + + + blocks_throttle + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (496, 355) + + + _rotation + 0 + + + id + blocks_throttle_0 + + + ignoretag + True + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + samples_per_second + samp_rate + + + type + complex + + + vlen + 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 + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (864, 345) + + + _rotation + 0 + + + id + digital_costas_loop_cc_0 + + + w + loop_bw + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + order + 2 + + + use_snr + False + + + + freq_xlating_fir_filter_xxx + + alias + + + + center_freq + freq_add + + + comment + + + + affinity + + + + decim + 1 + + + _enabled + 1 + + + _coordinate + (232, 331) + + + _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 + 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 + + + + affinity + + + + _enabled + 1 + + + _coordinate + (840, 163) + + + _rotation + 0 + + + id + ha5kfu_execproc_xx_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + cc + + + + wxgui_scopesink2 + + ac_couple + False + + + alias + + + + comment + + + + affinity + + + + _enabled + 1 + + + _coordinate + (1104, 123) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_scopesink2_0_0 + + + notebook + + + + num_inputs + 1 + + + samp_rate + samp_rate + + + t_scale + 0 + + + title + After Costas Loop (csdr) + + + 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, 299) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_scopesink2_0_0_0 + + + notebook + + + + num_inputs + 1 + + + samp_rate + samp_rate + + + t_scale + 0 + + + title + After Costas Loop (GNU Radio) + + + trig_mode + wxgui.TRIG_MODE_AUTO + + + type + complex + + + v_offset + 0 + + + v_scale + 0 + + + win_size + + + + xy_mode + True + + + y_axis_label + Counts + + + + analog_const_source_x_0 + blocks_float_to_complex_0 + 0 + 1 + + + analog_random_source_x_0 + blocks_int_to_float_0 + 0 + 0 + + + blocks_add_const_vxx_0 + blocks_float_to_complex_0 + 0 + 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 + digital_costas_loop_cc_0 + 0 + 0 + + + blocks_throttle_0 + ha5kfu_execproc_xx_0 + 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 + 0 + 0 + + + freq_xlating_fir_filter_xxx_0 + blocks_throttle_0 + 0 + 0 + + + ha5kfu_execproc_xx_0 + wxgui_scopesink2_0_0 + 0 + 0 + + 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..eb8abbf --- /dev/null +++ b/grc_tests/test_bpsk_costas_loop_convertwavs.sh @@ -0,0 +1,10 @@ +#!/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 --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 +sox -r 48k -t f32 -c 2 /s/tr_input -t wav -e floating-point /s/tr_input.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/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/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 + + diff --git a/grc_tests/test_noise.grc b/grc_tests/test_noise.grc new file mode 100644 index 0000000..7feed73 --- /dev/null +++ b/grc_tests/test_noise.grc @@ -0,0 +1,702 @@ + + + + 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/grc_tests/test_peaks_fir.grc b/grc_tests/test_peaks_fir.grc new file mode 100644 index 0000000..7b36429 --- /dev/null +++ b/grc_tests/test_peaks_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 + 1e3 + + + + 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*10 + + + type + complex + + + vlen + 1 + + + + ha5kfu_execproc_xx + + alias + + + + commandline + csdr peaks_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/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 + + 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 21f7723..1eb91b3 --- 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 /* _ _ __ _ _ @@ -51,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); } /* @@ -113,63 +114,63 @@ 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)); - } +void normalize_fir_f(float* input, float* output, int length) +{ + //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; } /* @@ -184,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 @@ -320,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 @@ -398,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 @@ -470,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; 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; } /* @@ -636,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); } /* @@ -974,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 @@ -994,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; + } } /* @@ -1190,60 +1219,60 @@ 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 +}; + +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 +}; + +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; } + + } + 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; + } + } + } +} + +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; +} + +#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; + 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 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 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++; + + 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 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; +} + +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 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) + for(int i=0;i < | | | | | | | | | | | | | (_| | | | \ \ __/ (_| (_) \ V / __/ | | |_| | + \_____\__,_|_| |_| |_|\___|_| \___/\/ |_| |_|_| |_| |_|_|_| |_|\__, | |_| \_\___|\___\___/ \_/ \___|_| \__, | + __/ | __/ | + |___/ |___/ +*/ + +void pll_cc_init_pi_controller(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; +} + +void pll_cc_init_p_controller(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_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 + + //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); + + 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; + } +} + +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); + int* points_color = (int*)malloc(sizeof(int)*points_size); + va_list vl; + va_start(vl,points_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; +} + +#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; + float error; + int el_point_left_index, el_point_right_index, el_point_mid_index; + int si = 0; + 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(;;) + { + //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; + if(sampled_indexes) sampled_indexes[si]=el_point_left_index; + 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; + + if(timing_error) timing_error[si-1]=error; //it is not written if NULL + + if(error>state->max_error) error=state->max_error; + if(error<-state->max_error) error=-state->max_error; + if(state->debug_every_nth>=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; + 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; + +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"; +} + +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*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->current_freq = s->dphase = s->nco_phase = 0; + 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) +{ + for(int i=0;inco_phase); + cmult(&output[i], &input[i], &nco_sample); + if(output_nco) output_nco[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 = PI*iof(output,i)*qof(output,i); + if(output_error) output_error[i]=error; + 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_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); + + //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; + } +} + +#if 0 +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; +} + +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"); + 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); + } +} +#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; + 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_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 + 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; + + 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); + } + fprintf(stderr, "ndiff_rad_mean = %f\n", ndiff_rad_mean); + + float result = 0; + 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 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(y))?(y):(x)) +#define MAX_M(x,y) (((x)<(y))?(y):(x)) /* _____ _ @@ -47,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; } @@ -68,7 +69,7 @@ typedef struct complexf_s { float i; float q; } complexf; //window typedef enum window_s { - WINDOW_BOXCAR, WINDOW_BLACKMAN, WINDOW_HAMMING + WINDOW_BOXCAR, WINDOW_BLACKMAN, WINDOW_HAMMING } window_t; #define WINDOW_DEFAULT WINDOW_HAMMING @@ -101,37 +102,38 @@ void limit_ff(float* input, float* output, int input_size, float max_amplitude); //filters, decimators, resamplers, shift, etc. float fir_one_pass_ff(float* input, float* taps, int taps_length); int fir_decimate_cc(complexf *input, complexf *output, int input_size, int decimation, float *taps, int taps_length); +int fir_interpolate_cc(complexf *input, complexf *output, int input_size, int interpolation, float *taps, int taps_length); int deemphasis_nfm_ff (float* input, float* output, int input_size, int sample_rate); float deemphasis_wfm_ff (float* input, float* output, int input_size, float tau, int sample_rate, float last_output); float shift_math_cc(complexf *input, complexf* output, int input_size, float rate, float starting_phase); typedef struct dcblock_preserve_s { - float last_input; - float last_output; + float last_input; + float last_output; } dcblock_preserve_t; dcblock_preserve_t dcblock_ff(float* input, float* output, int input_size, float a, dcblock_preserve_t preserved); float fastdcblock_ff(float* input, float* output, int input_size, float last_dc_level); typedef struct fastagc_ff_s { - float* buffer_1; - float* buffer_2; - float* buffer_input; //it is the actual input buffer to fill - float peak_1; - float peak_2; - int input_size; - float reference; - float last_gain; + float* buffer_1; + float* buffer_2; + float* buffer_input; //it is the actual input buffer to fill + float peak_1; + float peak_2; + int input_size; + float reference; + float last_gain; } fastagc_ff_t; void fastagc_ff(fastagc_ff_t* input, float* output); typedef struct rational_resampler_ff_s { - int input_processed; - int output_size; - int last_taps_delay; + int input_processed; + int output_size; + int last_taps_delay; } rational_resampler_ff_t; 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); @@ -148,37 +150,37 @@ void log_ff(float* input, float* output, int size, float add_db); typedef struct fractional_decimator_ff_s { - float where; - int input_processed; - int output_size; - int num_poly_points; //number of samples that the Lagrange interpolator will use - float* poly_precalc_denomiator; //while we don't precalculate coefficients here as in a Farrow structure, because it is a fractional interpolator, but we rather precaculate part of the interpolator expression - //float* last_inputs_circbuf; //circular buffer to store the last (num_poly_points) number of input samples. - //int last_inputs_startsat; //where the circular buffer starts now - //int last_inputs_samplewhere; - float* coeffs_buf; - float* filtered_buf; - int xifirst; - int xilast; - float rate; - float *taps; - int taps_length; + float where; + int input_processed; + int output_size; + int num_poly_points; //number of samples that the Lagrange interpolator will use + float* poly_precalc_denomiator; //while we don't precalculate coefficients here as in a Farrow structure, because it is a fractional interpolator, but we rather precaculate part of the interpolator expression + //float* last_inputs_circbuf; //circular buffer to store the last (num_poly_points) number of input samples. + //int last_inputs_startsat; //where the circular buffer starts now + //int last_inputs_samplewhere; + float* coeffs_buf; + float* filtered_buf; + int xifirst; + int xilast; + float rate; + float *taps; + int taps_length; } fractional_decimator_ff_t; fractional_decimator_ff_t fractional_decimator_ff_init(float rate, int num_poly_points, float* taps, int taps_length); void fractional_decimator_ff(float* input, float* output, int input_size, fractional_decimator_ff_t* d); typedef struct old_fractional_decimator_ff_s { - float remain; - int input_processed; - int output_size; + float remain; + int input_processed; + int output_size; } old_fractional_decimator_ff_t; old_fractional_decimator_ff_t old_fractional_decimator_ff(float* input, float* output, int input_size, float rate, float *taps, int taps_length, old_fractional_decimator_ff_t d); typedef struct shift_table_data_s { - float* table; - int table_size; + float* table; + int table_size; } shift_table_data_t; void shift_table_deinit(shift_table_data_t table_data); shift_table_data_t shift_table_init(int table_size); @@ -186,9 +188,9 @@ float shift_table_cc(complexf* input, complexf* output, int input_size, float ra typedef struct shift_addfast_data_s { - float dsin[4]; - float dcos[4]; - float phase_increment; + float dsin[4]; + float dcos[4]; + float phase_increment; } shift_addfast_data_t; shift_addfast_data_t shift_addfast_init(float rate); shift_addfast_data_t shift_addfast_init(float rate); @@ -196,10 +198,10 @@ float shift_addfast_cc(complexf *input, complexf* output, int input_size, shift_ typedef struct shift_unroll_data_s { - float* dsin; - float* dcos; - float phase_increment; - int size; + float* dsin; + float* dcos; + float phase_increment; + int size; } shift_unroll_data_t; float shift_unroll_cc(complexf *input, complexf* output, int input_size, shift_unroll_data_t* d, float starting_phase); shift_unroll_data_t shift_unroll_init(float rate, int size); @@ -228,3 +230,183 @@ void convert_s24_f(unsigned char* input, float* output, int input_size, int bige int is_nan(float f); + +//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; + int databits; //including parity + float stopbits; + int output_size; + int input_used; + 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); +void binary_slicer_f_u8(float* input, unsigned char* output, int input_size); + + +typedef enum pll_type_e +{ + PLL_P_CONTROLLER=1, + PLL_PI_CONTROLLER=2 +} pll_type_t; + +typedef struct pll_s +{ + pll_type_t pll_type; + //common: + float output_phase; + float dphase; + float frequency; + float alpha; + float beta; + float iir_temp; +} pll_t; + +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 + int debug_phase; + 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, 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 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); +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); + +#if 0 +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; + float last_vco_phase_addition; +} 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); +#endif + +typedef struct bpsk_costas_loop_state_s +{ + float alpha; + float beta; + int decision_directed; + float current_freq; + float dphase; + float nco_phase; + float dphase_max; + int dphase_max_reset_to_zero; +} 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, 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_peak_c(complexf* output, int length, float rate, window_t window, int add, int normalize); +int apply_fir_cc(complexf* input, complexf* output, int input_size, complexf* taps, int taps_length); + + +FILE* init_get_random_samples_f(); +void get_random_samples_f(float* output, int output_size, FILE* status); +void get_random_gaussian_samples_c(complexf* output, int output_size, FILE* status); +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, int debug_print); + +typedef enum matched_filter_type_e +{ + MATCHED_FILTER_RRC, + MATCHED_FILTER_COSINE +} matched_filter_type_t; + +#define MATCHED_FILTER_DEFAULT MATCHED_FILTER_RRC + +int firdes_cosine_f(float* taps, int taps_length, int samples_per_symbol); +int firdes_rrc_f(float* taps, int taps_length, int samples_per_symbol, float beta); +matched_filter_type_t matched_filter_get_type_from_string(char* input); +int apply_real_fir_cc(complexf* input, complexf* output, int input_size, float* taps, int taps_length); +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); +float* add_const_cc(complexf* input, complexf* output, int input_size, complexf x); +void pack_bits_1to8_u8_u8(unsigned char* input, unsigned char* output, int input_size); +unsigned char pack_bits_8to1_u8_u8(unsigned char* input); +void dbpsk_decoder_c_u8(complexf* input, unsigned char* output, int input_size); +int bfsk_demod_cf(complexf* input, float* output, int input_size, complexf* mark_filter, complexf* space_filter, int taps_length);