generic-yasim-engine.nas 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. # generic-yasim-engine.nas -- a generic Nasal-based engine control system for YASim
  2. # Version 1.0.0
  3. #
  4. # Copyright (C) 2011 Ryan Miller
  5. #
  6. # This program is free software; you can redistribute it and/or
  7. # modify it under the terms of the GNU General Public License as
  8. # published by the Free Software Foundation; either version 2 of the
  9. # License, or (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful, but
  12. # WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. # General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program; if not, write to the Free Software
  18. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. #
  20. var UPDATE_PERIOD = 0; # update interval for engine init() functions
  21. # jet engine class
  22. var Jet =
  23. {
  24. # creates a new engine object
  25. new: func(n, running = 0, idle_throttle = 0.01, max_start_n1 = 5.21, start_threshold = 3, spool_time = 4, start_time = 0.02, shutdown_time = 4)
  26. {
  27. # copy the Jet object
  28. var m = { parents: [Jet] };
  29. # declare object variables
  30. m.number = n;
  31. m.autostart_status = 0;
  32. m.autostart_id = -1;
  33. m.loop_running = 0;
  34. m.started = 0;
  35. m.starting = 0;
  36. m.idle_throttle = idle_throttle;
  37. m.max_start_n1 = max_start_n1;
  38. m.start_threshold = start_threshold;
  39. m.spool_time = spool_time;
  40. m.start_time = start_time;
  41. m.shutdown_time = shutdown_time;
  42. # create references to properties and set default values
  43. m.cutoff = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/cutoff", 1);
  44. m.cutoff.setBoolValue(!running);
  45. m.n1 = props.globals.getNode("engines/engine[" ~ n ~ "]/n1", 1);
  46. m.n1.setDoubleValue(0);
  47. m.out_of_fuel = props.globals.getNode("engines/engine[" ~ n ~ "]/out-of-fuel", 1);
  48. m.out_of_fuel.setBoolValue(0);
  49. m.reverser = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/reverser", 1);
  50. m.reverser.setBoolValue(0);
  51. m.rpm = props.globals.getNode("engines/engine[" ~ n ~ "]/rpm", 1);
  52. m.rpm.setDoubleValue(running ? 100 : 0);
  53. m.running = props.globals.getNode("engines/engine[" ~ n ~ "]/running", 1);
  54. m.running.setBoolValue(running);
  55. m.serviceable = props.globals.getNode("engines/engine[" ~ n ~ "]/serviceable", 1);
  56. m.serviceable.setBoolValue(1);
  57. m.starter = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/starter", 1);
  58. m.starter.setBoolValue(0);
  59. m.throttle = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/throttle", 1);
  60. m.throttle.setDoubleValue(0);
  61. m.throttle_lever = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/throttle-lever", 1);
  62. m.throttle_lever.setDoubleValue(0);
  63. # return our new object
  64. return m;
  65. },
  66. # engine-specific autostart
  67. autostart: func
  68. {
  69. if (me.autostart_status)
  70. {
  71. me.autostart_status = 0;
  72. me.cutoff.setBoolValue(1);
  73. }
  74. else
  75. {
  76. me.autostart_status = 1;
  77. me.starter.setBoolValue(1);
  78. settimer(func
  79. {
  80. me.cutoff.setBoolValue(0);
  81. }, me.max_start_n1 / me.start_time);
  82. }
  83. },
  84. # creates an engine update loop (optional)
  85. init: func
  86. {
  87. if (me.loop_running) return;
  88. me.loop_running = 1;
  89. var loop = func
  90. {
  91. me.update();
  92. settimer(loop, UPDATE_PERIOD);
  93. };
  94. settimer(loop, 0);
  95. },
  96. # updates the engine
  97. update: func
  98. {
  99. if (me.running.getBoolValue() and !me.started)
  100. {
  101. me.running.setBoolValue(0);
  102. }
  103. if (me.cutoff.getBoolValue() or !me.serviceable.getBoolValue() or me.out_of_fuel.getBoolValue())
  104. {
  105. var rpm = me.rpm.getValue();
  106. var time_delta = getprop("sim/time/delta-realtime-sec");
  107. if (me.starter.getBoolValue())
  108. {
  109. rpm += time_delta * me.spool_time;
  110. me.rpm.setValue(rpm >= me.max_start_n1 ? me.max_start_n1 : rpm);
  111. }
  112. else
  113. {
  114. rpm -= time_delta * me.shutdown_time;
  115. me.rpm.setValue(rpm <= 0 ? 0 : rpm);
  116. me.running.setBoolValue(0);
  117. me.throttle_lever.setDoubleValue(0);
  118. me.started = 0;
  119. }
  120. }
  121. elsif (me.starter.getBoolValue())
  122. {
  123. var rpm = me.rpm.getValue();
  124. if (rpm >= me.start_threshold)
  125. {
  126. var time_delta = getprop("sim/time/delta-realtime-sec");
  127. rpm += time_delta * me.spool_time;
  128. me.rpm.setValue(rpm);
  129. if (rpm >= me.n1.getValue())
  130. {
  131. me.running.setBoolValue(1);
  132. me.starter.setBoolValue(0);
  133. me.started = 1;
  134. }
  135. else
  136. {
  137. me.running.setBoolValue(0);
  138. }
  139. }
  140. }
  141. elsif (me.running.getBoolValue())
  142. {
  143. me.throttle_lever.setValue(me.idle_throttle + (1 - me.idle_throttle) * me.throttle.getValue());
  144. me.rpm.setValue(me.n1.getValue());
  145. }
  146. }
  147. };
  148. # turboprop engine class
  149. var turboprop_condition_cutoff = 0.001; # minimum condition value for YASim turboprops to start
  150. var Turboprop =
  151. {
  152. new: func(n, running = 0, min_condition = 0.2)
  153. {
  154. # copy the Turboprop object
  155. var m = { parents: [Turboprop] };
  156. # declare object variables
  157. m.number = n;
  158. m.autostart_status = 0;
  159. m.loop_running = 0;
  160. m.min_condition = min_condition;
  161. # create references to properties and set default values
  162. m.condition = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/condition", 1);
  163. m.condition.setDoubleValue(0);
  164. m.condition_lever = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/condition-lever", 1);
  165. m.condition_lever.setDoubleValue(running ? min_condition : 0);
  166. m.cutoff = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/cutoff", 1);
  167. m.cutoff.setBoolValue(!running);
  168. m.n1 = props.globals.getNode("engines/engine[" ~ n ~ "]/n1", 1);
  169. m.n1.setDoubleValue(running ? 100 : 0);
  170. m.n2 = props.globals.getNode("engines/engine[" ~ n ~ "]/n2", 1);
  171. m.n2.setDoubleValue(0);
  172. m.out_of_fuel = props.globals.getNode("engines/engine[" ~ n ~ "]/out-of-fuel", 1);
  173. m.out_of_fuel.setBoolValue(0);
  174. m.propeller_feather = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/propeller-feather", 1);
  175. m.propeller_feather.setBoolValue(0);
  176. m.starter = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/starter", 1);
  177. m.starter.setBoolValue(0);
  178. # return our new object
  179. return m;
  180. },
  181. # engine-specific autostart
  182. autostart: func
  183. {
  184. if (me.autostart_status)
  185. {
  186. me.autostart_status = 0;
  187. me.cutoff.setBoolValue(1);
  188. me.condition.setValue(0);
  189. }
  190. else
  191. {
  192. me.autostart_status = 1;
  193. me.cutoff.setBoolValue(0);
  194. me.starter.setBoolValue(1);
  195. me.condition.setValue(me.min_condition);
  196. }
  197. },
  198. # creates an engine update loop (optional)
  199. init: func
  200. {
  201. if (me.loop_running) return;
  202. me.loop_running = 1;
  203. var loop = func
  204. {
  205. me.update();
  206. settimer(loop, UPDATE_PERIOD);
  207. };
  208. settimer(loop, 0);
  209. },
  210. # updates the engine
  211. update: func
  212. {
  213. if (me.cutoff.getBoolValue())
  214. {
  215. me.out_of_fuel.setBoolValue(1);
  216. }
  217. if (me.starter.getBoolValue() and me.condition_lever.getValue() < turboprop_condition_cutoff and me.condition.getValue() >= me.min_condition)
  218. {
  219. me.condition_lever.setValue(me._get_condition_value(me.condition.getValue()));
  220. }
  221. elsif (me.condition_lever.getValue() < turboprop_condition_cutoff and me.n2.getValue() < 0.5)
  222. {
  223. if (me.propeller_feather.getBoolValue())
  224. {
  225. me.n1.setValue(0);
  226. }
  227. me.condition_lever.setValue(0);
  228. }
  229. if (me.n2.getValue() >= 0.5)
  230. {
  231. if (me.condition_lever.getValue() >= turboprop_condition_cutoff)
  232. {
  233. me.condition_lever.setValue(me._get_condition_value(me.condition.getValue()));
  234. }
  235. else
  236. {
  237. me.condition_lever.setValue(0);
  238. }
  239. me.n1.setValue(me.n2.getValue());
  240. }
  241. },
  242. _get_condition_value: func(v)
  243. {
  244. if (v >= me.min_condition)
  245. {
  246. return turboprop_condition_cutoff + (v - me.min_condition) / (1 - me.min_condition) * (1 - turboprop_condition_cutoff);
  247. }
  248. return v / me.min_condition * turboprop_condition_cutoff;
  249. }
  250. };