2017-07-26 06:22:14 +00:00
|
|
|
/*=============================================================================
|
|
|
|
Copyright (c) 2011-2016 Bolero MURAKAMI
|
|
|
|
https://github.com/bolero-MURAKAMI/Sprout
|
|
|
|
|
|
|
|
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
|
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
=============================================================================*/
|
|
|
|
#ifndef SPROUT_NUMERIC_FFT_FIXED_FFT_HPP
|
|
|
|
#define SPROUT_NUMERIC_FFT_FIXED_FFT_HPP
|
|
|
|
|
|
|
|
#include <sprout/config.hpp>
|
|
|
|
#include <sprout/array.hpp>
|
|
|
|
#include <sprout/index_tuple/make_index_tuple.hpp>
|
|
|
|
#include <sprout/algorithm/fixed/results.hpp>
|
|
|
|
#include <sprout/complex.hpp>
|
|
|
|
#include <sprout/math/less.hpp>
|
|
|
|
#include <sprout/pit/pit.hpp>
|
|
|
|
#include <sprout/numeric/fft/coefficients.hpp>
|
|
|
|
|
|
|
|
namespace sprout {
|
|
|
|
namespace fixed {
|
|
|
|
namespace detail {
|
|
|
|
template<typename value_type, std::size_t Size>
|
|
|
|
inline SPROUT_CONSTEXPR sprout::complex<value_type>
|
|
|
|
fft_element(
|
|
|
|
sprout::array<sprout::complex<value_type>, Size> const& arr,
|
|
|
|
std::size_t step, std::size_t i, std::size_t j, bool sub,
|
|
|
|
sprout::array<sprout::complex<value_type>, Size> const& coeffs
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return sub
|
|
|
|
? arr[i * step + j] - coeffs[j * (Size / 2 / step)] * arr[i * step + j + Size / 2]
|
|
|
|
: arr[i * step + j] + coeffs[j * (Size / 2 / step)] * arr[i * step + j + Size / 2]
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename value_type, std::size_t Size, sprout::index_t... Indexes>
|
|
|
|
inline SPROUT_CONSTEXPR sprout::array<sprout::complex<value_type>, Size>
|
|
|
|
butterfly(
|
|
|
|
sprout::array<sprout::complex<value_type>, Size> const& arr,
|
|
|
|
std::size_t step,
|
|
|
|
sprout::array<sprout::complex<value_type>, Size> const& coeffs,
|
|
|
|
sprout::index_tuple<Indexes...>
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return sprout::array<sprout::complex<value_type>, Size> { {
|
|
|
|
fft_element(arr, step, Indexes / (step * 2), Indexes%step, (Indexes&step) != 0, coeffs)...
|
|
|
|
} };
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename value_type, std::size_t Size>
|
|
|
|
inline SPROUT_CONSTEXPR sprout::array<sprout::complex<value_type>, Size>
|
|
|
|
fft_loop(
|
|
|
|
sprout::array<sprout::complex<value_type>, Size> const& arr,
|
|
|
|
std::size_t step,
|
|
|
|
sprout::array<sprout::complex<value_type>, Size> const& coeffs
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return step == Size ? arr
|
|
|
|
: fft_loop(butterfly(arr, step, coeffs, sprout::make_index_tuple<Size>()), step * 2, coeffs);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename value_type, std::size_t Size>
|
|
|
|
inline SPROUT_CONSTEXPR sprout::array<sprout::complex<value_type>, Size>
|
|
|
|
fft(sprout::array<sprout::complex<value_type>, Size> const& arr) {
|
|
|
|
return fft_loop(arr, 1, sprout::make_fft_coefficients<value_type, Size>());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<typename Container, sprout::index_t... Indexes>
|
|
|
|
inline SPROUT_CONSTEXPR sprout::array<typename sprout::container_traits<Container>::value_type, sizeof...(Indexes)>
|
|
|
|
make_input_impl(Container const& cont, sprout::index_tuple<Indexes...>) {
|
|
|
|
return sprout::array<typename sprout::container_traits<Container>::value_type, sizeof...(Indexes)> { {
|
|
|
|
(sprout::math::less(Indexes, cont.size())
|
|
|
|
? *sprout::next(sprout::begin(cont), Indexes)
|
|
|
|
: static_cast<typename sprout::container_traits<Container>::value_type>(0)
|
|
|
|
)...
|
|
|
|
} };
|
|
|
|
}
|
|
|
|
template<std::size_t Size, typename Container>
|
|
|
|
inline SPROUT_CONSTEXPR sprout::array<typename sprout::container_traits<Container>::value_type, Size>
|
|
|
|
make_input(Container const& cont) {
|
|
|
|
return make_input_impl(cont, sprout::make_index_tuple<Size>());
|
|
|
|
}
|
|
|
|
template<typename value_type, std::size_t Size, typename Result, sprout::index_t... Indexes>
|
|
|
|
inline SPROUT_CONSTEXPR typename sprout::fixed::results::algorithm<Result>::type
|
|
|
|
make_fft_result_impl(sprout::array<sprout::complex<value_type>, Size> const& cont, Result const& result, sprout::index_tuple<Indexes...>) {
|
|
|
|
return remake<Result>(result, sprout::size(result), cont[Indexes]...);
|
|
|
|
}
|
|
|
|
template<typename value_type, std::size_t Size, typename Result>
|
|
|
|
inline SPROUT_CONSTEXPR typename sprout::fixed::results::algorithm<Result>::type
|
|
|
|
make_fft_result(sprout::array<sprout::complex<value_type>, Size> const& cont, Result const& result) {
|
|
|
|
return make_fft_result_impl(cont, result, sprout::make_index_tuple<sprout::container_traits<Result>::static_size>());
|
|
|
|
}
|
|
|
|
} // namespace detail
|
|
|
|
//
|
|
|
|
// fft
|
|
|
|
// Algorithm: Stockham decimation-in-time
|
|
|
|
//
|
|
|
|
template<typename Container, typename Result>
|
|
|
|
inline SPROUT_CONSTEXPR typename sprout::fixed::results::algorithm<Result>::type
|
|
|
|
fft(Container const& cont, Result const& result) {
|
|
|
|
return sprout::fixed::detail::make_fft_result(
|
|
|
|
sprout::fixed::detail::fft(sprout::fixed::detail::make_input<sprout::container_traits<Result>::static_size>(cont)), result
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Result, typename Container>
|
|
|
|
inline SPROUT_CONSTEXPR typename sprout::fixed::results::algorithm<Result>::type
|
|
|
|
fft(Container const& cont) {
|
|
|
|
return sprout::fixed::fft(cont, sprout::pit<Result>());
|
|
|
|
}
|
|
|
|
} // namespace fixed
|
|
|
|
|
|
|
|
using sprout::fixed::fft;
|
|
|
|
} // namespace sprout
|
|
|
|
|
|
|
|
#endif // #ifndef SPROUT_NUMERIC_FFT_FIXED_FFT_HPP
|