Speaker_to_Delta.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. /* Speaker_to_Delta.cpp
  2. *
  3. * Copyright (C) 1992-2005,2006,2011,2015-2018 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 "Art_Speaker.h"
  19. #include "Speaker_to_Delta.h"
  20. #define SMOOTH_LUNGS true
  21. #define FIRST_TUBE 7
  22. autoDelta Speaker_to_Delta (Speaker me) {
  23. double f = my relativeSize * 1e-3; // we shall use millimetres and grams
  24. double xe [30], ye [30], xi [30], yi [30], xmm [30], ymm [30], dx, dy;
  25. autoDelta thee = Delta_create (89);
  26. Melder_assert (my cord.numberOfMasses == 1 || my cord.numberOfMasses == 2 || my cord.numberOfMasses == 10);
  27. /* Lungs: tubes 1..23. */
  28. for (integer itube = 1; itube <= 23; itube ++) {
  29. Delta_Tube t = thy tube + itube;
  30. t -> Dx = t -> Dxeq = 10.0 * f;
  31. t -> Dy = t -> Dyeq = 100.0 * f;
  32. t -> Dz = t -> Dzeq = 230.0 * f;
  33. t -> mass = 10.0 * my relativeSize * t -> Dx * t -> Dz; // 80 * f; 35 * Dx * Dz
  34. t -> k1 = 200.0; // 90000 * Dx * Dz; Newtons per metre
  35. t -> k3 = 0.0;
  36. t -> Brel = 0.8;
  37. t -> parallel = 1000;
  38. }
  39. /* Bronchi: tubes 24..29. */
  40. for (integer itube = 24; itube <= 29; itube ++) {
  41. Delta_Tube t = thy tube + itube;
  42. t -> Dx = t -> Dxeq = 10.0 * f;
  43. t -> Dy = t -> Dyeq = 15.0 * f;
  44. t -> Dz = t -> Dzeq = 30.0 * f;
  45. t -> mass = 10.0 * f;
  46. t -> k1 = 40.0; // 125000 * Dx * Dz; Newtons per metre
  47. t -> k3 = 0.0;
  48. t -> Brel = 0.8;
  49. }
  50. /* Trachea: tubes 30..35; four of these may be replaced by conus elasticus (see below). */
  51. for (integer itube = 30; itube <= 35; itube ++) {
  52. Delta_Tube t = thy tube + itube;
  53. t -> Dx = t -> Dxeq = 10.0 * f;
  54. t -> Dy = t -> Dyeq = 15.0 * f;
  55. t -> Dz = t -> Dzeq = 16.0 * f;
  56. t -> mass = 5.0 * f;
  57. t -> k1 = 160.0; // 100000 * Dx * Dz; Newtons per metre
  58. t -> k3 = 0.0;
  59. t -> Brel = 0.8;
  60. }
  61. if (SMOOTH_LUNGS) {
  62. struct { integer itube; double Dy, Dz, parallel; } data [] = {
  63. { 7, 120.0, 240.0, 5000.0 }, { 8, 120.0, 240.0, 5000.0 }, { 9, 120.0, 240.0, 5000.0 },
  64. { 10, 120.0, 240.0, 5000.0 }, { 11, 120.0, 240.0, 5000.0 }, { 12, 120.0, 240.0, 5000.0 },
  65. { 13, 120.0, 240.0, 2500.0 }, { 14, 120.0, 240.0, 1250.0 }, { 15, 120.0, 240.0, 640.0 },
  66. { 16, 120.0, 240.0, 320.0 }, { 17, 120.0, 240.0, 160.0 }, { 18, 120.0, 140.0, 80.0 },
  67. { 19, 70.0, 70.0, 40.0 }, { 20, 35.0, 35.0, 20.0 }, { 21, 18.0, 18.0, 10.0 },
  68. { 22, 12.0, 12.0, 5.0 }, { 23, 12.0, 12.0, 3.0 }, { 24, 18.0, 9.0, 2.0 },
  69. { 25, 18.0, 19.0, 2.0 }, { } };
  70. for (integer i = 0; data [i]. itube; i ++) {
  71. Delta_Tube t = thy tube + data [i]. itube;
  72. t -> Dy = t -> Dyeq = data [i]. Dy * f;
  73. t -> Dz = t -> Dzeq = data [i]. Dz * f;
  74. t -> parallel = data [i]. parallel;
  75. }
  76. for (integer itube = 26; itube <= 35; itube ++) {
  77. Delta_Tube t = thy tube + itube;
  78. t -> Dy = t -> Dyeq = 11.0 * f;
  79. t -> Dz = t -> Dzeq = 14.0 * f;
  80. t -> parallel = 1;
  81. }
  82. for (integer itube = FIRST_TUBE; itube <= 18; itube ++) {
  83. Delta_Tube t = thy tube + itube;
  84. t -> Dx = t -> Dxeq = 10.0 * f;
  85. t -> mass = 10.0 * my relativeSize * t -> Dx * t -> Dz; // 10 mm
  86. t -> k1 = 1e5 * t -> Dx * t -> Dz; // elastic tissue: 1 mbar/mm
  87. t -> k3 = 0.0;
  88. t -> Brel = 1.0;
  89. }
  90. for (integer itube = 19; itube <= 35; itube ++) {
  91. Delta_Tube t = thy tube + itube;
  92. t -> Dx = t -> Dxeq = 10.0 * f;
  93. t -> mass = 3.0 * my relativeSize * t -> Dx * t -> Dz; // 3 mm
  94. t -> k1 = 10e5 * t -> Dx * t -> Dz; // cartilage: 10 mbar/mm
  95. t -> k3 = 0.0;
  96. t -> Brel = 1.0;
  97. }
  98. }
  99. /* Glottis: tubes 36 and 37; the last one may be disconnected (see below). */
  100. {
  101. Delta_Tube t = thy tube + 36;
  102. t -> Dx = t -> Dxeq = my lowerCord.thickness;
  103. t -> Dy = t -> Dyeq = 0.0;
  104. t -> Dz = t -> Dzeq = my cord.length;
  105. t -> mass = my lowerCord.mass;
  106. t -> k1 = my lowerCord.k1;
  107. t -> k3 = t -> k1 * (20.0 / t -> Dz) * (20.0 / t -> Dz);
  108. t -> Brel = 0.2;
  109. }
  110. /*
  111. * Fill in the values for the upper part of the glottis (tube 37) only if there is no one-mass model.
  112. */
  113. if (my cord.numberOfMasses >= 2) {
  114. Delta_Tube t = thy tube + 37;
  115. t -> Dx = t -> Dxeq = my upperCord.thickness;
  116. t -> Dy = t -> Dyeq = 0.0;
  117. t -> Dz = t -> Dzeq = my cord.length;
  118. t -> mass = my upperCord.mass;
  119. t -> k1 = my upperCord.k1;
  120. t -> k3 = t -> k1 * (20.0 / t -> Dz) * (20.0 / t -> Dz);
  121. t -> Brel = 0.2;
  122. /* Couple spring with lower cord. */
  123. t -> k1left1 = thy tube [36]. k1right1 = 1.0;
  124. }
  125. /*
  126. * Fill in the values for the conus elasticus (tubes 79..86) only if we want to model it.
  127. */
  128. if (my cord.numberOfMasses == 10) {
  129. thy tube [79]. Dx = thy tube [79]. Dxeq = 8.0 * f;
  130. thy tube [80]. Dx = thy tube [80]. Dxeq = 7.0 * f;
  131. thy tube [81]. Dx = thy tube [81]. Dxeq = 6.0 * f;
  132. thy tube [82]. Dx = thy tube [82]. Dxeq = 5.0 * f;
  133. thy tube [83]. Dx = thy tube [83]. Dxeq = 4.0 * f;
  134. thy tube [84]. Dx = thy tube [84]. Dxeq = 0.75 * 4.0 * f + 0.25 * my lowerCord.thickness;
  135. thy tube [85]. Dx = thy tube [85]. Dxeq = 0.50 * 4.0 * f + 0.50 * my lowerCord.thickness;
  136. thy tube [86]. Dx = thy tube [86]. Dxeq = 0.25 * 4.0 * f + 0.75 * my lowerCord.thickness;
  137. thy tube [79]. Dy = thy tube [79]. Dyeq = 11.0 * f;
  138. thy tube [80]. Dy = thy tube [80]. Dyeq = 7.0 * f;
  139. thy tube [81]. Dy = thy tube [81]. Dyeq = 4.0 * f;
  140. thy tube [82]. Dy = thy tube [82]. Dyeq = 2.0 * f;
  141. thy tube [83]. Dy = thy tube [83]. Dyeq = 1.0 * f;
  142. thy tube [84]. Dy = thy tube [84]. Dyeq = 0.75 * f;
  143. thy tube [85]. Dy = thy tube [85]. Dyeq = 0.50 * f;
  144. thy tube [86]. Dy = thy tube [86]. Dyeq = 0.25 * f;
  145. thy tube [79]. Dz = thy tube [79]. Dzeq = 16.0 * f;
  146. thy tube [80]. Dz = thy tube [80]. Dzeq = 16.0 * f;
  147. thy tube [81]. Dz = thy tube [81]. Dzeq = 16.0 * f;
  148. thy tube [82]. Dz = thy tube [82]. Dzeq = 16.0 * f;
  149. thy tube [83]. Dz = thy tube [83]. Dzeq = 16.0 * f;
  150. thy tube [84]. Dz = thy tube [84]. Dzeq = 0.75 * 16.0 * f + 0.25 * my cord.length;
  151. thy tube [85]. Dz = thy tube [85]. Dzeq = 0.50 * 16.0 * f + 0.50 * my cord.length;
  152. thy tube [86]. Dz = thy tube [86]. Dzeq = 0.25 * 16.0 * f + 0.75 * my cord.length;
  153. thy tube [79]. k1 = 160.0;
  154. thy tube [80]. k1 = 160.0;
  155. thy tube [81]. k1 = 160.0;
  156. thy tube [82]. k1 = 160.0;
  157. thy tube [83]. k1 = 160.0;
  158. thy tube [84]. k1 = 0.75 * 160.0 * f + 0.25 * my lowerCord.k1;
  159. thy tube [85]. k1 = 0.50 * 160.0 * f + 0.50 * my lowerCord.k1;
  160. thy tube [86]. k1 = 0.25 * 160.0 * f + 0.75 * my lowerCord.k1;
  161. thy tube [79]. Brel = 0.7;
  162. thy tube [80]. Brel = 0.6;
  163. thy tube [81]. Brel = 0.5;
  164. thy tube [82]. Brel = 0.4;
  165. thy tube [83]. Brel = 0.3;
  166. thy tube [84]. Brel = 0.2;
  167. thy tube [85]. Brel = 0.2;
  168. thy tube [86]. Brel = 0.2;
  169. for (integer itube = 79; itube <= 86; itube ++) {
  170. Delta_Tube t = thy tube + itube;
  171. t -> mass = t -> Dx * t -> Dz / (30.0 * f);
  172. t -> k3 = t -> k1 * (20.0 / t -> Dz) * (20.0 / t -> Dz);
  173. t -> k1left1 = t -> k1right1 = 1.0;
  174. }
  175. thy tube [79]. k1left1 = 0.0;
  176. thy tube [36]. k1left1 = 1.0; // the essence: couple spring with lower vocal cords
  177. }
  178. /*
  179. * Fill in the values of the glottal shunt only if we want to model it.
  180. */
  181. if (my shunt.Dx != 0.0) {
  182. for (integer itube = 87; itube <= 89; itube ++) {
  183. Delta_Tube t = thy tube + itube;
  184. t -> Dx = t -> Dxeq = my shunt.Dx;
  185. t -> Dy = t -> Dyeq = my shunt.Dy;
  186. t -> Dz = t -> Dzeq = my shunt.Dz;
  187. t -> mass = 3.0 * my upperCord.mass; // heavy...
  188. t -> k1 = 3.0 * my upperCord.k1; // ...and stiff...
  189. t -> k3 = t -> k1 * (20.0 / t -> Dz) * (20.0 / t -> Dz);
  190. t -> Brel = 3.0; // ...and inelastic, so that the walls will not vibrate
  191. }
  192. }
  193. /* Vocal tract from neutral articulation. */
  194. bool closed [40];
  195. {
  196. autoArt art = Art_create ();
  197. Art_Speaker_meshVocalTract (art.get(), me, xi, yi, xe, ye, xmm, ymm, closed);
  198. }
  199. /* Pharynx and mouth: tubes 38..64. */
  200. for (integer itube = 38; itube <= 64; itube ++) {
  201. Delta_Tube t = thy tube + itube;
  202. integer i = itube - 37;
  203. dx = xmm [i] - xmm [i + 1];
  204. dy = ymm [i] - ymm [i + 1];
  205. t -> Dx = t -> Dxeq = sqrt (dx * dx + dy * dy);
  206. dx = xe [i] - xi [i];
  207. dy = ye [i] - yi [i];
  208. t -> Dyeq = sqrt (dx * dx + dy * dy);
  209. if (closed [i]) t -> Dyeq = - t -> Dyeq;
  210. t -> Dy = t -> Dyeq;
  211. t -> Dz = t -> Dzeq = 0.015;
  212. t -> mass = 0.006;
  213. t -> k1 = 30.0;
  214. t -> k3 = 0.0;
  215. t -> Brel = 1.0;
  216. }
  217. /* For tongue-tip vibration [r]: thy tube [60]. Brel = 0.1; thy tube [60]. k1 = 3; */
  218. /* Nose: tubes 65..78. */
  219. for (integer itube = 65; itube <= 78; itube ++) {
  220. Delta_Tube t = thy tube + itube;
  221. t -> Dx = t -> Dxeq = my nose.Dx;
  222. t -> Dy = t -> Dyeq = my nose.weq [itube - 64];
  223. t -> Dz = t -> Dzeq = my nose.Dz;
  224. t -> mass = 0.006;
  225. t -> k1 = 100.0;
  226. t -> k3 = 0.0;
  227. t -> Brel = 1.0;
  228. }
  229. thy tube [65]. Dy = thy tube [65]. Dyeq = 0.0; // override: nasopharyngeal port closed
  230. /* The default structure:
  231. * every tube is connected on the left to the previous tube (index one lower).
  232. * This corresponds to a two-mass model of the vocal cords without shunt.
  233. */
  234. for (integer itube = SMOOTH_LUNGS ? FIRST_TUBE : 1; itube <= thy numberOfTubes; itube ++) {
  235. Delta_Tube t = thy tube + itube;
  236. t -> s1 = 5e6 * t -> Dx * t -> Dz;
  237. t -> s3 = t -> s1 / (0.9e-3 * 0.9e-3);
  238. t -> dy = 1e-5;
  239. t -> left1 = t - 1; // connect to the previous tube on the left
  240. t -> right1 = t + 1; // connect to the next tube on the right
  241. }
  242. /***** Connections: boundaries and interfaces. *****/
  243. /* The leftmost boundary: the diaphragm (tube 1).
  244. * Disconnect on the left.
  245. */
  246. thy tube [SMOOTH_LUNGS ? FIRST_TUBE : 1]. left1 = nullptr; // closed at diaphragm
  247. /* Optional one-mass model of the vocal cords.
  248. * Short-circuit over tube 37 (upper glottis).
  249. */
  250. if (my cord.numberOfMasses == 1) {
  251. /* Connect the right side of tube 36 to the left side of tube 38. */
  252. thy tube [36]. right1 = thy tube + 38;
  253. thy tube [38]. left1 = thy tube + 36;
  254. /* Disconnect tube 37 on both sides. */
  255. thy tube [37]. left1 = thy tube [37]. right1 = nullptr;
  256. }
  257. /* Optionally couple vocal cords with conus elasticus.
  258. * Replace tubes 32..35 (upper trachea) by tubes 79..86 (conus elasticus).
  259. */
  260. if (my cord.numberOfMasses == 10) {
  261. /* Connect the right side of tube 31 to the left side of tube 79. */
  262. thy tube [31]. right1 = thy tube + 79;
  263. thy tube [79]. left1 = thy tube + 31;
  264. /* Connect the right side of tube 86 to the left side of tube 36. */
  265. thy tube [86]. right1 = thy tube + 36;
  266. thy tube [36]. left1 = thy tube + 86;
  267. /* Disconnect tubes 32..35 on both sides. */
  268. thy tube [32]. left1 = thy tube [32]. right1 = nullptr;
  269. thy tube [33]. left1 = thy tube [33]. right1 = nullptr;
  270. thy tube [34]. left1 = thy tube [34]. right1 = nullptr;
  271. thy tube [35]. left1 = thy tube [35]. right1 = nullptr;
  272. } else {
  273. /* Disconnect tubes 79..86 on both sides. */
  274. for (integer itube = 79; itube <= 86; itube ++)
  275. thy tube [itube]. left1 = thy tube [itube]. right1 = nullptr;
  276. }
  277. /* Optionally add a shunt parallel to the glottis.
  278. * Create a side branch from tube 34/35 (or 85/86) to tube 38/39 with tubes 87..89.
  279. */
  280. if (my shunt.Dx != 0.0) {
  281. integer topOfTrachea = ( my cord.numberOfMasses == 10 ? 86 : 35 );
  282. /* Create a three-way interface below the shunt.
  283. * Connect lowest shunt tube (87) with top of trachea (34/35 or 85/86).
  284. */
  285. thy tube [topOfTrachea - 1]. right2 = thy tube + 87; // trachea to shunt
  286. thy tube [87]. left1 = thy tube + topOfTrachea - 1; // shunt to trachea
  287. thy tube [87]. Dxeq = thy tube [topOfTrachea - 1]. Dxeq = thy tube [topOfTrachea]. Dxeq; // equal length
  288. thy tube [87]. Dx = thy tube [topOfTrachea - 1]. Dx = thy tube [topOfTrachea]. Dx;
  289. /* Create a three-way interface above the shunt.
  290. * Connect highest shunt tube (89) with bottom of pharynx (38/39).
  291. */
  292. thy tube [89]. right1 = thy tube + 39; // shunt to pharynx
  293. thy tube [39]. left2 = thy tube + 89; // pharynx to shunt
  294. thy tube [89]. Dxeq = thy tube [39]. Dxeq = thy tube [38]. Dxeq; // all three of equal length
  295. thy tube [89]. Dx = thy tube [39]. Dx = thy tube [38]. Dx;
  296. } else {
  297. /* Disconnect tubes 87..89 on both sides. */
  298. for (integer itube = 87; itube <= 89; itube ++)
  299. thy tube [itube]. left1 = thy tube [itube]. right1 = nullptr;
  300. }
  301. /* Create a three-way interface at the nasopharyngeal port.
  302. * Connect tubes 50 (pharynx), 51 (mouth), and 65 (nose).
  303. */
  304. thy tube [50]. right2 = thy tube + 65; // pharynx to nose
  305. thy tube [65]. left1 = thy tube + 50; // nose to pharynx
  306. thy tube [65]. Dxeq = thy tube [51]. Dxeq = thy tube [50]. Dxeq; // all three must be of equal length
  307. thy tube [65]. Dx = thy tube [51]. Dx = thy tube [50]. Dx;
  308. /* The rightmost boundaries: the lips (tube 64) and the nostrils (tube 78).
  309. * Disconnect on the right.
  310. */
  311. thy tube [64]. right1 = nullptr; // radiation at the lips
  312. thy tube [78]. right1 = nullptr; // radiation at the nostrils
  313. for (integer itube = 1; itube <= thy numberOfTubes; itube ++) {
  314. Delta_Tube t = thy tube + itube;
  315. Melder_assert (! t->left1 || t->left1->right1 == t || t->left1->right2 == t);
  316. Melder_assert (! t->left2 || t->left2->right1 == t);
  317. Melder_assert (! t->right1 || t->right1->left1 == t || t->right1->left2 == t);
  318. Melder_assert (! t->right2 || t->right2->left1 == t);
  319. }
  320. return thee;
  321. }
  322. /* End of file Speaker_to_Delta.cpp */