332static void s_MotionLogging(
const std::string& _callsign,
double tInterp, SGVec3d ecPos,
const SGGeod& pos)
334 SGGeod pos_geod = pos;
335 if (!
fgGetBool(
"/sim/replay/replay-state-eof"))
337 static SGVec3d s_pos_0;
338 static SGVec3d s_pos_prev;
339 static double s_t_prev = -1;
340 SGVec3d pos2 = ecPos;
341 double sim_replay_time =
fgGetDouble(
"/sim/replay/time");
342 double t =
fgGetBool(
"/sim/replay/replay-state") ? sim_replay_time : tInterp;
349 double t_dt = t - s_t_prev;
352 SGVec3d delta_pos = pos2 - s_pos_prev;
353 SGVec3d delta_pos_norm = normalize(delta_pos);
354 double distance0 = length(pos2 - s_pos_0);
355 double distance = length(delta_pos);
356 double speed = (t_dt) ? distance / t_dt : -999;
360 SGPropertyNode* n0 =
fgGetNode(
"/sim/replay/log-raw-speed-multiplayer-post-values",
true );
363 n = n0->addChild(
"value");
364 n->setDoubleValue(speed);
366 n = n0->addChild(
"description");
368 snprintf(buffer,
sizeof(buffer),
"s_t_prev=%f t=%f t_dt=%f distance=%f",
369 s_t_prev, t, t_dt, distance);
370 n->setStringValue(buffer);
373 SGGeod user_pos_geod =
globals->get_aircraft_position();
374 SGVec3d user_pos =
globals->get_aircraft_position_cart();
376 double user_to_mp_distance = SGGeodesy::distanceM(user_pos_geod, pos_geod);
377 double user_to_mp_bearing = SGGeodesy::courseDeg(user_pos_geod, pos_geod);
378 double user_distance0 = length(user_pos - s_pos_0);
380 fgGetNode(
"/sim/replay/log-raw-speed-multiplayer-post-relative-distance",
true )
382 ->setDoubleValue(user_to_mp_distance);
383 fgGetNode(
"/sim/replay/log-raw-speed-multiplayer-post-relative-bearing",
true )
385 ->setDoubleValue(user_to_mp_bearing);
386 fgGetNode(
"/sim/replay/log-raw-speed-multiplayer-post-absolute-distance",
true )
388 ->setDoubleValue(distance0);
389 fgGetNode(
"/sim/replay/log-raw-speed-multiplayer-post-user-absolute-distance",
true )
391 ->setDoubleValue(user_distance0);
413 if (mMotionInfo.empty())
421 bool motion_logging =
false;
423 string callsign = mLogRawSpeedMultiplayer->getStringValue();
424 if (!callsign.empty() && this->_callsign == callsign)
426 motion_logging =
true;
432 if (m_simple_time_enabled->getBoolValue())
436 if (m_sim_replay_replay_state->getBoolValue())
438 tInterp = m_sim_replay_time->getDoubleValue();
439 SG_LOG(SG_GENERAL, SG_BULK,
"tInterp=" << std::fixed << std::setprecision(6) << tInterp);
450 MotionInfo::reverse_iterator motioninfo_back = mMotionInfo.rbegin();
451 const double curentPkgTime = motioninfo_back->first;
468 double lag = motioninfo_back->second.lag;
470 rawLag = curentPkgTime - curtime;
475 mTimeOffsetSet =
true;
476 mTimeOffset = curentPkgTime - curtime - lag;
477 lastTime = curentPkgTime;
478 lagModAveraged = remainder((curentPkgTime - curtime), 3600.0);
479 m_lagPPSAveragedNode->setDoubleValue(lagPpsAveraged);
480 m_lagModAveragedNode->setDoubleValue(lagModAveraged);
484 if ((curentPkgTime - lastTime) != 0)
486 lagPpsAveraged = 0.99 * lagPpsAveraged + 0.01 * fabs( 1 / (lastTime - curentPkgTime));
487 lastTime = curentPkgTime;
488 rawLagMod = remainder(rawLag, 3600.0);
489 lagModAveraged = lagModAveraged *0.99 + 0.01 * rawLagMod;
490 m_lagPPSAveragedNode->setDoubleValue(lagPpsAveraged);
491 m_lagModAveragedNode->setDoubleValue(lagModAveraged);
497 if (compensateLag == 3)
499 offset = curentPkgTime - curtime - lag + playerLag;
502 else if (compensateLag == 1)
504 offset = curentPkgTime - curtime - lag;
509 else if (fabs(lagModAveraged) < 0.3)
511 mTimeOffset = (round(rawLag/3600))*3600;
516 offset = curentPkgTime - curtime + 0.48*lag + playerLag;
521 if ((!mAllowExtrapolation && offset + lag < mTimeOffset) || (offset - 10 > mTimeOffset))
523 mTimeOffset = offset;
524 SG_LOG(SG_AI, SG_DEBUG,
"Resetting time offset adjust system to "
525 "avoid extrapolation: time offset = " << mTimeOffset);
531 double err = offset - mTimeOffset;
542 sysSpeed = mLagAdjustSystemSpeed*err*0.01;
546 sysSpeed = SGMiscd::min(0.5*err*err, 0.05);
555 sysSpeed = mLagAdjustSystemSpeed*err;
560 sysSpeed = SGMiscd::min(0.1*err*err, 0.5);
567 double systemIncrement = dt*sysSpeed;
568 if (fabs(err) < fabs(systemIncrement))
570 systemIncrement = err;
572 mTimeOffset += systemIncrement;
574 SG_LOG(SG_AI, SG_DEBUG,
"Offset adjust system: time offset = "
575 << mTimeOffset <<
", expected longitudinal position error due to "
576 " current adjustment of the offset: "
577 << fabs(norm(motioninfo_back->second.linearVel)*systemIncrement));
584 tInterp = curtime + mTimeOffset;
591 MotionInfo::iterator nextIt = mMotionInfo.upper_bound(tInterp);
592 MotionInfo::iterator prevIt = nextIt;
594 if (nextIt != mMotionInfo.end() && nextIt->first >= tInterp)
601 if (nextIt == mMotionInfo.begin())
604 SG_LOG(SG_GENERAL, SG_DEBUG,
"Only one frame for interpolation: " <<
_callsign);
610 double intervalStart = prevIt->first;
611 double intervalEnd = nextIt->first;
613 double intervalLen = intervalEnd - intervalStart;
614 if (intervalLen != 0.0)
616 tau = (tInterp - intervalStart) / intervalLen;
620 FGAIMultiplayerInterpolate(prevIt, nextIt, tau, ecPos, ecOrient, ecLinearVel);
628 FGAIMultiplayerExtrapolate(nextIt, tInterp, motion_logging, ecPos, ecOrient, ecLinearVel);
634 mMotionInfo.erase(mMotionInfo.begin(), prevIt);
637 pos = SGGeod::fromCart(ecPos);
642 if (lastUpdateTime != 0)
644 double dT = curtime - lastUpdateTime;
653 lastUpdateTime = curtime;
657 SGQuatf qEc2Hl = SGQuatf::fromLonLatRad((
float)
pos.getLongitudeRad(), (
float)
pos.getLatitudeRad());
659 SGQuatf hlOr = conj(qEc2Hl)*ecOrient;
660 float hDeg, pDeg, rDeg;
661 hlOr.getEulerDeg(hDeg, pDeg, rDeg);
667 _uBodyNode->setValue(ecLinearVel[0] * SG_METER_TO_FEET);
668 _vBodyNode->setValue(ecLinearVel[1] * SG_METER_TO_FEET);
669 _wBodyNode->setValue(ecLinearVel[2] * SG_METER_TO_FEET);
671 if (ecLinearVel[0] == 0) {
674 double speed_kts =
props->getDoubleValue(
"velocities/speed-kts");
675 double speed_fps = speed_kts * SG_KT_TO_FPS;
679 std::string ai_latch = m_node_ai_latch->getStringValue();
680 if (ai_latch != m_ai_latch) {
681 SG_LOG(SG_AI, SG_ALERT,
"latching _callsign=" <<
_callsign <<
" to mp " << ai_latch);
682 m_ai_latch = ai_latch;
683 SGPropertyNode* mp_node =
globals->get_props()->getNode(ai_latch,
false );
684 m_node_ai_latch_latitude = mp_node ? mp_node->getNode(
"position/latitude-deg",
true ) :
nullptr;
685 m_node_ai_latch_longitude = mp_node ? mp_node->getNode(
"position/longitude-deg",
true ) :
nullptr;
686 m_node_ai_latch_altitude = mp_node ? mp_node->getNode(
"position/altitude-ft",
true ) :
nullptr;
687 m_node_ai_latch_heading = mp_node ? mp_node->getNode(
"orientation/true-heading-deg",
true ) :
nullptr;
688 m_node_ai_latch_pitch = mp_node ? mp_node->getNode(
"orientation/pitch-deg",
true ) :
nullptr;
689 m_node_ai_latch_roll = mp_node ? mp_node->getNode(
"orientation/roll-deg",
true ) :
nullptr;
690 m_node_ai_latch_ubody_fps = mp_node ? mp_node->getNode(
"velocities/uBody-fps",
true ) :
nullptr;
691 m_node_ai_latch_vbody_fps = mp_node ? mp_node->getNode(
"velocities/vBody-fps",
true ) :
nullptr;
692 m_node_ai_latch_wbody_fps = mp_node ? mp_node->getNode(
"velocities/wBody-fps",
true ) :
nullptr;
693 m_node_ai_latch_speed_kts = mp_node ? mp_node->getNode(
"velocities/speed-kts",
true ) :
nullptr;
695 if (ai_latch !=
"") {
696 SGPropertyNode* mp_node =
globals->get_props()->getNode(ai_latch,
true );
697 assert(m_node_ai_latch_latitude->getPath() == mp_node->getNode(
"position/latitude-deg")->getPath());
698 m_node_ai_latch_latitude->setDoubleValue(
pos.getLatitudeDeg());
699 m_node_ai_latch_longitude->setDoubleValue(
pos.getLongitudeDeg());
700 m_node_ai_latch_altitude->setDoubleValue(
pos.getElevationFt());
701 m_node_ai_latch_heading->setDoubleValue(hDeg);
702 m_node_ai_latch_pitch->setDoubleValue(
pitch);
703 m_node_ai_latch_roll->setDoubleValue(
roll);
704 m_node_ai_latch_ubody_fps->setDoubleValue(_uBodyNode->getDoubleValue());
705 m_node_ai_latch_vbody_fps->setDoubleValue(_vBodyNode->getDoubleValue());
706 m_node_ai_latch_wbody_fps->setDoubleValue(_wBodyNode->getDoubleValue());
722 m_node_ai_latch_speed_kts->setDoubleValue(_uBodyNode->getDoubleValue() * SG_FPS_TO_KT);
724 assert(m_node_ai_latch ==
props->getNode(
"ai-latch"));
745 if (range_ft2 < 250.0 * 250.0 && y_shift > 0.0 &&
elevation > 0.0)
771 mLastTimestamp = stamp;
773 if (m_simple_time_enabled->getBoolValue()) {
776 double t = m_sim_replay_replay_state->getBoolValue()
777 ? m_sim_replay_time->getDoubleValue()
781 m_simple_time_offset = motionInfo.
time - t;
782 if (m_simple_time_first_time)
784 m_simple_time_first_time =
false;
785 m_simple_time_offset_smoothed = m_simple_time_offset;
788 m_simple_time_offset_smoothed = (1-
e) * m_simple_time_offset_smoothed
789 +
e * m_simple_time_offset;
791 if (m_simple_time_offset_smoothed < -2.0 || m_simple_time_offset_smoothed > 1)
815 m_simple_time_compensation = -m_simple_time_offset_smoothed;
820 m_lagModAveragedNode->setDoubleValue(0.0);
824 m_simple_time_compensation = 0;
825 m_lagModAveragedNode->setDoubleValue(m_simple_time_offset_smoothed);
828 m_node_simple_time_latest->setDoubleValue(motionInfo.
time);
829 m_node_simple_time_offset->setDoubleValue(m_simple_time_offset);
830 m_node_simple_time_offset_smoothed->setDoubleValue(m_simple_time_offset_smoothed);
831 m_node_simple_time_compensation->setDoubleValue(m_simple_time_compensation);
833 double t_key = motionInfo.
time + m_simple_time_compensation;
834 if (m_simple_time_recent_packet_time)
836 double dt = t_key - m_simple_time_recent_packet_time;
840 lagPpsAveraged = (1-ep) * lagPpsAveraged + ep * (1/dt);
841 m_lagPPSAveragedNode->setDoubleValue(lagPpsAveraged);
845 m_simple_time_recent_packet_time = t_key;
855 mMotionInfo[t_key] = motionInfo;
859 mMotionInfo[motionInfo.
time] = motionInfo;
869 if (m_node_log_multiplayer->getStringValue() == this->_callsign)
871 static SGVec3d pos_prev;
872 static double t_prev = 0;
874 double distance = length(motionInfo.
position - pos_prev);
875 double dt = motionInfo.
time - t_prev;
876 double speed = distance / dt;
878 double linear_vel = norm(motionInfo.
linearVel);
880 SGPropertyNode* item =
fgGetNode(
"/sim/log-multiplayer",
true )->addChild(
"mppacket");
881 item->setDoubleValue(
"distance", distance);
882 item->setDoubleValue(
"speed",
speed);
883 item->setDoubleValue(
"dt", dt);
884 item->setDoubleValue(
"linear_vel", linear_vel);
885 item->setDoubleValue(
"t", motionInfo.
time );
888 t_prev = motionInfo.
time;