Code Monkey home page Code Monkey logo

csdr's Introduction

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.

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.

csdr has already been used to build:

  • AM, FM, SSB, CW and BPSK31 demodulators and waterfall display in OpenWebRX,
  • AM, FM, SSB modulators in qtcsdr that can also be used standalone with rpitx,
  • 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

(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

The project was only tested on Linux. It has the following dependencies: libfftw3-dev

If you compile on ARM, please edit the Makefile and tailor PARAMS_NEON for your CPU.

To run the examples, you will also need 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:

./configure --enable-float

(This is for fftw3, not libcsdr. You do not need to run the configure script before compiling libcsdr.)

Credits

The library was written by Andras Retzler, HA7ILM <[email protected]>.

I would like to say special thanks to Péter Horváth, PhD (HA5CQA) and János Selmeczi, PhD (HA5FT) for their continous help and support.

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 -
  • 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.
  • We want to listen one radio station at the frequency -f 89500000 Hz (89.5 MHz).
  • No other radio station is within the sampled bandwidth, so we send the signal directly to the demodulator. (This is an easy, but not perfect solution as the anti-aliasing filter at RTL-SDR DDC is too short.)
  • After FM demodulation we decimate the signal by a factor of 5 to match the rate of the audio card (240000 / 5 = 48000).
  • A de-emphasis filter is used, because pre-emphasis is applied at the transmitter to compensate noise at higher frequencies. The time constant for de-emphasis for FM broadcasting in Europe is 50 microseconds (hence the 50e-6).
  • Also, mplayer cannot play floating point audio, so we convert our signal to a stream of 16-bit integers.

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 -
  • 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.
  • We decimate the signal by a factor of 10. The transition bandwidth of the FIR filter used for decimation will be 10% of total bandwidth (as of parameter 0.05 is 10% of 0.5). Hamming window will be used for windowed FIR filter design.

Sample rates look like this:

             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

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 -
  • 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.
  • The de-emphasis filter is a fixed FIR filter that has a passband of 400-4000 Hz, also with a roll-off of -20 dB/decade.

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 -
  • 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
  • ...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).
  • If --octave and everything that follows is removed from the command, you get only the taps. E. g. the raw output of firdes_lowpass_f can be easily copied to C code.

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 -
  • 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.1 to bandpass_fir_fft_cc -0.1 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
  • 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.

Usage

Some basic concepts on using libcsdr:

Data types

Function name endings found in libcsdr mean the input and output data types of the particular function. (This is similar to GNU Radio naming conventions). Data types are noted as it follows:

  • f is float (single percision)
  • c is complexf (two single precision floating point values in a struct)
  • u8 is unsigned char of 1 byte/8 bits (e. g. the output of rtl_sdr is of u8)
  • s16 is signed short of 2 bytes/16 bits (e. g. sound card input is usually s16)

Functions usually end as:

  • _ff float input, float output
  • _cf complex input, float output
  • _cc complex input, complex output

Regarding csdr, it can convert a real/complex stream from one data format to another, to interface it with other SDR tools and the sound card. The following commands are available:

  • csdr convert_u8_f
  • csdr convert_f_u8
  • csdr convert_s8_f
  • 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_<src>_<dst> You can use these commands on complex streams, too, as they are only interleaved values (I,Q,I,Q,I,Q... coming after each other).

Note: The the functions with i16 in their names have been renamed, but still work (e.g. csdr convert_f_i16).

csdr commands

csdr should be considered as a reference implementation on using libcsdr. For additional details on how to use the library, check csdr.c and libcsdr.c.

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 <parameter>, optional parameters are noted as [parameter]. Optional parameters have safe defaults, for more info look at the code.


Syntax:

csdr realpart_cf

It takes the real part of the complex signal, and throws away the imaginary part.


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.


Syntax:

csdr limit_ff [max_amplitude]

The input signal amplitude will not be let out of the -max_amplitude ... max_amplitude range.


Syntax:

csdr gain_ff <gain>

It multiplies all samples by gain.


Syntax:

csdr clone

It copies the input to the output.


Syntax:

csdr through

It copies the input to the output, while also displaying the data rate going through it.


Syntax:

csdr none

The csdr process just exits with 0.


Syntax:

csdr yes_f <to_repeat> [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.


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.


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


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


Syntax:

csdr flowcontrol <data_rate> <reads_per_second>

It limits the data rate of a stream to a given data_rate number of bytes per second.

It copies data_rate / reads_per_second bytes from the input to the output, doing it reads_per_second times every second.


Syntax:

csdr shift_math_cc <rate>

It shifts the signal in the frequency domain by rate.

rate is a floating point number between -0.5 and 0.5.

rate is relative to the sampling rate.

Internally, a sine and cosine wave is generated, and this function uses math.h for this purpose, which is quite accurate, but not always very fast.


Syntax:

csdr shift_addition_cc <rate>

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.)


Syntax:

csdr shift_addition_cc_test

This function was used to test the accuracy of the method above.


Syntax:

csdr shift_table_cc <rate> [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.


Syntax:

csdr shift_addfast_cc <rate>

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.


Syntax:

csdr shift_unroll_cc <rate>

Operation is the same as for shift_math_cc.

This uses a modified algoritm that first stores a vector of sine and cosine values for given phase differences.

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.


Syntax:

csdr decimating_shift_addition_cc <rate> [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.


Syntax:

csdr shift_addition_fc <rate>

It converts the real input signal to complex, and then shifts it in the frequency domain by rate.


Syntax:

csdr dcblock_ff

This is a DC blocking IIR filter.


Syntax:

csdr fastdcblock_ff

This is a DC blocker that works based on the average of the buffer.


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.


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.


Syntax:

csdr fmdemod_quadri_novect_cf

It has more easily understandable code than the previous one, but can't be auto-vectorized.


Syntax:

csdr deemphasis_wfm_ff <sample_rate> <tau>

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.


Syntax:

csdr deemphasis_nfm_ff <one_of_the_predefined_sample_rates>

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

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.


Syntax:

csdr amdemod_estimator_cf

It is an AM demodulator that uses an estimation method that is faster but less accurate than amdemod_cf.


Syntax:

csdr firdes_lowpass_f <cutoff_rate> <length> [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.


Syntax:

csdr firdes_bandpass_c <low_cut> <high_cut> <length> [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.


Syntax:

csdr fir_decimate_cc <decimation_factor> [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 from the input signal.


Syntax:

csdr fir_interpolate_cc <interpolation_factor> [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.


Syntax:

csdr rational_resampler_ff <interpolation> <decimation> [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.


Syntax:

csdr fractional_decimator_ff <decimation_rate> [num_poly_points ( [transition_bw [window]] | --prefilter )]

It can decimate by a floating point ratio.

It uses Lagrance interpolation, where num_poly_points (12 by default) input samples are taken into consideration while calculating one output sample.

It can filter the signal with an anti-aliasing FIR filter before applying the Lagrange interpolation. This filter is inactive by default, but can be activated by:

  • 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.

Syntax:

csdr old_fractional_decimator_ff <decimation_rate> [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.)


Syntax:

csdr bandpass_fir_fft_cc <low_cut> <high_cut> <transition_bw> [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.


Syntax:

csdr agc_ff [hang_time [reference [attack_rate [decay_rate [max_gain [attack_wait [filter_alpha]]]]]]]

It is an automatic gain control function.

  • hang_time is the number of samples to wait before starting to increase the gain after a peak.
  • reference is the reference level for the AGC. It tries to keep the amplitude of the output signal close to that.
  • attack_rate is the rate of decreasing the signal level if it gets higher than it used to be before.
  • decay_rate is the rate of increasing the signal level if it gets lower than it used to be before.
  • AGC won't increase the gain over max_gain.
  • attack_wait is the number of sampels to wait before starting to decrease the gain, because sometimes very short peaks happen, and we don't want them to spoil the reception by substantially decreasing the gain of the AGC.
  • filter_alpha is the parameter of the loop filter.

Its default parameters work best for an audio signal sampled at 48000 Hz.


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.


Syntax:

csdr fft_cc <fft_size> <out_of_every_n_samples> [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.

It can draw the spectrum by using --octave, for more information, look at the [Usage by example] section.

FFTW can be faster if we let it optimalize a while before starting the first transform, hence the --benchmark switch.


Syntax:

csdr fft_fc <fft_out_size> <out_of_every_n_samples> [--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.


Syntax:

csdr fft_benchmark <fft_size> <fft_cycles> [--benchmark]

It measures the time taken to process fft_cycles transforms of fft_size. It lets FFTW optimalize if used with the --benchmark switch.


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.


Syntax:

csdr csdr encode_ima_adpcm_i16_u8

Encodes the audio stream to IMA ADPCM, which decreases the size to 25% of the original.


Syntax:

csdr decode_ima_adpcm_u8_i16

Decodes the audio stream from IMA ADPCM.


Syntax:

csdr compress_fft_adpcm_f_u8 <fft_size>

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"

Syntax:

csdr fft_exchange_sides_ff <fft_size>

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.


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.


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


Syntax:

csdr convert_f_samplerf <wait_for_this_sample>

It converts a real signal to the -mRF input format of https://github.com/F5OEO/rpitx, so it allows you to generate frequency modulation. The input signal will be the modulating signal. The <wait_for_this_sample> parameter is the value for rpitx indicating the time to wait between samples. For a sampling rate of 48 ksps, this is 20833.


Syntax:

csdr fmmod_fc

It generates a complex FM modulated output from a real input signal.


Syntax:

csdr fixed_amplitude_cc <new_amplitude>

It changes the amplitude of every complex input sample to a fixed value. It does not change the phase information of the samples.


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

Syntax:

csdr setbuf <buffer_size>

See the buffer sizes section.

squelch_and_smeter_cc --fifo <squelch_fifo> --outfifo <smeter_fifo> <use_every_nth> <report_every_nth>

This is a controllable squelch, which reads the squelch level input from <squelch_fifo> and writes the power level output to <smeter_fifo>. Both input and output are in the format of %g\n. While calculating the power level, it takes only every <use_every_nth> sample into consideration. It writes the S-meter value for every <report_every_nth> buffer to <smeter_fifo>. If the squelch level is set to 0, it it forces the squelch to be open. If the squelch is closed, it fills the output with zero.


Syntax:

csdr fifo <buffer_size> <number_of_buffers>

It is similar to clone, but internally it uses a circular buffer. It reads as much as possible from the input. It discards input samples if the input buffer is full.


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

Syntax:

csdr repeat_u8 <data_bytes × N>

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

Syntax:

csdr uniform_noise_f

It outputs uniform white noise. All samples are within the range [-1.0, 1.0].


Syntax:

csdr gaussian_noise_c

It outputs Gaussian white noise. All samples are within the unit circle.


Syntax:

csdr pack_bits_8to1_u8_u8 

TODO


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 

Syntax:

csdr awgn_cc <snr_db> [--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.


Syntax:

csdr add_n_zero_samples_at_beginning_f <n_zero_samples> 

When the function is executed, it furst writes <n_zero_samples> 32-bit floating point zeros at the output, after that it just clones the input at the output.


Syntax:

csdr fft_one_side_ff <fft_size>

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).


Syntax:

csdr logaveragepower_cf <add_db> <fft_size> <avgnumber>

It works like logpower_cf , but it calculates the average of every avgnumber FFTs.


Syntax:

csdr mono2stereo_s16

It duplicates each 16-bit integer input sample.


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.


Syntax:

csdr _fft2octave <fft_size>

It is used for plotting FFT data with a GNU Octave session, piping its output to octave -i.


Syntax:

csdr invert_u8_u8

It maps

  • each 0x00 to 0x01,
  • each 0x01 to 0x00.

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.


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.

Syntax:

csdr serial_line_decoder_f_u8 <samples_per_bits> [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.


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.


Syntax:

csdr timing_recovery_cc  <algorithm> <decimation> [mu [max_error [--add_q [--output_error | --output_indexes |  --octave <show_every_nth> |  --octave_save <show_every_nth> <directory> ]]]] 

It implements non-data aided timing recovery (Gardner and early-late gate algorithms).

More information (section 4.4 from page 34)


Syntax:

csdr octave_complex_c <samples_to_plot> <out_of_n_samples> [--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.


Syntax:

csdr psk_modulator_u8_c <n_psk>

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.

Syntax:

csdr duplicate_samples_ntimes_u8_u8 <sample_size_bytes> <ntimes>

It duplicates each sample of sample_size_bytes the given ntimes times.


Syntax:

csdr psk31_interpolate_sine_cc <interpolation>

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).


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.

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

Syntax:

csdr bpsk_costas_loop_cc <loop_bandwidth> <damping_factor> [--dd | --decision_directed] [--output_error | --output_dphase | --output_nco | --output_combined <error_file> <dphase_file> <nco_file>]

It implements a Costas loop for BPSK signals.

More information (section 5.4 from page 55)


Syntax:

csdr simple_agc_cc <rate> [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


Syntax:

csdr peaks_fir_cc <taps_length> <peak_rate × N>

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.


Syntax:

csdr firdes_peak_c <rate> <length> [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.


Syntax:

csdr normalized_timing_variance_u32_f <samples_per_symbol> <initial_sample_offset> [--debug]

It calculates the normalized timing variance. It works on the sample indexes output from the timing_recovery_cc function.


Syntax:

csdr pulse_shaping_filter_cc (RRC <samples_per_symbol> <num_taps> <beta> | COSINE <samples_per_symbol>)

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.

Syntax:

csdr firdes_pulse_shaping_filter_f (RRC <samples_per_symbol> <num_taps> <beta> | COSINE <samples_per_symbol>)

It designs a pulse shaping filter, and outputs the taps. It has the same parameters as pulse_shaping_filter_cc.


Syntax:

csdr generic_slicer_f_u8 <n_symbols>

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.

Syntax:

csdr plain_interpolate_cc <interpolation>

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.


Syntax:

csdr dbpsk_decoder_c_u8

It implements a differential BPSK demodulator, with the following data flow:

DBPSK dataflow

The output is 0x00 or 0x01.


Syntax:

csdr bfsk_demod_cf <spacing> <filter_length>

It implements a 2-FSK demodulator, with the following data flow:

BFSK dataflow

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.


Syntax:

csdr add_const_cc <i> <q>

It adds a constant value of i+q*j to each input sample.


Syntax:

csdr pattern_search_u8_u8 <values_after> <pattern_values × N>

It can be used for preamble search. It looks for a given sequence of N bytes (<pattern_values × N>) in the input data, and if the sequence is found, it reads the following <values_after> bytes and outputs them. The <pattern_values × N> parameter is read as unsigned integers.


Syntax:

csdr tee <path> [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

Syntax:

csdr ?<search_the_function_list>

You can search the functions available in csdr just as if you typed: csdr 2>&1 | grep <search_what>

Syntax:

csdr =<evaluate_python_expression>

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:

import os, sys
from math import *
print <evaluate_python_expression>

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 <fifo_path>

By writing to the given FIFO file with the syntax below, you can control the shift rate:

<shift_rate>\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 <fifo_path> <transition_bw> [window]

By writing to the given FIFO file with the syntax below, you can control the shift rate:

<low_cut> <high_cut>\n

E.g. you can send -0.05 0.02\n

Buffer sizes

csdr has three modes of determining the buffer sizes, which can be chosen by the appropriate environment variables:

  • default: 16k or 1k buffer is chosen based on function,
  • dynamic buffer size determination: input buffer size is recommended by the previous process, output buffer size is determined by the process,
  • fixed buffer sizes.

csdr can choose from two different buffer sizes by default.

  • For operations handling the full-bandwidth I/Q data from the receiver, a buffer size of 16384 samples is used (see env_csdr_fixed_big_bufsize in the code).
  • For operations handling only a selected channel, a buffer size of 1024 samples is used (see env_csdr_fixed_bufsize in the code).

csdr now has an experimental feature called dynamic buffer size determination, which is switched on by issuing export CSDR_DYNAMIC_BUFSIZE_ON=1 in the shell before running csdr. If it is enabled:

  • All csdr processes in a DSP chain acquire their recommended input buffer size from the previous csdr process. This information is in the first 8 bytes of the input stream.
  • Each process can decide whether to use this or choose another input buffer size (if that's more practical).
  • Every process sends out its output buffer size to the next process. Then it startss processing data.
  • The DSP chain should start with a csdr setbuf <buffer_size> process, which only copies data from the input to the output, but also sends out the given buffer size information to the next process.
  • The 8 bytes of information included in the beginning of the stream is:
    • a preamble of the bytes 'c','s','d','r' (4 bytes),
    • the buffer size stored as int (4 bytes).
  • This size always counts as samples, as we expect that the user takes care of connecting the functions with right data types to each other.

I added this feature while researching how to decrease the latency of a DSP chain consisting of several multirate algorithms.
For example, a csdr fir_decimate_cc 10 would use an input buffer of 10240, and an output buffer of 1024. The next process in the chain, csdr bandpass_fir_fft_cc would automatically adjust to it, using a buffer of 1024 for both input and output.
In contrast to original expectations, using dynamic buffer sizes didn't decrease the latency much.

If dynamic buffer size determination is disabled, you can still set a fixed buffer size with export CSDR_FIXED_BUFSIZE=<buffer_size>.

For debug purposes, buffer sizes of all processes can be printed using export CSDR_PRINT_BUFSIZES=1.

If you add your own functions to csdr, you have to initialize the buffers before doing the processing. Buffer size will be stored in the global variable the_bufsize.

Example of initialization if the process generates N output samples for N input samples:

if(!sendbufsize(initialize_buffers())) return -2;

Example of initalization if the process generates N/D output samples for N input samples:

if(!initialize_buffers()) return -2;
sendbufsize(the_bufsize/D);

Example of initialization if the process allocates memory for itself, and it doesn't want to use the global buffers:

getbufsize(); //dummy
sendbufsize(my_own_bufsize);

Example of initialization if the process always works with a fixed output size, regardless of the input:

if(!initialize_buffers()) return -2;
sendbufsize(fft_size);

Testbench

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 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.

The purpose of sdr.js is to make SDR DSP processing available in the web browser. However, it is not easy to use in production yet. By now, only those functions have wrappers that the front-end of OpenWebRX uses.

To compile sdr.js, first get Emscripten. (It turns out that there is an emscripten package in Ubuntu repositories.)

To install and build dependencies (for now, only FFTW3):

make emcc-get-deps

To compile sdr.js (which will be created in the sdr.js subdirectory):

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

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.
  • --bufsize (-b), --bufcnt (-n): Internal buffer size and count.
  • --help (-h): Show help message.

nmux was originally written for use in OpenWebRX.

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. In order to eliminate any licesing issues, these parts are placed under a different file. However, the library is still fully functional with BSD-only code, altough having only less-optimized versions of some algorithms.
It should also be noted that if you compile with -DUSE_FFTW and -DLIBCSDR_GPL (as default), the GPL license would apply on the whole result.

csdr's People

Contributors

ckuethe avatar ha7ilm avatar mossmann avatar ricovangenugten avatar tejeez avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

csdr's Issues

Bug on Pi4-4GB + Odroid N2 4G "Buster" csdr jump 100% CPU usage on 20-30 seconds!

csdr run on 20-30sec to 100 % CPU on a "openwebrx" Setup with csdr preinstalled! if i start the openwebrx webinterface with waterfall. At Debian Stretch Release this does NOT happen, does anyone know why and whats changed between the OS Releases? both python 2.7, both compliled seemless!
Openwebrx -> csdr set Hz-filters ->start rtl_sdr ..
Every switch i press on the interface restart a command to csdr at backend, then csdr waits 20-30sec like hang/freeze the Audio, after 30 seconds the Sound runs and the Waterfall works too.
Tested varios Browsers, same issue. No logged Errors..
...make me nuts.. new hardware and lookups.. thanks for infos..

Bandpass fails to stop every now and then, hanging the rest of OpenWebRX

On very rare occassions, OpenWebRX fails to show connecting user the waterfall, while the background services continue running. The analysis of the situation with GDB has shown the following:

  1. SDR source fails to start for the user because of modificationLock taken by a previous attempt to stop this same SDR source.

  2. The previous SDR stop is being caused by the scheduler shutting down an FT8 service.

  3. Tracking down where it hangs shows the following:

(gdb) py-bt
Traceback (most recent call first):
  File "/usr/lib/python3/dist-packages/csdr/chain/__init__.py", line 139, in stop
    w.stop()
  File "/usr/lib/python3/dist-packages/csdr/chain/__init__.py", line 139, in stop
    w.stop()
  File "/usr/lib/python3/dist-packages/owrx/service/__init__.py", line 106, in stopServices
    service.stop()
  File "/usr/lib/python3/dist-packages/owrx/service/__init__.py", line 76, in onStateChange
    self.stopServices()
  File "/usr/lib/python3/dist-packages/owrx/source/__init__.py", line 579, in setState
    c.onStateChange(state)
  File "/usr/lib/python3/dist-packages/owrx/source/__init__.py", line 474, in stop
    self.setState(SdrSourceState.STOPPING)
  File "/usr/lib/python3/dist-packages/owrx/source/connector.py", line 66, in stop
    super().stop()
  File "/usr/lib/python3/dist-packages/owrx/source/__init__.py", line 539, in checkStatus
    self.stop()
  File "/usr/lib/python3/dist-packages/owrx/service/schedule.py", line 293, in _setCurrentEntry
    self.source.checkStatus()
  File "/usr/lib/python3/dist-packages/owrx/service/schedule.py", line 306, in selectProfile
  1. The native code where it hangs is inside CSDR:
#4  0x0000ffffa13e32a0 in std::thread::join() () from /lib/aarch64-linux-gnu/libstdc++.so.6
#5  0x0000ffffa15a385c in Csdr::AsyncRunner::stop() () from /lib/aarch64-linux-gnu/libcsdr++.so.0.18
  1. And the hanging module is Bandpass, that is inside Selector, that is inside ServiceSelectorChain for FT8:
(gdb) py-print w
local 'w' = <pycsdr.modules.Bandpass at remote 0xffffa0b7ad30>

Support for AARCH64 (aka 64bit ARM)

I saw that the Makefile already tries to detect running on ARMv6, but not ARMv7/v8 or even AARCH64, so it would be a nice addition to support those.

Since on my device /proc/cpuinfo looks like

processor       : 0
BogoMIPS        : 38.40
Features        : fp asimd evtstrm crc32 cpuid
CPU implementer : 0x41
CPU architecture: 8
CPU variant     : 0x0
CPU part        : 0xd03
CPU revision    : 4

It would be better to change the detection to use uname -m anyway, to at least detect the platform properly.

#11 could also apply here though, I'll see how far I get

Edit: According to https://stackoverflow.com/a/29891469 the following PARAMS should be enough for AARCH64 on a Raspberry Pi 3+:
PARAMS_RASPI = -mcpu=cortex-a53 -mtune=cortex-a53 -funsafe-math-optimizations -Wformat=0

Edit2:

cat /proc/device-tree/model 
Raspberry Pi 3 Model B Plus Rev 1.3

That's another good detection method, just search for "Raspberry Pi" and then differ by architecture (and maybe also derive the cortex by that information)

Pizero : Auto detect Raspberry platform improvement

Pizero CPU info :
processor : 0
model name : ARMv6-compatible processor rev 7 (v6l)
BogoMIPS : 697.95
Features : half thumb fastmult vfp edsp java tls
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x0
CPU part : 0xb76
CPU revision : 7
Hardware : BCM2835
Revision : 900093

Maybe modify auto-detect using Hardware or feature ? For example
PARAMS_ARM = $(if $(call cpufeature,ARMv6,dummy-text),$(PARAMS_RASPI),$(PARAMS_NEON))

Correct a sample rate from adc

Hello,

Sorry to post this here since it's not a problem but a question I don't know where to post it.
Is it possible to fix a quartz sampling clock fault of an adc in command line?
For example I have an I/Q stream of 384khz 16bits with an error of 5pps and whose receiver frequency is 50.500mhz.
In fact, it is not only a question of correcting the frequency offset but also the induced excursion.
If anyone has an answer?
Many thanks in advance

octave output plots to PDF/PS/PNG instead of display

I'm trying to get the fft plots working with the command as shown.

rtl_sdr -s 2400000 -f 104300000 -g 20 - | csdr convert_u8_f | csdr fft_cc 1024 1200000 HAMMING --octave | octave -i > /dev/null

For some strange reason, octave output plots do not show up when connecting remotely to a Raspberry Pi with an rtl-sdr dongle.

[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
octave-gui: ../../src/xcb_io.c:259: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.
panic: Aborted -- stopping myself...

Likely this is an octave specific x11 authentication issue as other X11 windows show up correctly. I have never used octave but is it possible to send the output directly to a pdf (or ps or png) by modifying the above command without the octave gui.

Make error

Hi:
When i try to do a make it gives me this error
error at code quality check: badsyntax() used in csdr.c without return.
Makefile:106: recipe for target 'codequality' failed
make: *** [codequality] Error 1

Thanks
Xarbot

./parsevect

When running Makefile:

./parsevect dumpvect*.vect
/bin/sh: 1: ./parsevect: not found
Makefile:47: recipe for target 'all' failed

Needed to chmod +x parsevect

Hope that helps.

Please use a SONAME for libcsdr

Hi,

To make it easier for others to build software using libcsdr, please use a SONAME to allow for tracking of the API/ABI.

"A shared object was identified in a library directory (a directory in the standard linker path) which doesn't have a SONAME. This is usually an error.

SONAMEs are set with something like gcc -Wl,-soname,libfoo.so.0, where 0 is the major version of the library. If your package uses libtool, then libtool invoked with the right options should be doing this."

Thanks,

Support for ARMv8

Looks like some of the ASM changed, I tried fixing but have never done any ASM, let alone ARM.

/tmp/ccyqVRJR.s: Assembler messages:
/tmp/ccyqVRJR.s:1390: Error: unknown mnemonic vmov.f32' --vmov.f32 q4,#0.0'
/tmp/ccyqVRJR.s:1391: Error: unknown mnemonic vmov.f32' --vmov.f32 q5,#0.0'
/tmp/ccyqVRJR.s:1392: Error: unknown mnemonic vld2.32' --vld2.32 {q0-q1},[x6]!'
/tmp/ccyqVRJR.s:1393: Error: unknown mnemonic vld1.32' --vld1.32 {q2},[x7]!'
/tmp/ccyqVRJR.s:1394: Error: unknown mnemonic vmla.f32' --vmla.f32 q4,q0,q2'
/tmp/ccyqVRJR.s:1395: Error: unknown mnemonic vmla.f32' --vmla.f32 q5,q1,q2'
/tmp/ccyqVRJR.s:1398: Error: unknown mnemonic vst1.32' --vst1.32 {q4},[x10]'
/tmp/ccyqVRJR.s:1399: Error: unknown mnemonic vst1.32' --vst1.32 {q5},[x11]'
Makefile:47: recipe for target 'all' failed

Build is on a pine64 with A64 (cortex-a53) on ubuntu 16.04.

Compiling Issue: Raspberry Pi 3 + Raspbian Buster

Hello,

This is what I get when I make the master branch in a Raspberry Pi 3 + Raspbian Buster. Although it seems to work, with OpenwebRX, I'm getting a lot of audio underruns:

`NOTE: you may have to manually edit Makefile to optimize for your CPU (especially if you compile on ARM, please edit PARAMS_NEON).
Auto-detected optimization parameters: -mfloat-abi=hard -march=armv7-a -mtune=cortex-a8 -mfpu=neon -mvectorize-with-neon-quad -funsafe-math-optimizations -Wformat=0 -DNEON_OPTS

rm -f dumpvect*.vect
gcc -std=gnu99 -O3 -ffast-math -fdump-tree-vect-details -dumpbase dumpvect -mfloat-abi=hard -march=armv7-a -mtune=cortex-a8 -mfpu=neon -mvectorize-with-neon-quad -funsafe-math-optimizations -Wformat=0 -DNEON_OPTS fft_fftw.c libcsdr_wrapper.c -g -lm -lrt -lfftw3f -DUSE_FFTW -DLIBCSDR_GPL -DUSE_IMA_ADPCM -Wno-unused-result -fpic -shared -Wl,-soname,libcsdr.so.0.15 -o libcsdr.so.0.15
In file included from libcsdr_wrapper.c:1:
libcsdr.c:320:9: note: #pragma message: Manual NEON optimizations are ON: we have a faster shift_addfast_cc now.
#pragma message "Manual NEON optimizations are ON: we have a faster shift_addfast_cc now."
^~~~~~~
In file included from libcsdr_wrapper.c:1:
libcsdr.c:468:9: note: #pragma message: Manual NEON optimizations are ON: we have a faster fir_decimate_cc now.
#pragma message "Manual NEON optimizations are ON: we have a faster fir_decimate_cc now."
^~~~~~~
./parsevect dumpvect*.vect

Auto-vectorization built into gcc can increase the execution speed of algorithms with automatic
generation of SIMD instructions if the CPU is capable.
We parse the output of the vectorizer to analyze which loops could be optimized (thus speeded up) this way.
Warning! The result may be different on different CPU architectures...

Colors:

  • can't be vectorized
  • successfully vectorized
  • not intended to be vectorized (not important)

libcsdr.c:123:5: note: LOOP VECTORIZED normalize_fir_f: normalize pass 2
libcsdr.c:121:5: note: LOOP VECTORIZED normalize_fir_f: normalize pass 1
libcsdr.c:136:5: note: not vectorized: loop contains function calls or data references that cannot be analyzed firdes_lowpass_f: calculate taps
libcsdr.c:156:5: note: not vectorized: multiple nested loops. firdes_bandpass_c
libcsdr.c:162:14: note: not vectorized: number of iterations cannot be computed. firdes_bandpass_c
libcsdr.c:161:14: note: not vectorized: number of iterations cannot be computed. firdes_bandpass_c
libcsdr.c:193:5: note: not vectorized: multiple nested loops. shift_math_cc
libcsdr.c:204:14: note: not vectorized: number of iterations cannot be computed. shift_math_cc: normalize phase
libcsdr.c:203:14: note: not vectorized: number of iterations cannot be computed. shift_math_cc: normalize phase
libcsdr.c:217:5: note: not vectorized: relevant stmt not supported: _34 = __builtin_sinf (_30);
libcsdr.c:217:5: note: not vectorized: relevant stmt not supported: _34 = __builtin_sinf (_30);
libcsdr.c:237:5: note: not vectorized: multiple nested loops. shift_math_cc
libcsdr.c:262:14: note: not vectorized: number of iterations cannot be computed. shift_math_cc: normalize phase
libcsdr.c:261:14: note: not vectorized: number of iterations cannot be computed. shift_math_cc: normalize phase
libcsdr.c:276:5: note: not vectorized: multiple nested loops.
libcsdr.c:280:14: note: not vectorized: number of iterations cannot be computed.
libcsdr.c:279:14: note: not vectorized: number of iterations cannot be computed.
libcsdr.c:303:10: note: not vectorized: number of iterations cannot be computed.
libcsdr.c:302:10: note: not vectorized: number of iterations cannot be computed.
libcsdr.c:294:5: note: LOOP VECTORIZED shift_unroll_cc
libcsdr.c:311:5: note: not vectorized: unsupported data-type complex float
libcsdr.c:311:5: note: not vectorized: unsupported data-type complex float
libcsdr.c:392:10: note: not vectorized: number of iterations cannot be computed.
libcsdr.c:391:10: note: not vectorized: number of iterations cannot be computed.
libcsdr.c:327:5: note: LOOP VECTORIZED
libcsdr.c:484:9: note: not vectorized: control flow in loop.
libcsdr.c:590:9: note: not vectorized: multiple nested loops.
libcsdr.c:590:9: note: not vectorized: multiple nested loops.
libcsdr.c:597:13: note: not vectorized: number of iterations cannot be computed. fir_interpolate_cc: i loop
libcsdr.c:596:13: note: not vectorized: number of iterations cannot be computed. fir_interpolate_cc: i loop
libcsdr.c:618:15: note: not vectorized: control flow in loop.
libcsdr.c:624:9: note: LOOP VECTORIZED rational_resampler_ff (inner loop)
libcsdr.c:678:5: note: LOOP VECTORIZED fir_one_pass_ff
libcsdr.c:699:5: note: not vectorized: multiple nested loops. fractional_decimator_ff
libcsdr.c:678:5: note: LOOP VECTORIZED fir_one_pass_ff
libcsdr.c:678:5: note: LOOP VECTORIZED fir_one_pass_ff
libcsdr.c:678:5: note: LOOP VECTORIZED fir_one_pass_ff
libcsdr.c:727:5: note: not vectorized: control flow in loop.
libcsdr.c:730:9: note: not vectorized: control flow in loop.
libcsdr.c:763:5: note: not vectorized: multiple nested loops. fractional_decimator_ff
libcsdr.c:784:9: note: not vectorized: relevant stmt not supported: _47 = _43 / _46;
libcsdr.c:784:9: note: not vectorized: relevant stmt not supported: _47 = _43 / _46;
libcsdr.c:774:9: note: not vectorized: control flow in loop.
libcsdr.c:777:13: note: not vectorized: control flow in loop.
libcsdr.c:769:13: note: not vectorized: control flow in loop.
libcsdr.c:678:5: note: LOOP VECTORIZED fir_one_pass_ff
libcsdr.c:771:13: note: LOOP VECTORIZED
libcsdr.c:843:5: note: LOOP VECTORIZED apply_fir_fft_cc: add overlap
libcsdr.c:837:5: note: LOOP VECTORIZED apply_fir_fft_cc: normalize by fft_size
libcsdr.c:825:5: note: LOOP VECTORIZED apply_fir_fft_cc: multiplication
libcsdr.c:869:5: note: not vectorized: relevant stmt not supported: _17 = __builtin_sqrtf (_16); amdemod: sqrt
libcsdr.c:869:5: note: not vectorized: relevant stmt not supported: _17 = __builtin_sqrtf (_16); amdemod: sqrt
libcsdr.c:864:5: note: LOOP VECTORIZED amdemod: ii+qq
libcsdr.c:888:5: note: LOOP VECTORIZED amdemod_estimator
libcsdr.c:911:5: note: not vectorized, possible dependence between data-refs *_14 and *_17 dcblock_f
libcsdr.c:911:5: note: not vectorized, possible dependence between data-refs *_14 and *_17 dcblock_f
libcsdr.c:935:5: note: LOOP VECTORIZED fastdcblock_ff: remove DC component
libcsdr.c:927:5: note: LOOP VECTORIZED fastdcblock_ff: calculate block average
libcsdr.c:975:5: note: not vectorized: unsupported data-type double fastagc_ff: apply gain
libcsdr.c:975:5: note: not vectorized: unsupported data-type double fastagc_ff: apply gain
libcsdr.c:959:5: note: LOOP VECTORIZED fastagc_ff: peak search
libcsdr.c:1009:5: note: not vectorized: unsupported use in stmt. fmdemod_atan_novect
libcsdr.c:1009:5: note: not vectorized: no grouped stores in basic block. fmdemod_atan_novect
libcsdr.c:1027:5: note: not vectorized: unsupported data-type double fmdemod_quadri_novect_cf
libcsdr.c:1027:5: note: not vectorized: unsupported data-type double fmdemod_quadri_novect_cf
libcsdr.c:1065:5: note: not vectorized: unsupported data-type double fmdemod_quadri_cf: output division
libcsdr.c:1065:5: note: not vectorized: unsupported data-type double fmdemod_quadri_cf: output division
libcsdr.c:1065:5: note: not vectorized: no grouped stores in basic block. fmdemod_quadri_cf: output division
libcsdr.c:1061:5: note: LOOP VECTORIZED fmdemod_quadri_cf: output denomiator
libcsdr.c:1057:5: note: LOOP VECTORIZED fmdemod_quadri_cf: output numerator
libcsdr.c:1052:5: note: LOOP VECTORIZED fmdemod_quadri_cf: di
libcsdr.c:1046:5: note: LOOP VECTORIZED fmdemod_quadri_cf: dq
libcsdr.c:1094:5: note: not vectorized, possible dependence between data-refs *_16 and *_19 deemphasis_wfm_ff
libcsdr.c:1094:5: note: not vectorized, possible dependence between data-refs *_16 and *_19 deemphasis_wfm_ff
libcsdr.c:1124:9: note: LOOP VECTORIZED deemphasis_nfm_ff: inner loop
libcsdr.c:1132:5: note: LOOP VECTORIZED limit_ff
libcsdr.c:1141:5: note: LOOP VECTORIZED gain_ff
libcsdr.c:1147:5: note: not vectorized: number of iterations cannot be computed.
libcsdr.c:1157:5: note: not vectorized: number of iterations cannot be computed.
libcsdr.c:1177:5: note: LOOP VECTORIZED
libcsdr.c:1176:5: note: LOOP VECTORIZED
libcsdr.c:1183:5: note: not vectorized: multiple nested loops.
libcsdr.c:1187:14: note: not vectorized: number of iterations cannot be computed.
libcsdr.c:1186:14: note: not vectorized: number of iterations cannot be computed.
libcsdr.c:1196:5: note: not vectorized: relevant stmt not supported: amplitude_now_22 = __builtin_sqrtf (_10);
libcsdr.c:1196:5: note: not vectorized: relevant stmt not supported: amplitude_now_22 = __builtin_sqrtf (_10);
libcsdr.c:1225:9: note: not vectorized: control flow in loop. log2n
libcsdr.c:1240:9: note: not vectorized: control flow in loop. next_pow2
libcsdr.c:1248:5: note: not vectorized: loop contains function calls or data references that cannot be analyzed apply_window_c
libcsdr.c:1261:5: note: not vectorized: loop contains function calls or data references that cannot be analyzed precalculate_window
libcsdr.c:1271:5: note: LOOP VECTORIZED apply_precalculated_window_c
libcsdr.c:1280:2: note: LOOP VECTORIZED apply_precalculated_window_f
libcsdr.c:1289:5: note: not vectorized: loop contains function calls or data references that cannot be analyzed apply_window_f
libcsdr.c:1302:5: note: LOOP VECTORIZED logpower_cf: pass 3
libcsdr.c:1300:5: note: not vectorized: relevant stmt not supported: _17 = __builtin_log10f (_16); logpower_cf: pass 2
libcsdr.c:1300:5: note: not vectorized: relevant stmt not supported: _17 = __builtin_log10f (_16); logpower_cf: pass 2
libcsdr.c:1298:5: note: LOOP VECTORIZED logpower_cf: pass 1
libcsdr.c:1307:5: note: LOOP VECTORIZED logpower_cf: pass 1
libcsdr.c:1313:5: note: LOOP VECTORIZED logpower_cf: pass 3
libcsdr.c:1311:5: note: not vectorized: relevant stmt not supported: _6 = __builtin_log10f (_4); logpower_cf: pass 2
libcsdr.c:1311:5: note: not vectorized: relevant stmt not supported: _6 = __builtin_log10f (_4); logpower_cf: pass 2
libcsdr.c:1319:5: note: LOOP VECTORIZED
libcsdr.c:1544:9: note: not vectorized: control flow in loop.
libcsdr.c:1560:22: note: not vectorized: multiple nested loops.
libcsdr.c:1564:17: note: not vectorized: data ref analysis failed *_29 = 0;
libcsdr.c:1564:17: note: not vectorized: data ref analysis failed *_14 = iftmp.223_41;
libcsdr.c:1559:13: note: not vectorized: control flow in loop.
libcsdr.c:1618:9: note: not vectorized: control flow in loop.
libcsdr.c:1674:13: note: not vectorized: multiple nested loops.
libcsdr.c:1710:9: note: LOOP VECTORIZED
libcsdr.c:1690:9: note: not vectorized: control flow in loop.
libcsdr.c:1697:13: note: LOOP VECTORIZED
libcsdr.c:1676:35: note: not vectorized: control flow in loop.
libcsdr.c:1734:5: note: not vectorized: control flow in loop.
libcsdr.c:1737:13: note: not vectorized: control flow in loop.
libcsdr.c:1769:5: note: not vectorized: relevant stmt not supported: _5 = _4 > 0.0;
libcsdr.c:1769:5: note: not vectorized: relevant stmt not supported: _5 = _4 > 0.0;
libcsdr.c:1776:5: note: not vectorized: unsupported data-type complex float
libcsdr.c:1776:5: note: not vectorized: unsupported data-type complex float
libcsdr.c:1787:5: note: not vectorized: multiple nested loops.
libcsdr.c:1788:9: note: not vectorized: control flow in loop.
libcsdr.c:1789:13: note: LOOP VECTORIZED
libcsdr.c:1796:5: note: not vectorized: control flow in loop.
libcsdr.c:1798:9: note: not vectorized: unsupported data-type double
libcsdr.c:1798:9: note: not vectorized: unsupported data-type double
libcsdr.c:1812:5: note: LOOP VECTORIZED
libcsdr.c:1821:5: note: not vectorized: unsupported use in stmt.
libcsdr.c:1831:9: note: not vectorized: unsupported use in stmt.
libcsdr.c:1837:9: note: not vectorized: unsupported use in stmt.
libcsdr.c:1837:9: note: not vectorized: no grouped stores in basic block.
libcsdr.c:1878:9: note: not vectorized: multiple nested loops.
libcsdr.c:1905:18: note: not vectorized: number of iterations cannot be computed.
libcsdr.c:1904:18: note: not vectorized: number of iterations cannot be computed.
libcsdr.c:1890:14: note: not vectorized: number of iterations cannot be computed.
libcsdr.c:1889:14: note: not vectorized: number of iterations cannot be computed.
libcsdr.c:1880:14: note: not vectorized: number of iterations cannot be computed.
libcsdr.c:1879:14: note: not vectorized: number of iterations cannot be computed.
libcsdr.c:1948:5: note: not vectorized: loop contains function calls or data references that cannot be analyzed
libcsdr.c:1948:5: note: not vectorized: loop contains function calls or data references that cannot be analyzed
libcsdr.c:1942:5: note: not vectorized: loop contains function calls or data references that cannot be analyzed
libcsdr.c:1942:5: note: not vectorized: loop contains function calls or data references that cannot be analyzed
libcsdr.c:1935:5: note: not vectorized: loop contains function calls or data references that cannot be analyzed
libcsdr.c:1935:5: note: not vectorized: loop contains function calls or data references that cannot be analyzed
libcsdr.c:1933:5: note: not vectorized: loop contains function calls or data references that cannot be analyzed
libcsdr.c:1931:5: note: not vectorized: loop contains function calls or data references that cannot be analyzed
libcsdr.c:1924:5: note: LOOP VECTORIZED
libcsdr.c:1993:9: note: not vectorized: control flow in loop.
libcsdr.c:2110:5: note: not vectorized: multiple nested loops.
libcsdr.c:2140:14: note: not vectorized: number of iterations cannot be computed.
libcsdr.c:2139:14: note: not vectorized: number of iterations cannot be computed.
libcsdr.c:2125:22: note: not vectorized: number of iterations cannot be computed.
libcsdr.c:2205:5: note: not vectorized: complicated access pattern.
libcsdr.c:2253:9: note: LOOP VECTORIZED firdes_add_peak_c: normalize pass 2
libcsdr.c:2249:9: note: not vectorized: unsupported use in stmt. firdes_add_peak_c: normalize pass 1
libcsdr.c:2240:9: note: LOOP VECTORIZED
libcsdr.c:2227:5: note: not vectorized: multiple nested loops. firdes_add_peak_c: calculate taps
libcsdr.c:2235:14: note: not vectorized: number of iterations cannot be computed.
libcsdr.c:2234:14: note: not vectorized: number of iterations cannot be computed.
libcsdr.c:2264:5: note: not vectorized: control flow in loop.
libcsdr.c:2267:9: note: not vectorized: complicated access pattern.
libcsdr.c:2279:5: note: not vectorized: control flow in loop.
libcsdr.c:2282:9: note: LOOP VECTORIZED
libcsdr.c:2314:5: note: LOOP VECTORIZED
libcsdr.c:2297:5: note: not vectorized: unsupported use in stmt.
libcsdr.c:2297:5: note: not vectorized: no grouped stores in basic block.
libcsdr.c:2297:5: note: not vectorized: control flow in loop.
libcsdr.c:2322:5: note: not vectorized: multiple nested loops.
libcsdr.c:2328:14: note: not vectorized: number of iterations cannot be computed.
libcsdr.c:2327:14: note: not vectorized: number of iterations cannot be computed.
libcsdr.c:2338:5: note: not vectorized: control flow in loop.
libcsdr.c:2342:9: note: LOOP VECTORIZED
libcsdr.c:2365:5: note: not vectorized: unsupported data-type double convert_u8_f
libcsdr.c:2365:5: note: not vectorized: unsupported data-type double convert_u8_f
libcsdr.c:2370:5: note: LOOP VECTORIZED convert_s8_f
libcsdr.c:2375:5: note: LOOP VECTORIZED convert_s16_f
libcsdr.c:2380:5: note: not vectorized: unsupported data-type double convert_f_u8
libcsdr.c:2380:5: note: not vectorized: unsupported data-type double convert_f_u8
libcsdr.c:2387:5: note: LOOP VECTORIZED convert_f_s8
libcsdr.c:2397:5: note: LOOP VECTORIZED convert_f_s16
libcsdr.c:2406:19: note: not vectorized: relevant stmt not supported: _12 = BIT_FIELD_REF <_6, 8, 8>;
libcsdr.c:2406:19: note: not vectorized: relevant stmt not supported: _12 = BIT_FIELD_REF <_6, 8, 8>;
libcsdr.c:2414:10: note: not vectorized: relevant stmt not supported: _24 = BIT_FIELD_REF <_21, 8, 16>;
libcsdr.c:2414:10: note: not vectorized: relevant stmt not supported: _24 = BIT_FIELD_REF <_21, 8, 16>;
libcsdr.c:2427:19: note: LOOP VECTORIZED
libcsdr.c:2432:10: note: LOOP VECTORIZED
libcsdr.c:2448:5: note: LOOP VECTORIZED
libcsdr.c:2459:5: note: not vectorized: unsupported data-type double
libcsdr.c:2459:5: note: not vectorized: unsupported data-type double
libcsdr.c:2477:5: note: not vectorized: unsupported data-type double
libcsdr.c:2477:5: note: not vectorized: unsupported data-type double
libcsdr.c:2487:5: note: not vectorized: unsupported data-type complex double
libcsdr.c:2487:5: note: not vectorized: unsupported data-type complex double
libcsdr.c:2487:5: note: not vectorized: no grouped stores in basic block.
libcsdr.c:2501:5: note: not vectorized: loop contains function calls or data references that cannot be analyzed
libcsdr.c:2520:5: note: LOOP VECTORIZED
libcsdr.c:2525:5: note: LOOP VECTORIZED
libcsdr.c:2536:5: note: LOOP VECTORIZED trivial_vectorize: should pass :-)
libcsdr_gpl.c:50:7: note: not vectorized: number of iterations cannot be computed. shift_addition_cc: normalize starting_phase
libcsdr_gpl.c:49:7: note: not vectorized: number of iterations cannot be computed. shift_addition_cc: normalize starting_phase
libcsdr_gpl.c:37:2: note: not vectorized: unsupported use in stmt. shift_addition_cc: work
libcsdr_gpl.c:77:7: note: not vectorized: number of iterations cannot be computed. shift_addition_cc: normalize starting_phase
libcsdr_gpl.c:76:7: note: not vectorized: number of iterations cannot be computed. shift_addition_cc: normalize starting_phase
libcsdr_gpl.c:64:2: note: not vectorized: unsupported use in stmt. shift_addition_cc: work
libcsdr_gpl.c:104:2: note: not vectorized: control flow in loop. shift_addition_cc: work
libcsdr_gpl.c:111:8: note: not vectorized: number of iterations cannot be computed. shift_addition_cc: normalize phase
libcsdr_gpl.c:158:7: note: not vectorized: number of iterations cannot be computed. shift_addition_cc: normalize starting_phase
libcsdr_gpl.c:157:7: note: not vectorized: number of iterations cannot be computed. shift_addition_cc: normalize starting_phase
libcsdr_gpl.c:142:2: note: not vectorized: number of iterations cannot be computed. shift_addition_cc: work
libcsdr_gpl.c:198:2: note: not vectorized: unsupported use in stmt. agc_ff
libcsdr_gpl.c:198:2: note: not vectorized: no grouped stores in basic block. agc_ff
ima_adpcm.c:157:2: note: not vectorized: data ref analysis failed step_57 = _stepSizeTable[state$index_19];
ima_adpcm.c:157:2: note: not vectorized: no grouped stores in basic block.
ima_adpcm.c:168:2: note: not vectorized: data ref analysis failed step_55 = _stepSizeTable[state_17];
fastddc.c:50:8: note: not vectorized: number of iterations cannot be computed.
fastddc.c:42:20: note: not vectorized: control flow in loop.
fastddc.c:95:2: note: LOOP VECTORIZED
fastddc.c:154:2: note: LOOP VECTORIZED fastddc_inv_cc: normalize by size
fastddc.c:144:2: note: LOOP VECTORIZED
fastddc.c:126:2: note: not vectorized: data ref analysis failed _18 = *_17;
fastddc.c:116:2: note: LOOP VECTORIZED
gcc -std=gnu99 -O3 -ffast-math -fdump-tree-vect-details -dumpbase dumpvect -mfloat-abi=hard -march=armv7-a -mtune=cortex-a8 -mfpu=neon -mvectorize-with-neon-quad -funsafe-math-optimizations -Wformat=0 -DNEON_OPTS csdr.c -g -lm -lrt -lfftw3f -DUSE_FFTW -DLIBCSDR_GPL -DUSE_IMA_ADPCM -L. -lcsdr -Wno-unused-result -o csdr
In file included from /usr/include/arm-linux-gnueabihf/bits/libc-header-start.h:33,
from /usr/include/stdio.h:27,
from csdr.c:34:
/usr/include/features.h:184:3: warning: #warning "_BSD_SOURCE and _SVID_SOURCE are deprecated, use _DEFAULT_SOURCE" [-Wcpp]

warning "_BSD_SOURCE and _SVID_SOURCE are deprecated, use _DEFAULT_SOURCE"

^~~~~~~
csdr.c:163:6: warning: trigraph ??< ignored, use -trigraphs to enable [-Wtrigraphs]
" ??<jump_to_function_docs_on_github>\n"

g++ -O3 -ffast-math -fdump-tree-vect-details -dumpbase dumpvect -mfloat-abi=hard -march=armv7-a -mtune=cortex-a8 -mfpu=neon -mvectorize-with-neon-quad -funsafe-math-optimizations -Wformat=0 -DNEON_OPTS nmux.cpp tsmpool.cpp -g -lm -lrt -lfftw3f -DUSE_FFTW -DLIBCSDR_GPL -DUSE_IMA_ADPCM -L. -lcsdr -lpthread -Wno-unused-result -o nmux
`

Please make a release

Hi,

The last release was a long time ago and there have been many commits since that release.

Are you planning to make one soon?

Thanks,

convert_i16_f adds a portional of original data to the end

Thank you for this useful DSP tool which I am hoping to use. But I notice something strange when converting data types.

I recorded a 1 second IQ sine wave at 48kHz, and used csdr convert_i16_f to convert to a float file. The int16 file is 185.k where as the float32 file is 176k, which is 1k bigger than the expected 187.5*2.

Using python to read the int16 data to array yy and the float32 data to zz.
The beginnings are the same
yy[:5] = array([ 0.+250.j, -812.+134.j, -824. +18.j, -818. -98.j, -800.-213.j])
np.round(zz[:5]*(1<<15))
array([ 0.+250.j, -812.+134.j, -824. +18.j, -818. -98.j, -800.-213.j], dtype=complex64)

The end of the int16 data is
yy[-5:] = array([ 298.+834.j, 195.+868.j, 88.+885.j, -19.+889.j, -129.+876.j])

While the float32 data extends 128 samples beyond sample 48,000
np.round(zz[-131:-126]*(1<<15))
array([ 88.+885.j, -19.+889.j, -129.+876.j, -564.-658.j, -478.-730.j], dtype=complex64)

So the last sample in the int16 data, shown in bold, is at sample [-129] which corresponds to the expected 48000 th sample of the float32. But there are 128 more samples after 48000.

Then, by scanning through the int data, I found the start of the 128 sample extension to be sample 512 from the end of the original
yy[-513:-508].
array([-637.-573.j, -564.-658.j, -478.-730.j, -389.-789.j, -290.-837.j])
np.round(zz[-129:-124]*(1<<15))
array([-129.+876.j, -564.-658.j, -478.-730.j, -389.-789.j, -290.-837.j], dtype=complex64)

In summary the converted data is 128 samples longer than the original with the added data being a 128 sample section taken 512 samples from the end of the original data. I suspect some buffer under/over run but cannot see where this might occur.

Help in understanding and fixing this would be appreciated. R

Capture

PS this is running on a raspberry pi using the branch recommended in the QTCSDR installation instructions.

Install on RPI Zero

Hello all
I try to install on RPI zero (not a programmer I just follow instruction !)
All seems go ok but when launch i get : Illegal instruction error

I need to configure "NEON" ? but how ?

Thank you

Poor WFM decoding performance with homepage example

Hello,
I am playing around with SDR with my newly bought RTL-SDR and I tried some of the examples given on the homepage (https://github.com/simonyiszk/csdr).

However, I could not manage to make any good quality demodulation of a standard WFM commercial broadcast using csdr. I applied the "Demodulate WFM: Advanced" command line almost as-it:
rtl_sdr -s 2400000 -f 97700000 -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 > csdr_decode.raw

but all I could get was a very noisy decoded sound. Here is a short audio clip after converting the raw to wav: Link to WAV file

This is surprising since I can get a much better output in GNU Radio using the very same sequence as csdr:
untitled2 grc

And then, on the same channel, only a few seconds apart, the output is really good: Link to WAV file

Am I missing something? Are these two doing something different?

--
felixzero

Add support for FFT integration

Could you add the support of FFT integration, aka, averaging x number of FFTs?

This has numerous uses, including better power measurements and smaller FFT files (used in radar and radio-astronomy applications).

Thanks!

FT8 decoding with Airspy HF+ Discovery

FT8 decoding works well with RTL-SDR V3 Dongle:

$ ~/librtlsdr/src/rtl_sdr -s 1000000 -f 14074000 -g 20 -O dm=4:dm=20E6 - | csdr convert_u8_f | csdr fir_decimate_cc 250 0.00166665 HAMMING > /tmp/ft8_14074000.c2

$ ./ft8d backup/ft8_14074000.c2 
 00   2.6  -9 -0.15 14074124 VU3CER VU3FOE MK68   MK68
 00   3.8  -6 -0.15 14074424 VU3CER VU3FOE MK68   MK68
 00   3.1  -5 -0.15 14074523 VU3CER VU3FOE MK68   MK68
 00   3.3   3 -0.14 14074623 VU3CER VU3FOE MK68   MK68
 00   3.8  12 -0.13 14074723 VU3CER VU3FOE MK68   MK68

The ft8d binary comes from https://github.com/pavel-demin/ft8d project.

Next, I tried using Airspy HF+ Discovery instead of the RTL-SDR V3 Dongle.

$ airspyhf_rx -r /dev/stdout -a 384000 -f 14.074000 -g on -m on - | csdr fir_decimate_cc 80 0.00166665 HAMMING > /tmp/ft8_14074000.c2"

$ ./ft8d backup/ft8_14074000.c2
<no decodes>

https://github.com/airspy/airspyhf/blob/master/tools/src/airspyhf_rx.c <-- I am using this to grab the IQ samples. I am guessing that the output format is CF32 which is directly supported by csdr tools. I could be totally wrong here.

No luck here!

Next, I tried using the Airspy HF+ Discover with rx_tools.

$ rx_sdr -s 384000 -f 14074000 -I CF32 -F CF32 - | csdr fir_decimate_cc 80 0.00166665 HAMMING > /tmp/ft8_14074000.c2

$ ./ft8d backup/ft8_14074000.c2
<no decodes>

No luck here either.

To ensure that FT8 traffic in always on the air, I use my https://github.com/kholia/Easy-Digital-Beacons-v1 project to generate such test FT8 traffic.

I am trying to understand where the bug is. Am I using csdr correctly? Or is airspyhf_rx subtly different in its behavior compared to rtl_sdr?

Note: All software versions are freshly built from git repos.

Thanks for the help.

Feature request: Add support for CS16

Just making my request 'official'. :) Happy to help/donate where I can, but unfortunately not a programmer. This change could help reduce overall CPU usage of all csdr processes, not to mention also whichever tool is used to provide the I/Q data, i.e., rtl_sdr, rx_sdr or hackrf_transfer. (Where supported, obviously. I can confirm rx_sdr supports this as long as the device backed by SoapySDR also does.)

Help creating a working chain...

Hi!
I'm fighting with my receiver and csd for months...and cannot find a valid "chain" of commands to decode some audio...
My receiver outputs samples at a samplerate of 192khz 24 bit integer...
What i would like to do is: tune the receiver to a central frequency (for example 7070000) and decode an lsb audio signal at 7073000 (so +3 khz from the tuned freq) with a bandwidth of 2.7khz (standard ham audio bandwidth).
The output of the soundcard is 44.100 (i'm using a raspberry 3 with the classic 3.5mm jack).
The receiver outputs samples in this way:
elad_sdr_24 7070000 0 | csdr... (where frequency is 7070000 and 0 means infinite samples).

Can someone provide me the command to use?

Many thanks!

'73 de IU5HES


http://www.iu5hes.it

can't make for mac osx

make                                
cat: /proc/cpuinfo: No such file or directory
cat: /proc/cpuinfo: No such file or directory
cat: /proc/cpuinfo: No such file or directory
cat: /proc/cpuinfo: No such file or directory
NOTE: you may have to manually edit Makefile to optimize for your CPU (especially if you compile on ARM, please edit PARAMS_NEON).
Auto-detected optimization parameters: -mfloat-abi=hard -march=armv7-a -mtune=cortex-a8 -mfpu=neon -mvectorize-with-neon-quad -funsafe-math-optimizations -Wformat=0 -DNEON_OPTS

rm -f dumpvect*.vect
gcc -std=gnu99 -O3 -ffast-math -fdump-tree-vect-details -dumpbase dumpvect -mfloat-abi=hard -march=armv7-a -mtune=cortex-a8 -mfpu=neon -mvectorize-with-neon-quad -funsafe-math-optimizations -Wformat=0 -DNEON_OPTS fft_fftw.c libcsdr_wrapper.c  -g -lm -lrt -lfftw3f -DUSE_FFTW -DLIBCSDR_GPL -DUSE_IMA_ADPCM -Wno-unused-result -fpic -shared -o libcsdr.so
clang: error: unknown argument: '-fdump-tree-vect-details'
clang: error: unknown argument: '-mvectorize-with-neon-quad'
clang: error: no such file or directory: 'dumpvect'
make: *** [libcsdr.so] Error 1

Advise in piping sound stream to RPITX

Hello,

I'm trying to pipe audio from ALSA_LOOPBACK to RPITX using csdr libraries, and to transmit it on USB, using the following statement :

arecord -c1 -r 48000 -D hw:Loopback,1,0 -f S16_LE - | csdr convert_s16_f | csdr dsb_fc | csdr bandpass_fir_fft_cc 0 0.1 0.01 | csdr gain_ff 2.0 | csdr shift_addition_cc 0.2 | sudo rpitx -i- -m IQ -f $FREQUENCY

...on Frequency 28150 KHz.

The effect is to trasmit noise.

Please consider :
A) that audio recorded from alsa_loopback after the "arecord -c1 -r 48000 -D hw:Loopback,1,0 -f S16_LE" statement is correct.
B) that test audio USB transmissions from RPITX on the same frequency using :

rpitx -m IQ -i /home/pi/pat/ssbIQ.wav -f $FREQUENCY -l

... after having created ssbIQ.wav with the RPITX pissb utility, are correctly transmitted over radio channel.

I'm probably making some mistake in using csdr : can you put me on the right way ?

Thank-you
73
Best regards
Ugo IU1IOB

compile csdr on openwrt platform with error

error message:
`NOTE: you may have to manually edit Makefile to optimize for your CPU (especially if you compile on ARM, please edit PARAMS_NEON).
Auto-detected optimization parameters: -msse -msse2 -msse3 -msse4.1 -msse4.2 -msse4 -mfpmath=sse

rm -f dumpvect*.vect
gcc -I /home/openwrt/openwrt/build_dir/target-mipsel_24kc_musl/fftw3-single/fftw-3.3.7/api -L /home/openwrt/openwrt/build_dir/target-mipsel_24kc_musl/fftw3-single/fftw-3.3.7/.libs -std=gnu99 -O3 -ffast-math -fdump-tree-vect-details -dumpbase dumpvect -msse -msse2 -msse3 -msse4.1 -msse4.2 -msse4 -mfpmath=sse fft_fftw.c libcsdr_wrapper.c -g -lm -lrt -lfftw3f -DUSE_FFTW -DLIBCSDR_GPL -DUSE_IMA_ADPCM -Wno-unused-result -fpic -shared -Wl,-soname,libcsdr.so.0.15 -o libcsdr.so.0.15
/usr/bin/ld: skipping incompatible /home/openwrt/openwrt/build_dir/target-mipsel_24kc_musl/fftw3-single/fftw-3.3.7/.libs/libfftw3f.so when searching for -lfftw3f
/usr/bin/ld: skipping incompatible /home/openwrt/openwrt/build_dir/target-mipsel_24kc_musl/fftw3-single/fftw-3.3.7/.libs/libfftw3f.a when searching for -lfftw3f
/usr/bin/ld: cannot find -lfftw3f
collect2: error: ld returned 1 exit status
Makefile:54: recipe for target 'libcsdr.so' failed
make[4]: *** [libcsdr.so] Error 1
make[4]: Leaving directory '/home/openwrt/openwrt/build_dir/target-mipsel_24kc_musl/csdr-0.1'
Makefile:81: recipe for target '/home/openwrt/openwrt/build_dir/target-mipsel_24kc_musl/csdr-0.1/.built' failed
make[3]: *** [/home/openwrt/openwrt/build_dir/target-mipsel_24kc_musl/csdr-0.1/.built] Error 2
make[3]: Leaving directory '/home/openwrt/csdr.openwrt'
time: package/csdr/compile#2.57#0.12#2.80
package/Makefile:111: recipe for target 'package/csdr/compile' failed
make[2]: *** [package/csdr/compile] Error 2
make[2]: Leaving directory '/home/openwrt/openwrt'
package/Makefile:107: recipe for target '/home/openwrt/openwrt/staging_dir/target-mipsel_24kc_musl/stamp/.package_compile' failed
make[1]: *** [/home/openwrt/openwrt/staging_dir/target-mipsel_24kc_musl/stamp/.package_compile] Error 2
make[1]: Leaving directory '/home/openwrt/openwrt'
/home/openwrt/openwrt/include/toplevel.mk:216: recipe for target 'world' failed
make: *** [world] Error 2
`

when I compile csdr on openwrt playform , and the hardware cpu is MediaTek Ralink MIPS (MT7621), the fftw3 module is also compilie from openwrt original package source.

and I checked the libfftw3f.so is elf32-little :
`objdump -p /home/openwrt/openwrt/build_dir/target-mipsel_24kc_musl/fftw3-single/fftw-3.3.7/.libs/libfftw3f.so

/home/openwrt/openwrt/build_dir/target-mipsel_24kc_musl/fftw3-single/fftw-3.3.7/.libs/libfftw3f.so: file format elf32-little`

README.md has Broken Examples


The python math calculation used within one of the examples is broken. The python print command now requires an additional set of parenthesis around the entire python print argument, after a recent python version release.

Also, mplayer incantation doesn't work here using ALSA, so I'm readily suspecting mplayer will not also work with other recent Linux distributions using pulseaudio for the past many years.  I'm thinking, probably best relying upon rarely changing simplistic software tools, or boring and stable tools such as either ALSA aplay or sox software tools for the examples.  Albeit, mplayer and mpv are great multi tools, myself using mpv more often.  Regardless, aplay is easy and simplistic, and when dealing with sound file manipulation, always find sox performs well.

So far, the below modified examples currently works for me.  Note, the previously mentioned bugs have been fixed within the incantations below:

# fm demodulation
$ airspyhf_rx -z -d -r stdout -f 105.5 | ./csdr fir_decimate_cc 2 0.25 HAMMING | ./csdr fmdemod_quadri_cf | ./csdr fractional_decimator_ff 8 | ./csdr deemphasis_wfm_ff 48000 50e-6 | ./csdr convert_f_s16 |  play -t s16 -r 48000 -

# am demodulation
airspyhf_rx -z -d -r stdout -f 0.970 |  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 |  play -t s16 -r 48000 -

Since I'm relatively new to airspyhf_rx and csdr, there maybe errors.  airspyhf hardware suggests always using AGC on (or set to low) setting.

Adding two signals

Hi,

I'm willing to add two signals. One baseband (say 500 KHz wide) I/Q stream coming from a rtl-sdr dongle and another signal, locally created, carrying some arbitrary modulation. The resulting baseband can be used to modulate using SSB an output signal.

Main purpose is to implement a linear transponder and adding some local telemetry channel.

I've been exploring the functions of csdr but found no function that can be used as a linear sum of two signals with proper alignment of sample rates.

¿Any idea?

73 de Pedro, LU7DID

Pocsag chain: rtl_tcp -> cdr -> multimon-ng

Hi,

i am trying to build a chain for POCSAG decoding.

ALready used rtl_fm & multimon - works like a charm.

Now i am trying to use rtl_tcp and csdr for fm decoding.
In my understanding, the deemphasis_nfm_ff is not useable as the BW is too narrow.

Tried this chain:
(Incoming IQ - BW 1024000, Output SR 22050)

'csdr convert_u8_f |'+
'csdr shift_addition_cc 0.126953125 |'+
'csdr fir_decimate_cc 46 0.0010869565217391304 BLACKMAN |'+
'csdr fmdemod_quadri_cf |'+
'csdr limit_ff |'+
'csdr deemphasis_wfm_ff 22050 50e-6 |'+
'csdr fastagc_ff 1024 |'+
'csdr convert_f_s16'

But result is just garbage

Whitch screws i have to turn?

Csdr (or Gnuradio) interfacing to RPITX

Hello group,

I'm more and more bit confused regarding interfacing of GnuRadio with Evariste's RPITX, and I hope you can help.
I have used several test SSB flowgraph or CSDR tfor modulating in USB audio files and transmitting them over RPITX.
The situation is the following :

I'm using RPITX "standard version" (not the new one) installed on a RaspberryPI2 with Stretch (Linux 4.14.49+ #11201 armv6l GNU/Linux)
Test trasmission over RPITX on USB of sampleaudio.wav test file, modulated using the Evariste's modulation program pissb is successful over 10 m band
I made a test flowgraph on GnuRadio on Windows that reads the "modulated" (by pissb) wav file and send it to the RaspberryPI via UDP sink : this allows an RPITX correct transmission, but only if I use the following receaving statement :
nc -u -l 8011 | sudo rpitx -i - -m IQ -a 14 -f $FREQUENCY

Gnuradio reads in FLOAT format and send it to UDPsink in FLOAT format (not in COMPLEX)

If I start modulating the sampleaudio.wav using different USB TX flowgraph (I can share them, for example the one of oz9aec or of ha7ilm) or also CSDR and I send the modulated output (correct, checking FFT scope...) to RPITX using again UDP sink, the result is a noise transmission (both setting RPITX in IQ or IQFLOAT format, both transmitting float or complex data flow over UDP sink.
Worst, the "correctly running" output of PISSB utility can be played o using any kind of playing audio tool, while the modulated output of the different flowgraphs (being IQ) should not.
I'm consequently a bit confused : what is the real data format accepted as input from RPITX, and which the correct way for interfacing it with Gnuradio and csdr ? (I guess that UDP or TCP sink - now deprecated - is not the issue...)

Any help appreciated
Regards, 73
Ugo

Decoding SSB with ELAD FDM-S2

Hi, can someone provide an example of demodulating LSB voice at an input samplerate of 192k 24 bit integer?
I find it quite difficult to build the string

I provide the input 192k i/ with this command:

elad_sdr_24 14248800 0

that output an infinite i/q stream at 192k on the frequency 14.248800kHz

Any help?

Compiling on RPi - armv6

Hi,

i'm trying to compile on an old RPi with armv6. Tried with the flags below but still getting an Illegal Instruction on nmux. Any clues?

PARAMS_NEON = -mfloat-abi=hard -march=armv6 -mtune=arm6 -mfpu=neon -mvectorize-with-neon-quad -funsafe-math-optimizations -Wformat=0 -DNEON_OPTS

Thanks in advance
Dominic

root@pi:~/csdr# rtl_sdr -s 250000 -f 145525000 -p 0 -g 5 -| nmux --bufsize 65536 --bufcnt 763 --port 4951
nmux: listening on 127.0.0.1:4951
Found 1 device(s):
  0:  Realtek, RTL2838UHIDIR, SN: 00000001
Using device 0: Generic RTL2832U OEM
Found Rafael Micro R820T tuner
Exact sample rate is: 250000.000414 Hz
Sampling at 250000 S/s.
Tuned to 145525000 Hz.
Tuner gain set to 3.70 dB.
Reading samples in async mode...
Signal caught, exiting!
Short write, samples lost, exiting!
User cancel, exiting...
Illegal instruction


root@pi:~/csdr# nmux --bufsize 65536 --port 4951 --address 127.0.0.1
nmux: listening on 127.0.0.1:4951
Illegal instruction


root@pi:~/csdr# cat /proc/cpuinfo 
processor	: 0
model name	: ARMv6-compatible processor rev 7 (v6l)
BogoMIPS	: 697.95
Features	: half thumb fastmult vfp edsp java tls 
CPU implementer	: 0x41
CPU architecture: 7
CPU variant	: 0x0
CPU part	: 0xb76
CPU revision	: 7
Hardware	: BCM2835
Revision	: 000f

[Feature request] 24 bit integer and 32 bit float support

Hi!
Is it possible to add the support for 24 bit integers and 32 bit float as input data types?
That would be really great! (i'm using a professional receiver...not an rtl-sdr).
Many many many many thanks!
Best regards

Michele

using csdr encode_ima_adpcm and decode_ima_adpcm_u8_i16

Hi, about the IMA ADPCM encode and decode, I am trying to chain and play using pipes. In my first attempt use play
nc -l -u 7355 | csdr encode_ima_adpcm_i16_u8 | play -tima -r8k -

The input source has a 8kHz sample rate and the input format is signed short to encode_ima_adpcm but the sound is a bit distorted after decoded (using play), so my question here is: does the input source need a particular sample rate to use with csdr encode_ima_adpcm_i16_u8 ?

In the othe side if I want to use csdr encode and csdr decode which player do you recommend (play, mplayer) and how would be the parameters?, . It is something li ke this:
nc -l -u 7355 | csdr encode_ima_adpcm_i16_u8 | csdr decode_ima_adpcm_u8_i16 | mplayer...

Thanks and regards

Help editing Makefile

Hi!
Can someone help me modifing the Makefile for Raspberry?
Have not understood how should i change it...
Many thanks!
Michele

Decoding SSB with airspy

Using the example on the README I created a line to use airspy_rx and achieve a similar result:

airspy_rx -t 0 -r /dev/stdout -a 1 -f 434.253 -g 18 | csdr fir_decimate_cc 59 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 -ao jack:name=RTTY -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -&

I don't really understand what each part is doing but signal sounds correct, however there are occasional pauses in the signal which make it really hard to decode. Is there anything in this command which could cause this.

Runnning on Raspberry Pi 3

nmux crash (+fix)

Just came across this while deploying OpenWebRx on Arch Linux x86_64. The first client connects to nmux, then disconnects, the second client connects and then I get a 100% reproducible crash:

Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00007fd653522fcd in __memmove_ssse3 () from /usr/lib/libc.so.6
(gdb) bt
#0  0x00007fd653522fcd in __memmove_ssse3 () from /usr/lib/libc.so.6
#1  0x00005562be082fac in std::__copy_move<true, true, std::random_access_iterator_tag>::__copy_m<tsmthread_s*> (__result=<optimized out>,
    __last=<optimized out>, __first=<optimized out>) at /usr/include/c++/8.2.0/bits/stl_algobase.h:479
#2  std::__copy_move_a<true, tsmthread_s**, tsmthread_s**> (__result=<optimized out>, __last=<optimized out>, __first=<optimized out>)
    at /usr/include/c++/8.2.0/bits/stl_algobase.h:386
#3  std::__copy_move_a2<true, __gnu_cxx::__normal_iterator<tsmthread_s**, std::vector<tsmthread_s*, std::allocator<tsmthread_s*> > >, __gnu_cxx::__normal_iterator<tsmthread_s**, std::vector<tsmthread_s*, std::allocator<tsmthread_s*> > > > (__result=..., __last=..., __first=...)
    at /usr/include/c++/8.2.0/bits/stl_algobase.h:422
#4  std::move<__gnu_cxx::__normal_iterator<tsmthread_s**, std::vector<tsmthread_s*, std::allocator<tsmthread_s*> > >, __gnu_cxx::__normal_iterator<tsmthread_s**, std::vector<tsmthread_s*, std::allocator<tsmthread_s*> > > > (__result=..., __last=..., __first=...) at /usr/include/c++/8.2.0/bits/stl_algobase.h:487
#5  std::vector<tsmthread_s*, std::allocator<tsmthread_s*> >::_M_erase (__position=..., this=0x5562be48c1a0) at /usr/include/c++/8.2.0/bits/vector.tcc:163
#6  std::vector<tsmthread_s*, std::allocator<tsmthread_s*> >::erase (__position=..., this=0x5562be48c1a0) at /usr/include/c++/8.2.0/bits/stl_vector.h:1318
#7  tsmpool::remove_thread (this=0x5562be48c1a0, thread=0x5562be48c250) at tsmpool.cpp:52
#8  0x00005562be082873 in main (argc=<optimized out>, argv=<optimized out>) at nmux.cpp:206

This might be a clue:

tsmpool.cpp: In member function ‘int tsmpool::remove_thread(tsmthread_t*)’:
tsmpool.cpp:56:1: warning: no return statement in function returning non-void [-Wreturn-type]
 }

Indeed, I changed int tsmpool::remove_thread to void and voila, no more crashes.

Bug in fir_decimate_cc NEON implementation at higher decimation rates

I encountered this issue when trying to run OpenWebRX on an Odroid-U3. When running at a sample rate of 0.25 Msps everything works fine, while at a sample rate of 2.048 Msps the audio would drop out, even though the CPU usage was very low.

After some investigation this seems to be an issue with fir_decimate_cc, it started outputting zeros with higher decimation rates (185 at 2.048 Msps) after about 1 second of operation while it works fine with lower rates (22 at 0.25 Msps). When not using the NEON optimized implementation of fir_decimate_cc by removing -DNEON_OPTS in PARAMS_NEON this issue does not arise.

Without the optimized implementation the Odroid-U3 uses 22% CPU when sampling at 2.048 Msps with 1 client connected, so this workaround is (pretty much) usable.

This issue could of course be specific to the Odroid-U3, please report if anyone has the current NEON-implementation working using another board/cpu with NEON FPU, then the solution is to use the workaround when using an Odroid-U3. :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.