2014-11-28 23:44:41 +08:00
/*
2016-03-20 23:41:37 +08:00
This software is part of libcsdr , a set of simple DSP routines for
2014-11-28 23:44:41 +08:00
Software Defined Radio .
Copyright ( c ) 2014 , Andras Retzler < randras @ sdr . hu >
All rights reserved .
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions are met :
* Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
* Redistributions in binary form must reproduce the above copyright
notice , this list of conditions and the following disclaimer in the
documentation and / or other materials provided with the distribution .
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS " AND
ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED . IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY
DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES
( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ;
LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# pragma once
# define MIN_M(x,y) (((x)>(y))?(y):(x))
/*
2016-03-20 23:41:37 +08:00
_____ _
/ ____ | | |
| | ___ _ __ ___ _ __ | | _____ __
| | / _ \ | ' _ ` _ \ | ' _ \ | | / _ \ \ / /
| | ___ | ( _ ) | | | | | | | _ ) | | __ / > <
\ _____ \ ___ / | _ | | _ | | _ | . __ / | _ | \ ___ / _ / \ _ \
| |
| _ |
2014-11-28 23:44:41 +08:00
*/
typedef struct complexf_s { float i ; float q ; } complexf ;
//apply to pointers:
# define iof(complexf_input_p,i) (*(((float*)complexf_input_p)+2*(i)))
# define qof(complexf_input_p,i) (*(((float*)complexf_input_p)+2*(i)+1))
# define absof(complexf_input_p,i) (sqrt(iof(complexf_input_p,i)*iof(complexf_input_p,i)+qof(complexf_input_p,i)*qof(complexf_input_p,i)))
# define argof(complexf_input_p,i) (atan2(qof(complexf_input_p,i),iof(complexf_input_p,i)))
# define cmult(cfo, cfi1, cfi2) iof(cfo,0)=iof(cfi1,0)*iof(cfi2,0)-qof(cfi1,0)*qof(cfi2,0);qof(cfo,0)=iof(cfi1,0)*qof(cfi2,0)+iof(cfi2,0)*qof(cfi1,0)
//(ai+aq*j)*(bi+bq*j)=ai*bi-aq*bq+(aq*bi+ai*bq)*j
# define cmultadd(cfo, cfi1, cfi2) { iof(cfo,0)+=iof(cfi1,0)*iof(cfi2,0)-qof(cfi1,0)*qof(cfi2,0);qof(cfo,0)+=iof(cfi1,0)*qof(cfi2,0)+iof(cfi2,0)*qof(cfi1,0); }
# define csetnull(cf) { iof(cf,0)=0.0; qof(cf,0)=0.0; }
# define e_powj(cf,w) { iof(cf,0)=cos(w); qof(cf,0)=sin(w); }
# define ccopy(dst,src) { iof(dst,0)=iof(src,0); qof(dst,0)=qof(src,0); }
//apply to values
# define iofv(complexf_input) (*((float*)&complexf_input))
# define qofv(complexf_input) (*(((float*)&complexf_input)+1))
//they dropped M_PI in C99, so we define it:
# define PI ((float)3.14159265358979323846)
2015-11-30 03:05:28 +08:00
# define TIME_TAKEN(start,end) ((end.tv_sec-start.tv_sec)+(end.tv_nsec-start.tv_nsec) / 1e9)
2014-11-28 23:44:41 +08:00
//window
2016-03-20 23:41:37 +08:00
typedef enum window_s
2014-11-28 23:44:41 +08:00
{
WINDOW_BOXCAR , WINDOW_BLACKMAN , WINDOW_HAMMING
} window_t ;
# define WINDOW_DEFAULT WINDOW_HAMMING
//FFT
//Note: these reference to things in this file (e.g. complexf):
# include "fft_fftw.h"
# include "fft_rpi.h"
// =================================================================================
//filter design
void firdes_lowpass_f ( float * output , int length , float cutoff_rate , window_t window ) ;
void firdes_bandpass_c ( complexf * output , int length , float lowcut , float highcut , window_t window ) ;
float firdes_wkernel_blackman ( float input ) ;
float firdes_wkernel_hamming ( float input ) ;
float firdes_wkernel_boxcar ( float input ) ;
window_t firdes_get_window_from_string ( char * input ) ;
char * firdes_get_string_from_window ( window_t window ) ;
2014-12-14 06:46:41 +08:00
int firdes_filter_len ( float transition_bw ) ;
2014-11-28 23:44:41 +08:00
//demodulators
complexf fmdemod_quadri_cf ( complexf * input , float * output , int input_size , float * temp , complexf last_sample ) ;
complexf fmdemod_quadri_novect_cf ( complexf * input , float * output , int input_size , complexf last_sample ) ;
float fmdemod_atan_cf ( complexf * input , float * output , int input_size , float last_phase ) ;
void amdemod_cf ( complexf * input , float * output , int input_size ) ;
void amdemod_estimator_cf ( complexf * input , float * output , int input_size , float alpha , float beta ) ;
void limit_ff ( float * input , float * output , int input_size , float max_amplitude ) ;
//filters, decimators, resamplers, shift, etc.
2015-08-17 05:40:42 +08:00
float fir_one_pass_ff ( float * input , float * taps , int taps_length ) ;
2014-11-28 23:44:41 +08:00
int fir_decimate_cc ( complexf * input , complexf * output , int input_size , int decimation , float * taps , int taps_length ) ;
int deemphasis_nfm_ff ( float * input , float * output , int input_size , int sample_rate ) ;
float deemphasis_wfm_ff ( float * input , float * output , int input_size , float tau , int sample_rate , float last_output ) ;
float shift_math_cc ( complexf * input , complexf * output , int input_size , float rate , float starting_phase ) ;
typedef struct dcblock_preserve_s
{
float last_input ;
float last_output ;
} dcblock_preserve_t ;
dcblock_preserve_t dcblock_ff ( float * input , float * output , int input_size , float a , dcblock_preserve_t preserved ) ;
float fastdcblock_ff ( float * input , float * output , int input_size , float last_dc_level ) ;
typedef struct fastagc_ff_s
{
2016-03-20 23:41:37 +08:00
float * buffer_1 ;
2014-11-28 23:44:41 +08:00
float * buffer_2 ;
float * buffer_input ; //it is the actual input buffer to fill
float peak_1 ;
float peak_2 ;
int input_size ;
float reference ;
float last_gain ;
} fastagc_ff_t ;
void fastagc_ff ( fastagc_ff_t * input , float * output ) ;
typedef struct rational_resampler_ff_s
{
int input_processed ;
int output_size ;
int last_taps_delay ;
} rational_resampler_ff_t ;
rational_resampler_ff_t rational_resampler_ff ( float * input , float * output , int input_size , int interpolation , int decimation , float * taps , int taps_length , int last_taps_delay ) ;
void rational_resampler_get_lowpass_f ( float * output , int output_size , int interpolation , int decimation , window_t window ) ;
2016-03-26 17:44:28 +08:00
float * precalculate_window ( int size , window_t window ) ;
2014-11-28 23:44:41 +08:00
void apply_window_c ( complexf * input , complexf * output , int size , window_t window ) ;
2016-03-26 17:44:28 +08:00
void apply_precalculated_window_c ( complexf * input , complexf * output , int size , float * windowt ) ;
2014-11-28 23:44:41 +08:00
void apply_window_f ( float * input , float * output , int size , window_t window ) ;
void logpower_cf ( complexf * input , float * output , int size , float add_db ) ;
2016-03-26 00:00:20 +08:00
void accumulate_power_cf ( complexf * input , float * output , int size ) ;
void log_ff ( float * input , float * output , int size , float add_db ) ;
2014-11-28 23:44:41 +08:00
typedef struct fractional_decimator_ff_s
{
2017-02-18 22:49:04 +08:00
float where ;
2014-11-28 23:44:41 +08:00
int input_processed ;
int output_size ;
2017-02-18 22:49:04 +08:00
int num_poly_points ; //number of samples that the Lagrange interpolator will use
float * poly_precalc_denomiator ; //while we don't precalculate coefficients here as in a Farrow structure, because it is a fractional interpolator, but we rather precaculate part of the interpolator expression
//float* last_inputs_circbuf; //circular buffer to store the last (num_poly_points) number of input samples.
//int last_inputs_startsat; //where the circular buffer starts now
//int last_inputs_samplewhere;
float * coeffs_buf ;
float * filtered_buf ;
int xifirst ;
int xilast ;
float rate ;
float * taps ;
int taps_length ;
2014-11-28 23:44:41 +08:00
} fractional_decimator_ff_t ;
2017-02-18 22:49:04 +08:00
fractional_decimator_ff_t fractional_decimator_ff_init ( float rate , int num_poly_points , float * taps , int taps_length ) ;
void fractional_decimator_ff ( float * input , float * output , int input_size , fractional_decimator_ff_t * d ) ;
typedef struct old_fractional_decimator_ff_s
{
float remain ;
int input_processed ;
int output_size ;
} old_fractional_decimator_ff_t ;
old_fractional_decimator_ff_t old_fractional_decimator_ff ( float * input , float * output , int input_size , float rate , float * taps , int taps_length , old_fractional_decimator_ff_t d ) ;
2014-11-28 23:44:41 +08:00
2015-08-17 05:40:42 +08:00
typedef struct shift_table_data_s
{
float * table ;
2016-03-20 23:41:37 +08:00
int table_size ;
2015-08-17 05:40:42 +08:00
} shift_table_data_t ;
void shift_table_deinit ( shift_table_data_t table_data ) ;
shift_table_data_t shift_table_init ( int table_size ) ;
float shift_table_cc ( complexf * input , complexf * output , int input_size , float rate , shift_table_data_t table_data , float starting_phase ) ;
2015-11-29 20:54:09 +08:00
typedef struct shift_addfast_data_s
{
float dsin [ 4 ] ;
float dcos [ 4 ] ;
2015-11-30 03:05:28 +08:00
float phase_increment ;
2015-11-29 20:54:09 +08:00
} shift_addfast_data_t ;
shift_addfast_data_t shift_addfast_init ( float rate ) ;
2015-11-30 06:46:06 +08:00
shift_addfast_data_t shift_addfast_init ( float rate ) ;
2015-11-29 20:54:09 +08:00
float shift_addfast_cc ( complexf * input , complexf * output , int input_size , shift_addfast_data_t * d , float starting_phase ) ;
2015-11-30 06:46:06 +08:00
typedef struct shift_unroll_data_s
{
float * dsin ;
float * dcos ;
float phase_increment ;
int size ;
} shift_unroll_data_t ;
float shift_unroll_cc ( complexf * input , complexf * output , int input_size , shift_unroll_data_t * d , float starting_phase ) ;
shift_unroll_data_t shift_unroll_init ( float rate , int size ) ;
2015-08-17 05:40:42 +08:00
2014-11-28 23:44:41 +08:00
int log2n ( int x ) ;
int next_pow2 ( int x ) ;
void apply_fir_fft_cc ( FFT_PLAN_T * plan , FFT_PLAN_T * plan_inverse , complexf * taps_fft , complexf * last_overlap , int overlap_size ) ;
void gain_ff ( float * input , float * output , int input_size , float gain ) ;
2016-03-20 23:41:37 +08:00
float get_power_f ( float * input , int input_size , int decimation ) ;
float get_power_c ( complexf * input , int input_size , int decimation ) ;
2014-11-28 23:44:41 +08:00
2015-10-31 23:22:33 +08:00
void add_dcoffset_cc ( complexf * input , complexf * output , int input_size ) ;
2015-10-31 23:42:17 +08:00
float fmmod_fc ( float * input , complexf * output , int input_size , float last_phase ) ;
2015-11-01 19:30:03 +08:00
void fixed_amplitude_cc ( complexf * input , complexf * output , int input_size , float amp ) ;
2015-10-31 23:22:33 +08:00
2014-11-28 23:44:41 +08:00
void convert_u8_f ( unsigned char * input , float * output , int input_size ) ;
void convert_f_u8 ( float * input , unsigned char * output , int input_size ) ;
2015-11-23 03:53:10 +08:00
void convert_s8_f ( signed char * input , float * output , int input_size ) ;
void convert_f_s8 ( float * input , signed char * output , int input_size ) ;
2016-02-14 18:19:36 +08:00
void convert_f_s16 ( float * input , short * output , int input_size ) ;
void convert_s16_f ( short * input , float * output , int input_size ) ;
2014-11-28 23:44:41 +08:00
void convert_f_i16 ( float * input , short * output , int input_size ) ;
void convert_i16_f ( short * input , float * output , int input_size ) ;
2016-06-21 06:14:03 +08:00
void convert_f_s24 ( float * input , unsigned char * output , int input_size , int bigendian ) ;
void convert_s24_f ( unsigned char * input , float * output , int input_size , int bigendian ) ;
2014-11-28 23:44:41 +08:00
2015-08-17 05:40:42 +08:00
int is_nan ( float f ) ;