Spectrum_extensions.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. /* Spectrum_extensions.cpp
  2. *
  3. * Copyright (C) 1993-2017 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 20010718
  20. djmw 20020813 GPL header
  21. djmw 20030929 Added a warning in Spectrum_drawPhases.
  22. djmw 20031023 New: Spectra_multiply, Spectrum_conjugate
  23. djmw 20040506 Changed warning message in Spectrum_drawPhases.
  24. djmw 20041124 Changed call to Sound_to_Spectrum.
  25. djmw 20061218 Introduction of Melder_information<12...9>
  26. djmw 20071022 phase_unwrap initialize phase = 0.
  27. djmw 20080122 float -> double
  28. djmw 20080202 Warning in Spectrum_drawPhases to wchar
  29. djmw 20080411 Removed define NUM2pi
  30. */
  31. #include "Ltas.h"
  32. #include "Spectrum_extensions.h"
  33. #include "Sound_and_Spectrum.h"
  34. #include "NUM2.h"
  35. #define SIGN(x,s) ((s) < 0 ? -fabs (x) : fabs(x))
  36. #define THLCON 0.5
  37. #define THLINC 1.5
  38. #define EXP2 12
  39. #define PPVPHA(x,y,test) ((test) ? atan2 (-(y),-(x)) : atan2 ((y),(x)))
  40. #define PHADVT(xr,xi,yr,yi,xa) ((xa) > 0 ? ((xr)*(yr)+(xi)*(yi))/ (xa) : 0)
  41. struct tribolet_struct {
  42. double thlinc, thlcon;
  43. double ddf, dvtmn2;
  44. double *x;
  45. integer nx, l, count;
  46. int reverse_sign;
  47. };
  48. /*
  49. Perform modified Goertzel algorithm to calculate, at frequency 'freq_rad',
  50. the real and imaginary part of the spectrum and the d/df of the
  51. spectrum of x.
  52. Reference: Bonzanigo (1978), IEEE Trans. ASSP, Vol. 26.
  53. */
  54. static void getSpectralValues (struct tribolet_struct *tbs, double freq_rad, double *xr, double *xi, double *nxr, double *nxi) {
  55. double cosf = cos (freq_rad), sinf = sin (freq_rad);
  56. double a = 2 * cosf, b, u1 = 0, u2 = u1, w1 = u1, w2 = u1;
  57. double *x = tbs -> x;
  58. integer nx = tbs -> nx;
  59. for (integer j = 1; j <= nx; j ++) {
  60. double xj = x [j];
  61. double u0 = xj + a * u1 - u2;
  62. double w0 = (j - 1) * xj + a * w1 - w2;
  63. u2 = u1;
  64. u1 = u0;
  65. w2 = w1;
  66. w1 = w0;
  67. }
  68. // Bonzanigo's phase correction
  69. a = freq_rad * (nx - 1);
  70. u1 = cos (a);
  71. u2 = - sin (a);
  72. a = u1 - u2 * cosf;
  73. b = u2 * sinf;
  74. *xr = u1 * a - u2 * b;
  75. *xi = u2 * a + u1 * b;
  76. a = w1 - w2 * cosf;
  77. b = w2 * sinf;
  78. *nxr = u1 * a - u2 * b;
  79. *nxi = u2 * a + u1 * b;
  80. tbs -> count ++;
  81. }
  82. // Find the closest unwrapped phase estimate from the two admissible phase values (a1 & a2).
  83. static int phase_check (double pv, double *phase, double thlcon) {
  84. double a0 = (*phase - pv) / NUM2pi;
  85. integer k = Melder_ifloor (a0); // ppgb: instead of truncation toward zero
  86. double a1 = pv + k * NUM2pi;
  87. double a2 = a1 + SIGN (NUM2pi, a0);
  88. double a3 = fabs (a1 - *phase);
  89. double a4 = fabs (a2 - *phase);
  90. if (a3 > thlcon && a4 > thlcon) {
  91. return 0;
  92. }
  93. *phase = a3 > a4 ? a2 : a1;
  94. return 1;
  95. }
  96. // Phase unwrapping based on Tribolet's adaptive integration method.
  97. // the unwrapped phase estimate is returned.
  98. static double phase_unwrap (struct tribolet_struct *tbs, double pfreq, double ppv, double pdvt, double *pphase, double *ppdvt) {
  99. double sdvt [25], sppv [25];
  100. double freq, phase = 0, phase_inc;
  101. double delta, xr, xi, xmsq, nxr, nxi;
  102. integer k, sindex [25], pindex = 1, sp = 1;
  103. sppv [sp] = ppv;
  104. sdvt [sp] = pdvt;
  105. sindex [sp] = tbs -> l + 1;
  106. goto p40;
  107. p20:
  108. /*
  109. When the routine runs out of stack space, there probably is
  110. a zero very near the unit circle that results in a jump of
  111. pi in the phase.
  112. */
  113. if ((sindex [sp] - pindex) <= 1) {
  114. return phase;
  115. }
  116. /* p30:
  117. Get the intermediate frequency value and compute its phase
  118. derivative and principal value.
  119. */
  120. k = (sindex [sp] + pindex) / 2;
  121. freq = pfreq + (k - 1) * tbs -> ddf;
  122. getSpectralValues (tbs, freq, &xr, &xi, &nxr, &nxi);
  123. sindex [ ++sp] = k;
  124. sppv [sp] = PPVPHA (xr, xi, tbs -> reverse_sign);
  125. xmsq = xr * xr + xi * xi;
  126. sdvt [sp] = PHADVT (xr, xi, nxr, nxi, xmsq);
  127. p40:
  128. /*
  129. Evaluate the phase increment.
  130. If the phase increment, reduced by the expected linear phase
  131. increment, is greater than the specified threshold, adapt step size.
  132. */
  133. delta = 0.5 * tbs -> ddf * (sindex [sp] - pindex);
  134. phase_inc = delta * (*ppdvt + sdvt [sp]);
  135. if (fabs (phase_inc - delta * tbs -> dvtmn2) > tbs -> thlinc) {
  136. goto p20;
  137. }
  138. phase = *pphase + phase_inc;
  139. if (! phase_check (sppv [sp], &phase, tbs -> thlcon)) {
  140. goto p20;
  141. }
  142. if (fabs (phase - *pphase) > NUMpi) {
  143. goto p20;
  144. }
  145. if (sp == 1) {
  146. return phase;
  147. }
  148. // p10: Update previous estimate.
  149. pindex = sindex [sp];
  150. *pphase = phase;
  151. *ppdvt = sdvt [sp--];
  152. goto p40;
  153. }
  154. autoMatrix Spectrum_unwrap (Spectrum me) {
  155. try {
  156. struct tribolet_struct tbs;
  157. int remove_linear_part = 1;
  158. integer nfft = 2;
  159. while (nfft < my nx - 1) {
  160. nfft *= 2;
  161. }
  162. nfft *= 2;
  163. Melder_require (nfft / 2 == my nx - 1, U"Dimension of Spectrum should be a power of 2 - 1.");
  164. autoSound x = Spectrum_to_Sound (me);
  165. autoSound nx = Data_copy (x.get());
  166. for (integer i = 1; i <= x -> nx; i ++) {
  167. nx -> z [1] [i] *= (i - 1);
  168. }
  169. autoSpectrum snx = Sound_to_Spectrum (nx.get(), true);
  170. autoMatrix thee = Matrix_create (my xmin, my xmax, my nx, my dx, my x1, 1, 2, 2, 1, 1);
  171. // Common variables.
  172. tbs.thlinc = THLINC;
  173. tbs.thlcon = THLCON;
  174. tbs.x = x -> z [1];
  175. tbs.nx = x -> nx;
  176. tbs.l = Melder_ifloor (pow (2, EXP2) + 0.1);
  177. tbs.ddf = NUM2pi / ( (tbs.l) * nfft);
  178. tbs.reverse_sign = my z [1] [1] < 0;
  179. tbs.count = 0;
  180. // Reuse snx : put phase derivative (d/df) in imaginary part.
  181. tbs.dvtmn2 = 0;
  182. for (integer i = 1; i <= my nx; i ++) {
  183. double xr = my z [1] [i], xi = my z [2] [i];
  184. double nxr = snx -> z [1] [i], nxi = snx -> z [2] [i];
  185. double xmsq = xr * xr + xi * xi;
  186. double pdvt = PHADVT (xr, xi, nxr, nxi, xmsq);
  187. thy z [1] [i] = xmsq;
  188. snx -> z [2] [i] = pdvt;
  189. tbs.dvtmn2 += pdvt;
  190. }
  191. tbs.dvtmn2 = (2 * tbs.dvtmn2 - snx -> z [2] [1] - snx -> z [2] [my nx]) / (my nx - 1);
  192. autoMelderProgress progress (U"Phase unwrapping");
  193. double pphase = 0, phase = 0;
  194. double ppdvt = snx -> z [2] [1];
  195. thy z [2] [1] = PPVPHA (my z [1] [1], my z [2] [1], tbs.reverse_sign);
  196. for (integer i = 2; i <= my nx; i ++) {
  197. double pfreq = NUM2pi * (i - 1) / nfft;
  198. double pdvt = snx -> z [2] [i];
  199. double ppv = PPVPHA (my z [1] [i], my z [2] [i], tbs.reverse_sign);
  200. phase = phase_unwrap (&tbs, pfreq, ppv, pdvt, &pphase, &ppdvt);
  201. ppdvt = pdvt;
  202. thy z [2] [i] = pphase = phase;
  203. Melder_progress ( (double) i / my nx, i,
  204. U" unwrapped phases from ", my nx, U".");
  205. }
  206. integer iphase = Melder_ifloor (phase / NUMpi + 0.1); // ppgb: better than truncation toward zero
  207. if (remove_linear_part) {
  208. phase /= my nx - 1;
  209. for (integer i = 2; i <= my nx; i ++) {
  210. thy z [2] [i] -= phase * (i - 1);
  211. }
  212. }
  213. Melder_information (U"Number of spectral values: ", tbs.count);
  214. Melder_information (U" iphase = ", iphase);
  215. return thee;
  216. } catch (MelderError) {
  217. Melder_throw (me, U": not unwrapped.");
  218. }
  219. }
  220. void Spectrum_drawPhases (Spectrum me, Graphics g, double fmin, double fmax, double phase_min, double phase_max, int unwrap, int garnish) {
  221. autoMatrix thee;
  222. int reverse_sign = my z [1] [1] < 0;
  223. if (unwrap) {
  224. thee = Spectrum_unwrap (me);
  225. } else {
  226. thee = Matrix_create (my xmin, my xmax, my nx, my dx, my x1, 1.0, 2.0, 2, 1.0, 1.0);
  227. for (integer i = 1; i <= my nx; i ++) {
  228. thy z [2] [i] = PPVPHA (my z [1] [i], my z [2] [i], reverse_sign);
  229. }
  230. }
  231. Matrix_drawRows (thee.get(), g, fmin, fmax, 1.9, 2.1, phase_min, phase_max);
  232. if (garnish) {
  233. }
  234. }
  235. autoSpectrum Spectra_multiply (Spectrum me, Spectrum thee) {
  236. try {
  237. Melder_require (my nx == thy nx && my x1 == thy x1 && my xmax == thy xmax && my dx == thy dx,
  238. U"Dimensions of both spectra should be the same.");
  239. autoSpectrum him = Data_copy (me);
  240. for (integer i = 1; i <= his nx; i ++) {
  241. his z [1] [i] = my z [1] [i] * thy z [1] [i] - my z [2] [i] * thy z [2] [i];
  242. his z [2] [i] = my z [1] [i] * thy z [2] [i] + my z [2] [i] * thy z [1] [i];
  243. }
  244. return him;
  245. } catch (MelderError) {
  246. Melder_throw (me, U": not multiplied.");
  247. }
  248. }
  249. void Spectrum_conjugate (Spectrum me) {
  250. for (integer i = 1; i <= my nx; i ++) {
  251. my z [2] [i] = - my z [2] [i];
  252. }
  253. }
  254. autoSpectrum Spectrum_resample (Spectrum me, integer numberOfFrequencies) {
  255. try {
  256. double newSamplingFrequency = (1 / my dx) * numberOfFrequencies / my nx;
  257. // resample real and imaginary part !
  258. autoSound thee = Sound_resample ((Sound) me, newSamplingFrequency, 50);
  259. autoSpectrum him = Spectrum_create (my xmax, numberOfFrequencies);
  260. matrixcopy_preallocated (his z.get(), thy z.get());
  261. return him;
  262. } catch (MelderError) {
  263. Melder_throw (me, U": not resampled.");
  264. }
  265. }
  266. #if 0
  267. static autoSpectrum Spectrum_shiftFrequencies2 (Spectrum me, double shiftBy, bool changeMaximumFrequency) {
  268. try {
  269. double xmax = my xmax;
  270. integer numberOfFrequencies = my nx, interpolationDepth = 50;
  271. if (changeMaximumFrequency) {
  272. xmax += shiftBy;
  273. numberOfFrequencies += (xmax - my xmax) / my dx;
  274. }
  275. autoSpectrum thee = Spectrum_create (xmax, numberOfFrequencies);
  276. // shiftBy >= 0
  277. for (integer i = 1; i <= thy nx; i ++) {
  278. double thyf = thy x1 + (i - 1) * thy dx;
  279. double myf = thyf - shiftBy;
  280. if (myf >= my xmin && myf <= my xmax) {
  281. double index = Sampled_xToIndex (me, myf);
  282. thy z [1] [i] = NUM_interpolate_sinc (my z [1], my nx, index, interpolationDepth);
  283. thy z [2] [i] = NUM_interpolate_sinc (my z [2], my nx, index, interpolationDepth);
  284. }
  285. }
  286. return thee;
  287. } catch (MelderError) {
  288. Melder_throw (me, U": not shifted.");
  289. }
  290. }
  291. #endif
  292. autoSpectrum Spectrum_shiftFrequencies (Spectrum me, double shiftBy, double newMaximumFrequency, integer interpolationDepth) {
  293. try {
  294. double xmax = my xmax;
  295. integer numberOfFrequencies = my nx;
  296. if (newMaximumFrequency != 0.0) {
  297. numberOfFrequencies = Melder_ifloor (newMaximumFrequency / my dx) + 1;
  298. xmax = newMaximumFrequency;
  299. }
  300. autoSpectrum thee = Spectrum_create (xmax, numberOfFrequencies);
  301. // shiftBy >= 0
  302. for (integer i = 1; i <= thy nx; i ++) {
  303. double thyf = thy x1 + (i - 1) * thy dx;
  304. double myf = thyf - shiftBy;
  305. if (myf >= my xmin && myf <= my xmax) {
  306. double index = Sampled_xToIndex (me, myf);
  307. thy z [1] [i] = NUM_interpolate_sinc (my z [1], my nx, index, interpolationDepth);
  308. thy z [2] [i] = NUM_interpolate_sinc (my z [2], my nx, index, interpolationDepth);
  309. }
  310. }
  311. // Make imaginary part of first and last sample zero
  312. // so Spectrum_to_Sound uses FFT if numberOfSamples was power of 2!
  313. double amp = sqrt (thy z [1] [1] * thy z [1] [1] + thy z [2] [1] * thy z [2] [1]);
  314. thy z [1] [1] = amp; thy z [2] [1] = 0;
  315. amp = sqrt (thy z [1] [thy nx] * thy z [1] [thy nx] + thy z [2] [thy nx] * thy z [2] [thy nx]);
  316. thy z [1] [thy nx] = amp; thy z [2] [thy nx] = 0;
  317. return thee;
  318. } catch (MelderError) {
  319. Melder_throw (me, U": not shifted.");
  320. }
  321. }
  322. autoSpectrum Spectrum_compressFrequencyDomain (Spectrum me, double fmax, integer interpolationDepth, int freqscale, int method) {
  323. try {
  324. double fdomain = my xmax - my xmin, factor = fdomain / fmax ;
  325. //integer numberOfFrequencies = 1.0 + fmax / my dx; // keep dx the same, otherwise the "duration" changes
  326. double xmax = my xmax / factor;
  327. integer numberOfFrequencies = Melder_ifloor (my nx / factor); // keep dx the same, otherwise the "duration" changes
  328. autoSpectrum thee = Spectrum_create (xmax, numberOfFrequencies);
  329. thy z [1] [1] = my z [1] [1]; thy z [2] [1] = my z [2] [1];
  330. double df = freqscale == 1 ? factor * my dx : log10 (fdomain) / (numberOfFrequencies - 1);
  331. for (integer i = 2; i <= numberOfFrequencies; i ++) {
  332. double f = my xmin + (freqscale == 1 ? (i - 1) * df : pow (10.0, (i - 1) * df));
  333. double x, y, index = (f - my x1) / my dx + 1;
  334. if (index > my nx) {
  335. break;
  336. }
  337. if (method == 1) {
  338. x = NUM_interpolate_sinc (my z [1], my nx, index, interpolationDepth);
  339. y = NUM_interpolate_sinc (my z [2], my nx, index, interpolationDepth);
  340. } else {
  341. x = undefined; // ppgb: better than data from random memory
  342. y = undefined;
  343. }
  344. thy z [1] [i] = x; thy z [2] [i] = y;
  345. }
  346. return thee;
  347. } catch (MelderError) {
  348. Melder_throw (me, U": not compressed.");
  349. }
  350. }
  351. #if 0
  352. static void Spectrum_fitTiltLine (Spectrum me, double fmin, double fmax, bool logf, double bandwidth, double *a, double *intercept, int method) {
  353. (void) me; (void) fmin; (void) fmax; (void) logf; (void) bandwidth; (void) a; (void) intercept; (void) method;
  354. try {
  355. } catch (MelderError) {
  356. Melder_throw (U"Tilt line not fitted.");
  357. }
  358. }
  359. #endif
  360. /* End of file Spectrum_extensions.cpp */