srsRAN/lib/src/phy/utils/vector.c

477 lines
13 KiB
C

/**
*
* \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 <float.h>
#include <complex.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "srslte/phy/utils/vector.h"
#include "srslte/phy/utils/vector_simd.h"
#include "srslte/phy/utils/bit.h"
void srslte_vec_xor_bbb(int8_t *x,int8_t *y,int8_t *z, const uint32_t len) {
srslte_vec_xor_bbb_simd(x, y, z, len);
}
// Used in PRACH detector, AGC and chest_dl for noise averaging
float srslte_vec_acc_ff(const float *x, const uint32_t len) {
return srslte_vec_acc_ff_simd(x, len);
}
cf_t srslte_vec_acc_cc(const cf_t *x, const uint32_t len) {
return srslte_vec_acc_cc_simd(x, len);
}
void srslte_vec_sub_fff(const float *x, const float *y, float *z, const uint32_t len) {
srslte_vec_sub_fff_simd(x, y, z, len);
}
void srslte_vec_sub_sss(const int16_t *x, const int16_t *y, int16_t *z, const uint32_t len) {
srslte_vec_sub_sss_simd(x, y, z, len);
}
void srslte_vec_sub_bbb(const int8_t *x, const int8_t *y, int8_t *z, const uint32_t len) {
srslte_vec_sub_bbb_simd(x, y, z, len);
}
// Noise estimation in chest_dl, interpolation
void srslte_vec_sub_ccc(const cf_t *x, const cf_t *y, cf_t *z, const uint32_t len) {
return srslte_vec_sub_fff((const float*) x,(const float*) y,(float*) z, 2*len);
}
// Used in PSS/SSS and sum_ccc
void srslte_vec_sum_fff(const float *x, const float *y, float *z, const uint32_t len) {
srslte_vec_add_fff_simd(x, y, z, len);
}
void srslte_vec_sum_sss(const int16_t *x, const int16_t *y, int16_t *z, const uint32_t len) {
srslte_vec_sum_sss_simd(x, y, z, len);
}
void srslte_vec_sum_ccc(const cf_t *x, const cf_t *y, cf_t *z, const uint32_t len) {
srslte_vec_sum_fff((float*) x,(float*) y,(float*) z,2*len);
}
// PSS, PBCH, DEMOD, FFTW, etc.
void srslte_vec_sc_prod_fff(const float *x, const float h, float *z, const uint32_t len) {
srslte_vec_sc_prod_fff_simd(x, h, z, len);
}
// Used throughout
void srslte_vec_sc_prod_cfc(const cf_t *x, const float h, cf_t *z, const uint32_t len) {
srslte_vec_sc_prod_cfc_simd(x,h,z,len);
}
// Chest UL
void srslte_vec_sc_prod_ccc(const cf_t *x, const cf_t h, cf_t *z, const uint32_t len) {
srslte_vec_sc_prod_ccc_simd(x,h,z,len);
}
// Used in turbo decoder
void srslte_vec_convert_if(const int16_t *x, const float scale, float *z, const uint32_t len) {
srslte_vec_convert_if_simd(x, z, scale, len);
}
void srslte_vec_convert_fi(const float *x, const float scale, int16_t *z, const uint32_t len) {
srslte_vec_convert_fi_simd(x, z, scale, len);
}
void srslte_vec_convert_fb(const float *x, const float scale, int8_t *z, const uint32_t len) {
srslte_vec_convert_fb_simd(x, z, scale, len);
}
void srslte_vec_lut_sss(const short *x, const unsigned short *lut, short *y, const uint32_t len) {
srslte_vec_lut_sss_simd(x, lut, y, len);
}
void srslte_vec_lut_bbb(const int8_t *x, const unsigned short *lut, int8_t *y, const uint32_t len) {
srslte_vec_lut_bbb_simd(x, lut, y, len);
}
void srslte_vec_lut_sis(const short *x, const unsigned int *lut, short *y, const uint32_t len) {
for (int i=0; i < len; i++) {
y[lut[i]] = x[i];
}
}
void *srslte_vec_malloc(uint32_t size) {
void *ptr;
if (posix_memalign(&ptr, SRSLTE_SIMD_BIT_ALIGN, size)) {
return NULL;
} else {
return ptr;
}
}
void *srslte_vec_realloc(void *ptr, uint32_t old_size, uint32_t new_size) {
#ifndef LV_HAVE_SSE
return realloc(ptr, new_size);
#else
void *new_ptr;
if (posix_memalign(&new_ptr, SRSLTE_SIMD_BIT_ALIGN, new_size)) {
return NULL;
} else {
memcpy(new_ptr, ptr, old_size);
free(ptr);
return new_ptr;
}
#endif
}
void srslte_vec_fprint_c(FILE *stream, cf_t *x, const uint32_t len) {
int i;
fprintf(stream, "[");
for (i=0;i<len;i++) {
fprintf(stream, "%+2.5f%+2.5fi, ", __real__ x[i], __imag__ x[i]);
}
fprintf(stream, "];\n");
}
void srslte_vec_fprint_f(FILE *stream, float *x, const uint32_t len) {
int i;
fprintf(stream, "[");
for (i=0;i<len;i++) {
fprintf(stream, "%+2.2f, ", x[i]);
}
fprintf(stream, "];\n");
}
void srslte_vec_fprint_b(FILE *stream, uint8_t *x, const uint32_t len) {
int i;
fprintf(stream, "[");
for (i=0;i<len;i++) {
fprintf(stream, "%d, ", x[i]);
}
fprintf(stream, "];\n");
}
void srslte_vec_fprint_bs(FILE *stream, int8_t *x, const uint32_t len) {
int i;
fprintf(stream, "[");
for (i=0;i<len;i++) {
fprintf(stream, "%4d, ", x[i]);
}
fprintf(stream, "];\n");
}
void srslte_vec_fprint_byte(FILE *stream, uint8_t *x, const uint32_t len) {
int i;
fprintf(stream, "[");
for (i=0;i<len;i++) {
fprintf(stream, "%02x ", x[i]);
}
fprintf(stream, "];\n");
}
void srslte_vec_fprint_i(FILE *stream, int *x, const uint32_t len) {
int i;
fprintf(stream, "[");
for (i=0;i<len;i++) {
fprintf(stream, "%d, ", x[i]);
}
fprintf(stream, "];\n");
}
void srslte_vec_fprint_s(FILE *stream, short *x, const uint32_t len) {
int i;
fprintf(stream, "[");
for (i=0;i<len;i++) {
fprintf(stream, "%4d, ", x[i]);
}
fprintf(stream, "];\n");
}
void srslte_vec_fprint_hex(FILE *stream, uint8_t *x, const uint32_t len) {
uint32_t i, nbytes;
uint8_t byte;
nbytes = len/8;
fprintf(stream, "[");
for (i=0;i<nbytes;i++) {
byte = (uint8_t) srslte_bit_pack(&x, 8);
fprintf(stream, "%02x ", byte);
}
if (len%8) {
byte = (uint8_t) srslte_bit_pack(&x, len%8)<<(8-(len%8));
fprintf(stream, "%02x ", byte);
}
fprintf(stream, "];\n");
}
void srslte_vec_sprint_hex(char *str, const uint32_t max_str_len, uint8_t *x, const uint32_t len) {
uint32_t i, nbytes;
uint8_t byte;
nbytes = len/8;
// check that hex string fits in buffer (every byte takes 3 characters, plus brackets)
if ((3*(len/8 + ((len%8)?1:0))) + 2 >= max_str_len) {
fprintf(stderr, "Buffer too small for printing hex string (max_str_len=%d, payload_len=%d).\n", max_str_len, len);
return;
}
int n=0;
n+=sprintf(&str[n], "[");
for (i=0;i<nbytes;i++) {
byte = (uint8_t) srslte_bit_pack(&x, 8);
n+=sprintf(&str[n], "%02x ", byte);
}
if (len%8) {
byte = (uint8_t) srslte_bit_pack(&x, len%8)<<(8-(len%8));
n+=sprintf(&str[n], "%02x ", byte);
}
n+=sprintf(&str[n], "]");
str[max_str_len-1] = 0;
}
void srslte_vec_save_file(char *filename, const void *buffer, const uint32_t len) {
FILE *f;
f = fopen(filename, "w");
if (f) {
fwrite(buffer, len, 1, f);
fclose(f);
} else {
perror("fopen");
}
}
void srslte_vec_load_file(char *filename, void *buffer, const uint32_t len) {
FILE *f;
f = fopen(filename, "r");
if (f) {
fread(buffer, len, 1, f);
fclose(f);
} else {
perror("fopen");
}
}
// Used in PSS
void srslte_vec_conj_cc(const cf_t *x, cf_t *y, const uint32_t len) {
/* This function is used in initialisation only, then no optimisation is required */
int i;
for (i=0;i<len;i++) {
y[i] = conjf(x[i]);
}
}
// Used in scrambling complex
void srslte_vec_prod_cfc(const cf_t *x, const float *y, cf_t *z, const uint32_t len) {
srslte_vec_prod_cfc_simd(x, y, z, len);
}
// Used in scrambling float
void srslte_vec_prod_fff(const float *x, const float *y, float *z, const uint32_t len) {
srslte_vec_prod_fff_simd(x, y, z, len);
}
void srslte_vec_prod_sss(const int16_t *x, const int16_t *y, int16_t *z, const uint32_t len) {
srslte_vec_prod_sss_simd(x,y,z,len);
}
// Scrambling
void srslte_vec_neg_sss(const int16_t *x, const int16_t *y, int16_t *z, const uint32_t len) {
srslte_vec_neg_sss_simd(x,y,z,len);
}
void srslte_vec_neg_bbb(const int8_t *x, const int8_t *y, int8_t *z, const uint32_t len) {
srslte_vec_neg_bbb_simd(x,y,z,len);
}
// CFO and OFDM processing
void srslte_vec_prod_ccc(const cf_t *x, const cf_t *y, cf_t *z, const uint32_t len) {
srslte_vec_prod_ccc_simd(x,y,z,len);
}
void srslte_vec_prod_ccc_split(const float *x_re, const float *x_im, const float *y_re, const float *y_im,
float *z_re, float *z_im, const uint32_t len) {
srslte_vec_prod_ccc_split_simd(x_re, x_im, y_re , y_im, z_re,z_im, len);
}
// PRACH, CHEST UL, etc.
void srslte_vec_prod_conj_ccc(const cf_t *x, const cf_t *y, cf_t *z, const uint32_t len) {
srslte_vec_prod_conj_ccc_simd(x,y,z,len);
}
//#define DIV_USE_VEC
// Used in SSS
void srslte_vec_div_ccc(const cf_t *x, const cf_t *y, cf_t *z, const uint32_t len) {
srslte_vec_div_ccc_simd(x, y, z, len);
}
/* Complex division by float z=x/y */
void srslte_vec_div_cfc(const cf_t *x, const float *y, cf_t *z, const uint32_t len) {
srslte_vec_div_cfc_simd(x, y, z, len);
}
void srslte_vec_div_fff(const float *x, const float *y, float *z, const uint32_t len) {
srslte_vec_div_fff_simd(x, y, z, len);
}
// PSS. convolution
cf_t srslte_vec_dot_prod_ccc(const cf_t *x, const cf_t *y, const uint32_t len) {
return srslte_vec_dot_prod_ccc_simd(x, y, len);
}
// Convolution filter and in SSS search
cf_t srslte_vec_dot_prod_cfc(const cf_t *x, const float *y, const uint32_t len) {
uint32_t i;
cf_t res = 0;
for (i=0;i<len;i++) {
res += x[i]*y[i];
}
return res;
}
// SYNC
cf_t srslte_vec_dot_prod_conj_ccc(const cf_t *x, const cf_t *y, const uint32_t len) {
return srslte_vec_dot_prod_conj_ccc_simd(x, y, len);
}
// PHICH
float srslte_vec_dot_prod_fff(const float *x, const float *y, const uint32_t len) {
uint32_t i;
float res = 0;
for (i=0;i<len;i++) {
res += x[i]*y[i];
}
return res;
}
int32_t srslte_vec_dot_prod_sss(const int16_t *x, const int16_t *y, const uint32_t len) {
return srslte_vec_dot_prod_sss_simd(x, y, len);
}
float srslte_vec_avg_power_cf(const cf_t *x, const uint32_t len) {
return crealf(srslte_vec_dot_prod_conj_ccc(x,x,len)) / len;
}
// Correlation assumes zero-mean x and y
float srslte_vec_corr_ccc(const cf_t *x, cf_t *y, const uint32_t len) {
// return crealf(srslte_vec_dot_prod_conj_ccc(x,y,len)) / len;
float s_x = crealf(srslte_vec_dot_prod_conj_ccc(x, x, len))/len;
float s_y = crealf(srslte_vec_dot_prod_conj_ccc(y, y, len))/len;
float cov = crealf(srslte_vec_dot_prod_conj_ccc(x, y, len))/len;
return cov/(sqrtf(s_x*s_y));
}
// PSS (disabled and using abs_square )
void srslte_vec_abs_cf(const cf_t *x, float *abs, const uint32_t len) {
srslte_vec_abs_cf_simd(x, abs, len);
}
// PRACH
void srslte_vec_abs_square_cf(const cf_t *x, float *abs_square, const uint32_t len) {
srslte_vec_abs_square_cf_simd(x,abs_square,len);
}
uint32_t srslte_vec_max_fi(const float *x, const uint32_t len) {
return srslte_vec_max_fi_simd(x, len);
}
uint32_t srslte_vec_max_abs_fi(const float *x, const uint32_t len) {
return srslte_vec_max_abs_fi_simd(x, len);
}
// CP autocorr
uint32_t srslte_vec_max_abs_ci(const cf_t *x, const uint32_t len) {
return srslte_vec_max_ci_simd(x, len);
}
void srslte_vec_quant_fus(float *in, uint16_t *out, float gain, float offset, float clip, uint32_t len) {
int i;
long tmp;
for (i=0;i<len;i++) {
tmp = (long) (offset + gain * in[i]);
if (tmp < 0)
tmp = 0;
if (tmp > clip)
tmp = clip;
out[i] = (uint16_t) tmp;
}
}
void srslte_vec_quant_fuc(const float *in, uint8_t *out, const float gain, const float offset, const float clip, const uint32_t len) {
int i;
int tmp;
for (i=0;i<len;i++) {
tmp = (int) (offset + gain * in[i]);
if (tmp < 0)
tmp = 0;
if (tmp > clip)
tmp = clip;
out[i] = (uint8_t) tmp;
}
}
void srslte_vec_quant_suc(const int16_t *in, uint8_t *out, const float gain, const int16_t offset, const int16_t clip, const uint32_t len) {
int i;
int16_t tmp;
for (i=0;i<len;i++) {
tmp = (int16_t) (offset + in[i]*gain);
if (tmp < 0)
tmp = 0;
if (tmp > clip)
tmp = clip;
out[i] = (uint8_t) tmp;
}
}
void srslte_vec_quant_sus(const int16_t *in, uint16_t *out, const float gain, const int16_t offset, const uint32_t len) {
int i;
int16_t tmp;
for (i=0;i<len;i++) {
tmp = (offset + in[i]*gain);
if (tmp < 0)
tmp = 0;
out[i] = (uint16_t) tmp;
}
}
void srs_vec_cf_cpy(const cf_t *src, cf_t *dst, int len) {
srslte_vec_cp_simd(src, dst, len);
}
void srslte_vec_interleave(const cf_t *x, const cf_t *y, cf_t *z, const int len) {
srslte_vec_interleave_simd(x, y, z, len);
}
void srslte_vec_interleave_add(const cf_t *x, const cf_t *y, cf_t *z, const int len) {
srslte_vec_interleave_add_simd(x, y, z, len);
}
void srslte_vec_apply_cfo(const cf_t *x, float cfo, cf_t *z, int len) {
srslte_vec_apply_cfo_simd(x, cfo, z, len);
}