diff options
Diffstat (limited to 'Transceiver52M/arch/common')
-rw-r--r-- | Transceiver52M/arch/common/Makefile.am | 15 | ||||
-rw-r--r-- | Transceiver52M/arch/common/convert.h | 15 | ||||
-rw-r--r-- | Transceiver52M/arch/common/convert_base.c | 34 | ||||
-rw-r--r-- | Transceiver52M/arch/common/convolve.h | 32 | ||||
-rw-r--r-- | Transceiver52M/arch/common/convolve_base.c | 156 | ||||
-rw-r--r-- | Transceiver52M/arch/common/fft.c | 112 | ||||
-rw-r--r-- | Transceiver52M/arch/common/fft.h | 13 | ||||
-rw-r--r-- | Transceiver52M/arch/common/mult.h | 6 | ||||
-rw-r--r-- | Transceiver52M/arch/common/scale.h | 6 |
9 files changed, 389 insertions, 0 deletions
diff --git a/Transceiver52M/arch/common/Makefile.am b/Transceiver52M/arch/common/Makefile.am new file mode 100644 index 0000000..6b37906 --- /dev/null +++ b/Transceiver52M/arch/common/Makefile.am @@ -0,0 +1,15 @@ +AM_CFLAGS = -Wall -std=gnu99 + +noinst_LTLIBRARIES = libarch_common.la + +noinst_HEADERS = \ + convolve.h \ + convert.h \ + scale.h \ + mult.h \ + fft.h + +libarch_common_la_SOURCES = \ + convolve_base.c \ + convert_base.c \ + fft.c diff --git a/Transceiver52M/arch/common/convert.h b/Transceiver52M/arch/common/convert.h new file mode 100644 index 0000000..73402b0 --- /dev/null +++ b/Transceiver52M/arch/common/convert.h @@ -0,0 +1,15 @@ +#ifndef _CONVERT_H_ +#define _CONVERT_H_ + +void convert_float_short(short *out, const float *in, float scale, int len); + +void convert_short_float(float *out, const short *in, int len); + +void base_convert_float_short(short *out, const float *in, + float scale, int len); + +void base_convert_short_float(float *out, const short *in, int len); + +void convert_init(void); + +#endif /* _CONVERT_H_ */ diff --git a/Transceiver52M/arch/common/convert_base.c b/Transceiver52M/arch/common/convert_base.c new file mode 100644 index 0000000..5251fb8 --- /dev/null +++ b/Transceiver52M/arch/common/convert_base.c @@ -0,0 +1,34 @@ +/* + * Conversion + * Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "convert.h" + +void base_convert_float_short(short *out, const float *in, + float scale, int len) +{ + for (int i = 0; i < len; i++) + out[i] = in[i] * scale; +} + +void base_convert_short_float(float *out, const short *in, int len) +{ + for (int i = 0; i < len; i++) + out[i] = in[i]; +} + diff --git a/Transceiver52M/arch/common/convolve.h b/Transceiver52M/arch/common/convolve.h new file mode 100644 index 0000000..43db577 --- /dev/null +++ b/Transceiver52M/arch/common/convolve.h @@ -0,0 +1,32 @@ +#ifndef _CONVOLVE_H_ +#define _CONVOLVE_H_ + +void *convolve_h_alloc(int num); + +int convolve_real(const float *x, int x_len, + const float *h, int h_len, + float *y, int y_len, + int start, int len, + int step, int offset); + +int convolve_complex(const float *x, int x_len, + const float *h, int h_len, + float *y, int y_len, + int start, int len, + int step, int offset); + +int base_convolve_real(const float *x, int x_len, + const float *h, int h_len, + float *y, int y_len, + int start, int len, + int step, int offset); + +int base_convolve_complex(const float *x, int x_len, + const float *h, int h_len, + float *y, int y_len, + int start, int len, + int step, int offset); + +void convolve_init(void); + +#endif /* _CONVOLVE_H_ */ diff --git a/Transceiver52M/arch/common/convolve_base.c b/Transceiver52M/arch/common/convolve_base.c new file mode 100644 index 0000000..71453a1 --- /dev/null +++ b/Transceiver52M/arch/common/convolve_base.c @@ -0,0 +1,156 @@ +/* + * Convolution + * Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <malloc.h> +#include <string.h> +#include <stdio.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Base multiply and accumulate complex-real */ +static void mac_real(const float *x, const float *h, float *y) +{ + y[0] += x[0] * h[0]; + y[1] += x[1] * h[0]; +} + +/* Base multiply and accumulate complex-complex */ +static void mac_cmplx(const float *x, const float *h, float *y) +{ + y[0] += x[0] * h[0] - x[1] * h[1]; + y[1] += x[0] * h[1] + x[1] * h[0]; +} + +/* Base vector complex-complex multiply and accumulate */ +static void mac_real_vec_n(const float *x, const float *h, float *y, + int len, int step, int offset) +{ + for (int i = offset; i < len; i += step) + mac_real(&x[2 * i], &h[2 * i], y); +} + +/* Base vector complex-complex multiply and accumulate */ +static void mac_cmplx_vec_n(const float *x, const float *h, float *y, + int len, int step, int offset) +{ + for (int i = offset; i < len; i += step) + mac_cmplx(&x[2 * i], &h[2 * i], y); +} + +/* Base complex-real convolution */ +int _base_convolve_real(const float *x, int x_len, + const float *h, int h_len, + float *y, int y_len, + int start, int len, + int step, int offset) +{ + for (int i = 0; i < len; i++) { + mac_real_vec_n(&x[2 * (i - (h_len - 1) + start)], + h, + &y[2 * i], h_len, + step, offset); + } + + return len; +} + +/* Base complex-complex convolution */ +int _base_convolve_complex(const float *x, int x_len, + const float *h, int h_len, + float *y, int y_len, + int start, int len, + int step, int offset) +{ + for (int i = 0; i < len; i++) { + mac_cmplx_vec_n(&x[2 * (i - (h_len - 1) + start)], + h, + &y[2 * i], + h_len, step, offset); + } + + return len; +} + +/* Buffer validity checks */ +int bounds_check(int x_len, int h_len, int y_len, + int start, int len, int step) +{ + if ((x_len < 1) || (h_len < 1) || + (y_len < 1) || (len < 1) || (step < 1)) { + fprintf(stderr, "Convolve: Invalid input\n"); + return -1; + } + + if ((start + len > x_len) || (len > y_len) || (x_len < h_len)) { + fprintf(stderr, "Convolve: Boundary exception\n"); + fprintf(stderr, "start: %i, len: %i, x: %i, h: %i, y: %i\n", + start, len, x_len, h_len, y_len); + return -1; + } + + return 0; +} + +/* API: Non-aligned (no SSE) complex-real */ +int base_convolve_real(const float *x, int x_len, + const float *h, int h_len, + float *y, int y_len, + int start, int len, + int step, int offset) +{ + if (bounds_check(x_len, h_len, y_len, start, len, step) < 0) + return -1; + + memset(y, 0, len * 2 * sizeof(float)); + + return _base_convolve_real(x, x_len, + h, h_len, + y, y_len, + start, len, step, offset); +} + +/* API: Non-aligned (no SSE) complex-complex */ +int base_convolve_complex(const float *x, int x_len, + const float *h, int h_len, + float *y, int y_len, + int start, int len, + int step, int offset) +{ + if (bounds_check(x_len, h_len, y_len, start, len, step) < 0) + return -1; + + memset(y, 0, len * 2 * sizeof(float)); + + return _base_convolve_complex(x, x_len, + h, h_len, + y, y_len, + start, len, step, offset); +} + +/* Aligned filter tap allocation */ +void *convolve_h_alloc(int len) +{ +#ifdef HAVE_SSE3 + return memalign(16, len * 2 * sizeof(float)); +#else + return malloc(len * 2 * sizeof(float)); +#endif +} diff --git a/Transceiver52M/arch/common/fft.c b/Transceiver52M/arch/common/fft.c new file mode 100644 index 0000000..18b2de7 --- /dev/null +++ b/Transceiver52M/arch/common/fft.c @@ -0,0 +1,112 @@ +/* + * Fast Fourier transform + * + * Copyright (C) 2012 Tom Tsou <tom@tsou.cc> + * + * This program 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. + * + * This program 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. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * See the COPYING file in the main directory for details. + */ + +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <fftw3.h> + +#include "fft.h" + +struct fft_hdl { + float *fft_in; + float *fft_out; + int len; + fftwf_plan fft_plan; +}; + +/*! \brief Initialize FFT backend + * \param[in] reverse FFT direction + * \param[in] m FFT length + * \param[in] istride input stride count + * \param[in] ostride output stride count + * \param[in] in input buffer (FFTW aligned) + * \param[in] out output buffer (FFTW aligned) + * \param[in] ooffset initial offset into output buffer + * + * If the reverse is non-NULL, then an inverse FFT will be used. This is a + * wrapper for advanced non-contiguous FFTW usage. See FFTW documentation for + * further details. + * + * http://www.fftw.org/doc/Advanced-Complex-DFTs.html + * + * It is currently unknown how the offset of the output buffer affects FFTW + * memory alignment. + */ +struct fft_hdl *init_fft(int reverse, int m, int istride, int ostride, + float *in, float *out, int ooffset) +{ + int rank = 1; + int n[] = { m }; + int howmany = istride; + int idist = 1; + int odist = 1; + int *inembed = n; + int *onembed = n; + fftwf_complex *obuffer, *ibuffer; + + struct fft_hdl *hdl = (struct fft_hdl *) malloc(sizeof(struct fft_hdl)); + if (!hdl) + return NULL; + + int direction = FFTW_FORWARD; + if (reverse) + direction = FFTW_BACKWARD; + + ibuffer = (fftwf_complex *) in; + obuffer = (fftwf_complex *) out + ooffset; + + hdl->fft_in = in; + hdl->fft_out = out; + hdl->fft_plan = fftwf_plan_many_dft(rank, n, howmany, + ibuffer, inembed, istride, idist, + obuffer, onembed, ostride, odist, + direction, FFTW_MEASURE); + return hdl; +} + +void *fft_malloc(size_t size) +{ + return fftwf_malloc(size); +} + +void fft_free(void *ptr) +{ + free(ptr); +} + +/*! \brief Free FFT backend resources + */ +void free_fft(struct fft_hdl *hdl) +{ + fftwf_destroy_plan(hdl->fft_plan); + free(hdl); +} + +/*! \brief Run multiple DFT operations with the initialized plan + * \param[in] hdl handle to an intitialized fft struct + * + * Input and output buffers are configured with init_fft(). + */ +int cxvec_fft(struct fft_hdl *hdl) +{ + fftwf_execute(hdl->fft_plan); + return 0; +} diff --git a/Transceiver52M/arch/common/fft.h b/Transceiver52M/arch/common/fft.h new file mode 100644 index 0000000..fb7bede --- /dev/null +++ b/Transceiver52M/arch/common/fft.h @@ -0,0 +1,13 @@ +#ifndef _FFT_H_ +#define _FFT_H_ + +struct fft_hdl; + +struct fft_hdl *init_fft(int reverse, int m, int istride, int ostride, + float *in, float *out, int ooffset); +void *fft_malloc(size_t size); +void fft_free(void *ptr); +void free_fft(struct fft_hdl *hdl); +int cxvec_fft(struct fft_hdl *hdl); + +#endif /* _FFT_H_ */ diff --git a/Transceiver52M/arch/common/mult.h b/Transceiver52M/arch/common/mult.h new file mode 100644 index 0000000..4d96efb --- /dev/null +++ b/Transceiver52M/arch/common/mult.h @@ -0,0 +1,6 @@ +#ifndef _MULT_H_ +#define _MULT_H_ + +void mul_complex(float *out, float *a, float *b, int len); + +#endif /* _MULT_H_ */ diff --git a/Transceiver52M/arch/common/scale.h b/Transceiver52M/arch/common/scale.h new file mode 100644 index 0000000..da867e7 --- /dev/null +++ b/Transceiver52M/arch/common/scale.h @@ -0,0 +1,6 @@ +#ifndef _SCALE_H_ +#define _SCALE_H_ + +void scale_complex(float *out, float *in, float *scale, int len); + +#endif /* _SCALE_H_ */ |