Changeset 10946 in ntrip for trunk/BNC/src/bncantex.cpp
- Timestamp:
- Jun 24, 2026, 4:39:53 PM (13 hours ago)
- File:
-
- 1 edited
-
trunk/BNC/src/bncantex.cpp (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/BNC/src/bncantex.cpp
r10619 r10946 40 40 41 41 #include <iostream> 42 #include <cmath> 42 43 #include <newmatio.h> 43 44 … … 330 331 } 331 332 333 // GLONASS Yaw Angle (Sun-pointing law overridden near noon/midnight when 334 // the satellite cannot mechanically keep up, following the GLONASS-M 335 // "yaw-fixed" behaviour described in Dilssner, Springer, Flohrer, Dow 336 // (2011), "The GLONASS-M satellite yaw-attitude model", Advances in Space 337 // Research 47(1), 160-171. 338 // 339 // Unlike GPS/Galileo/BeiDou, which are commonly approximated by the 340 // nominal Sun-pointing yaw-steering law of Bar-Sever (1996) at all times, 341 // GLONASS-M has been found to stop tracking that law and hold a constant 342 // (frozen) yaw angle whenever the required yaw rate would exceed the 343 // satellite's slew capability - which happens close to the orbit 344 // noon/midnight points whenever the Sun's elevation above the orbital 345 // plane (the "beta" angle) is small. The maximum yaw rate used below 346 // (0.25 deg/s) and the general approach follow that paper; satellite 347 // telemetry was not available to validate the exact rate against this 348 // installation's GLONASS satellites, so it should be checked against 349 // independently-known attitude/orbit residuals if high accuracy matters. 350 //////////////////////////////////////////////////////////////////////////// 351 double bncAntex::glonassYawAngle(const QString& prn, const ColumnVector& xSat, 352 const ColumnVector& vSat, 353 const ColumnVector& xSun) { 354 355 const double MAX_YAW_RATE = 0.25 * M_PI / 180.0; // [rad/s], approximate 356 357 // Inertial-consistent velocity (xSat, vSat are Earth-fixed; remove the 358 // Earth-rotation contribution so that the orbit normal below is not 359 // contaminated by it) 360 // ------------------------------------------------------------------- 361 ColumnVector Omega(3); Omega(1) = 0.0; Omega(2) = 0.0; Omega(3) = t_CST::omega; 362 ColumnVector vInert = vSat + crossproduct(Omega, xSat); 363 364 // Orbit normal and instantaneous orbital rate from r x v (exact, valid 365 // for any Keplerian orbit, not just circular ones) 366 // --------------------------------------------------------------------- 367 ColumnVector h = crossproduct(xSat, vInert); 368 double hNorm = sqrt(DotProduct(h, h)); 369 ColumnVector orbNormal = h / hNorm; 370 double r = sqrt(DotProduct(xSat, xSat)); 371 double nRate = hNorm / (r * r); // [rad/s] 372 373 // Beta angle (Sun elevation above the orbital plane) 374 // ---------------------------------------------------- 375 double beta = asin(DotProduct(orbNormal, xSun)); 376 377 // Orbit angle mu, measured from the orbit midnight point, increasing in 378 // the direction of satellite motion 379 // ----------------------------------------------------------------------- 380 ColumnVector sunProj = xSun - DotProduct(xSun, orbNormal) * orbNormal; 381 sunProj /= sqrt(DotProduct(sunProj, sunProj)); 382 ColumnVector eX = -1.0 * sunProj; // midnight direction, mu = 0 383 ColumnVector eY = crossproduct(orbNormal, eX); 384 ColumnVector rHat = xSat / r; 385 double mu = atan2(DotProduct(rHat, eY), DotProduct(rHat, eX)); 386 387 // Nominal Sun-pointing yaw angle and its rate (Bar-Sever 1996) 388 // ---------------------------------------------------------------- 389 double tanBeta = tan(beta); 390 double sinMu = sin(mu); 391 double psiNom = atan2(-tanBeta, sinMu); 392 double denom = tanBeta * tanBeta + sinMu * sinMu; 393 double psiRate = (denom > 1e-12) 394 ? nRate * fabs(tanBeta * cos(mu)) / denom 395 : 1e9; 396 397 t_glonassYaw& st = _glonassYaw[prn]; 398 double psiEff; 399 if (psiRate > MAX_YAW_RATE) { 400 if (!st.valid) { 401 st.yaw = psiNom; // no prior history - best available estimate 402 } 403 psiEff = st.yaw; // hold the frozen yaw angle 404 } 405 else { 406 st.yaw = psiNom; 407 st.valid = true; 408 psiEff = psiNom; 409 } 410 411 return psiEff; 412 } 413 332 414 // Satellite Antenna Offset 333 415 //////////////////////////////////////////////////////////////////////////// 334 416 t_irc bncAntex::satCoMcorrection(const QString& prn, double Mjd, 335 const ColumnVector& xSat, ColumnVector& dx) { 417 const ColumnVector& xSat, 418 const ColumnVector& vSat, ColumnVector& dx) { 336 419 337 420 t_frequency::type frqType = t_frequency::dummy; … … 374 457 xSun /= sqrt(DotProduct(xSun,xSun)); 375 458 376 ColumnVector sy = crossproduct(sz, xSun); 377 sy /= sqrt(DotProduct(sy,sy)); 378 379 ColumnVector sx = crossproduct(sy, sz); 459 ColumnVector sy, sx; 460 461 // GLONASS: override the nominal Sun-pointing attitude near the 462 // orbit noon/midnight points when the beta angle is small (see 463 // glonassYawAngle() above). Elsewhere GLONASS-M follows the same 464 // nominal law as the other constellations, so the result is 465 // identical to the direct Sun-pointing computation used below. 466 // ----------------------------------------------------------------- 467 if (prn[0] == 'R' && vSat.size() == 3) { 468 double psi = glonassYawAngle(prn, xSat, vSat, xSun); 469 470 ColumnVector vInert = vSat; 471 ColumnVector Omega(3); Omega(1) = 0.0; Omega(2) = 0.0; Omega(3) = t_CST::omega; 472 vInert += crossproduct(Omega, xSat); 473 474 ColumnVector sy0 = crossproduct(sz, vInert); 475 sy0 /= sqrt(DotProduct(sy0,sy0)); 476 ColumnVector sx0 = crossproduct(sy0, sz); 477 478 // Rodrigues rotation of (sx0, sy0) around sz by angle psi 479 double cosY = cos(psi); 480 double sinY = sin(psi); 481 sx = sx0 * cosY + crossproduct(sz, sx0) * sinY; 482 sy = sy0 * cosY + crossproduct(sz, sy0) * sinY; 483 } 484 else { 485 sy = crossproduct(sz, xSun); 486 sy /= sqrt(DotProduct(sy,sy)); 487 sx = crossproduct(sy, sz); 488 } 380 489 381 490 dx[0] = sx[0] * neu[0] + sy[0] * neu[1] + sz[0] * neu[2];
Note:
See TracChangeset
for help on using the changeset viewer.
