LPC_and_LineSpectralFrequencies.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. /* LPC_and_LineSpectralFrequencies.cpp
  2. *
  3. * Copyright (C) 2016-2018 David Weenink
  4. *
  5. * This program 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 program 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 program; if not, write to the Free Software
  17. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */
  19. /*
  20. djmw 20160421 Initial version
  21. */
  22. #include "LPC_and_LineSpectralFrequencies.h"
  23. #include "NUM2.h"
  24. #include "Polynomial.h"
  25. /*
  26. Conversion from Y(w) to a polynomial in x (= 2 cos (w))
  27. From: Joseph Rothweiler (1999), "On Polynomial Reduction in the Computation of LSP Frequencies."
  28. IEEE Trans. on ASSP 7, 592--594.
  29. */
  30. static void cos2x (double *g, integer order) {
  31. for (integer i = 2; i <= order; i ++) {
  32. for (integer j = order; j > i; j --) {
  33. g [j - 2] -= g [j];
  34. }
  35. g [i - 2] -= 2.0 * g [i];
  36. }
  37. }
  38. static void Polynomial_fromLPC_Frame_lspsum (Polynomial me, LPC_Frame lpc) {
  39. // Fs (z) = A(z) + z^-(p+1) A(1/z)
  40. integer order = lpc -> nCoefficients, g_order = (order + 1) / 2; // orders
  41. my coefficients [order + 2] = 1.0;
  42. for (integer i = 1; i <= order; i ++) {
  43. my coefficients [order + 2 - i] = lpc -> a [i] + lpc -> a [order + 1 - i];
  44. }
  45. my coefficients [1] = 1.0;
  46. my numberOfCoefficients = order + 2;
  47. if (order % 2 == 0) { // order even
  48. Polynomial_divide_firstOrderFactor (me, -1.0, nullptr);
  49. }
  50. // transform to cos(w) terms
  51. for (integer i = 1; i <= g_order + 1; i ++) {
  52. my coefficients [i] = my coefficients [g_order + i];
  53. }
  54. my numberOfCoefficients = g_order + 1;
  55. // to Chebychev
  56. cos2x (& my coefficients [1], g_order);
  57. }
  58. static void Polynomial_fromLPC_Frame_lspdif (Polynomial me, LPC_Frame lpc) {
  59. // Fa (z) = A(z) - z^-(p+1)A(1/z)
  60. integer order = lpc -> nCoefficients;
  61. my coefficients [order + 2] = -1.0;
  62. for (integer i = 1; i <= order; i ++) {
  63. my coefficients [order + 2 - i] = - lpc -> a [i] + lpc -> a [order + 1 - i];
  64. }
  65. my coefficients [1] = 1.0;
  66. my numberOfCoefficients = order + 2;
  67. if (order % 2 == 0) { // Fa(z)/(z-1)
  68. Polynomial_divide_firstOrderFactor (me, 1.0, nullptr);
  69. } else { // Fa(z) / (z^2 - 1)
  70. Polynomial_divide_secondOrderFactor (me, 1.0);
  71. }
  72. // transform to cos(w) terms
  73. integer g_order = my numberOfCoefficients / 2;
  74. for (integer i = 1; i <= g_order + 1; i ++) {
  75. my coefficients [i] = my coefficients [g_order + i];
  76. }
  77. my numberOfCoefficients = g_order + 1;
  78. // to Chebychev
  79. cos2x (& my coefficients [1], g_order);
  80. }
  81. #if 0
  82. /* g[0]+g[1]x + ... g[m]*x^ m = 0 ; m should be even
  83. * Semenov, Kalyuzhny, Kovtonyuk (2003), Efficient calculation of line spectral frequencies based on new method for solution of transcendental equations,
  84. * ICASSP 2003, 457--460
  85. * g[0 .. g_order]
  86. * work [0.. g_order + 1 + (numberOfDerivatives + 1) * 5]
  87. * root [1 .. (g_order+1)/2]
  88. */
  89. static void Roots_fromPolynomial (Roots me, Polynomial g, integer numberOfDerivatives, double *work) {
  90. if (numberOfDerivatives < 3) {
  91. Melder_throw (U"Number of derivatives should be at least 3.");
  92. }
  93. double xmin = -1.0, xmax = 1.0;
  94. integer numberOfRootsFound = 0;
  95. integer g_order = g -> numberOfCoefficients - 1;
  96. double *gabs = work, *fact = gabs + g_order + 1, *p2 = fact + numberOfDerivatives + 1;
  97. double *derivatives = p2 + numberOfDerivatives + 1, *constraints = derivatives + numberOfDerivatives + 1;
  98. double *intervals = constraints + numberOfDerivatives + 1;
  99. /* Fill vectors with j! and 2^j only once */
  100. fact [0] = p2 [0] = 1.0;
  101. for (integer j = 1; j <= numberOfDerivatives; j ++) {
  102. fact [j] = fact [j - 1] * j; // j!
  103. p2 [j] = p2 [j - 1] * 2.0; // 2^j
  104. }
  105. /* The constraints M[j] (Semenov et al. eq. (8)) can be calculated by taking absolute values of
  106. * the polynomial coefficients and evaluating the polynomial and the derivatives at x = 1.0
  107. */
  108. for (integer k = 0; k <= g_order; k ++) {
  109. gabs [k] = fabs (g -> coefficients [k + 1]);
  110. }
  111. evaluatePolynomialAndDerivatives (gabs, g_order, 1.0, constraints, numberOfDerivatives);
  112. intervals [0] = 1.0;
  113. while (numberOfRootsFound < g_order || xmin == xmax) {
  114. double dsum1 = 0.0, dsum2 = 0.0;
  115. double xmid = (xmin + xmax) / 2.0;
  116. evaluatePolynomialAndDerivatives (g, g_order, xmid, derivatives, numberOfDerivatives);
  117. double fxmid = derivatives[0], fdxmin = derivatives[1];
  118. integer j = 1;
  119. bool rootsOnIntervalPossible_f = true, rootsOnIntervalPossible_df = true;
  120. while (j <= numberOfDerivatives && (rootsOnIntervalPossible_f || rootsOnIntervalPossible_df)) {
  121. intervals [j] = intervals [j - 1] * (xmax - xmin);
  122. integer k = j - 1;
  123. if (j > 1) { // start at first derivative
  124. dsum1 += fabs (derivatives [k]) * intervals [k] / (p2 [k] * fact [k]);
  125. }
  126. if (j > 2) { // start at second derivative
  127. dsum2 += fabs (derivatives [k]) * intervals [k - 1] / (p2 [k - 1] * fact [k - 1]);
  128. if (rootsOnIntervalPossible_f) {
  129. double testValue1 = dsum1 + constraints [j] * intervals [j] / (p2 [j] * fact [j]);
  130. rootsOnIntervalPossible_f = ! (fxmid + testValue1 < 0.0 || fxmid - testValue1 > 0.0);
  131. }
  132. if (rootsOnIntervalPossible_df) {
  133. double testValue2 = dsum2 + constraints [j] * intervals [j - 1] / (p2 [j - 1] * fact [j - 1]);
  134. rootsOnIntervalPossible_df = ! (fdxmin + testValue2 < 0.0 || fdxmin - testValue2 > 0.0);
  135. }
  136. }
  137. j++;
  138. }
  139. if (rootsOnIntervalPossible_f) {
  140. if (rootsOnIntervalPossible_df) { // f(x) uncertain && f'(x) uncertain: bisect
  141. xmax = xmid;
  142. } else { // f(x) uncertain; f'(x) certain
  143. double fxmin = evaluatePolynomial (g, g_order, xmin);
  144. double fxmax = evaluatePolynomial (g, g_order, xmax);
  145. if (fxmin * fxmax <= 0.0) {
  146. double root;
  147. NUMnrbis (dpoly, xmin, xmax, &poly, &root);
  148. roots [++numberOfRootsFound] = root;
  149. } else {
  150. xmin = xmax; xmax = 1.0;
  151. }
  152. }
  153. } else {
  154. xmin = xmax; xmax = 1.0;
  155. }
  156. }
  157. }
  158. #endif
  159. static integer Roots_fromPolynomial_grid (Roots me, Polynomial thee, double gridSize) {
  160. Melder_assert (my max >= thy numberOfCoefficients - 1);
  161. double xmin = thy xmin;
  162. integer numberOfRootsFound = 0;
  163. while (xmin < thy xmax && numberOfRootsFound < thy numberOfCoefficients - 1) {
  164. double xmax = xmin + gridSize;
  165. xmax = xmax > thy xmax ? thy xmax : xmax;
  166. //double root = Polynomial_findOneRealRoot_nr (thee, xmin, xmax);
  167. double root = Polynomial_findOneSimpleRealRoot_ridders (thee, xmin, xmax);
  168. if (isdefined (root) && (numberOfRootsFound == 0 || my v [numberOfRootsFound].re != root)) {
  169. my v [++numberOfRootsFound].re = root; // root not at border of interval
  170. my v [numberOfRootsFound].im = 0.0;
  171. }
  172. xmin = xmax;
  173. }
  174. // make rest of storage undefined (not necessary)
  175. return numberOfRootsFound;
  176. }
  177. static void LineSpectralFrequencies_Frame_initFromLPC_Frame_grid (LineSpectralFrequencies_Frame me, LPC_Frame thee, Polynomial g1, Polynomial g2, Roots roots, double gridSize, double maximumFrequency) {
  178. /* Construct Fs and Fa
  179. divide out the zeros
  180. transform to polynomial equations g1 and g2 of half the order
  181. */
  182. LineSpectralFrequencies_Frame_init (me, thy nCoefficients);
  183. Polynomial_fromLPC_Frame_lspsum (g1, thee);
  184. integer half_order_g1 = g1 -> numberOfCoefficients - 1;
  185. Polynomial_fromLPC_Frame_lspdif (g2, thee);
  186. integer half_order_g2 = g2 -> numberOfCoefficients - 1;
  187. integer numberOfBisections = 0, numberOfRootsFound = 0;
  188. while (numberOfRootsFound < half_order_g1 && numberOfBisections < 10) {
  189. numberOfRootsFound = Roots_fromPolynomial_grid (roots, g1, gridSize);
  190. gridSize *= 0.5; numberOfBisections++;
  191. }
  192. Melder_require (numberOfBisections < 10, U"Too many bisections.");
  193. // [g1-> xmin, g1 -> xmax] <==> [nyquistFrequency, 0] i.e. highest root corresponds to lowest frequency
  194. for (integer i = 1; i <= half_order_g1; i ++) {
  195. my frequencies [2 * i - 1] = acos (roots -> v [half_order_g1 + 1 - i].re / 2.0) / NUMpi * maximumFrequency;
  196. }
  197. // the roots of g2 lie inbetween the roots of g1
  198. for (integer i = 1; i <= half_order_g2; i ++) {
  199. double xmax = roots -> v [half_order_g1 + 1 - i].re;
  200. double xmin = i == half_order_g1 ? g1 -> xmin : roots -> v [half_order_g1 - i].re;
  201. double root = Polynomial_findOneSimpleRealRoot_ridders (g2, xmin, xmax);
  202. if (isdefined (root)) {
  203. my frequencies [2 * i] = acos (root / 2.0) / NUMpi * maximumFrequency;
  204. } else {
  205. my numberOfFrequencies --;
  206. }
  207. }
  208. }
  209. autoLineSpectralFrequencies LPC_to_LineSpectralFrequencies (LPC me, double gridSize) {
  210. try {
  211. if (gridSize == 0.0) {
  212. gridSize = 0.02;
  213. }
  214. double nyquistFrequency = 0.5 / my samplingPeriod;
  215. autoLineSpectralFrequencies thee = LineSpectralFrequencies_create (my xmin, my xmax, my nx, my dx, my x1, my maxnCoefficients, nyquistFrequency);
  216. autoPolynomial g1 = Polynomial_create (-2.0, 2.0, my maxnCoefficients + 1); // large enough
  217. autoPolynomial g2 = Polynomial_create (-2.0, 2.0, my maxnCoefficients + 1);
  218. autoRoots roots = Roots_create ((my maxnCoefficients + 1) / 2);
  219. for (integer iframe = 1; iframe <= my nx; iframe ++) {
  220. LPC_Frame lpc_frame = & my d_frames [iframe];
  221. LineSpectralFrequencies_Frame lsf_frame = & thy d_frames [iframe];
  222. /* Construct Fs and Fa
  223. divide out the zeros
  224. transform to polynomial equations g1 and g2 of half the order
  225. find zeros
  226. */
  227. LineSpectralFrequencies_Frame_initFromLPC_Frame_grid (lsf_frame, lpc_frame, g1.get(), g2.get(), roots.get(), gridSize, nyquistFrequency);
  228. }
  229. return thee;
  230. } catch (MelderError) {
  231. Melder_throw (me, U": no LineSpectralFrequencies created.");
  232. }
  233. }
  234. /*
  235. Polynomials fs & fs are buffering intermediate results
  236. */
  237. static void LPC_Frame_initFromLineSpectralFrequencies_Frame (LPC_Frame me, LineSpectralFrequencies_Frame thee, Polynomial fs, Polynomial fa, double maximumFrequency) {
  238. LPC_Frame_init (me, thy numberOfFrequencies);
  239. /*
  240. Reconstruct Fs (z)
  241. Use my a as a buffer whose size changes!!!
  242. */
  243. integer numberOfOmegas = (thy numberOfFrequencies + 1) / 2;
  244. for (integer i = 1; i <= numberOfOmegas; i ++) {
  245. double omega = thy frequencies [2 * i -1] / maximumFrequency * NUMpi;
  246. my a [i] = -2.0 * cos (omega);
  247. }
  248. Polynomial_initFromProductOfSecondOrderTerms (fs, {my a.at, numberOfOmegas});
  249. /*
  250. Reconstruct Fa (z)
  251. */
  252. numberOfOmegas = thy numberOfFrequencies / 2;
  253. for (integer i = 1; i <= numberOfOmegas; i ++) {
  254. double omega = thy frequencies [2 * i] / maximumFrequency * NUMpi;
  255. my a [i] = -2.0 * cos (omega);
  256. }
  257. Polynomial_initFromProductOfSecondOrderTerms (fa, {my a.at, numberOfOmegas});
  258. if (thy numberOfFrequencies % 2 == 0) {
  259. Polynomial_multiply_firstOrderFactor (fs, -1.0); // * (z + 1)
  260. Polynomial_multiply_firstOrderFactor (fa, 1.0); // * (z - 1)
  261. } else {
  262. Polynomial_multiply_secondOrderFactor (fa, 1.0); // * (z^2 - 1)
  263. }
  264. Melder_assert (fs -> numberOfCoefficients == fa -> numberOfCoefficients);
  265. /*
  266. A(z) = (Fs(z) + Fa(z) / 2
  267. */
  268. for (integer i = 1; i <= fs -> numberOfCoefficients - 2; i ++) {
  269. my a [thy numberOfFrequencies - i + 1] = 0.5 * (fs -> coefficients [i + 1] + fa -> coefficients [i + 1]);
  270. }
  271. }
  272. autoLPC LineSpectralFrequencies_to_LPC (LineSpectralFrequencies me) {
  273. try {
  274. autoLPC thee = LPC_create (my xmin, my xmax, my nx, my dx, my x1, my maximumNumberOfFrequencies, 0.5 / my maximumFrequency);
  275. autoPolynomial fs = Polynomial_create (-1.0, 1.0, my maximumNumberOfFrequencies + 2);
  276. autoPolynomial fa = Polynomial_create (-1.0, 1.0, my maximumNumberOfFrequencies + 2);
  277. for (integer iframe = 1; iframe <= my nx; iframe ++) {
  278. LineSpectralFrequencies_Frame lsf_frame = & my d_frames [iframe];
  279. LPC_Frame lpc_frame = & thy d_frames [iframe];
  280. /* Construct Fs and Fa
  281. A(z) = (Fs(z) + Fa(z))/2
  282. */
  283. LPC_Frame_initFromLineSpectralFrequencies_Frame (lpc_frame, lsf_frame, fs.get(), fa.get(), my maximumFrequency);
  284. }
  285. return thee;
  286. } catch (MelderError) {
  287. Melder_throw (me, U": no LPC created from LineSpectralFrequencies.");
  288. }
  289. }
  290. /* End of file LPC_and_LineSpectralFrequencies.cpp */