LPC_to_Spectrum.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /* LPC_to_Spectrum.cpp
  2. *
  3. * Copyright (C) 1994-2018 David Weenink
  4. *
  5. * This code is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This code is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this work. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /*
  19. djmw 20020529 GPL header
  20. djmw 20020529 Changed NUMrealft to NUMforwardRealFastFourierTransform
  21. djmw 20030708 Added NUM2.h
  22. djmw 20080122 float -> double
  23. */
  24. #include "LPC_to_Spectrum.h"
  25. #include "NUM2.h"
  26. /*
  27. PSD(f) = (sigma^2 T) /|1 + Sum (k=1..p, a [k] exp(-2 pi i f k T))|^2,
  28. where sigma^2 == gain, T is samplinginterval
  29. LPC-spectrum is approximately 20 dB too high (w.r.t. 25 ms spectrum from Sound)
  30. */
  31. void LPC_Frame_into_Spectrum (LPC_Frame me, Spectrum thee, double bandwidthReduction, double deEmphasisFrequency) {
  32. if (my nCoefficients == 0) {
  33. for (integer i = 1; i <= thy nx; i ++) {
  34. thy z [1] [i] = thy z [2] [i] = 0.0;
  35. }
  36. return;
  37. }
  38. // When deEmphasisFrequency is effective we need 1 extra position in the fftbuffer.
  39. integer nfft = 2 * (thy nx - 1), ndata = my nCoefficients + 1;
  40. double scale = 1.0 / sqrt (2.0 * thy xmax * thy dx);
  41. if (ndata >= nfft - 1 && (deEmphasisFrequency < thy xmax || ndata > nfft))
  42. Melder_throw (U"Spectrum size not large enough.");
  43. autoVEC fftbuffer = VECzero (nfft);
  44. // Copy 1, a [1], ... a [p] into fftbuffer
  45. fftbuffer [1] = 1;
  46. for (integer i = 2; i <= ndata; i ++) {
  47. fftbuffer [i] = my a [i - 1];
  48. }
  49. if (deEmphasisFrequency < thy xmax) {
  50. // Multiply (1, a [1] z^-1, ... a [p] z^-p) by (1 - b z^-1)
  51. double b = exp (- 2.0 * NUMpi * deEmphasisFrequency / thy xmax);
  52. ndata ++;
  53. for (integer i = ndata; i > 1; i--)
  54. fftbuffer [i] -= b * fftbuffer [i - 1];
  55. }
  56. /*
  57. Calculate sum (k=0..ndata; a [k] (z)^-k) along a contour with radius r:
  58. sum (k=0..ndata; a [k] (rz)^-k) = sum (k=0..ndata; (a [k]r^-k) z^-k)
  59. */
  60. double g = exp (NUMpi * bandwidthReduction / (thy dx * nfft)); /* r = 1/g */
  61. for (integer i = 2; i <= ndata; i ++)
  62. fftbuffer [i] *= pow (g, i - 1);
  63. /*
  64. Perform the fft.
  65. The LPC spectrum is obtained by inverting this spectrum.
  66. The imaginary parts of the frequencies 0 and Nyquist are 0.
  67. */
  68. NUMforwardRealFastFourierTransform (fftbuffer.get());
  69. if (my gain > 0.0)
  70. scale *= sqrt (my gain);
  71. thy z [1] [1] = scale / fftbuffer [1];
  72. thy z [2] [1] = 0.0;
  73. for (integer i = 2; i <= nfft / 2; i ++) {
  74. // We use: 1 / (a + ib) = (a - ib) / (a^2 + b^2)
  75. double re = fftbuffer [i + i - 1], im = fftbuffer [i + i];
  76. double invSquared = scale / (re * re + im * im);
  77. thy z [1] [i] = re * invSquared;
  78. thy z [2] [i] = -im * invSquared;
  79. }
  80. thy z [1] [thy nx] = scale / fftbuffer [2];
  81. thy z [2] [thy nx] = 0.0;
  82. }
  83. autoSpectrum LPC_to_Spectrum (LPC me, double t, double dfMin, double bandwidthReduction, double deEmphasisFrequency) {
  84. try {
  85. double samplingFrequency = 1.0 / my samplingPeriod;
  86. integer nfft = 2, index = Sampled_xToNearestIndex (me, t);
  87. if (index < 1) index = 1;
  88. if (index > my nx) index = my nx;
  89. if (dfMin <= 0) {
  90. nfft = 512;
  91. dfMin = samplingFrequency / nfft;
  92. }
  93. while (samplingFrequency / nfft > dfMin || nfft <= my d_frames [index].nCoefficients)
  94. nfft *= 2;
  95. autoSpectrum thee = Spectrum_create (samplingFrequency / 2.0, nfft / 2 + 1);
  96. LPC_Frame_into_Spectrum (& my d_frames [index], thee.get(), bandwidthReduction, deEmphasisFrequency);
  97. return thee;
  98. } catch (MelderError) {
  99. Melder_throw (me, U": no Spectrum created.");
  100. }
  101. }
  102. /* End of file LPC_to_Spectrum.cpp */