Introduction
postlong(size);
The FTS Vector Function Library provides a C API to a number of frequently used DSP routines.
Most of them are vector routines in the sence of applying a certain function to each element of an array.
Others (like the dot product) implement true vector operations.
Each function of this library exists in two versions.
One of these functions can be called with arrays of any size.
Its name starts with the prefix "fts_vec_
" followed by the actual function name.
The name of the second version of each function has the prefix "fts_vecx_
".
It is probable that this calls a routine using loop unrolling to fasten the execution.
At least will this version run as fast as the other.
It can be applied only to vectors of a size which is a multiple of a constant.
The value of this constant can be different for different plattforms and is assigned to the C macro FTS_VECX_BASE. However the user can rely on following assumptions:
The arguments in the signature of the "vec
" and the "vecx
"
version of a function are strictly the same.
To keep this documentation brief in the following reference just the "fts_vec_
..."
function call is listed representing both versions.
float
as general floating point and
long
as integer data type.
The complex
type is defined as a couple
of two floats in a C structure:
Since this can be eather in rectangular or in polar representation C marcos are defined to
support writing readable code.
typdef struct{
float re;
float im;
} complex;
In case of rectangular representation use:
In case of polar representation use:
complex z;
float re = z.RE; /* real part of z */
float im = z.IM; /* imaginary part of z */
complex z;
float mag = z.MAG; /* magnitude of z */
float arg = z.ARG; /* argument of z */
Is an operation provided for two vectors as well as for a vector and a scalar
- again like the arithmetic and comparison functions -,
the vector/scalar version has a prefix like "fts_vec_scl_
" or "fts_vecx_scl_
".
out[i] = in0[i] + in1[i], for i = 0...size-1
out[i] = in0[i] - in1[i], for i = 0...size-1
out[i] = in0[i] * in1[i], for i = 0...size-1
out[i] = in0[i] / in1[i], for i = 0...size-1
The vector elements are treated as if they are in rectangular representation.
The dot product is implemented for float vectors only.
*ptr = sum(in0[i] * in1[i], for i = 0...size-1)
out[i].RE = in0[i].RE * in1[i], out[i].IM = in0[i].IM * in1[i],
for i = 0...size-1)
fts_vec_fadd(float *in0, float *in1, float *out, long size);
fts_vec_fsub(float *in0, float *in1, float *out, long size);
fts_vec_fmul(float *in0, float *in1, float *out, long size);
fts_vec_fdiv(float *in0, float *in1, float *out, long size);
fts_vec_fdot(float *in0, float *in1, float *ptr, long size);
fts_vec_iadd(long *in0, long *in1, long *out, long size);
fts_vec_isub(long *in0, long *in1, long *out, long size);
fts_vec_imul(long *in0, long *in1, long *out, long size);
fts_vec_idiv(long *in0, long *in1, long *out, long size);
fts_vec_cadd(complex *in0, complex *in1, complex *out, long size);
fts_vec_csub(complex *in0, complex *in1, complex *out, long size);
fts_vec_cmul(complex *in0, complex *in1, complex *out, long size);
fts_vec_cdiv(complex *in0, complex *in1, complex *out, long size);
fts_vec_cfmul(complex *in0, float *in1, complex *out, long size);
out[i] = in[i] + scl, for i = 0...size-1
out[i] = in[i] - scl, for i = 0...size-1
out[i] = in[i] * scl, for i = 0...size-1
out[i] = scl - in[i], for i = 0...size-1
out[i] = scl / in[i], for i = 0...size-1
The vector elements are treated as if they are in rectangular representation.
The mixed complex/float multiplication scales a complex vector with a float scalar.
out[i].RE = in[i].RE * scl, out[i].IM = in[i].IM * scl,
for i = 0...size-1)
fts_vec_scl_fadd(float *in, float scl, float *out, long size);
fts_vec_scl_fsub(float *in, float scl, float *out, long size);
fts_vec_scl_fmul(float *in, float scl, float *out, long size);
fts_vec_scl_fdiv(float *in, float scl, float *out, long size);
fts_vec_scl_fbus(float *in, float scl, float *out, long size);
fts_vec_scl_fvid(float *in, float scl, float *out, long size);
fts_vec_scl_iadd(long *in, long scl, long *out, long size);
fts_vec_scl_isub(long *in, long scl, long *out, long size);
fts_vec_scl_imul(long *in, long scl, long *out, long size);
fts_vec_scl_idiv(long *in, long scl, long *out, long size);
fts_vec_scl_ibus(long *in, long scl, long *out, long size);
fts_vec_scl_ivid(long *in, long scl, long *out, long size);
fts_vec_scl_cadd(complex *in, complex scl, complex *out, long size);
fts_vec_scl_csub(complex *in, complex scl, complex *out, long size);
fts_vec_scl_cmul(complex *in, complex scl, complex *out, long size);
fts_vec_scl_cdiv(complex *in, complex scl, complex *out, long size);
fts_vec_scl_cbus(complex *in, complex scl, complex *out, long size);
fts_vec_scl_cvid(complex *in, complex scl, complex *out, long size);
fts_vec_scl_cfmul(complex *in, float scl, complex *out, long size);
out[i] = (in0[i] == in1[i]), for i = 0...size-1
out[i] = (in0[i] != in1[i]), for i = 0...size-1
out[i] = (in0[i] < = in1[i]), for i = 0...size-1
out[i] = (in0[i] > = in1[i]), for i = 0...size-1
out[i] = (in0[i] < in1[i]), for i = 0...size-1
out[i] = (in0[i] > in1[i]), for i = 0...size-1
fts_vec_fcmp_eq(float *in0, float *in1, long *out, long size);
fts_vec_fcmp_neq(float *in0, float *in1, long *out, long size);
fts_vec_fcmp_leq(float *in0, float *in1, long *out, long size);
fts_vec_fcmp_geq(float *in0, float *in1, long *out, long size);
fts_vec_fcmp_lt(float *in0, float *in1, long *out, long size);
fts_vec_fcmp_gt(float *in0, float *in1, long *out, long size);
fts_vec_icmp_eq(long *in0, long *in1, long *out, long size);
fts_vec_icmp_neq(long *in0, long *in1, long *out, long size);
fts_vec_icmp_leq(long *in0, long *in1, long *out, long size);
fts_vec_icmp_geq(long *in0, long *in1, long *out, long size);
fts_vec_icmp_lt(long *in0, long *in1, long *out, long size);
fts_vec_icmp_gt(long *in0, long *in1, long *out, long size);
out[i] = (in[i] == scl), for i = 0...size-1
out[i] = (in[i] != scl), for i = 0...size-1
out[i] = (in[i] < = scl), for i = 0...size-1
out[i] = (in[i] > = scl), for i = 0...size-1
out[i] = (in[i] < scl), for i = 0...size-1
out[i] = (in[i] > scl), for i = 0...size-1
fts_vec_scl_fcmp_eq(float *in, float scl, long *out, long size);
fts_vec_scl_fcmp_neq(float *in, float scl, long *out, long size);
fts_vec_scl_fcmp_leq(float *in, float scl, long *out, long size);
fts_vec_scl_fcmp_geq(float *in, float scl, long *out, long size);
fts_vec_scl_fcmp_lt(float *in, float scl, long *out, long size);
fts_vec_scl_fcmp_gt(float *in, float scl, long *out, long size);
fts_vec_scl_icmp_eq(long *in, long scl, long *out, long size);
fts_vec_scl_icmp_neq(long *in, long scl, long *out, long size);
fts_vec_scl_icmp_leq(long *in, long scl, long *out, long size);
fts_vec_scl_icmp_geq(long *in, long scl, long *out, long size);
fts_vec_scl_icmp_lt(long *in, long scl, long *out, long size);
fts_vec_scl_icmp_gt(long *in, long scl, long *out, long size);
*ptr = min(in[i], for i = 0...size-1)
*ptr = max(in[i], for i = 0...size-1)
*ptr = sum(in[i], for i = 0...size-1)
fts_vec_fmin(float *in, float *ptr, long size);
fts_vec_fmax(float *in, float *ptr, long size);
fts_vec_fsum(float *in, float *ptr, long size);
fts_vec_imin(long *in, long *ptr, long size);
fts_vec_imax(long *in, long *ptr, long size);
fts_vec_isum(long *in, long *ptr, long size);
fts_vec_csum(complex *in, complex *ptr, long size);
out[i].RE = |in[i]|, for i = 0...size-1
out[i] = (in[i] < min)? (min):
((in[i] > max)? (max): (in[i])),
for i = 0...size-1
out[i] = scl, for i = 0...size-1
out[i] = 0, for i = 0...size-1
out[i] = in[i], for i = 0...size-1
fts_vec_fabs(float *in, float *out, long size);
fts_vec_fclip(float *in, float min, float max, float *out,
long size);
fts_vec_ffill(float scl, float *out, long size);
fts_vec_fzero(float *out, long size);
fts_vec_fcpy(float *in, float *out, long size);
fts_vec_iabs(long *in, long *out, long size);
fts_vec_iclip(long *in, long min, long max, long *out,
long size);
fts_vec_ifill(long scl, long *out, long size);
fts_vec_izero(long *out, long size);
fts_vec_icpy(long *in, long *out, long size);
fts_vec_cabs(complex *in, complex *out, long size);
fts_vec_cfill(complex scl, complex *out, long size);
fts_vec_czero(complex *out, long size);
fts_vec_ccpy(complex *in, complex *out, long size);
Most of them call functions equivalent to those of the ANSI C math library for each element of a vector:
out[i] = sin(in[i]), for i = 0...size-1
exp
):
out[i] = exp(scl * in[i]), for i = 0...size-1
log
):
out[i] = scl * log(in[i]), for i = 0...size-1
out[i] = 1./sqrt(in[i]), for i = 0...size-1
fts_vec_sin(float *in, float *out, long size);
fts_vec_cos(float *in, float *out, long size);
fts_vec_tan(float *in, float *out, long size);
fts_vec_asin(float *in, float *out, long size);
fts_vec_acos(float *in, float *out, long size);
fts_vec_atan(float *in, float *out, long size);
fts_vec_sinh(float *in, float *out, long size);
fts_vec_cosh(float *in, float *out, long size);
fts_vec_tanh(float *in, float *out, long size);
fts_vec_exp(float *in, float *out, long size);
fts_vec_log(float *in, float *out, long size);
fts_vec_log10(float *in, float *out, long size);
fts_vec_expb(float *in, float scl, float *out, long size);
fts_vec_logb(float *in, float scl, float *out, long size);
fts_vec_sqrt(float *in, float *out, long size);
fts_vec_rsqrt(float *in, float *out, long size);
Just like the arithmetic operations and the comparison functions,
the bitwise operations (not the not
)
are available as a conjunction of a
vector with another vector
(in0 and in1) or a
vector with a scalar
(in and scl):
out[i] = in[i], for i = 0...size-1
out[i] = in0[i] & in1[i], for i = 0...size-1
out[i] = in[i] & scl, for i = 0...size-1
out[i] = in0[i] | in1[i], for i = 0...size-1
out[i] = in[i] | scl, for i = 0...size-1
out[i] = in0[i] ^ in1[i], for i = 0...size-1
out[i] = in[i] ^ scl, for i = 0...size-1
out[i] = in0[i] < < in1[i], for i = 0...size-1
out[i] = in[i] < < scl, for i = 0...size-1
out[i] = in0[i] > > in1[i], for i = 0...size-1
out[i] = in[i] > > scl, for i = 0...size-1
fts_vec_bitnot(long *in, long *out, long size);
fts_vec_bitand(long *in0, long *in1, long *out, long size);
fts_vec_bitor(long *in0, long *in1, long *out, long size);
fts_vec_bitxor(long *in0, long *in1, long *out, long size);
fts_vec_bitshl(long *in0, long *in1, long *out, long size);
fts_vec_bitshr(long *in0, long *in1, long *out, long size);
fts_vec_scl_bitand(long *in, long scl, long *out, long size);
fts_vec_scl_bitor(long *in, long scl, long *out, long size);
fts_vec_scl_bitxor(long *in, long scl, long *out, long size);
fts_vec_scl_bitshl(long *in, long scl, long *out, long size);
fts_vec_scl_bitshr(long *in, long scl, long *out, long size);
crect
the vector elements are treated as if they are in
rectangular representation):
out[i].RE = in[i].RE, out[i].IM = -in[i].IM,
for i = 0...size-1
out[i].RE = in[i].RE * in[i].RE + in[i].IM * in[i].IM,
for i = 0...size-1
out[i].MAG = cabs(in), out[i].ARG = atan2(in[i].IM, in[i].RE),
for i = 0...size-1
out[i].RE = in[i].MAG * cos(in[i].ARG),
out[i].IM = in[i].MAG * sin(in[i].ARG),
for i = 0...size-1
fts_vec_conj(complex *in, complex *out, long size);
fts_vec_csqr(complex *in, complex *out, long size);
fts_vec_cpolar(complex *in, complex *out, long size);
fts_vec_crect(complex *in, complex *out, long size);
(in all functions converting complex vectors the complex vector elements are treated as if they are in rectangular representation):
out[i] = sqrt(in[i].RE * in[i].RE + in[i].IM * in[i].IM),
for i = 0...size-1
out[i] = in[i].RE * in[i].RE + in[i].IM * in[i].IM,
for i = 0...size-1
out0[i] = in[i].RE, out1[i] = in[i].IM, for i = 0...size-1
out[i].RE = in0[i], out[i].IM = in1[i], for i = 0...size-1
out[i].RE = in[i], for i = 0...size-1
out[i].IM = in[i], for i = 0...size-1
out[i].RE = scl, for i = 0...size-1
out[i].IM = scl, for i = 0...size-1
out[i] = in[i].RE, for i = 0...size-1
out[i] = in[i].IM, for i = 0...size-1
out[i] = (long)in[i], for i = 0...size-1
out[i] = (float)in[i], for i = 0...size-1
out[i] = (long)(in[i] + 0.5), for i = 0...size-1
fts_vec_cabsf(complex *in, float *out, long size);
fts_vec_csqrf(complex *in, float *out, long size);
fts_vec_re(complex in, float *out, long size);
fts_vec_im(complex in, float *out, long size);
fts_vec_csplit(complex *in0, float *out0, float *out1, long size);
fts_vec_cmerge(float *in0, float *in1, complex *out, long size);
fts_vec_fcpyre(float *in, complex *out, long size);
fts_vec_fcpyim(float *in, complex *out, long size);
fts_vec_ffillre(float scl, complex *out, long size);
fts_vec_ffillim(float scl, complex *out, long size);
fts_vec_fcasti(float *in, long *out, long size);
fts_vec_icastf(long *in, float *out, long size);
fts_vec_round(float *in, long *out, long size);
The "real" FFT's are computed for a float time domain signal of size by use of a size/2 point complex FFT and some extra computation. In frequency domain there is just half of the complex spectrum and a single float for the signed magnitude of the bin related to the half sampling frequency.
There are two versions of each FFT function; one does the computation inplace the other may be used inplace as well as out of place. The inplace versions might be a little more efficient on some plattforms.
The size argument is allways related to the time domain data (number of float or complex points) and
must be strictly a power of two.
The lower and upper limit of the size is assigned to C makros.
This range can be guarantied for all plattforms, but on a single plattform the called routine
(and with it the efficientcy of the FFT computation) might depend on the size argument.
FTS_MIN_FFT_SIZE 16
FTS_MAX_FFT_SIZE 134217728
Ones before an FFT computation of a certain size the function fts_fft_declaresize()
must be
called successfully with the size argument.
The call of this function might cause the allocation and initialisation of FFT coefficient tables.
The function fts_is_fft_size()
returns non zero if the given size argument is possible
for an FFT computation, otherwise zero.
The other FFT functions return fts_Success
in case of success, otherwise an error handle.
fts_status_t fts_fft_declaresize(long size);
int fts_is_fft_size(long size);
fts_status_t fts_cfft(complex *in, complex *out, long size);
fts_status_t fts_cfft_inplc(complex *buf, long size);
fts_status_t fts_cifft(complex *in, complex *buf, long size);
fts_status_t fts_cifft_inplc(complex *buf, long size);
fts_status_t fts_rfft(float *in, complex *out, float *mag_pi, long size);
fts_status_t fts_rfft_inplc(float *buf, float *mag_pi, long size);
fts_status_t fts_rifft(complex *in, float mag_pi, float *out, long size);
fts_status_t fts_rifft_inplc(float *buf, float mag_pi, long size);
Author: nos
Copyright © 1996 IRCAM .