RealTier.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. /* RealTier.cpp
  2. *
  3. * Copyright (C) 1992-2012,2014,2015,2016,2017 Paul Boersma
  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.
  13. * See the GNU 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. #include "RealTier.h"
  19. #include "Formula.h"
  20. #include "oo_DESTROY.h"
  21. #include "RealTier_def.h"
  22. #include "oo_COPY.h"
  23. #include "RealTier_def.h"
  24. #include "oo_EQUAL.h"
  25. #include "RealTier_def.h"
  26. #include "oo_CAN_WRITE_AS_ENCODING.h"
  27. #include "RealTier_def.h"
  28. #include "oo_WRITE_TEXT.h"
  29. #include "RealTier_def.h"
  30. #include "oo_READ_TEXT.h"
  31. #include "RealTier_def.h"
  32. #include "oo_WRITE_BINARY.h"
  33. #include "RealTier_def.h"
  34. #include "oo_READ_BINARY.h"
  35. #include "RealTier_def.h"
  36. #include "oo_DESCRIPTION.h"
  37. #include "RealTier_def.h"
  38. /********** class RealPoint **********/
  39. Thing_implement (RealPoint, AnyPoint, 0);
  40. autoRealPoint RealPoint_create (double time, double value) {
  41. autoRealPoint me = Thing_new (RealPoint);
  42. my number = time;
  43. my value = value;
  44. return me;
  45. }
  46. /********** class RealTier **********/
  47. void structRealTier :: v_info () {
  48. structFunction :: v_info ();
  49. MelderInfo_writeLine (U"Number of points: ", our points.size);
  50. MelderInfo_writeLine (U"Minimum value: ", RealTier_getMinimumValue (this));
  51. MelderInfo_writeLine (U"Maximum value: ", RealTier_getMaximumValue (this));
  52. }
  53. double structRealTier :: v_getVector (integer irow, integer icol) {
  54. (void) irow;
  55. return RealTier_getValueAtIndex (this, icol);
  56. }
  57. double structRealTier :: v_getFunction1 (integer irow, double x) {
  58. (void) irow;
  59. return RealTier_getValueAtTime (this, x);
  60. }
  61. Thing_implement (RealTier, AnyTier, 0); // the semantic superclass (see RealTier_def.h for explanation)
  62. void RealTier_init (RealTier me, double tmin, double tmax) {
  63. my xmin = tmin;
  64. my xmax = tmax;
  65. }
  66. autoRealTier RealTier_create (double tmin, double tmax) {
  67. try {
  68. autoRealTier me = Thing_new (RealTier);
  69. RealTier_init (me.get(), tmin, tmax);
  70. return me;
  71. } catch (MelderError) {
  72. Melder_throw (U"RealTier not created.");
  73. }
  74. }
  75. autoRealTier RealTier_createWithClass (double tmin, double tmax, ClassInfo klas) {
  76. try {
  77. autoRealTier me = Thing_newFromClass (klas).static_cast_move <structRealTier> ();
  78. RealTier_init (me.get(), tmin, tmax);
  79. return me;
  80. } catch (MelderError) {
  81. Melder_throw (klas -> className, U" not created.");
  82. }
  83. }
  84. template <typename T> autoSomeThing <T> Thing_create () {
  85. return Thing_newFromClass (nullptr);
  86. }
  87. template <>
  88. autoSomeThing <structRealTier> Thing_create <structRealTier> () {
  89. return Thing_newFromClass (classRealTier). static_cast_move<structRealTier>();
  90. }
  91. template <typename structSomeRealTier>
  92. autoSomeThing <structSomeRealTier> SomeRealTier_create (double tmin, double tmax) {
  93. try {
  94. autoSomeThing <structSomeRealTier> me = Thing_create <structSomeRealTier> ();
  95. RealTier_init (me.get(), tmin, tmax);
  96. return me;
  97. } catch (MelderError) {
  98. Melder_throw (U"RealTier not created.");
  99. }
  100. }
  101. void RealTier_addPoint (RealTier me, double t, double value) {
  102. try {
  103. autoRealPoint point = RealPoint_create (t, value);
  104. my points. addItem_move (point.move());
  105. } catch (MelderError) {
  106. Melder_throw (me, U": point not added.");
  107. }
  108. }
  109. double RealTier_getValueAtIndex (RealTier me, integer i) {
  110. if (i < 1 || i > my points.size) return undefined;
  111. return my points.at [i] -> value;
  112. }
  113. double RealTier_getValueAtTime (RealTier me, double t) {
  114. integer n = my points.size;
  115. if (n == 0) return undefined;
  116. RealPoint pointRight = my points.at [1];
  117. if (t <= pointRight -> number) return pointRight -> value; // constant extrapolation
  118. RealPoint pointLeft = my points.at [n];
  119. if (t >= pointLeft -> number) return pointLeft -> value; // constant extrapolation
  120. Melder_assert (n >= 2);
  121. integer ileft = AnyTier_timeToLowIndex (me->asAnyTier(), t), iright = ileft + 1;
  122. Melder_assert (ileft >= 1 && iright <= n);
  123. pointLeft = my points.at [ileft];
  124. pointRight = my points.at [iright];
  125. double tleft = pointLeft -> number, fleft = pointLeft -> value;
  126. double tright = pointRight -> number, fright = pointRight -> value;
  127. return t == tright ? fright // be very accurate
  128. : tleft == tright ? 0.5 * (fleft + fright) // unusual, but possible; no preference
  129. : fleft + (t - tleft) * (fright - fleft) / (tright - tleft); // linear interpolation
  130. }
  131. double RealTier_getMaximumValue (RealTier me) {
  132. double result = undefined;
  133. integer n = my points.size;
  134. for (integer i = 1; i <= n; i ++) {
  135. RealPoint point = my points.at [i];
  136. if (isundef (result) || point -> value > result)
  137. result = point -> value;
  138. }
  139. return result;
  140. }
  141. double RealTier_getMinimumValue (RealTier me) {
  142. double result = undefined;
  143. integer n = my points.size;
  144. for (integer i = 1; i <= n; i ++) {
  145. RealPoint point = my points.at [i];
  146. if (isundef (result) || point -> value < result)
  147. result = point -> value;
  148. }
  149. return result;
  150. }
  151. double RealTier_getArea (RealTier me, double tmin, double tmax) {
  152. integer n = my points.size, imin, imax;
  153. if (n == 0) return undefined;
  154. if (n == 1) return (tmax - tmin) * my points.at [1] -> value;
  155. imin = AnyTier_timeToLowIndex (me->asAnyTier(), tmin);
  156. if (imin == n) return (tmax - tmin) * my points.at [n] -> value;
  157. imax = AnyTier_timeToHighIndex (me->asAnyTier(), tmax);
  158. if (imax == 1) return (tmax - tmin) * my points.at [1] -> value;
  159. Melder_assert (imin < n);
  160. Melder_assert (imax > 1);
  161. /*
  162. * Sum the areas between the points.
  163. * This works even if imin is 0 (offleft) and/or imax is n + 1 (offright).
  164. */
  165. longdouble area = 0.0;
  166. for (integer i = imin; i < imax; i ++) {
  167. double tleft, fleft, tright, fright;
  168. if (i == imin) {
  169. tleft = tmin;
  170. fleft = RealTier_getValueAtTime (me, tmin);
  171. } else {
  172. tleft = my points.at [i] -> number;
  173. fleft = my points.at [i] -> value;
  174. }
  175. if (i + 1 == imax) {
  176. tright = tmax;
  177. fright = RealTier_getValueAtTime (me, tmax);
  178. } else {
  179. tright = my points.at [i + 1] -> number;
  180. fright = my points.at [i + 1] -> value;
  181. }
  182. area += 0.5 * (fleft + fright) * (tright - tleft);
  183. }
  184. return (double) area;
  185. }
  186. double RealTier_getMean_curve (RealTier me, double tmin, double tmax) {
  187. if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; } // autowindow
  188. double area = RealTier_getArea (me, tmin, tmax);
  189. if (isundef (area)) return undefined;
  190. return area / (tmax - tmin);
  191. }
  192. double RealTier_getStandardDeviation_curve (RealTier me, double tmin, double tmax) {
  193. integer n = my points.size, imin, imax;
  194. if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; } // autowindow
  195. if (n == 0) return undefined;
  196. if (n == 1) return 0.0;
  197. imin = AnyTier_timeToLowIndex (me->asAnyTier(), tmin);
  198. if (imin == n) return 0.0;
  199. imax = AnyTier_timeToHighIndex (me->asAnyTier(), tmax);
  200. if (imax == 1) return 0.0;
  201. Melder_assert (imin < n);
  202. Melder_assert (imax > 1);
  203. /*
  204. * Add the areas between the points.
  205. * This works even if imin is 0 (offleft) and/or imax is n + 1 (offright).
  206. */
  207. double mean = RealTier_getMean_curve (me, tmin, tmax);
  208. longdouble integral = 0.0;
  209. for (integer i = imin; i < imax; i ++) {
  210. double tleft, fleft, tright, fright;
  211. if (i == imin) {
  212. tleft = tmin;
  213. fleft = RealTier_getValueAtTime (me, tmin);
  214. } else {
  215. tleft = my points.at [i] -> number;
  216. fleft = my points.at [i] -> value - mean;
  217. }
  218. if (i + 1 == imax) {
  219. tright = tmax;
  220. fright = RealTier_getValueAtTime (me, tmax);
  221. } else {
  222. tright = my points.at [i + 1] -> number;
  223. fright = my points.at [i + 1] -> value - mean;
  224. }
  225. /*
  226. * The area is integral dt f^2
  227. * = integral dt [f1 + (f2-f1)/(t2-t1) (t-t1)]^2
  228. * = int dt f1^2 + int dt 2 f1 (f2-f1)/(t2-t1) (t-t1) + int dt [(f2-f1)/(t2-t1)]^2 (t-t1)^2
  229. * = f1^2 (t2-t1) + f1 (f2-f1)/(t2-t1) (t2-t1)^2 + 1/3 [(f2-f1)/(t2-t1)]^2 (t2-t1)^3
  230. * = (t2-t1) [f1 f2 + 1/3 (f2-f1)^2]
  231. * = (t2-t1) (f1^2 + f2^2 + 1/3 f1 f2)
  232. * = (t2-t1) [1/4 (f1+f2)^2 + 1/12 (f1-f2)^2]
  233. * In the last expression, we have a sum of squares, which is computationally best.
  234. */
  235. double sum = fleft + fright;
  236. double diff = fleft - fright;
  237. integral += (sum * sum + (1.0/3.0) * diff * diff) * (tright - tleft);
  238. }
  239. return sqrt (0.25 * (double) integral / (tmax - tmin));
  240. }
  241. double RealTier_getMean_points (RealTier me, double tmin, double tmax) {
  242. if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; } // autowindow
  243. integer imin, imax;
  244. integer n = AnyTier_getWindowPoints (me->asAnyTier(), tmin, tmax, & imin, & imax);
  245. if (n == 0) return undefined;
  246. longdouble sum = 0.0;
  247. for (integer i = imin; i <= imax; i ++)
  248. sum += my points.at [i] -> value;
  249. return (double) sum / n;
  250. }
  251. double RealTier_getStandardDeviation_points (RealTier me, double tmin, double tmax) {
  252. if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; } // autowindow
  253. integer imin, imax;
  254. integer n = AnyTier_getWindowPoints (me->asAnyTier(), tmin, tmax, & imin, & imax);
  255. if (n < 2) return undefined;
  256. double mean = RealTier_getMean_points (me, tmin, tmax);
  257. longdouble sum = 0.0;
  258. for (integer i = imin; i <= imax; i ++) {
  259. double diff = my points.at [i] -> value - mean;
  260. sum += diff * diff;
  261. }
  262. return sqrt ((double) sum / (n - 1));
  263. }
  264. void RealTier_multiplyPart (RealTier me, double tmin, double tmax, double factor) {
  265. for (integer ipoint = 1; ipoint <= my points.size; ipoint ++) {
  266. RealPoint point = my points.at [ipoint];
  267. double t = point -> number;
  268. if (t >= tmin && t <= tmax) {
  269. point -> value *= factor;
  270. }
  271. }
  272. }
  273. void RealTier_draw (RealTier me, Graphics g, double tmin, double tmax, double fmin, double fmax,
  274. int garnish, conststring32 method, conststring32 quantity)
  275. {
  276. bool drawLines = str32str (method, U"lines") || str32str (method, U"Lines");
  277. bool drawSpeckles = str32str (method, U"speckles") || str32str (method, U"Speckles");
  278. integer n = my points.size, imin, imax, i;
  279. if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }
  280. Graphics_setWindow (g, tmin, tmax, fmin, fmax);
  281. Graphics_setInner (g);
  282. imin = AnyTier_timeToHighIndex (me->asAnyTier(), tmin);
  283. imax = AnyTier_timeToLowIndex (me->asAnyTier(), tmax);
  284. if (n == 0) {
  285. } else if (imax < imin) {
  286. double fleft = RealTier_getValueAtTime (me, tmin);
  287. double fright = RealTier_getValueAtTime (me, tmax);
  288. if (drawLines) Graphics_line (g, tmin, fleft, tmax, fright);
  289. } else for (i = imin; i <= imax; i ++) {
  290. RealPoint point = my points.at [i];
  291. double t = point -> number, f = point -> value;
  292. if (drawSpeckles) Graphics_speckle (g, t, f);
  293. if (drawLines) {
  294. if (i == 1)
  295. Graphics_line (g, tmin, f, t, f);
  296. else if (i == imin)
  297. Graphics_line (g, t, f, tmin, RealTier_getValueAtTime (me, tmin));
  298. if (i == n)
  299. Graphics_line (g, t, f, tmax, f);
  300. else if (i == imax)
  301. Graphics_line (g, t, f, tmax, RealTier_getValueAtTime (me, tmax));
  302. else {
  303. RealPoint pointRight = my points.at [i + 1];
  304. Graphics_line (g, t, f, pointRight -> number, pointRight -> value);
  305. }
  306. }
  307. }
  308. Graphics_unsetInner (g);
  309. if (garnish) {
  310. Graphics_drawInnerBox (g);
  311. Graphics_textBottom (g, true, my v_getUnitText (0, 0, 0));
  312. Graphics_marksBottom (g, 2, true, true, false);
  313. Graphics_marksLeft (g, 2, true, true, false);
  314. if (quantity) Graphics_textLeft (g, true, quantity);
  315. }
  316. }
  317. autoTableOfReal RealTier_downto_TableOfReal (RealTier me, conststring32 timeLabel, conststring32 valueLabel) {
  318. try {
  319. autoTableOfReal thee = TableOfReal_create (my points.size, 2);
  320. TableOfReal_setColumnLabel (thee.get(), 1, timeLabel);
  321. TableOfReal_setColumnLabel (thee.get(), 2, valueLabel);
  322. for (integer i = 1; i <= my points.size; i ++) {
  323. RealPoint point = my points.at [i];
  324. thy data [i] [1] = point -> number;
  325. thy data [i] [2] = point -> value;
  326. }
  327. return thee;
  328. } catch (MelderError) {
  329. Melder_throw (me, U": not converted to TableOfReal.");
  330. }
  331. }
  332. void RealTier_interpolateQuadratically (RealTier me, integer numberOfPointsPerParabola, int logarithmically) {
  333. try {
  334. autoRealTier thee = Data_copy (me);
  335. for (integer ipoint = 1; ipoint < my points.size; ipoint ++) {
  336. RealPoint point1 = my points.at [ipoint], point2 = my points.at [ipoint + 1];
  337. double time1 = point1 -> number, time2 = point2 -> number, tmid = 0.5 * (time1 + time2);
  338. double value1 = point1 -> value, value2 = point2 -> value, valuemid;
  339. double timeStep = (tmid - time1) / (numberOfPointsPerParabola + 1);
  340. if (logarithmically) value1 = log (value1), value2 = log (value2);
  341. valuemid = 0.5 * (value1 + value2);
  342. /*
  343. * Left from the midpoint.
  344. */
  345. for (integer inewpoint = 1; inewpoint <= numberOfPointsPerParabola; inewpoint ++) {
  346. double newTime = time1 + inewpoint * timeStep;
  347. double phase = (newTime - time1) / (tmid - time1);
  348. double newValue = value1 + (valuemid - value1) * phase * phase;
  349. if (logarithmically) newValue = exp (newValue);
  350. RealTier_addPoint (thee.get(), newTime, newValue);
  351. }
  352. /*
  353. * The midpoint.
  354. */
  355. RealTier_addPoint (thee.get(), tmid, logarithmically ? exp (valuemid) : valuemid);
  356. /*
  357. * Right from the midpoint.
  358. */
  359. for (integer inewpoint = 1; inewpoint <= numberOfPointsPerParabola; inewpoint ++) {
  360. double newTime = tmid + inewpoint * timeStep;
  361. double phase = (time2 - newTime) / (time2 - tmid);
  362. double newValue = value2 + (valuemid - value2) * phase * phase;
  363. if (logarithmically) newValue = exp (newValue);
  364. RealTier_addPoint (thee.get(), newTime, newValue);
  365. }
  366. }
  367. Thing_swap (me, thee.get());
  368. } catch (MelderError) {
  369. Melder_throw (me, U": not interpolated quadratically.");
  370. }
  371. }
  372. autoTable RealTier_downto_Table (RealTier me, conststring32 indexText, conststring32 timeText, conststring32 valueText) {
  373. try {
  374. autoTable thee = Table_createWithoutColumnNames (my points.size,
  375. (!! indexText) + (!! timeText) + (!! valueText));
  376. integer icol = 0;
  377. if (indexText) Table_setColumnLabel (thee.get(), ++ icol, indexText);
  378. if (timeText ) Table_setColumnLabel (thee.get(), ++ icol, timeText);
  379. if (valueText) Table_setColumnLabel (thee.get(), ++ icol, valueText);
  380. for (integer ipoint = 1; ipoint <= my points.size; ipoint ++) {
  381. RealPoint point = my points.at [ipoint];
  382. icol = 0;
  383. if (indexText) Table_setNumericValue (thee.get(), ipoint, ++ icol, ipoint);
  384. if (timeText) Table_setNumericValue (thee.get(), ipoint, ++ icol, point -> number);
  385. if (valueText) Table_setNumericValue (thee.get(), ipoint, ++ icol, point -> value);
  386. }
  387. return thee;
  388. } catch (MelderError) {
  389. Melder_throw (me, U": not converted to Table.");
  390. }
  391. }
  392. autoRealTier Vector_to_RealTier (Vector me, integer channel, ClassInfo klas) {
  393. try {
  394. autoRealTier thee = RealTier_createWithClass (my xmin, my xmax, klas);
  395. for (integer i = 1; i <= my nx; i ++) {
  396. RealTier_addPoint (thee.get(), Sampled_indexToX (me, i), my z [channel] [i]);
  397. }
  398. return thee;
  399. } catch (MelderError) {
  400. Melder_throw (me, U": not converted to ", klas -> className, U".");
  401. }
  402. }
  403. autoRealTier Vector_to_RealTier_peaks (Vector me, integer channel, ClassInfo klas) {
  404. try {
  405. autoRealTier thee = RealTier_createWithClass (my xmin, my xmax, klas);
  406. for (integer i = 2; i < my nx; i ++) {
  407. double left = my z [channel] [i - 1], centre = my z [channel] [i], right = my z [channel] [i + 1];
  408. if (left <= centre && right < centre) {
  409. double x, maximum;
  410. Vector_getMaximumAndX (me, my x1 + (i - 2.5) * my dx, my x1 + (i + 0.5) * my dx,
  411. channel, NUM_PEAK_INTERPOLATE_PARABOLIC, & maximum, & x);
  412. RealTier_addPoint (thee.get(), x, maximum);
  413. }
  414. }
  415. return thee;
  416. } catch (MelderError) {
  417. Melder_throw (me, U": not converted to ", klas -> className, U" (peaks).");
  418. }
  419. }
  420. autoRealTier Vector_to_RealTier_valleys (Vector me, integer channel, ClassInfo klas) {
  421. try {
  422. autoRealTier thee = RealTier_createWithClass (my xmin, my xmax, klas);
  423. for (integer i = 2; i < my nx; i ++) {
  424. double left = my z [channel] [i - 1], centre = my z [channel] [i], right = my z [channel] [i + 1];
  425. if (left >= centre && right > centre) {
  426. double x, minimum;
  427. Vector_getMinimumAndX (me, my x1 + (i - 2.5) * my dx, my x1 + (i + 0.5) * my dx,
  428. channel, NUM_PEAK_INTERPOLATE_PARABOLIC, & minimum, & x);
  429. RealTier_addPoint (thee.get(), x, minimum);
  430. }
  431. }
  432. return thee;
  433. } catch (MelderError) {
  434. Melder_throw (me, U": not converted to ", klas -> className, U" (valleys).");
  435. }
  436. }
  437. autoRealTier PointProcess_upto_RealTier (PointProcess me, double value, ClassInfo klas) {
  438. try {
  439. autoRealTier thee = RealTier_createWithClass (my xmin, my xmax, klas);
  440. for (integer i = 1; i <= my nt; i ++) {
  441. RealTier_addPoint (thee.get(), my t [i], value);
  442. }
  443. return thee;
  444. } catch (MelderError) {
  445. Melder_throw (me, U": not converted to RealTier.");
  446. }
  447. }
  448. void RealTier_formula (RealTier me, conststring32 expression, Interpreter interpreter, RealTier thee) {
  449. try {
  450. Formula_compile (interpreter, me, expression, kFormula_EXPRESSION_TYPE_NUMERIC, true);
  451. Formula_Result result;
  452. if (! thee)
  453. thee = me;
  454. for (integer icol = 1; icol <= my points.size; icol ++) {
  455. Formula_run (0, icol, & result);
  456. if (isundef (result. numericResult))
  457. Melder_throw (U"Cannot put an undefined value into the tier.");
  458. thy points.at [icol] -> value = result. numericResult;
  459. }
  460. } catch (MelderError) {
  461. Melder_throw (me, U": formula not completed.");
  462. }
  463. }
  464. void RealTier_removePointsBelow (RealTier me, double level) {
  465. for (integer ipoint = my points.size; ipoint > 0; ipoint --) {
  466. RealPoint point = my points.at [ipoint];
  467. if (point -> value < level)
  468. AnyTier_removePoint (me->asAnyTier(), ipoint);
  469. }
  470. }
  471. /* End of file RealTier.cpp */