mirror of
https://github.com/Serial-Studio/Serial-Studio.git
synced 2025-01-31 17:42:55 +08:00
184 lines
6.0 KiB
C++
184 lines
6.0 KiB
C++
/*****************************************************************************
|
|
|
|
FFTRealPassDirect.hpp
|
|
By Laurent de Soras
|
|
|
|
--- Legal stuff ---
|
|
|
|
This program is free software. It comes without any warranty, to
|
|
the extent permitted by applicable law. You can redistribute it
|
|
and/or modify it under the terms of the Do What The Fuck You Want
|
|
To Public License, Version 2, as published by Sam Hocevar. See
|
|
http://sam.zoy.org/wtfpl/COPYING for more details.
|
|
|
|
*Tab=3***********************************************************************/
|
|
|
|
#if defined(ffft_FFTRealPassDirect_CURRENT_CODEHEADER)
|
|
# error Recursive inclusion of FFTRealPassDirect code header.
|
|
#endif
|
|
#define ffft_FFTRealPassDirect_CURRENT_CODEHEADER
|
|
|
|
#if !defined(ffft_FFTRealPassDirect_CODEHEADER_INCLUDED)
|
|
# define ffft_FFTRealPassDirect_CODEHEADER_INCLUDED
|
|
|
|
/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
|
|
|
|
# include "FFTRealUseTrigo.h"
|
|
|
|
namespace ffft
|
|
{
|
|
|
|
/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
|
|
|
|
template<>
|
|
inline void
|
|
FFTRealPassDirect<1>::process(long len, DataType dest_ptr[], DataType src_ptr[],
|
|
const DataType x_ptr[], const DataType cos_ptr[],
|
|
long cos_len, const long br_ptr[],
|
|
OscType osc_list[])
|
|
{
|
|
(void)src_ptr;
|
|
(void)cos_len;
|
|
(void)cos_ptr;
|
|
(void)osc_list;
|
|
// First and second pass at once
|
|
const long qlen = len >> 2;
|
|
|
|
long coef_index = 0;
|
|
do
|
|
{
|
|
// To do: unroll the loop (2x).
|
|
const long ri_0 = br_ptr[coef_index >> 2];
|
|
const long ri_1 = ri_0 + 2 * qlen; // bit_rev_lut_ptr [coef_index + 1];
|
|
const long ri_2 = ri_0 + 1 * qlen; // bit_rev_lut_ptr [coef_index + 2];
|
|
const long ri_3 = ri_0 + 3 * qlen; // bit_rev_lut_ptr [coef_index + 3];
|
|
|
|
DataType *const df2 = dest_ptr + coef_index;
|
|
df2[1] = x_ptr[ri_0] - x_ptr[ri_1];
|
|
df2[3] = x_ptr[ri_2] - x_ptr[ri_3];
|
|
|
|
const DataType sf_0 = x_ptr[ri_0] + x_ptr[ri_1];
|
|
const DataType sf_2 = x_ptr[ri_2] + x_ptr[ri_3];
|
|
|
|
df2[0] = sf_0 + sf_2;
|
|
df2[2] = sf_0 - sf_2;
|
|
|
|
coef_index += 4;
|
|
} while (coef_index < len);
|
|
}
|
|
|
|
template<>
|
|
inline void
|
|
FFTRealPassDirect<2>::process(long len, DataType dest_ptr[], DataType src_ptr[],
|
|
const DataType x_ptr[], const DataType cos_ptr[],
|
|
long cos_len, const long br_ptr[],
|
|
OscType osc_list[])
|
|
{
|
|
// Executes "previous" passes first. Inverts source and destination buffers
|
|
FFTRealPassDirect<1>::process(len, src_ptr, dest_ptr, x_ptr, cos_ptr, cos_len,
|
|
br_ptr, osc_list);
|
|
|
|
// Third pass
|
|
const DataType sqrt2_2 = DataType(SQRT2 * 0.5);
|
|
|
|
long coef_index = 0;
|
|
do
|
|
{
|
|
dest_ptr[coef_index] = src_ptr[coef_index] + src_ptr[coef_index + 4];
|
|
dest_ptr[coef_index + 4] = src_ptr[coef_index] - src_ptr[coef_index + 4];
|
|
dest_ptr[coef_index + 2] = src_ptr[coef_index + 2];
|
|
dest_ptr[coef_index + 6] = src_ptr[coef_index + 6];
|
|
|
|
DataType v;
|
|
|
|
v = (src_ptr[coef_index + 5] - src_ptr[coef_index + 7]) * sqrt2_2;
|
|
dest_ptr[coef_index + 1] = src_ptr[coef_index + 1] + v;
|
|
dest_ptr[coef_index + 3] = src_ptr[coef_index + 1] - v;
|
|
|
|
v = (src_ptr[coef_index + 5] + src_ptr[coef_index + 7]) * sqrt2_2;
|
|
dest_ptr[coef_index + 5] = v + src_ptr[coef_index + 3];
|
|
dest_ptr[coef_index + 7] = v - src_ptr[coef_index + 3];
|
|
|
|
coef_index += 8;
|
|
} while (coef_index < len);
|
|
}
|
|
|
|
template<int PASS>
|
|
void FFTRealPassDirect<PASS>::process(long len, DataType dest_ptr[],
|
|
DataType src_ptr[],
|
|
const DataType x_ptr[],
|
|
const DataType cos_ptr[], long cos_len,
|
|
const long br_ptr[], OscType osc_list[])
|
|
{
|
|
// Executes "previous" passes first. Inverts source and destination buffers
|
|
FFTRealPassDirect<PASS - 1>::process(len, src_ptr, dest_ptr, x_ptr, cos_ptr,
|
|
cos_len, br_ptr, osc_list);
|
|
|
|
const long dist = 1L << (PASS - 1);
|
|
const long c1_r = 0;
|
|
const long c1_i = dist;
|
|
const long c2_r = dist * 2;
|
|
const long c2_i = dist * 3;
|
|
const long cend = dist * 4;
|
|
const long table_step = cos_len >> (PASS - 1);
|
|
|
|
enum
|
|
{
|
|
TRIGO_OSC = PASS - FFTRealFixLenParam::TRIGO_BD_LIMIT
|
|
};
|
|
enum
|
|
{
|
|
TRIGO_DIRECT = (TRIGO_OSC >= 0) ? 1 : 0
|
|
};
|
|
|
|
long coef_index = 0;
|
|
do
|
|
{
|
|
const DataType *const sf = src_ptr + coef_index;
|
|
DataType *const df = dest_ptr + coef_index;
|
|
|
|
// Extreme coefficients are always real
|
|
df[c1_r] = sf[c1_r] + sf[c2_r];
|
|
df[c2_r] = sf[c1_r] - sf[c2_r];
|
|
df[c1_i] = sf[c1_i];
|
|
df[c2_i] = sf[c2_i];
|
|
|
|
FFTRealUseTrigo<TRIGO_DIRECT>::prepare(osc_list[TRIGO_OSC]);
|
|
|
|
// Others are conjugate complex numbers
|
|
for (long i = 1; i < dist; ++i)
|
|
{
|
|
DataType c;
|
|
DataType s;
|
|
FFTRealUseTrigo<TRIGO_DIRECT>::iterate(osc_list[TRIGO_OSC], c, s, cos_ptr,
|
|
i * table_step,
|
|
(dist - i) * table_step);
|
|
|
|
const DataType sf_r_i = sf[c1_r + i];
|
|
const DataType sf_i_i = sf[c1_i + i];
|
|
|
|
const DataType v1 = sf[c2_r + i] * c - sf[c2_i + i] * s;
|
|
df[c1_r + i] = sf_r_i + v1;
|
|
df[c2_r - i] = sf_r_i - v1;
|
|
|
|
const DataType v2 = sf[c2_r + i] * s + sf[c2_i + i] * c;
|
|
df[c2_r + i] = v2 + sf_i_i;
|
|
df[cend - i] = v2 - sf_i_i;
|
|
}
|
|
|
|
coef_index += cend;
|
|
} while (coef_index < len);
|
|
}
|
|
|
|
/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
|
|
|
|
/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
|
|
|
|
} // namespace ffft
|
|
|
|
#endif // ffft_FFTRealPassDirect_CODEHEADER_INCLUDED
|
|
|
|
#undef ffft_FFTRealPassDirect_CURRENT_CODEHEADER
|
|
|
|
/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
|