dct.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. #include "simple/compress/fft.hpp"
  2. #include "simple/support/random.hpp"
  3. #include <cassert>
  4. #include <vector>
  5. #include <cmath>
  6. #include <algorithm>
  7. #include <numeric>
  8. #include <complex>
  9. #include <random>
  10. #include <iostream>
  11. #include <iomanip>
  12. using namespace simple::compress;
  13. const float tau = 2*std::acos(-1);
  14. // DCT more widely used than DFT, as it has several practical advantages
  15. // the end result is the same size as input, instead of double the size
  16. // cosine being even function behaves better at endpoints of the window
  17. template <typename Waveform>
  18. void DCT_1(std::size_t size, Waveform waveform)
  19. {
  20. std::vector<float> wave;
  21. wave.resize(size);
  22. std::iota(wave.begin(), wave.end(), 0);
  23. std::transform(wave.begin(), wave.end(), wave.begin(), [&](auto x) { return x/size; });
  24. std::transform(wave.begin(), wave.end(), wave.begin(), waveform);
  25. const auto dft_size = 2*(size-1);
  26. wave.resize(dft_size);
  27. // symmetric extension of the waveform results in canceling of sine/imaginary components
  28. std::copy(wave.rbegin()+size-1, wave.rend()-1, wave.begin() + size);
  29. std::vector<std::complex<float>> frequencies;
  30. frequencies.resize(dft_size);
  31. fft(std::multiplies<>{}, std::polar(1.f,tau/wave.size()), wave, frequencies);
  32. for(auto&& x : frequencies)
  33. x = x / float(dft_size);
  34. for(std::size_t i = 0; i != size; ++i)
  35. assert(std::abs(frequencies[i].imag()) < 0.001);
  36. for(auto&& x : frequencies)
  37. x.imag(0);
  38. // no idea how or why symmetric extension of the frequencies works to do the inverse... magic...
  39. std::copy(frequencies.rbegin()+size-1, frequencies.rend()-1, frequencies.begin() + size);
  40. std::vector<std::complex<float>> aaanback;
  41. aaanback.resize(dft_size);
  42. fft(std::multiplies<>{}, std::polar(1.f,tau/wave.size()), frequencies, aaanback);
  43. for(std::size_t i = 0; i != size; ++i)
  44. assert(std::abs(aaanback[i].real() - wave[i]) < 0.001);
  45. wave.resize(size);
  46. frequencies.resize(size);
  47. aaanback.resize(size);
  48. #if defined SIMPLE_SUPPORT_DEBUG_HPP
  49. if(size <= 33)
  50. {
  51. std::cerr << std::fixed;
  52. std::cerr << std::setprecision(3);
  53. simple::support::print('\n');
  54. simple::support::print("IN : [ ");
  55. for(auto&& x : wave)
  56. simple::support::print(x, " ");
  57. simple::support::print("]\n");
  58. simple::support::print("DEC: [ ");
  59. for(auto&& x : aaanback)
  60. simple::support::print(x.real(), " ");
  61. simple::support::print("]\n");
  62. simple::support::print("ENC: [ ");
  63. for(auto&& x : frequencies)
  64. simple::support::print(x.real(), " ");
  65. simple::support::print("]\n");
  66. }
  67. #endif
  68. }
  69. int main()
  70. {
  71. DCT_1(5, [&](auto x) { return std::sin(tau*x) + std::cos(tau*x*2); });
  72. DCT_1(5, [&](auto x) { return std::sin(tau*x) + std::cos(tau*x); });
  73. DCT_1(5, [&](auto x) { return std::sin(tau*x); });
  74. DCT_1(5, [&](auto x) { return std::cos(tau*x); });
  75. DCT_1(9, [&](auto x) { return std::sin(tau*x) + std::cos(tau*x*2); });
  76. DCT_1(9, [&](auto x) { return std::sin(tau*x) + std::cos(tau*x); });
  77. DCT_1(9, [&](auto x) { return std::sin(tau*x); });
  78. DCT_1(9, [&](auto x) { return std::cos(tau*x); });
  79. DCT_1(17, [&](auto x) { return std::sin(tau*x) + std::cos(tau*x*2); });
  80. DCT_1(17, [&](auto x) { return std::sin(tau*x) + std::cos(tau*x); });
  81. DCT_1(17, [&](auto x) { return std::sin(tau*x); });
  82. DCT_1(17, [&](auto x) { return std::cos(tau*x); });
  83. DCT_1(33, [&](auto x) { return std::sin(tau*x); });
  84. DCT_1(33, [&](auto x) { return std::cos(tau*x); });
  85. DCT_1(33, [&](auto x) { return std::sin(tau*x) + std::cos(tau*x*2); });
  86. DCT_1(1025, [&](auto x) { return std::sin(tau*x) + std::cos(tau*x*2); });
  87. DCT_1(1025, [&](auto x) { return std::sin(tau*x) + std::cos(tau*x); });
  88. DCT_1(1025, [&](auto x) { return std::sin(tau*x); });
  89. DCT_1(1025, [&](auto x) { return std::cos(tau*x); });
  90. DCT_1(2049, [&](auto x) { return std::sin(tau*x) + std::cos(tau*x*2); });
  91. DCT_1(2049, [&](auto x) { return std::sin(tau*x) + std::cos(tau*x); });
  92. DCT_1(2049, [&](auto x) { return std::sin(tau*x)/2; });
  93. DCT_1(2049, [&](auto x) { return std::sin(tau*x); });
  94. DCT_1(2049, [&](auto x) { return std::cos(tau*x); });
  95. DCT_1(2049, [&](auto x) { return std::sin(tau*13*x) + std::cos(tau*345*x); });
  96. DCT_1(2049, [&](auto x) { return std::sin(tau*134*x) + std::sin(tau*345*x) + std::cos(tau*789*x); });
  97. auto seed = std::random_device{}();
  98. std::cout << "DCT_1 random test seed: " << std::hex << std::showbase << seed << std::dec << std::endl;
  99. simple::support::random::engine::tiny<unsigned long long> random{seed};
  100. std::uniform_real_distribution<double> number{};
  101. DCT_1(2049, [&](auto) { return number(random); });
  102. return 0;
  103. }