adding native lime, soapy, decimation filtering and neon optimizations

This commit is contained in:
yagoda 2017-05-03 16:48:40 +01:00
parent 783d26b40a
commit ae94416395
25 changed files with 2134 additions and 19 deletions

View File

@ -0,0 +1,28 @@
if(NOT LIMESDR_FOUND)
pkg_check_modules (LIMESDR_PKG LimeSuite)
find_path(LIMESDR_INCLUDE_DIRS
NAMES LimeSuite.h
PATHS ${LIMESDR_PKG_INCLUDE_DIRS}
/usr/include/lime
/usr/local/include/lime
)
find_library(LIMESDR_LIBRARIES
NAMES LimeSuite
PATHS ${LIMESDR_PKG_LIBRARY_DIRS}
/usr/lib
/usr/local/lib
)
if(LIMESDR_INCLUDE_DIRS AND LIMESDR_LIBRARIES)
set(LIMESDR_FOUND TRUE CACHE INTERNAL "libLimeSuite found")
message(STATUS "Found libLimeSuite: ${LIMESDR_INCLUDE_DIRS}, ${LIMESDR_LIBRARIES}")
else(LIMESDR_INCLUDE_DIRS AND LIMESDR_LIBRARIES)
set(LIMESDR_FOUND FALSE CACHE INTERNAL "libLimeSuite found")
message(STATUS "libLimeSuite not found.")
endif(LIMESDR_INCLUDE_DIRS AND LIMESDR_LIBRARIES)
mark_as_advanced(LIMESDR_LIBRARIES LIMESDR_INCLUDE_DIRS)
endif(NOT LIMESDR_FOUND)

View File

@ -0,0 +1,31 @@
message(STATUS "FINDING SOAPY.")
if(NOT SOAPYSDR_FOUND)
pkg_check_modules (SOAPYSDR_PKG SoapySDR)
find_path(SOAPYSDR_INCLUDE_DIRS
NAMES Device.h
PATHS ${SOAPYSDR_PKG_INCLUDE_DIRS}
/usr/include/SoapySDR
/usr/include/local/SoapySDR
)
find_library(SOAPYSDR_LIBRARIES
NAMES SoapySDR
PATHS ${LIMESDR_PKG_LIBRARY_DIRS}
/usr/lib
/usr/local/lib
)
if(SOAPYSDR_INCLUDE_DIRS AND SOAPYSDR_LIBRARIES)
set(SOAPYSDR_FOUND TRUE CACHE INTERNAL "libSOAPYSDR found")
message(STATUS "Found libSOAPYSDR: ${SOAPYSDR_INCLUDE_DIRS}, ${SOAPYSDR_LIBRARIES}")
else(SOAPYSDR_INCLUDE_DIRS AND SOAPYSDR_LIBRARIES)
set(SOAPYSDR_FOUND FALSE CACHE INTERNAL "libSOAPYSDR found")
message(STATUS "libSOAPYSDR not found.")
endif(SOAPYSDR_INCLUDE_DIRS AND SOAPYSDR_LIBRARIES)
mark_as_advanced(SOAPYSDR_LIBRARIES SOAPYSDR_INCLUDE_DIRS)
endif(NOT SOAPYSDR_FOUND)

View File

@ -69,12 +69,27 @@ if(NOT DisableBladeRF)
endif(BLADERF_FOUND)
endif(NOT DisableBladeRF)
if(BLADERF_FOUND OR UHD_FOUND)
find_package(SoapySDR)
if(SOAPYSDR_FOUND)
include_directories(${SOAPYSDR_INCLUDE_DIRS})
link_directories(${SOAPYSDR_LIBRARY_DIRS})
endif(SOAPYSDR_FOUND)
find_package(LimeSDR)
if(LIMESDR_FOUND)
include_directories(${LIMESDR_INCLUDE_DIRS})
link_directories(${LIMESDR_LIBRARY_DIRS})
endif(LIMESDR_FOUND)
if(BLADERF_FOUND OR UHD_FOUND OR SOAPYSDR_FOUND OR LIMESDR_FOUND)
set(RF_FOUND TRUE CACHE INTERNAL "RF frontend found")
else(BLADERF_FOUND OR UHD_FOUND)
else(BLADERF_FOUND OR UHD_FOUND OR SOAPYSDR_FOUND OR LIMESDR_FOUND)
set(RF_FOUND FALSE CACHE INTERNAL "RF frontend found")
add_definitions(-DDISABLE_RF)
endif(BLADERF_FOUND OR UHD_FOUND)
endif(BLADERF_FOUND OR UHD_FOUND OR SOAPYSDR_FOUND OR LIMESDR_FOUND)
include(CheckFunctionExistsMath)
if(${DISABLE_VOLK})

View File

@ -95,7 +95,8 @@ typedef struct {
int net_port;
char *net_address;
int net_port_signal;
char *net_address_signal;
char *net_address_signal;
int decimate;
}prog_args_t;
void args_default(prog_args_t *args) {
@ -124,6 +125,7 @@ void args_default(prog_args_t *args) {
args->net_address = "127.0.0.1";
args->net_port_signal = -1;
args->net_address_signal = "127.0.0.1";
args->decimate = 0;
}
void usage(prog_args_t *args, char *prog) {
@ -166,7 +168,7 @@ void usage(prog_args_t *args, char *prog) {
void parse_args(prog_args_t *args, int argc, char **argv) {
int opt;
args_default(args);
while ((opt = getopt(argc, argv, "aAoglipPcOCtdDnvrfuUsS")) != -1) {
while ((opt = getopt(argc, argv, "aAoglipPcOCtdDnvrfuUsSZ")) != -1) {
switch (opt) {
case 'i':
args->input_file_name = argv[optind];
@ -234,6 +236,9 @@ void parse_args(prog_args_t *args, int argc, char **argv) {
case 'v':
srslte_verbose++;
break;
case 'Z':
args->decimate = atoi(argv[optind]);
break;
default:
usage(args, argv[0]);
exit(-1);
@ -412,6 +417,8 @@ int main(int argc, char **argv) {
} else {
#ifndef DISABLE_RF
if(!prog_args.decimate)
ue_sync.decimate = prog_args.decimate;
if (srslte_ue_sync_init_multi(&ue_sync, cell, srslte_rf_recv_wrapper, prog_args.rf_nof_rx_ant, (void*) &rf)) {
fprintf(stderr, "Error initiating ue_sync\n");
exit(-1);

View File

@ -100,6 +100,12 @@ SRSLTE_API int srslte_viterbi_init_sse(srslte_viterbi_t *q,
uint32_t max_frame_length,
bool tail_bitting);
SRSLTE_API int srslte_viterbi_init_neon(srslte_viterbi_t *q,
srslte_viterbi_type_t type,
int poly[3],
uint32_t max_frame_length,
bool tail_bitting);
#endif

View File

@ -51,6 +51,7 @@
#include "srslte/config.h"
#include "srslte/common/phy_common.h"
#include "srslte/utils/convolution.h"
#include "srslte/utils/filter.h"
#define CONVOLUTION_FFT
@ -74,8 +75,10 @@ typedef struct SRSLTE_API {
#ifdef CONVOLUTION_FFT
srslte_conv_fft_cc_t conv_fft;
#endif
srslte_filt_cc_t filter;
#endif
int decimate;
uint32_t frame_size;
uint32_t N_id_2;
uint32_t fft_size;

View File

@ -65,7 +65,7 @@ typedef struct SRSLTE_API {
srslte_sss_synch_t sss;
srslte_cp_synch_t cp_synch;
cf_t *cfo_i_corr[2];
int decimate;
float threshold;
float peak_value;
uint32_t N_id_2;

View File

@ -73,7 +73,7 @@ typedef struct SRSLTE_API {
srslte_agc_t agc;
bool do_agc;
uint32_t agc_period;
int decimate;
void *stream;
void *stream_single;
int (*recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*);

View File

@ -49,6 +49,9 @@ typedef struct SRSLTE_API {
srslte_dft_plan_t input_plan;
srslte_dft_plan_t filter_plan;
srslte_dft_plan_t output_plan;
cf_t *pss_signal_time_fft[3]; // One sequence for each N_id_2
cf_t *pss_signal_time[3];
}srslte_conv_fft_cc_t;
SRSLTE_API int srslte_conv_fft_cc_init(srslte_conv_fft_cc_t *q,
@ -62,6 +65,11 @@ SRSLTE_API uint32_t srslte_conv_fft_cc_run(srslte_conv_fft_cc_t *q,
cf_t *filter,
cf_t *output);
SRSLTE_API uint32_t srslte_conv_fft_cc_run_opt(srslte_conv_fft_cc_t *q,
cf_t *input,
int N_id_2,
cf_t *output);
SRSLTE_API uint32_t srslte_conv_cc(cf_t *input,
cf_t *filter,
cf_t *output,

View File

@ -0,0 +1,60 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
/******************************************************************************
* File: debug.h
*
* Description: Debug output utilities.
*
* Reference:
*****************************************************************************/
#ifndef FILTER_H
#define FILTER_H
#include <stdlib.h>
#include <stdio.h>
#include "srslte/config.h"
#include <stdbool.h>
#include "srslte/utils/vector.h"
typedef struct SRSLTE_API{
cf_t *filter_input;
cf_t *downsampled_input;
cf_t *filter_output;
bool is_decimator;
int factor;
int num_taps;
float *taps;
}srslte_filt_cc_t;
void srslte_filt_decim_cc_init(srslte_filt_cc_t *q, int factor, int order);
void srslte_filt_decim_cc_free(srslte_filt_cc_t *q);
void srslte_filt_decim_cc_execute(srslte_filt_cc_t *q, cf_t *input, cf_t *downsampled_input, cf_t *output, int size);
void srslte_downsample_cc(cf_t *input, cf_t *output, int M, int size) ;
#endif // FILTER_H

View File

@ -95,6 +95,15 @@ if(RF_FOUND)
if(BLADERF_FOUND)
target_link_libraries(srslte ${BLADERF_LIBRARIES})
endif(BLADERF_FOUND)
if(LIMESDR_FOUND)
target_link_libraries(srslte ${LIMESDR_LIBRARIES})
endif(LIMESDR_FOUND)
if(SOAPYSDR_FOUND)
target_link_libraries(srslte ${SOAPYSDR_LIBRARIES})
endif(SOAPYSDR_FOUND)
endif(RF_FOUND)
if(VOLK_FOUND)

View File

@ -119,6 +119,51 @@ void free37_sse(void *o) {
#endif
#ifdef HAVE_NEON
int decode37_neon(void *o, uint8_t *symbols, uint8_t *data, uint32_t frame_length) {
srslte_viterbi_t *q = o;
uint32_t best_state;
if (frame_length > q->framebits) {
fprintf(stderr, "Initialized decoder for max frame length %d bits\n",
q->framebits);
return -1;
}
/* Initialize Viterbi decoder */
init_viterbi37_neon(q->ptr, q->tail_biting?-1:0);
/* Decode block */
if (q->tail_biting) {
for (int i=0;i<TB_ITER;i++) {
memcpy(&q->tmp[i*3*frame_length], symbols, 3*frame_length*sizeof(uint8_t));
}
update_viterbi37_blk_neon(q->ptr, q->tmp, TB_ITER*frame_length, &best_state);
chainback_viterbi37_neon(q->ptr, q->tmp, TB_ITER*frame_length, best_state);
memcpy(data, &q->tmp[((int) (TB_ITER/2))*frame_length], frame_length*sizeof(uint8_t));
} else {
update_viterbi37_blk_neon(q->ptr, symbols, frame_length+q->K-1, NULL);
chainback_viterbi37_neon(q->ptr, data, frame_length, 0);
}
return q->framebits;
}
void free37_neon(void *o) {
srslte_viterbi_t *q = o;
if (q->symbols_uc) {
free(q->symbols_uc);
}
if (q->tmp) {
free(q->tmp);
}
delete_viterbi37_neon(q->ptr);
}
#endif
void free37(void *o) {
srslte_viterbi_t *q = o;
if (q->symbols_uc) {
@ -203,6 +248,44 @@ int init37_sse(srslte_viterbi_t *q, int poly[3], uint32_t framebits, bool tail_b
}
#endif
#ifdef HAVE_NEON
int init37_neon(srslte_viterbi_t *q, int poly[3], uint32_t framebits, bool tail_biting) {
q->K = 7;
q->R = 3;
q->framebits = framebits;
q->gain_quant_s = 4;
q->gain_quant = DEFAULT_GAIN;
q->tail_biting = tail_biting;
q->decode = decode37_neon;
q->free = free37_neon;
q->decode_f = NULL;
printf("USING NEON VITERBI***************\n");
q->symbols_uc = srslte_vec_malloc(3 * (q->framebits + q->K - 1) * sizeof(uint8_t));
if (!q->symbols_uc) {
perror("malloc");
return -1;
}
if (q->tail_biting) {
q->tmp = srslte_vec_malloc(TB_ITER*3*(q->framebits + q->K - 1) * sizeof(uint8_t));
if (!q->tmp) {
perror("malloc");
free37(q);
return -1;
}
} else {
q->tmp = NULL;
}
if ((q->ptr = create_viterbi37_neon(poly, TB_ITER*framebits)) == NULL) {
fprintf(stderr, "create_viterbi37 failed\n");
free37(q);
return -1;
} else {
return 0;
}
}
#endif
void srslte_viterbi_set_gain_quant(srslte_viterbi_t *q, float gain_quant) {
q->gain_quant = gain_quant;
}
@ -218,7 +301,11 @@ int srslte_viterbi_init(srslte_viterbi_t *q, srslte_viterbi_type_t type, int pol
#ifdef LV_HAVE_SSE
return init37_sse(q, poly, max_frame_length, tail_bitting);
#else
#ifdef HAVE_NEON
return init37_neon(q, poly, max_frame_length, tail_bitting);
#else
return init37(q, poly, max_frame_length, tail_bitting);
#endif
#endif
default:
fprintf(stderr, "Decoder not implemented\n");

View File

@ -65,3 +65,26 @@ int update_viterbi37_blk_sse(void *p,
uint8_t *syms,
uint32_t nbits,
uint32_t *best_state);
void *create_viterbi37_neon(int polys[3],
uint32_t len);
int init_viterbi37_neon(void *p,
int starting_state);
void reset_blk_neon(void *p, int nbits);
int chainback_viterbi37_neon(void *p,
uint8_t *data,
uint32_t nbits,
uint32_t endstate);
void delete_viterbi37_neon(void *p);
int update_viterbi37_blk_neon(void *p,
uint8_t *syms,
uint32_t nbits,
uint32_t *best_state);

View File

@ -0,0 +1,354 @@
/* Adapted Phil Karn's r=1/3 k=9 viterbi decoder to r=1/3 k=7
*
* K=15 r=1/6 Viterbi decoder for ARM NEON
* Copyright Mar 2004, Phil Karn, KA9Q
* May be used under the terms of the GNU Lesser General Public License (LGPL)
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <memory.h>
#include <limits.h>
#include "parity.h"
//#define DEBUG
//#define HAVE_NEON
#ifdef HAVE_NEON
#include <arm_neon.h>
typedef union {
unsigned char c[64];
uint8x16_t v[4];
} metric_t;
typedef union {
unsigned long w[2];
unsigned char c[8];
unsigned short s[4];
uint8x8_t v[1];
} decision_t;
union branchtab27{
unsigned char c[32];
uint8x16_t v[2];
} Branchtab37_neon[3];
int8_t __attribute__((aligned(16))) xr[8];
uint8x8_t mask_and;
int8x8_t mask_shift;
int firstGo;
/* State info for instance of Viterbi decoder */
struct v37 {
metric_t metrics1; /* path metric buffer 1 */
metric_t metrics2; /* path metric buffer 2 */
decision_t *dp; /* Pointer to current decision */
metric_t *old_metrics,*new_metrics; /* Pointers to path metrics, swapped on every bit */
decision_t *decisions; /* Beginning of decisions for block */
uint32_t len;
};
void set_viterbi37_polynomial_neon(int polys[3]) {
int state;
for(state=0;state < 32;state++){
Branchtab37_neon[0].c[state] = (polys[0] < 0) ^ parity((2*state) & polys[0]) ? 255:0;
Branchtab37_neon[1].c[state] = (polys[1] < 0) ^ parity((2*state) & polys[1]) ? 255:0;
Branchtab37_neon[2].c[state] = (polys[2] < 0) ^ parity((2*state) & polys[2]) ? 255:0;
}
}
void clear_v37_neon(struct v37 *vp) {
bzero(vp->decisions, sizeof(decision_t)*vp->len);
vp->dp = NULL;
bzero(&vp->metrics1, sizeof(metric_t));
bzero(&vp->metrics2, sizeof(metric_t));
vp->old_metrics = NULL;
vp->new_metrics = NULL;
}
/* Initialize Viterbi decoder for start of new frame */
int init_viterbi37_neon(void *p, int starting_state) {
struct v37 *vp = p;
uint32_t i;
firstGo = 1;
for(i=0;i<64;i++)
vp->metrics1.c[i] = 63;
clear_v37_neon(vp);
for(int i = 0; i <8;i++)
xr[i] = i-7;
mask_and = vdup_n_u8(0x80);
mask_shift = vld1_s8(xr);
vp->old_metrics = &vp->metrics1;
vp->new_metrics = &vp->metrics2;
vp->dp = vp->decisions;
if (starting_state != -1) {
vp->old_metrics->c[starting_state & 63] = 0; /* Bias known start state */
}
return 0;
}
/* Create a new instance of a Viterbi decoder */
void *create_viterbi37_neon(int polys[3], uint32_t len) {
void *p;
struct v37 *vp;
set_viterbi37_polynomial_neon(polys);
/* Ordinary malloc() only returns 8-byte alignment, we need 16 */
if(posix_memalign(&p, sizeof(uint8x16_t),sizeof(struct v37)))
return NULL;
vp = (struct v37 *)p;
if(posix_memalign(&p, sizeof(uint8x16_t),(len+6)*sizeof(decision_t))) {
free(vp);
return NULL;
}
vp->decisions = (decision_t *)p;
vp->len = len+6;
return vp;
}
/* Viterbi chainback */
int chainback_viterbi37_neon(
void *p,
uint8_t *data, /* Decoded output data */
uint32_t nbits, /* Number of data bits */
uint32_t endstate) { /* Terminal encoder state */
struct v37 *vp = p;
if (p == NULL)
return -1;
decision_t *d = (decision_t *)vp->decisions;
/* Make room beyond the end of the encoder register so we can
* accumulate a full byte of decoded data
*/
endstate %= 64;
endstate <<= 2;
/* The store into data[] only needs to be done every 8 bits.
* But this avoids a conditional branch, and the writes will
* combine in the cache anyway
*/
d += 6; /* Look past tail */
while(nbits--) {
int k;
k = (d[nbits].c[(endstate>>2)/8] >> ((endstate>>2)%8)) & 1;
endstate = (endstate >> 1) | (k << 7);
data[nbits] = k;
//printf("nbits=%d, endstate=%3d, k=%d, w[0]=%d, w[1]=%d, c=%d\n", nbits, endstate, k, d[nbits].s[1]&1, d[nbits].s[2]&1, d[nbits].c[(endstate>>2)/8]&1);
}
return 0;
}
/* Delete instance of a Viterbi decoder */
void delete_viterbi37_neon(void *p){
struct v37 *vp = p;
if(vp != NULL){
free(vp->decisions);
free(vp);
}
}
void print_uint8x16_t(char *s, uint8x16_t val) {
printf("%s: ", s);
uint8_t *x = (uint8_t*) &val;
for (int i=0;i<16;i++) {
printf("%3d, ", x[i]);
}
printf("\n");
}
int movemask_neon(uint8x16_t movemask_low_in)
{
uint8x8_t lo = vget_low_u8(movemask_low_in);
uint8x8_t hi = vget_high_u8(movemask_low_in);
lo = vand_u8(lo, mask_and);
lo = vshl_u8(lo, mask_shift);
hi = vand_u8(hi, mask_and);
hi = vshl_u8(hi, mask_shift);
lo = vpadd_u8(lo, lo);
lo = vpadd_u8(lo, lo);
lo = vpadd_u8(lo, lo);
hi = vpadd_u8(hi, hi);
hi = vpadd_u8(hi, hi);
hi = vpadd_u8(hi, hi);
return ((hi[0] << 8) | (lo[0] & 0xFF));
}
void update_viterbi37_blk_neon(void *p,unsigned char *syms,int nbits, uint32_t *best_state) {
struct v37 *vp = p;
decision_t *d;
uint8_t thirtyone;
thirtyone = 31;
if(p == NULL)
return;
#ifdef DEBUG
printf("[");
#endif
d = (decision_t *) vp->dp;
for (int s=0;s<nbits;s++) {
memset(d+s,0,sizeof(decision_t));
}
while(nbits--) {
uint8x16_t sym0v,sym1v,sym2v;
void *tmp;
int i;
// printf("nbits=%d, syms=%d,%d,%d\n", nbits, syms[0], syms[1], syms[2]);fflush(stdout);
/* Splat the 0th symbol across sym0v, the 1st symbol across sym1v, etc */
sym0v = vld1q_dup_u8(syms); // passing a char as opposed to a pointer to a char
sym1v = vld1q_dup_u8(syms+1);
sym2v = vld1q_dup_u8(syms+2);
syms += 3;
for(i=0;i<2;i++){
uint8x16_t decision0, decision1, metric, m_metric, m0, m1, m2, m3, survivor0, survivor1;
/* Form branch metrics */
m0 = vrhaddq_u8(veorq_u8(Branchtab37_neon[0].v[i],sym0v),veorq_u8(Branchtab37_neon[1].v[i],sym1v));
metric = vrhaddq_u8(veorq_u8(Branchtab37_neon[2].v[i],sym2v),m0);
metric = vshrq_n_u8(metric,3);
m_metric = vsubq_u8(vld1q_dup_u8(&thirtyone),metric);
/* Add branch metrics to path metrics */
m0 = vaddq_u8(vp->old_metrics->v[i],metric);
m3 = vaddq_u8(vp->old_metrics->v[2+i],metric);
m1 = vaddq_u8(vp->old_metrics->v[2+i],m_metric);
m2 = vaddq_u8(vp->old_metrics->v[i],m_metric);
/* Compare and select, using modulo arithmetic */
decision0 = (uint8x16_t)vcgtq_s8(vsubq_s8((int8x16_t)m0,(int8x16_t)m1),vdupq_n_s8(0));
decision1 = (uint8x16_t)vcgtq_s8(vsubq_s8((int8x16_t)m2,(int8x16_t)m3),vdupq_n_s8(0));
survivor0 = vorrq_u8(vandq_u8(decision0,m1),vandq_u8(vmvnq_u8(decision0),m0));
survivor1 = vorrq_u8 (vandq_u8(decision1,m3),vandq_u8(vmvnq_u8(decision1),m2) );
////// equal to _mm_unpacklo_epi8 //////////
uint8x8_t a1 = vget_low_u8(decision0);
uint8x8_t b1 = vget_low_u8(decision1);
uint8x8x2_t result = vzip_u8(a1, b1);
uint8x16_t movemask_low_in = vcombine_u8(result.val[0], result.val[1]);
/////////////////////////////////////////
////////equal to _mm_movemask_epi8 ////////
d->s[2*i] = movemask_neon(movemask_low_in);
///////equal to _mm_unpackhi_epi8////////////
a1 = vget_high_u8(decision0);
b1 = vget_high_u8(decision1);
result = vzip_u8(a1, b1);
uint8x16_t movemask_hi_in = vcombine_u8(result.val[0], result.val[1]);
////////equal to _mm_movemask//////////////
d->s[2*i+1] = movemask_neon(movemask_hi_in);
a1 = vget_low_u8(survivor0);
b1 = vget_low_u8(survivor1);
result = vzip_u8(a1, b1);
vp->new_metrics->v[2*i] = vcombine_u8(result.val[0], result.val[1]);
a1 = vget_high_u8(survivor0);
b1 = vget_high_u8(survivor1);
result = vzip_u8(a1, b1);
vp->new_metrics->v[2*i+1] = vcombine_u8(result.val[0], result.val[1]);
}
// See if we need to normalize
if (vp->new_metrics->c[0] > 100) {
int i;
uint8_t adjust;
uint8x16_t adjustv;
union { uint8x16_t v; signed short w[8]; } t;
adjustv = vp->new_metrics->v[0];
for(i=1;i<4;i++)
{
adjustv = vminq_u8(vp->new_metrics->v[i],adjustv);
}
adjustv = vminq_u8(adjustv,vextq_u8(adjustv, vdupq_n_u8(0), (8)));
adjustv = vminq_u8(adjustv,vextq_u8(adjustv, vdupq_n_u8(0), (4)));
adjustv = vminq_u8(adjustv,vextq_u8(adjustv, vdupq_n_u8(0), (2)));
t.v = adjustv;
adjust = t.w[0];
adjustv = vld1q_dup_u8(&adjust);
/* We cannot use a saturated subtract, because we often have to adjust by more than SHRT_MAX
* This is okay since it can't overflow anyway
*/
for(i=0;i<4;i++)
{
vp->new_metrics->v[i] = vsubq_u8(vp->new_metrics->v[i],adjustv);
}
}
d++;
/* Swap pointers to old and new metrics */
tmp = vp->old_metrics;
vp->old_metrics = vp->new_metrics;
vp->new_metrics = tmp;
//firstGo = 0;
}
if (best_state) {
uint32_t i, bst=0;
uint8_t minmetric=UINT8_MAX;
for (i=0;i<64;i++) {
if (vp->old_metrics->c[i] <= minmetric) {
bst = i;
minmetric = vp->old_metrics->c[i];
}
}
*best_state = bst;
}
#ifdef DEBUG
printf("];\n===========================================\n");
#endif
vp->dp = d;
}
#endif

View File

@ -33,6 +33,17 @@ if(RF_FOUND)
list(APPEND SOURCES_RF rf_blade_imp.c)
endif (BLADERF_FOUND)
if (LIMESDR_FOUND)
add_definitions(-DENABLE_LIMESDR)
list(APPEND SOURCES_RF rf_limesdr_imp.c)
endif (LIMESDR_FOUND)
if (SOAPYSDR_FOUND)
add_definitions(-DENABLE_SOAPYSDR)
list(APPEND SOURCES_RF rf_soapy_imp.c)
endif (SOAPYSDR_FOUND)
add_library(srslte_rf SHARED ${SOURCES_RF})
@ -44,6 +55,15 @@ if(RF_FOUND)
target_link_libraries(srslte_rf ${BLADERF_LIBRARIES})
endif (BLADERF_FOUND)
if (LIMESDR_FOUND)
target_link_libraries(srslte_rf ${LIMESDR_LIBRARIES})
endif (LIMESDR_FOUND)
if (SOAPYSDR_FOUND)
target_link_libraries(srslte_rf ${SOAPYSDR_LIBRARIES})
endif (SOAPYSDR_FOUND)
INSTALL(TARGETS srslte_rf DESTINATION ${LIBRARY_DIR})
SRSLTE_SET_PIC(srslte_rf)
endif(RF_FOUND)

View File

@ -140,6 +140,83 @@ static rf_dev_t dev_blade = {
};
#endif
/* Define implementation for LimeSDR */
#ifdef ENABLE_LIMESDR
#include "rf_limesdr_imp.h"
static rf_dev_t dev_limesdr = {
"limesdr",
rf_limesdr_devname,
rf_limesdr_rx_wait_lo_locked,
rf_limesdr_start_rx_stream,
rf_limesdr_stop_rx_stream,
rf_limesdr_flush_buffer,
rf_limesdr_has_rssi,
rf_limesdr_get_rssi,
rf_limesdr_suppress_stdout,
rf_limesdr_register_error_handler,
rf_limesdr_open,
rf_limesdr_open_multi,
rf_limesdr_close,
rf_limesdr_set_master_clock_rate,
rf_limesdr_is_master_clock_dynamic,
rf_limesdr_set_rx_srate,
rf_limesdr_set_rx_gain,
rf_limesdr_set_tx_gain,
rf_limesdr_get_rx_gain,
rf_limesdr_get_tx_gain,
rf_limesdr_set_rx_freq,
rf_limesdr_set_tx_srate,
rf_limesdr_set_tx_freq,
rf_limesdr_get_time,
rf_limesdr_recv_with_time,
rf_limesdr_recv_with_time_multi,
rf_limesdr_send_timed,
rf_limesdr_set_tx_cal,
rf_limesdr_set_rx_cal
};
#endif
#ifdef ENABLE_SOAPYSDR
#include "rf_soapy_imp.h"
static rf_dev_t dev_soapy = {
"soapy",
rf_soapy_devname,
rf_soapy_rx_wait_lo_locked,
rf_soapy_start_rx_stream,
rf_soapy_stop_rx_stream,
rf_soapy_flush_buffer,
rf_soapy_has_rssi,
rf_soapy_get_rssi,
rf_soapy_suppress_stdout,
rf_soapy_register_error_handler,
rf_soapy_open,
rf_soapy_open_multi,
rf_soapy_close,
rf_soapy_set_master_clock_rate,
rf_soapy_is_master_clock_dynamic,
rf_soapy_set_rx_srate,
rf_soapy_set_rx_gain,
rf_soapy_set_tx_gain,
rf_soapy_get_rx_gain,
rf_soapy_get_tx_gain,
rf_soapy_set_rx_freq,
rf_soapy_set_tx_srate,
rf_soapy_set_tx_freq,
rf_soapy_get_time,
rf_soapy_recv_with_time,
rf_soapy_recv_with_time_multi,
rf_soapy_send_timed,
rf_soapy_set_tx_cal,
rf_soapy_set_rx_cal
};
#endif
//#define ENABLE_DUMMY_DEV
#ifdef ENABLE_DUMMY_DEV
@ -183,12 +260,19 @@ static rf_dev_t dev_dummy = {
#endif
static rf_dev_t *available_devices[] = {
#ifdef ENABLE_UHD
&dev_uhd,
#endif
#ifdef ENABLE_SOAPYSDR
&dev_soapy,
#endif
#ifdef ENABLE_BLADERF
&dev_blade,
#endif
#ifdef ENABLE_LIMESDR
&dev_limesdr,
#endif
#ifdef ENABLE_DUMMY_DEV
&dev_dummy,
#endif

View File

@ -0,0 +1,475 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <sys/time.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include "srslte/srslte.h"
#include "rf_limesdr_imp.h"
#include "srslte/rf/rf.h"
#include "lime/LimeSuite.h"
typedef struct {
char *devname;
lms_dev_info_t *dev_info;
lms_device_t *device;
lms_info_str_t list[8];
lms_stream_t rx_stream;
lms_stream_t tx_stream;
int sampling_rate;
bool rx_is_streaming;
bool tx_is_streaming;
int channel;
int buffer_size;
int num_buffers;
lms_stream_meta_t tx_metadata; //Use metadata for additional control over sample receive function behaviour
lms_stream_meta_t rx_metadata; //Use metadata for additional control over sample receive function behaviour
lms_range_t rx_range;
lms_range_t tx_range;
} rf_limesdr_handler_t;
int lime_error(void *h)
{
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
//print last error message
fprintf(stderr, "Error: %s\n", LMS_GetLastErrorMessage());
if(handler->device != NULL)
LMS_Close(handler->device);
return SRSLTE_ERROR;
}
void rf_limesdr_get_freq_range(void *h)
{
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
LMS_GetLOFrequencyRange(handler->device, LMS_CH_RX, &(handler->rx_range));
LMS_GetLOFrequencyRange(handler->device, LMS_CH_TX, &(handler->tx_range));
}
void rf_limesdr_suppress_handler(const char *x)
{
// not supported
}
void rf_limesdr_msg_handler(const char *msg)
{
// not supported
}
void rf_limesdr_suppress_stdout(void *h)
{
// not supported
}
void rf_limesdr_register_error_handler(void *notused, srslte_rf_error_handler_t new_handler)
{
// not supported
}
static bool isLocked(rf_limesdr_handler_t *handler, char *sensor_name, void *value_h)
{
// not supported
return true;
}
char* rf_limesdr_devname(void* h)
{
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
handler->dev_info = LMS_GetDeviceInfo(handler);
return handler->dev_info->deviceName;
}
bool rf_limesdr_rx_wait_lo_locked(void *h)
{
// not supported
return true;
}
void rf_limesdr_set_tx_cal(void *h, srslte_rf_cal_t *cal)
{
// not supported
}
void rf_limesdr_set_rx_cal(void *h, srslte_rf_cal_t *cal)
{
// not supported
}
int rf_limesdr_start_rx_stream(void *h)
{
printf("Starting rx stream\n");
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
if(LMS_StartStream(&(handler->rx_stream)) != 0){
return lime_error(h);
}
return 0;
}
int rf_limesdr_start_tx_stream(void *h)
{
printf("Starting tx stream\n");
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
if(LMS_StartStream(&(handler->tx_stream)) != 0){
return lime_error(h);
}
return 0;
}
int rf_limesdr_stop_rx_stream(void *h)
{
printf("Stopping rx stream\n");
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
//stream is stopped but can be started again with LMS_StartStream()
if(LMS_StopStream(&(handler->rx_stream)) != 0){
return lime_error(h);
}
return 0;
}
int rf_limesdr_stop_tx_stream(void *h)
{
printf("Stopping tx stream\n");
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
//stream is stopped but can be started again with LMS_StartStream()
if(LMS_StopStream(&(handler->tx_stream)) != 0){
return lime_error(h);
}
return 0;
}
void rf_limesdr_flush_buffer(void *h)
{
int n;
cf_t tmp1[1024];
cf_t tmp2[1024];
void *data[2] = {tmp1, tmp2};
do {
n = rf_limesdr_recv_with_time_multi(h, data, 1024, 0, NULL, NULL);
} while (n > 0);
}
bool rf_limesdr_has_rssi(void *h)
{
return false;
}
float rf_limesdr_get_rssi(void *h)
{
return 0.0;
}
//TODO: add multi-channel support
int rf_limesdr_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
{
return rf_limesdr_open(args, h);
}
int rf_limesdr_open(char *args, void **h)
{
printf("Opening device\n");
*h = NULL;
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) malloc(sizeof(rf_limesdr_handler_t));
if (!handler) {
perror("malloc");
return -1;
}
*h = handler;
handler->device = NULL;
handler->buffer_size = 1024;
handler->num_buffers = 8;
handler->channel = 0;
int n;
if ((n = LMS_GetDeviceList(handler->list)) < 0) //NULL can be passed to only get number of devices
return SRSLTE_ERROR;
if (LMS_Open(&(handler->device), handler->list[0], NULL))
return SRSLTE_ERROR;
if (LMS_Init(handler->device) != 0)
return SRSLTE_ERROR;
if (LMS_EnableChannel(handler->device, LMS_CH_RX, handler->channel, true) != 0)
return lime_error(handler);
if (LMS_EnableChannel(handler->device, LMS_CH_TX, handler->channel, true) != 0)
return lime_error(handler);
rf_limesdr_get_freq_range(handler);
handler->rx_is_streaming = false;
handler->rx_stream.channel = handler->channel; //channel number
handler->rx_stream.fifoSize = 1024 * 1024; //fifo size in samples
handler->rx_stream.throughputVsLatency = 1.0; //optimize for max throughput
handler->rx_stream.isTx = false; //RX channel
handler->rx_stream.dataFmt = LMS_FMT_F32;
handler->rx_metadata.flushPartialPacket = false; //Do not discard data remainder when read size differs from packet size
handler->rx_metadata.waitForTimestamp = false; //Do not wait for specific timestamps
if (LMS_SetupStream(handler->device, &(handler->rx_stream)) != 0)
return lime_error(handler);
handler->tx_is_streaming = false;
handler->tx_stream.channel = handler->channel; //channel number
handler->tx_stream.fifoSize = 1024 * 1024; //fifo size in samples
handler->tx_stream.throughputVsLatency = 1.0; //optimize for max throughput
handler->tx_stream.isTx = true; //TX channel
handler->rx_stream.dataFmt = LMS_FMT_F32;
handler->tx_metadata.flushPartialPacket = false; //Do not discard data remainder when read size differs from packet size
handler->tx_metadata.waitForTimestamp = false; //Do not wait for specific timestamps
if (LMS_SetupStream(handler->device, &(handler->tx_stream)) != 0)
return lime_error(handler);
return SRSLTE_SUCCESS;
}
int rf_limesdr_close(void *h)
{
printf("Closing device\n");
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
if(handler->rx_is_streaming) {
LMS_StopStream(&(handler->rx_stream));
}
LMS_DestroyStream(handler->device, &(handler->rx_stream)); //stream is deallocated and can no longer be used
if(handler->tx_is_streaming) {
LMS_StopStream(&(handler->tx_stream));
}
LMS_DestroyStream(handler->device, &(handler->tx_stream)); //stream is deallocated and can no longer be used
LMS_Close(handler->device);
return SRSLTE_SUCCESS;
}
void rf_limesdr_set_master_clock_rate(void *h, double rate)
{
// Allow the limesdr to automatically set the appropriate clock rate
}
bool rf_limesdr_is_master_clock_dynamic(void *h)
{
return true;
}
double rf_limesdr_set_rx_srate(void *h, double rate)
{
fprintf(stdout, "Setting rx rate: %f\n", rate);
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
if (LMS_SetSampleRate(handler->device, rate, 0) != 0)
return lime_error(handler);
handler->sampling_rate = rate;
return rate;
}
double rf_limesdr_set_tx_srate(void *h, double rate)
{
fprintf(stdout, "Setting tx rate: %f\n", rate);
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
if (LMS_SetSampleRate(handler->device, rate, 0) != 0)
return lime_error(handler);
handler->sampling_rate = rate;
return rate;
}
double rf_limesdr_set_rx_gain(void *h, double gain)
{
fprintf(stdout, "Setting rx gain: %f\n", gain);
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
if (LMS_SetNormalizedGain(handler->device, LMS_CH_RX, handler->channel, gain) != 0)
return lime_error(handler);
return gain;
}
double rf_limesdr_set_tx_gain(void *h, double gain)
{
fprintf(stdout, "Setting tx gain: %f\n", gain);
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
if (LMS_SetNormalizedGain(handler->device, LMS_CH_TX, handler->channel, gain) != 0)
return lime_error(handler);
return gain;
}
double rf_limesdr_get_rx_gain(void *h)
{
double gain;
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
if(LMS_GetNormalizedGain(handler->device, LMS_CH_RX,handler->channel,&gain) != 0)
return lime_error(handler);
return gain;
}
double rf_limesdr_get_tx_gain(void *h)
{
double gain;
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
if(LMS_GetNormalizedGain(handler->device, LMS_CH_TX, handler->channel, &gain) != 0)
return lime_error(handler);
return gain;
}
double rf_limesdr_set_rx_freq(void *h, double freq)
{
fprintf(stdout, "Setting rx freq: %f\n", freq);
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
if(freq > handler->rx_range.max || freq < handler->rx_range.min) {
fprintf(stderr, "Requested freq outside supported range. freq: %f, min: %f, max: %f\n", freq, handler->rx_range.min, handler->rx_range.max);
return SRSLTE_ERROR;
}
if(LMS_SetLOFrequency(handler->device, LMS_CH_RX, handler->channel, freq) != 0)
return lime_error(handler);
// Automatic antenna port selection doesn't work - so set manually
int ant_port = 1; // manually select antenna index 1 (LNA_H)
if(freq < 1.5e9) {
ant_port = 2; // manually select antenna index 2 (LNA_L)
}
if (LMS_SetAntenna(handler->device, LMS_CH_RX, handler->channel, ant_port) != 0)
return lime_error(handler);
lms_name_t antenna_list[10]; //large enough list for antenna names.
//Alternatively, NULL can be passed to LMS_GetAntennaList() to find out number of available antennae
int n = 0;
if ((n = LMS_GetAntennaList(handler->device, LMS_CH_RX, 0, antenna_list)) < 0)
return lime_error(handler);
fprintf(stdout, "Available antennae:\n"); //print available antennae names
for(int i = 0; i < n; i++)
fprintf(stdout, "%d : %s\n", i, antenna_list[i]);
if((n = LMS_GetAntenna(handler->device, LMS_CH_RX, handler->channel)) < 0) //get currently selected antenna index
return lime_error(handler);
fprintf(stdout, "Selected antenna: %d : %s\n", n, antenna_list[n]); //print antenna index and name
return freq;
}
double rf_limesdr_set_tx_freq(void *h, double freq)
{
fprintf(stdout, "Setting tx freq: %f\n", freq);
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
if(freq > handler->tx_range.max || freq < handler->tx_range.min) {
fprintf(stderr, "Requested freq outside supported range. freq: %f, min: %f, max: %f\n", freq, handler->rx_range.min, handler->rx_range.max);
return SRSLTE_ERROR;
}
if(LMS_SetLOFrequency(handler->device, LMS_CH_TX, handler->channel, freq) != 0)
return lime_error(handler);
return freq;
}
void rf_limesdr_get_time(void *h, time_t *secs, double *frac_secs) {
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
LMS_RecvStream(&(handler->rx_stream),NULL,0, &(handler->rx_metadata), 0);
if (secs && frac_secs) {
*secs = (handler->rx_metadata.timestamp) / (handler->sampling_rate);
int remainder = handler->rx_metadata.timestamp % handler->sampling_rate;
*frac_secs = remainder/(handler->sampling_rate);
}
}
//TODO: add multi-channel support
int rf_limesdr_recv_with_time_multi(void *h,
void **data,
uint32_t nsamples,
bool blocking,
time_t *secs,
double *frac_secs)
{
return rf_limesdr_recv_with_time(h, *data, nsamples, blocking, secs, frac_secs);
}
int rf_limesdr_recv_with_time(void *h,
void *data,
uint32_t nsamples,
bool blocking,
time_t *secs,
double *frac_secs)
{
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
int samples = LMS_RecvStream(&(handler->rx_stream),data,nsamples, &(handler->rx_metadata), blocking ? 1000:0);
if (secs && frac_secs) {
*secs = (handler->rx_metadata.timestamp) / (handler->sampling_rate);
int remainder = handler->rx_metadata.timestamp % handler->sampling_rate;
*frac_secs = remainder/(handler->sampling_rate);
}
return samples;
}
int rf_limesdr_send_timed(void *h,
void *data,
int nsamples,
time_t secs,
double frac_secs,
bool has_time_spec,
bool blocking,
bool is_start_of_burst,
bool is_end_of_burst)
{
rf_limesdr_handler_t *handler = (rf_limesdr_handler_t*) h;
//float *data_in = (float*) data;
if(!handler->tx_is_streaming)
rf_limesdr_start_tx_stream(h);
handler->tx_metadata.timestamp = secs*handler->sampling_rate;
handler->tx_metadata.timestamp += frac_secs*handler->sampling_rate;
LMS_SendStream(&(handler->rx_stream), data, nsamples, &(handler->tx_metadata), blocking ? 1000:0);
return 1;
}

View File

@ -0,0 +1,118 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdbool.h>
#include <stdint.h>
#include "srslte/config.h"
#include "srslte/rf/rf.h"
SRSLTE_API int rf_limesdr_open( char *args,
void **handler);
SRSLTE_API int rf_limesdr_open_multi( char *args,
void **handler,
uint32_t nof_rx_antennas);
SRSLTE_API char* rf_limesdr_devname(void *h);
SRSLTE_API int rf_limesdr_close(void *h);
SRSLTE_API void rf_limesdr_set_tx_cal(void *h, srslte_rf_cal_t *cal);
SRSLTE_API void rf_limesdr_set_rx_cal(void *h, srslte_rf_cal_t *cal);
SRSLTE_API int rf_limesdr_start_rx_stream(void *h);
SRSLTE_API int rf_limesdr_stop_rx_stream(void *h);
SRSLTE_API void rf_limesdr_flush_buffer(void *h);
SRSLTE_API bool rf_limesdr_has_rssi(void *h);
SRSLTE_API float rf_limesdr_get_rssi(void *h);
SRSLTE_API bool rf_limesdr_rx_wait_lo_locked(void *h);
SRSLTE_API void rf_limesdr_set_master_clock_rate(void *h,
double rate);
SRSLTE_API bool rf_limesdr_is_master_clock_dynamic(void *h);
SRSLTE_API double rf_limesdr_set_rx_srate(void *h,
double freq);
SRSLTE_API double rf_limesdr_set_rx_gain(void *h,
double gain);
SRSLTE_API double rf_limesdr_get_rx_gain(void *h);
SRSLTE_API double rf_limesdr_set_tx_gain(void *h,
double gain);
SRSLTE_API double rf_limesdr_get_tx_gain(void *h);
SRSLTE_API void rf_limesdr_suppress_stdout(void *h);
SRSLTE_API void rf_limesdr_register_error_handler(void *h, srslte_rf_error_handler_t error_handler);
SRSLTE_API double rf_limesdr_set_rx_freq(void *h,
double freq);
SRSLTE_API int rf_limesdr_recv_with_time(void *h,
void *data,
uint32_t nsamples,
bool blocking,
time_t *secs,
double *frac_secs);
SRSLTE_API int rf_limesdr_recv_with_time_multi(void *h,
void **data,
uint32_t nsamples,
bool blocking,
time_t *secs,
double *frac_secs);
SRSLTE_API double rf_limesdr_set_tx_srate(void *h,
double freq);
SRSLTE_API double rf_limesdr_set_tx_freq(void *h,
double freq);
SRSLTE_API void rf_limesdr_get_time(void *h,
time_t *secs,
double *frac_secs);
SRSLTE_API int rf_limesdr_send_timed(void *h,
void *data,
int nsamples,
time_t secs,
double frac_secs,
bool has_time_spec,
bool blocking,
bool is_start_of_burst,
bool is_end_of_burst);

View File

@ -0,0 +1,457 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <sys/time.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include "srslte/srslte.h"
#include "rf_soapy_imp.h"
#include "srslte/rf/rf.h"
#include <SoapySDR/Device.h>
#include <SoapySDR/Formats.h>
//#include "lime/LimeSuite.h"
typedef struct {
SoapySDRKwargs args;
SoapySDRDevice *device;
SoapySDRRange *ranges;
SoapySDRStream *rxStream;
SoapySDRStream *txStream;
} rf_soapy_handler_t;
int soapy_error(void *h)
{
}
void rf_soapy_get_freq_range(void *h)
{
}
void rf_soapy_suppress_handler(const char *x)
{
// not supported
}
void rf_soapy_msg_handler(const char *msg)
{
// not supported
}
void rf_soapy_suppress_stdout(void *h)
{
// not supported
}
void rf_soapy_register_error_handler(void *notused, srslte_rf_error_handler_t new_handler)
{
// not supported
}
static bool isLocked(rf_soapy_handler_t *handler, char *sensor_name, void *value_h)
{
// not supported
return true;
}
char* rf_soapy_devname(void* h)
{
}
bool rf_soapy_rx_wait_lo_locked(void *h)
{
// not supported
return true;
}
void rf_soapy_set_tx_cal(void *h, srslte_rf_cal_t *cal)
{
// not supported
}
void rf_soapy_set_rx_cal(void *h, srslte_rf_cal_t *cal)
{
// not supported
}
int rf_soapy_start_rx_stream(void *h)
{
//printf("starting SOAPY rx stream \n");
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
//SoapySDRStream *rxStream;
if(SoapySDRDevice_activateStream(handler->device, handler->rxStream, 0, 0, 0)!=0)//start streaming
return SRSLTE_ERROR;
return SRSLTE_SUCCESS;
}
int rf_soapy_start_tx_stream(void *h)
{
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
//SoapySDRStream *rxStream;
if (SoapySDRDevice_setupStream(handler->device, &(handler->txStream), SOAPY_SDR_TX, SOAPY_SDR_CF32, NULL, 0, NULL) != 0)
{
printf("setupStream fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR;
}
if(SoapySDRDevice_activateStream(handler->device, handler->txStream, 0, 0, 0) != 0)
return SRSLTE_ERROR;
return SRSLTE_SUCCESS;
}
int rf_soapy_stop_rx_stream(void *h)
{
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
if(SoapySDRDevice_deactivateStream(handler->device, handler->rxStream, 0, 0) != 0)
return SRSLTE_ERROR;
return SRSLTE_SUCCESS;
}
int rf_soapy_stop_tx_stream(void *h)
{
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
if(SoapySDRDevice_deactivateStream(handler->device, handler->txStream, 0, 0) != 0)
return SRSLTE_ERROR;
return SRSLTE_SUCCESS;
}
void rf_soapy_flush_buffer(void *h)
{
int n;
cf_t tmp1[1024];
cf_t tmp2[1024];
void *data[2] = {tmp1, tmp2};
do {
n = rf_soapy_recv_with_time_multi(h, data, 1024, 0, NULL, NULL);
} while (n > 0);
}
bool rf_soapy_has_rssi(void *h)
{
}
float rf_soapy_get_rssi(void *h)
{
}
//TODO: add multi-channel support
int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
{//SoapySDRKwargs soapy_args = {};
size_t length;
const SoapySDRKwargs *soapy_args = SoapySDRDevice_enumerate(NULL, &length);
if(length == 0)
{
return SRSLTE_ERROR;
}
for (size_t i = 0; i < length; i++)
{
printf("Soapy Has Found device #%d: ", (int)i);
for (size_t j = 0; j < soapy_args[i].size; j++)
{
printf("%s=%s, ", soapy_args[i].keys[j], soapy_args[i].vals[j]);
}
printf("\n");
}
// SoapySDRrgs_set(&soapy_args, "driver", "rtlsdr");
SoapySDRDevice *sdr = SoapySDRDevice_make(&(soapy_args[0]));
if(sdr == NULL)
{
printf("failed to create SOAPY object\n");
return SRSLTE_ERROR;
}
//SoapySDRKwargs_clear(&soapy_args);
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) malloc(sizeof(rf_soapy_handler_t));
*h = handler;
handler->device = sdr;
//size_t channels[1];
//channels[0] = 0;
if (SoapySDRDevice_setupStream(handler->device, &(handler->rxStream), SOAPY_SDR_RX, SOAPY_SDR_CF32, NULL, 0, NULL) != 0)
{
printf("setupStream fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS;
}
int rf_soapy_open(char *args, void **h)
{
return rf_soapy_open_multi(args, h, 1);
}
int rf_soapy_close(void *h)
{
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
SoapySDRDevice_closeStream(handler->device, handler->txStream);
SoapySDRDevice_closeStream(handler->device, handler->rxStream);
SoapySDRDevice_unmake(handler->device);
}
void rf_soapy_set_master_clock_rate(void *h, double rate)
{
// Allow the soapy to automatically set the appropriate clock rate
printf("SET MASTER CLOCK RATE\n");
}
bool rf_soapy_is_master_clock_dynamic(void *h)
{
}
double rf_soapy_set_rx_srate(void *h, double rate)
{
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_RX, 0, rate) != 0)
{
printf("setSampleRate fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR;
}
double ret = SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_RX,0);
printf("Sampling rate is set to %f.3 : \n",ret);
return ret;
}
double rf_soapy_set_tx_srate(void *h, double rate)
{
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_TX, 0, rate) != 0)
{
printf("setSampleRate fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR;
}
double ret = SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_TX,0);
printf("Sampling rate is set to %f.3 : \n",ret);
return ret;
}
double rf_soapy_set_rx_gain(void *h, double gain)
{
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
if (SoapySDRDevice_setGain(handler->device, SOAPY_SDR_RX, 0, gain) != 0)
{
printf("setGain fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR;
}
double ret = rf_soapy_get_rx_gain(h);
printf("gain has been set to %f.2 \n",ret);
return ret;
}
double rf_soapy_set_tx_gain(void *h, double gain)
{
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
if (SoapySDRDevice_setGain(handler->device, SOAPY_SDR_TX, 0, gain) != 0)
{
printf("setGain fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR;
}
double ret = rf_soapy_get_rx_gain(h);
printf("gain has been set to %f.2 \n",ret);
return ret;
}
double rf_soapy_get_rx_gain(void *h)
{
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
return SoapySDRDevice_getGain(handler->device,SOAPY_SDR_RX,0);
}
double rf_soapy_get_tx_gain(void *h)
{
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
return SoapySDRDevice_getGain(handler->device,SOAPY_SDR_TX,0);
}
double rf_soapy_set_rx_freq(void *h, double freq)
{
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
if (SoapySDRDevice_setFrequency(handler->device, SOAPY_SDR_RX, 0, freq, NULL) != 0)
{
printf("setFrequency fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR;
}
double ret = SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_RX, 0);
printf("Frequency has been set to %f : \n",ret);
return ret;
}
double rf_soapy_set_tx_freq(void *h, double freq)
{
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
if (SoapySDRDevice_setFrequency(handler->device, SOAPY_SDR_TX, 0, freq, NULL) != 0)
{
printf("setFrequency fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR;
}
double ret = SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_RX, 0);
printf("Frequency has been set to %f : \n",ret);
return ret;
}
void rf_soapy_get_time(void *h, time_t *secs, double *frac_secs) {
}
//TODO: add multi-channel support
int rf_soapy_recv_with_time_multi(void *h,
void **data,
uint32_t nsamples,
bool blocking,
time_t *secs,
double *frac_secs)
{
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
//void *buffs[] = {buff}; //array of buffers
int flags; //flags set by receive operation
int num_channels = 1; // temp
int trials = 0;
int ret = 0;
long long timeNs; //timestamp for receive buffer
int n = 0;
do{
size_t rx_samples = nsamples;
if (rx_samples > nsamples - n)
{
rx_samples = nsamples - n;
}
void *buffs_ptr[4];
for (int i=0;i<num_channels;i++)
{
cf_t *data_c = (cf_t*) data[i];
buffs_ptr[i] = &data_c[n];
} //(void*)(&data)
ret = SoapySDRDevice_readStream(handler->device, handler->rxStream,buffs_ptr , rx_samples, &flags, &timeNs, 1000000);
if(ret < 0)
return SRSLTE_ERROR;
n += ret;
trials++;
}while (n < nsamples && trials < 100);
//*secs = timeNs / 1000000000;
//*frac_secs = (timeNs % 1000000000)/1000000000;
// printf("ret=%d, flags=%d, timeNs=%lld\n", ret, flags, timeNs);
return n;
}
int rf_soapy_recv_with_time(void *h,
void *data,
uint32_t nsamples,
bool blocking,
time_t *secs,
double *frac_secs)
{
return rf_soapy_recv_with_time_multi(h, &data, nsamples, blocking, secs, frac_secs);
}
int rf_soapy_send_timed(void *h,
void *data,
int nsamples,
time_t secs,
double frac_secs,
bool has_time_spec,
bool blocking,
bool is_start_of_burst,
bool is_end_of_burst)
{
int flags;
long long timeNs;
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
timeNs = secs * 1000000000;
timeNs = timeNs + (frac_secs * 1000000000);
int ret = SoapySDRDevice_writeStream(handler->device, handler->txStream, &data, nsamples, &flags, timeNs, 100000);
if(ret != nsamples)
return SRSLTE_ERROR;
return ret;
}

View File

@ -0,0 +1,118 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdbool.h>
#include <stdint.h>
#include "srslte/config.h"
#include "srslte/rf/rf.h"
SRSLTE_API int rf_soapy_open( char *args,
void **handler);
SRSLTE_API int rf_soapy_open_multi( char *args,
void **handler,
uint32_t nof_rx_antennas);
SRSLTE_API char* rf_soapy_devname(void *h);
SRSLTE_API int rf_soapy_close(void *h);
SRSLTE_API void rf_soapy_set_tx_cal(void *h, srslte_rf_cal_t *cal);
SRSLTE_API void rf_soapy_set_rx_cal(void *h, srslte_rf_cal_t *cal);
SRSLTE_API int rf_soapy_start_rx_stream(void *h);
SRSLTE_API int rf_soapy_stop_rx_stream(void *h);
SRSLTE_API void rf_soapy_flush_buffer(void *h);
SRSLTE_API bool rf_soapy_has_rssi(void *h);
SRSLTE_API float rf_soapy_get_rssi(void *h);
SRSLTE_API bool rf_soapy_rx_wait_lo_locked(void *h);
SRSLTE_API void rf_soapy_set_master_clock_rate(void *h,
double rate);
SRSLTE_API bool rf_soapy_is_master_clock_dynamic(void *h);
SRSLTE_API double rf_soapy_set_rx_srate(void *h,
double freq);
SRSLTE_API double rf_soapy_set_rx_gain(void *h,
double gain);
SRSLTE_API double rf_soapy_get_rx_gain(void *h);
SRSLTE_API double rf_soapy_set_tx_gain(void *h,
double gain);
SRSLTE_API double rf_soapy_get_tx_gain(void *h);
SRSLTE_API void rf_soapy_suppress_stdout(void *h);
SRSLTE_API void rf_soapy_register_error_handler(void *h, srslte_rf_error_handler_t error_handler);
SRSLTE_API double rf_soapy_set_rx_freq(void *h,
double freq);
SRSLTE_API int rf_soapy_recv_with_time(void *h,
void *data,
uint32_t nsamples,
bool blocking,
time_t *secs,
double *frac_secs);
SRSLTE_API int rf_soapy_recv_with_time_multi(void *h,
void **data,
uint32_t nsamples,
bool blocking,
time_t *secs,
double *frac_secs);
SRSLTE_API double rf_soapy_set_tx_srate(void *h,
double freq);
SRSLTE_API double rf_soapy_set_tx_freq(void *h,
double freq);
SRSLTE_API void rf_soapy_get_time(void *h,
time_t *secs,
double *frac_secs);
SRSLTE_API int rf_soapy_send_timed(void *h,
void *data,
int nsamples,
time_t secs,
double frac_secs,
bool has_time_spec,
bool blocking,
bool is_start_of_burst,
bool is_end_of_burst);

View File

@ -97,15 +97,33 @@ int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t frame_size,
ret = SRSLTE_ERROR;
uint32_t N_id_2;
uint32_t buffer_size;
uint32_t buffer_size;
int decimation_factor = q->decimate;
bzero(q, sizeof(srslte_pss_synch_t));
q->N_id_2 = 10;
q->N_id_2 = 10;
q->ema_alpha = 0.2;
q->decimate = decimation_factor;
fft_size = fft_size/q->decimate;
frame_size = frame_size/q->decimate;
q->fft_size = fft_size;
q->frame_size = frame_size;
q->ema_alpha = 0.2;
buffer_size = fft_size + frame_size + 1;
if(q->decimate > 1)
{
int filter_order = 3;
srslte_filt_decim_cc_init(&q->filter,q->decimate,filter_order);
q->filter.filter_output = srslte_vec_malloc((buffer_size) * sizeof(cf_t));
q->filter.downsampled_input = srslte_vec_malloc((buffer_size + filter_order) * sizeof(cf_t));
}
printf("decimation in the PSS is %d \n",q->decimate);
if (srslte_dft_plan(&q->dftp_input, fft_size, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)) {
fprintf(stderr, "Error creating DFT plan \n");
@ -115,7 +133,7 @@ int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t frame_size,
srslte_dft_plan_set_dc(&q->dftp_input, true);
srslte_dft_plan_set_norm(&q->dftp_input, true);
q->tmp_input = srslte_vec_malloc(buffer_size * sizeof(cf_t));
q->tmp_input = srslte_vec_malloc((buffer_size + frame_size*(q->decimate - 1)) * sizeof(cf_t));
if (!q->tmp_input) {
fprintf(stderr, "Error allocating memory\n");
goto clean_and_exit;
@ -159,6 +177,10 @@ int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t frame_size,
}
#ifdef CONVOLUTION_FFT
for(N_id_2 = 0; N_id_2<3; N_id_2++)
q->conv_fft.pss_signal_time[N_id_2] = q->pss_signal_time[N_id_2];
if (srslte_conv_fft_cc_init(&q->conv_fft, frame_size, fft_size)) {
fprintf(stderr, "Error initiating convolution FFT\n");
goto clean_and_exit;
@ -204,6 +226,14 @@ void srslte_pss_synch_free(srslte_pss_synch_t *q) {
}
srslte_dft_plan_free(&q->dftp_input);
if(q->decimate > 1)
{
srslte_filt_decim_cc_free(&q->filter);
free(q->filter.filter_output);
free(q->filter.downsampled_input);
}
bzero(q, sizeof(srslte_pss_synch_t));
}
@ -314,8 +344,17 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe
*/
if (q->frame_size >= q->fft_size) {
#ifdef CONVOLUTION_FFT
memcpy(q->tmp_input, input, q->frame_size * sizeof(cf_t));
conv_output_len = srslte_conv_fft_cc_run(&q->conv_fft, q->tmp_input, q->pss_signal_time[q->N_id_2], q->conv_output);
memcpy(q->tmp_input, input, (q->frame_size * q->decimate) * sizeof(cf_t));
if(q->decimate > 1)
{
srslte_filt_decim_cc_execute(&(q->filter), q->tmp_input, q->filter.downsampled_input, q->filter.filter_output , (q->frame_size * q->decimate));
conv_output_len = srslte_conv_fft_cc_run_opt(&q->conv_fft, q->filter.filter_output, q->N_id_2, q->conv_output);
}
else
{
conv_output_len = srslte_conv_fft_cc_run_opt(&q->conv_fft, q->tmp_input, q->N_id_2, q->conv_output);
}
#else
conv_output_len = srslte_conv_cc(input, q->pss_signal_time[q->N_id_2], q->conv_output, q->frame_size, q->fft_size);
#endif
@ -387,6 +426,14 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe
*corr_peak_value = q->conv_output_avg[corr_peak_pos];
}
#endif
if(q->decimate >1)
{
int decimation_correction = (q->filter.num_taps -2);
corr_peak_pos = corr_peak_pos - decimation_correction;
corr_peak_pos = corr_peak_pos*q->decimate;
}
if (q->frame_size >= q->fft_size) {
ret = (int) corr_peak_pos;

View File

@ -56,7 +56,8 @@ int srslte_sync_init(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset,
fft_size_isvalid(fft_size))
{
ret = SRSLTE_ERROR;
int decimate = q->decimate;
bzero(q, sizeof(srslte_sync_t));
q->detect_cp = true;
q->sss_en = true;
@ -105,7 +106,12 @@ int srslte_sync_init(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset,
}
srslte_sync_set_cp(q, SRSLTE_CP_NORM);
if(!decimate)
decimate = 1;
q->pss.decimate = decimate;
if (srslte_pss_synch_init_fft(&q->pss, max_offset, fft_size)) {
fprintf(stderr, "Error initializing PSS object\n");
goto clean_exit;

View File

@ -138,9 +138,9 @@ int srslte_ue_sync_init_multi(srslte_ue_sync_t *q,
recv_callback != NULL)
{
ret = SRSLTE_ERROR;
int decimate = q->decimate;
bzero(q, sizeof(srslte_ue_sync_t));
q->decimate = decimate;
q->stream = stream_handler;
q->recv_callback = recv_callback;
q->nof_rx_antennas = nof_rx_antennas;
@ -169,7 +169,16 @@ int srslte_ue_sync_init_multi(srslte_ue_sync_t *q,
}
q->frame_len = q->nof_recv_sf*q->sf_len;
if(q->fft_size > 1000 && q->decimate)
{
q->sfind.decimate = q->decimate;
}
else
{
q->sfind.decimate = 1;
}
if(srslte_sync_init(&q->sfind, q->frame_len, q->frame_len, q->fft_size)) {
fprintf(stderr, "Error initiating sync find\n");
goto clean_exit;

View File

@ -58,6 +58,15 @@ int srslte_conv_fft_cc_init(srslte_conv_fft_cc_t *q, uint32_t input_len, uint32_
srslte_dft_plan_set_norm(&q->input_plan, true);
srslte_dft_plan_set_norm(&q->filter_plan, true);
srslte_dft_plan_set_norm(&q->output_plan, false);
for(int i =0; i< 3; i++)
{
q->pss_signal_time_fft[i] = srslte_vec_malloc(sizeof(cf_t)*q->output_len);
srslte_dft_run_c(&q->filter_plan, q->pss_signal_time[i], q->pss_signal_time_fft[i]);
}
return SRSLTE_SUCCESS;
}
@ -71,6 +80,11 @@ void srslte_conv_fft_cc_free(srslte_conv_fft_cc_t *q) {
if (q->output_fft) {
free(q->output_fft);
}
for(int i = 0; i < 3;i++)
{
free(q->pss_signal_time_fft[i]);
}
srslte_dft_plan_free(&q->input_plan);
srslte_dft_plan_free(&q->filter_plan);
srslte_dft_plan_free(&q->output_plan);
@ -79,6 +93,16 @@ void srslte_conv_fft_cc_free(srslte_conv_fft_cc_t *q) {
}
uint32_t srslte_conv_fft_cc_run_opt(srslte_conv_fft_cc_t *q, cf_t *input, int N_id_2, cf_t *output)
{
srslte_dft_run_c(&q->input_plan, input, q->input_fft);
srslte_vec_prod_ccc(q->input_fft,q->pss_signal_time_fft[N_id_2],q->output_fft,q->output_len);
srslte_dft_run_c(&q->output_plan, q->output_fft, output);
return (q->output_len-1); // divide output length by dec factor
}
uint32_t srslte_conv_fft_cc_run(srslte_conv_fft_cc_t *q, cf_t *input, cf_t *filter, cf_t *output) {
srslte_dft_run_c(&q->input_plan, input, q->input_fft);

126
srslte/lib/utils/filter.c Normal file
View File

@ -0,0 +1,126 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "srslte/utils/filter.h"
#define SRSLTE_NUM_FILTERS 8
#define SRSLTE_MAX_FILTER_SIZE 11
float srslte_filt_decim2[SRSLTE_NUM_FILTERS][SRSLTE_MAX_FILTER_SIZE] =
{
{0.0167364016736, 0.48326359832636, 0.48326359832636, 0.01673640167364,0,0,0,0,0,0,0},
{0.000000000000000, 0.203712369200737, 0.592575261598526, 0.203712369200737, 0.000000000000000,0,0,0,0,0,0},
{-0.007776312719103, 0.064454645578710, 0.443321667140393, 0.443321667140393, 0.064454645578710, -0.007776312719103,0,0,0,0,0},
{-0.008721828105097, 0.000000000000000, 0.251842786534672, 0.513758083140849, 0.251842786534672, 0.000000000000000, -0.008721828105097,0,0,0,0},
{-0.005164298061200, -0.022882524920256, 0.096755650536968, 0.431291172444487, 0.431291172444487, 0.096755650536968, -0.022882524920256, -0.005164298061200,0,0,0},
{-0.000000000000000, -0.022663985459553, 0.000000000000000, 0.273977082565524, 0.497373805788057, 0.273977082565524, 0.000000000000000, -0.022663985459553, -0.000000000000000,0,0},
{ 0.003971846362414, -0.011976365116169, -0.041119498116286, 0.114687063714704, 0.434436953155337, 0.434436953155337, 0.114687063714704, -0.041119498116286, -0.011976365116169, 0.003971846362414,0},
{0.005060317124845, -0.000000000000000, -0.041942879431345, 0.000000000000000, 0.288484826302638, 0.496795472007725, 0.288484826302638, 0.000000000000000, -0.041942879431345, -0.000000000000000, 0.005060317124845}
};
float srslte_filt_decim3[SRSLTE_NUM_FILTERS][SRSLTE_MAX_FILTER_SIZE] =
{
{0.032388663967611, 0.467611336032389, 0.467611336032389, 0.032388663967611,0,0,0,0,0,0,0},
{0.016883339167609, 0.227925078762723, 0.510383164139335, 0.227925078762723, 0.016883339167609,0,0,0,0,0,0},
{0.006703633822959, 0.111127306155495, 0.382169060021546, 0.382169060021546, 0.111127306155495, 0.006703633822959,0,0,0,0,0},
{0.000000000000000, 0.050666848023938, 0.251699825667307, 0.395266652617510, 0.251699825667307, 0.050666848023938, 0.000000000000000,0,0,0,0},
{-0.004018779518049, 0.017806838679915, 0.150587600493065, 0.335624340345069, 0.335624340345069, 0.150587600493065, 0.017806838679915, -0.004018779518049,0,0,0},
{-0.005814396641997, 0.000000000000000, 0.078494354666956, 0.251550893097387, 0.351538297755307, 0.251550893097387, 0.078494354666956, 0.000000000000000, -0.005814396641997,0,0},
{ -0.005798226803038, -0.008741738083915, 0.030013771222565, 0.167423798937736, 0.317102394726653, 0.317102394726653, 0.167423798937736, 0.030013771222565, -0.008741738083915, -0.005798226803038,0},
{-0.004444793932295, -0.011657318166992, 0.000000000000000, 0.094750202492597, 0.253394317761931, 0.335915183689516, 0.253394317761931, 0.094750202492597, 0.000000000000000, -0.011657318166992, -0.004444793932295},
};
float srslte_filt_decim4[SRSLTE_NUM_FILTERS][SRSLTE_MAX_FILTER_SIZE] =
{
{ 0.038579006748772, 0.461420993251228, 0.461420993251228, 0.038579006748772,0,0,0,0,0,0,0},
{0.024553834015017, 0.234389464237986, 0.482113403493995, 0.234389464237986, 0.024553834015017,0,0,0,0,0,0},
{0.015196373491712, 0.125956465856097, 0.358847160652191, 0.358847160652191, 0.125956465856097, 0.015196373491712,0,0,0,0,0},
{0.008485920061584, 0.069755250084282, 0.245030941778248, 0.353455776151771, 0.245030941778248, 0.069755250084282, 0.008485920061584,0,0,0,0},
{0.003560172702629, 0.038083722795699, 0.161031852333115, 0.297324252168557, 0.297324252168557, 0.161031852333115, 0.038083722795699, 0.003560172702629,0,0,0},
{0.000000000000000, 0.019096925170212, 0.101875313412667, 0.230856124287772, 0.296343274258697, 0.230856124287772, 0.101875313412667, 0.019096925170212, 0.000000000000000,0,0},
{-0.002426023829880, 0.007315224335493, 0.060635381185575, 0.169119131895270, 0.265356286413542, 0.265356286413542, 0.169119131895270, 0.060635381185575 , 0.007315224335493, -0.002426023829880,0},
{-0.003871323167475, 0.000000000000000, 0.032087799410030, 0.116708621643743, 0.220701186106900, 0.268747432013603, 0.220701186106900, 0.116708621643743 , 0.032087799410030, 0.000000000000000,-0.003871323167475}
};
void srslte_filt_decim_cc_init(srslte_filt_cc_t *q, int factor, int order)
{
q->factor = factor;
q->num_taps = order + 1;
q->is_decimator = true;
q->taps = malloc(q->num_taps * sizeof(float));
switch(q->factor)
{
case 2:
for(int i = 0; i <(q->num_taps); i++)
q->taps[i] = srslte_filt_decim2[(q->num_taps) - 4][i];
break;
case 3:
for(int i = 0; i <(q->num_taps); i++)
q->taps[i] = srslte_filt_decim3[(q->num_taps) - 4][i];
case 4:
for(int i = 0; i <(q->num_taps); i++)
q->taps[i] = srslte_filt_decim4[(q->num_taps) - 4][i];
break;
default:
break;
}
for(int x = 0; x<(q->num_taps);x++)
{
printf("tap : %f.9\n" ,q->taps[x]);
}
}
void srslte_filt_decim_cc_free(srslte_filt_cc_t *q)
{
free(q->taps);
}
void srslte_filt_decim_cc_execute(srslte_filt_cc_t *q, cf_t *input, cf_t *downsampled_input, cf_t *output, int size)
{
// we assume that "downsampled_input" made size (input/2 + order) so as to have prepended zeros //
srslte_downsample_cc(input, downsampled_input + (q->num_taps - 1), q->factor, size);
for(int i = 0;i < size/q->factor;i++)
{
output[i] = srslte_vec_dot_prod_cfc(&(downsampled_input[i]), q->taps, q->num_taps);
}
}
/* Performs integer linear downsamling by a factor of M */
void srslte_downsample_cc(cf_t *input, cf_t *output, int M, int size) {
int i;
for (i=0;i<size/M;i++) {
output[i] = input[i*M];
}
}