27 _last_indicated_heading_dg(0),
30 if (!node->getBoolValue(
"new-default-power-path",
false)) {
31 setDefaultPowerSupplyPath(
"/systems/electrical/outputs/DG");
33 if (node->hasChild(
"suction")) {
36 _suctionPath = node->getStringValue(
"suction");
37 SGPropertyNode_ptr _cfg_node = node->getChild(
"power-supply", 0, true);
38 _cfg_node->setStringValue(_suctionPath);
40 _minVacuum = node->getDoubleValue(
"minimum-vacuum", _minVacuum);
43 _heading_in_nodePath = node->getStringValue(
"heading-source",
"/orientation/heading-deg");
45 SGPropertyNode* gyro_cfg = node->getChild(
"gyro", 0,
true);
46 _minSpin = gyro_cfg->getDoubleValue(
"minimum-spin-norm", 0.9);
47 _gyro_spin_up = gyro_cfg->getDoubleValue(
"spin-up-sec", 4.0);
48 _gyro_spin_down = gyro_cfg->getDoubleValue(
"spin-down-sec", 180.0);
50 SGPropertyNode* limits_cfg = node->getChild(
"limits", 0,
true);
51 _yaw_rate_nodePath = limits_cfg->getStringValue(
"yaw-rate-source",
"/orientation/yaw-rate-degps");
52 _yaw_error_factor = limits_cfg->getDoubleValue(
"yaw-error-factor", 0.033);
53 _yaw_limit_rate = limits_cfg->getDoubleValue(
"yaw-limit-rate", 5.0);
54 _g_error_factor = limits_cfg->getDoubleValue(
"g-error-factor", 0.033);
55 _gnodePath = limits_cfg->getStringValue(
"g-node",
"/accelerations/pilot-g");
56 _g_filtertime = limits_cfg->getDoubleValue(
"g-filter-time", 10.0);
57 _g_limit_lower = limits_cfg->getDoubleValue(
"g-limit-lower", -0.5);
58 _g_limit_upper = limits_cfg->getDoubleValue(
"g-limit-upper", 1.5);
59 _g_limit_tumble = limits_cfg->getDoubleValue(
"g-limit-tumble-factor", 1.5);
73 _heading_in_node =
fgGetNode(_heading_in_nodePath,
true);
74 _yaw_rate_node =
fgGetNode(_yaw_rate_nodePath,
true);
76 _we_speed_node =
fgGetNode(
"/velocities/east-relground-fps",
true);
78 SGPropertyNode *node =
fgGetNode(branch,
true );
79 _offset_node = node->getChild(
"offset-deg", 0,
true);
80 _heading_bug_error_node = node->getChild(
"heading-bug-error-deg", 0,
true);
81 _error_node = node->getChild(
"error-deg", 0,
true);
82 _nav1_error_node = node->getChild(
"nav1-course-error-deg", 0,
true);
83 _heading_out_node = node->getChild(
"indicated-heading-deg", 0,
true);
84 _drift_ph_out_node = node->getChild(
"drift-per-hour-deg", 0,
true);
85 _lat_nut_node = node->getChild(
"latitude-nut-setting", 0,
true);
86 _transp_wander_out_node = node->getChild(
"transport-wander-per-hour-deg", 0,
true);
87 _caged_node = node->getChild(
"caged-flag", 0,
true);
88 _tumble_node = node->getChild(
"tumble-norm", 0,
true);
89 _tumble_flag_node = node->getChild(
"tumble-flag", 0,
true);
90 _align_node = node->getChild(
"align-deg", 0,
true);
91 _spin_node = node->getChild(
"spin", 0,
true);
92 SGPropertyNode* gyro_node = node->getChild(
"gyro", 0,
true);
93 _minSpin_node = gyro_node->getChild(
"minimum-spin", 0,
true);
94 _gyro_spin_up_node = gyro_node->getChild(
"spin-up-sec", 0,
true);
95 _gyro_spin_down_node = gyro_node->getChild(
"spin-down-sec", 0,
true);
98 _suction_node =
fgGetNode(_suctionPath,
true);
99 _minVacuum_node = node->getChild(
"minimum-vacuum", 0,
true);
102 SGPropertyNode* limits_node = node->getChild(
"limits", 0,
true);
103 _yaw_error_factor_node = limits_node->getChild(
"yaw-error-factor", 0,
true);
104 _yaw_limit_rate_node = limits_node->getChild(
"yaw-limit-rate", 0,
true);
105 _g_filtertime_node = limits_node->getChild(
"g-filter-time", 0.0,
true);
106 _g_error_factor_node = limits_node->getChild(
"g-error-factor", 0,
true);
107 _g_limit_lower_node = limits_node->getChild(
"g-limit-lower", 0,
true);
108 _g_limit_upper_node = limits_node->getChild(
"g-limit-upper", 0,
true);
109 _g_limit_tumble_node = limits_node->getChild(
"g-limit-tumble-factor", 0,
true);
120 _align_node->setDoubleValue(0.0);
121 _error_node->setDoubleValue(0.0);
122 _offset_node->setDoubleValue(0.0);
124 _last_heading_deg = _heading_in_node->getDoubleValue();
125 _last_indicated_heading_dg = _last_heading_deg;
127 if (!_minSpin_node->hasValue())
128 _minSpin_node->setDoubleValue(_minSpin);
129 if (_vacuumDriven && !_minVacuum_node->hasValue())
130 _minVacuum_node->setDoubleValue(_minVacuum);
131 if (!_gyro_spin_up_node->hasValue())
132 _gyro_spin_up_node->setDoubleValue(_gyro_spin_up);
133 if (!_gyro_spin_down_node->hasValue())
134 _gyro_spin_down_node->setDoubleValue(_gyro_spin_down);
136 _yaw_error_factor_node->setDoubleValue(_yaw_error_factor);
137 _yaw_limit_rate_node->setDoubleValue(_yaw_limit_rate);
138 _g_filtertime_node->setDoubleValue(_g_filtertime);
139 _g_error_factor_node->setDoubleValue(_g_error_factor);
140 _g_limit_lower_node->setDoubleValue(_g_limit_lower);
141 _g_limit_upper_node->setDoubleValue(_g_limit_upper);
142 _g_limit_tumble_node->setDoubleValue(_g_limit_tumble);
143 _last_g = _g_node->getDoubleValue();
145 _tumble_flag_node->setBoolValue(0);
146 _tumble_node->setDoubleValue(0.0);
157 _minVacuum = _minVacuum_node->getDoubleValue();
164 _gyro.set_spin_up(_gyro_spin_up_node->getDoubleValue());
165 _gyro.set_spin_down(_gyro_spin_down_node->getDoubleValue());
166 _gyro.set_spin_norm(_spin_node->getDoubleValue());
170 double spin = _gyro.get_spin_norm();
171 double heading = _heading_in_node->getDoubleValue();
172 double offset = _offset_node->getDoubleValue();
173 bool isCaged = _caged_node->getBoolValue();
175 _spin_node->setDoubleValue( spin );
179 double factor = isCaged ? 0.0 :
POW6(spin);
185 double latPos =
globals->get_aircraft_position().getLatitudeRad();
186 double drift_per_hour = -15 * sin(latPos);
187 double lat_nut_setting = _lat_nut_node->getDoubleValue();
188 drift_per_hour += 15 * sin(lat_nut_setting * SG_DEGREES_TO_RADIANS);
189 drift_per_hour *= factor;
190 _drift_ph_out_node->setDoubleValue(drift_per_hour);
191 double drift_per_frame = (drift_per_hour / 60 / 60) * dt;
192 offset += drift_per_frame;
198 double gnd_speed_kth = (-1 * SG_FPS_TO_KT * _we_speed_node->getDoubleValue());
199 double transport_wander_p_hour = gnd_speed_kth * (tan(latPos) / 60);
200 transport_wander_p_hour *= factor;
201 _transp_wander_out_node->setDoubleValue(transport_wander_p_hour);
202 double transport_wander_per_frame = (transport_wander_p_hour / 60 / 60) * dt;
203 offset += transport_wander_per_frame;
206 _minSpin = _minSpin_node->getDoubleValue();
207 if (spin < _minSpin || isCaged) {
210 double diff = SGMiscd::normalizePeriodic(-180.0, 180.0, _last_heading_deg - heading);
213 offset += diff * (1.0 - factor) * dt;
215 if (isCaged && _gyro_lag == 0.0) {
220 _last_heading_deg = heading;
221 if (!isCaged && _gyro_lag != 0.0) {
223 offset += _gyro_lag - heading;
228 offset = SGMiscd::normalizePeriodic(-180.0,180.0,offset);
229 _offset_node->setDoubleValue(offset);
232 double align = _align_node->getDoubleValue();
235 double error = _error_node->getDoubleValue();
236 _yaw_error_factor = _yaw_error_factor_node->getDoubleValue();
237 _yaw_limit_rate = _yaw_limit_rate_node->getDoubleValue();
238 double yaw_rate = _yaw_rate_node->getDoubleValue();
239 if (fabs(yaw_rate) > _yaw_limit_rate) {
240 error += _yaw_error_factor * -yaw_rate * dt * factor;
243 _g_error_factor = _g_error_factor_node->getDoubleValue();
244 _g_limit_lower = _g_limit_lower_node->getDoubleValue();
245 _g_limit_upper = _g_limit_upper_node->getDoubleValue();
246 double g = _g_node->getDoubleValue();
247 _g_filtertime = _g_filtertime_node->getDoubleValue();
248 if (_g_filtertime > 0.0) {
252 if (g > _g_limit_upper || g < _g_limit_lower) {
253 error += _g_error_factor * g * dt * factor;
257 _g_limit_tumble = _g_limit_tumble_node->getDoubleValue();
258 double _g_limit_tumble_lower = _g_limit_lower * _g_limit_tumble;
259 double _g_limit_tumble_upper = _g_limit_upper * _g_limit_tumble;
260 double glimit_tumble_exceed = 0;
261 if (g < _g_limit_tumble_lower)
262 glimit_tumble_exceed = g / _g_limit_tumble_lower;
263 if (g > _g_limit_tumble_upper)
264 glimit_tumble_exceed = g / _g_limit_tumble_upper;
265 if (glimit_tumble_exceed > 0 && !isCaged)
266 _tumble_flag_node->setBoolValue(
true);
268 if (_tumble_flag_node->getBoolValue()) {
269 double tumble = _tumble_node->getDoubleValue();
270 double tumble_exceed = glimit_tumble_exceed / 2.0;
271 if (tumble_exceed > tumble)
272 tumble = tumble_exceed;
279 double t_reerect = isCaged ? 1.0 : 300.0;
280 double step = dt / t_reerect;
283 else if (tumble > step)
285 if (fabs(tumble) < 0.01) {
287 _tumble_flag_node->setBoolValue(
false);
290 error += tumble * 720.0 * dt / 1.0;
291 _tumble_node->setDoubleValue(tumble);
294 error = SGMiscd::normalizePeriodic(-180.0, 180.0, error);
295 _error_node->setDoubleValue(error);
298 _last_indicated_heading_dg = heading;
300 heading += offset + align + error;
301 heading = SGMiscd::normalizePeriodic(0.0,360.0,heading);
303 _heading_out_node->setDoubleValue(heading);
307 SGPropertyNode* bnode =
fgGetNode(
"/autopilot/settings/heading-bug-deg",
false);
309 auto diff = SGMiscd::normalizePeriodic(-180.0, 180.0, bnode->getDoubleValue() - heading);
310 _heading_bug_error_node->setDoubleValue(diff);
314 SGPropertyNode* nnode =
fgGetNode(
"/instrumentation/nav/radials/selected-deg",
false);
316 auto diff = SGMiscd::normalizePeriodic(-180.0, 180.0, nnode->getDoubleValue() - heading);
317 _nav1_error_node->setDoubleValue( diff );