BDSD2NavEph.cpp
Go to the documentation of this file.
1 //==============================================================================
2 //
3 // This file is part of GNSSTk, the ARL:UT GNSS Toolkit.
4 //
5 // The GNSSTk is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published
7 // by the Free Software Foundation; either version 3.0 of the License, or
8 // any later version.
9 //
10 // The GNSSTk is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with GNSSTk; if not, write to the Free Software Foundation,
17 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
18 //
19 // This software was developed by Applied Research Laboratories at the
20 // University of Texas at Austin.
21 // Copyright 2004-2022, The Board of Regents of The University of Texas System
22 //
23 //==============================================================================
24 
25 
26 //==============================================================================
27 //
28 // This software was developed by Applied Research Laboratories at the
29 // University of Texas at Austin, under contract to an agency or agencies
30 // within the U.S. Department of Defense. The U.S. Government retains all
31 // rights to use, duplicate, distribute, disclose, or release this software.
32 //
33 // Pursuant to DoD Directive 523024
34 //
35 // DISTRIBUTION STATEMENT A: This software has been approved for public
36 // release, distribution is unlimited.
37 //
38 //==============================================================================
39 #include "BDSD2NavEph.hpp"
40 #include "BDSWeekSecond.hpp"
41 #include "TimeString.hpp"
42 #include "GPS_URA.hpp"
43 #include "Matrix.hpp"
44 #include "CGCS2000Ellipsoid.hpp"
45 
46 using namespace std;
47 
48 namespace gnsstk
49 {
50  BDSD2NavEph ::
51  BDSD2NavEph()
52  : satH1(true),
53  aodc(0xff),
54  aode(0xff),
55  uraIndex(15),
56  tgd1(std::numeric_limits<double>::quiet_NaN()),
57  tgd2(std::numeric_limits<double>::quiet_NaN())
58  {
60  }
61 
62 
63  bool BDSD2NavEph ::
64  getXvt(const CommonTime& when, Xvt& xvt, const ObsID& oid)
65  {
67 
68  if ((signal.sat.id >= MIN_MEO_BDS) && (signal.sat.id <= MAX_MEO_BDS))
69  {
70  // use the standard getXvt for MEO/IGSO satellites
71  return OrbitDataKepler::getXvt(when, ell, xvt);
72  }
73  BDSWeekSecond bdsws = Toe;
74  double ToeSOW = bdsws.sow;
75  double ea; // eccentric anomaly
76  double delea; // delta eccentric anomaly during iteration
77  double elapte; // elapsed time since Toe
78  double q,sinea,cosea;
79  double GSTA,GCTA;
80  double amm;
81  double meana; // mean anomaly
82  double F,G; // temporary real variables
83  double alat,talat,c2al,s2al,du,dr,di,U,R,truea,AINC;
84  double ANLON,cosu,sinu,xip,yip,can,san,cinc,sinc;
85  double xef,yef,zef,dek,dlk,div,domk,duv,drv;
86  double dxp,dyp,vxef,vyef,vzef;
87  double xGK,yGK,zGK;
88 
89  // Compute time since ephemeris & clock epochs
90  elapte = when - Toe;
91  double sqrtgm = SQRT(ell.gm());
92 
93  // Compute A at time of interest
94  double Ak = A + Adot * elapte;
95 
96  double twoPI = 2.0e0 * PI;
97  double lecc; // eccentricity
98  double tdrinc; // dt inclination
99 
100  lecc = ecc;
101  tdrinc = idot;
102 
103  // Compute mean motion
104  double dnA = dn + 0.5 * dndot * elapte;
105  double Ahalf = SQRT(A);
106  amm = (sqrtgm / (A*Ahalf)) + dnA; // NOT Ak because this equation
107  // specifies A0, not Ak.
108 
109  // In-plane angles
110  // meana - Mean anomaly
111  // ea - Eccentric anomaly
112  // truea - True anomaly
113 
114  meana = M0 + elapte * amm;
115  meana = fmod(meana, twoPI);
116 
117  ea = meana + lecc * ::sin(meana);
118 
119  int loop_cnt = 1;
120  do {
121  F = meana - ( ea - lecc * ::sin(ea));
122  G = 1.0 - lecc * ::cos(ea);
123  delea = F/G;
124  ea = ea + delea;
125  loop_cnt++;
126  } while ( (fabs(delea) > 1.0e-11 ) && (loop_cnt <= 20) );
127 
128  // Compute clock corrections
129  xvt.relcorr = svRelativity(when);
130  xvt.clkbias = svClockBias(when);
131  xvt.clkdrift = svClockDrift(when);
132  xvt.frame = RefFrame(frame, when);
133 
134  // Compute true anomaly
135  q = SQRT( 1.0e0 - lecc*lecc);
136  sinea = ::sin(ea);
137  cosea = ::cos(ea);
138  G = 1.0e0 - lecc * cosea;
139 
140  // G*SIN(TA) AND G*COS(TA)
141  GSTA = q * sinea;
142  GCTA = cosea - lecc;
143 
144  // True anomaly
145  truea = atan2 ( GSTA, GCTA );
146 
147  // Argument of lat and correction terms (2nd harmonic)
148  alat = truea + w;
149  talat = 2.0e0 * alat;
150  c2al = ::cos( talat );
151  s2al = ::sin( talat );
152 
153  du = c2al * Cuc + s2al * Cus;
154  dr = c2al * Crc + s2al * Crs;
155  di = c2al * Cic + s2al * Cis;
156 
157  // U = updated argument of lat, R = radius, AINC = inclination
158  U = alat + du;
159  R = Ak*G + dr;
160  AINC = i0 + tdrinc * elapte + di;
161  // At this point, the ICD formulation diverges to something
162  // different.
163  // Longitude of ascending node (ANLON)
164  ANLON = OMEGA0 + OMEGAdot * elapte
165  - ell.angVelocity() * ToeSOW;
166 
167  // In plane location
168  cosu = ::cos(U);
169  sinu = ::sin(U);
170  xip = R * cosu;
171  yip = R * sinu;
172 
173  // Angles for rotation
174  can = ::cos(ANLON);
175  san = ::sin(ANLON);
176  cinc = ::cos(AINC);
177  sinc = ::sin(AINC);
178 
179  // GEO satellite coordinates in user-defined inertial system
180  xGK = xip*can - yip*cinc*san;
181  yGK = xip*san + yip*cinc*can;
182  zGK = yip*sinc;
183 
184  // Rz matrix
185  double angleZ = ell.angVelocity() * elapte;
186  double cosZ = ::cos(angleZ);
187  double sinZ = ::sin(angleZ);
188 
189  // Initiailize 3X3 with all 0.0
190  gnsstk::Matrix<double> matZ(3,3);
191  // Row,Col
192  matZ(0,0) = cosZ;
193  matZ(0,1) = sinZ;
194  matZ(0,2) = 0.0;
195  matZ(1,0) = -sinZ;
196  matZ(1,1) = cosZ;
197  matZ(1,2) = 0.0;
198  matZ(2,0) = 0.0;
199  matZ(2,1) = 0.0;
200  matZ(2,2) = 1.0;
201 
202  // Rx matrix
203  const double angleX = -5.0 * PI/180.0;
204  double cosX = ::cos(angleX);
205  double sinX = ::sin(angleX);
206  gnsstk::Matrix<double> matX(3,3);
207  matX(0,0) = 1.0;
208  matX(0,1) = 0.0;
209  matX(0,2) = 0.0;
210  matX(1,0) = 0.0;
211  matX(1,1) = cosX;
212  matX(1,2) = sinX;
213  matX(2,0) = 0.0;
214  matX(2,1) = -sinX;
215  matX(2,2) = cosX;
216 
217  // Matrix (single column) of xGK, yGK, zGK
218  gnsstk::Matrix<double> inertialPos(3,1);
219  inertialPos(0,0) = xGK;
220  inertialPos(1,0) = yGK;
221  inertialPos(2,0) = zGK;
222 
223  gnsstk::Matrix<double> result(3,1);
224  result = matZ * matX * inertialPos;
225 
226  xvt.x[0] = result(0,0);
227  xvt.x[1] = result(1,0);
228  xvt.x[2] = result(2,0);
229 
230  // derivatives of true anamoly and arg of latitude
231  dek = amm / G;
232  dlk = amm * q / (G*G);
233 
234  // in-plane, cross-plane, and radial derivatives
235  div = tdrinc - 2.0e0 * dlk * (Cic * s2al - Cis * c2al);
236  duv = dlk*(1.e0+ 2.e0 * (Cus*c2al - Cuc*s2al));
237  drv = A * lecc * dek * sinea + 2.e0 * dlk * (Crs * c2al - Crc * s2al) +
238  Adot * G;
239 
240  //
241  dxp = drv*cosu - R*sinu*duv;
242  dyp = drv*sinu + R*cosu*duv;
243 
244  // Time-derivative of Rz matrix
245  gnsstk::Matrix<double> dmatZ(3,3);
246  // Row,Col
247  dmatZ(0,0) = sinZ * -ell.angVelocity();
248  dmatZ(0,1) = -cosZ * -ell.angVelocity();
249  dmatZ(0,2) = 0.0;
250  dmatZ(1,0) = cosZ * -ell.angVelocity();
251  dmatZ(1,1) = sinZ * -ell.angVelocity();
252  dmatZ(1,2) = 0.0;
253  dmatZ(2,0) = 0.0;
254  dmatZ(2,1) = 0.0;
255  dmatZ(2,2) = 0.0;
256 
257  // Time-derivative of X,Y,Z in interial form
258  gnsstk::Matrix<double> dIntPos(3,1);
259  dIntPos(0,0) = - xip * san * OMEGAdot
260  + dxp * can
261  - yip * (cinc * can * OMEGAdot
262  -sinc * san * div )
263  - dyp * cinc * san;
264  dIntPos(1,0) = xip * can * OMEGAdot
265  + dxp * san
266  - yip * (cinc * san * OMEGAdot
267  +sinc * can * div )
268  + dyp * cinc * can;
269  dIntPos(2,0) = yip * cinc * div + dyp * sinc;
270 
271  gnsstk::Matrix<double> vresult(3,1);
272  vresult = matZ * matX * dIntPos +
273  dmatZ * matX * inertialPos;
274 
275  // Move results into output variables
276  xvt.v[0] = vresult(0,0);
277  xvt.v[1] = vresult(1,0);
278  xvt.v[2] = vresult(2,0);
279  switch (health)
280  {
281  case SVHealth::Unknown:
282  xvt.health = Xvt::Unknown;
283  break;
284  case SVHealth::Healthy:
285  xvt.health = Xvt::Healthy;
286  break;
287  case SVHealth::Unhealthy:
288  xvt.health = Xvt::Unhealthy;
289  break;
290  case SVHealth::Degraded:
291  xvt.health = Xvt::Degraded;
292  break;
293  default:
295  break;
296  }
297 
298  return true;
299  }
300 
301 
302  bool BDSD2NavEph ::
303  validate() const
304  {
305  return BDSD2NavData::validate();
306  }
307 
308 
311  {
312  // 10 pages, 3s between = 30s
313  return xmitTime + 30.0;
314  }
315 
316 
317  void BDSD2NavEph ::
319  {
320  beginFit = Toe - 7200.0; // Default case
321  // If elements were updated during the hour, then
322  // we want to use the later time.
324  if (xmitTime > Toe)
325  beginFit = xmitTime;
326  endFit = Toe + 7200;
327  }
328 
329 
330  void BDSD2NavEph ::
331  dumpSVStatus(std::ostream& s) const
332  {
333  const ios::fmtflags oldFlags = s.flags();
334  s.setf(ios::fixed, ios::floatfield);
335  s.setf(ios::right, ios::adjustfield);
336  s.setf(ios::uppercase);
337  s.precision(0);
338  s.fill(' ');
339  // Use these to print subframe SOW in a formatted fashion.
340  // We're not printing the week so setting the week to 0 is
341  // fine.
342  BDSWeekSecond ws1(0,sow);
343  s << " SV STATUS" << endl << endl
344  << "Health bit (SatH1) : 0x" << hex << (unsigned)satH1 << dec
345  << endl
346  << "AODC : " << setw(6) << getAOD(aodc) << " hours ("
347  << (unsigned)aodc << ")" << endl
348  << "AODE : " << setw(6) << getAOD(aode) << " hours ("
349  << (unsigned)aode << ")" << endl
350  << "URA index : " << setw(6) << (unsigned)uraIndex << endl
351  << "URA (nominal) : " << setw(6) << fixed
352  << SV_ACCURACY_GPS_NOMINAL_INDEX[uraIndex] << " m" << endl
353  << "Health : " << setw(9)
355  << "Tgd1 : " << setw(13) << setprecision(6)
356  << scientific << tgd1 << " sec" << endl
357  << "Tgd2 : " << setw(13) << setprecision(6)
358  << scientific << tgd2 << " sec" << endl << endl
359  << " SUBFRAME OVERHEAD" << endl << endl
360  << " SOW DOW:HH:MM:SS" << endl
361  << printTime(ws1, "Pg1 SOW: %6.0g %3a-%w:%02H:%02M:%02S\n");
362  s.flags(oldFlags);
363  }
364 
365  unsigned BDSD2NavEph ::
366  getAOD(uint8_t aod)
367  {
368  if (aod < 25)
369  return aod;
370  if (aod < 32)
371  return 24 * (aod-23);
372  return (unsigned)-1;
373  }
374 }
gnsstk::OrbitDataKepler::idot
double idot
Rate of inclination angle (rad/sec)
Definition: OrbitDataKepler.hpp:193
gnsstk::Xvt::Unknown
@ Unknown
Health state is unknown.
Definition: Xvt.hpp:93
gnsstk::SatID::id
int id
Satellite identifier, e.g. PRN.
Definition: SatID.hpp:154
gnsstk::MIN_MEO_BDS
const long MIN_MEO_BDS
The first ranging code number for BeiDou MEO/IGSO satellites.
Definition: GNSSconstants.hpp:213
gnsstk::CGCS2000Ellipsoid::gm
virtual double gm() const noexcept
Definition: CGCS2000Ellipsoid.hpp:96
BDSD2NavEph.hpp
gnsstk::OrbitDataKepler::frame
RefFrameSys frame
Definition: OrbitDataKepler.hpp:202
gnsstk::OrbitDataKepler::Cis
double Cis
Sine inclination (rad)
Definition: OrbitDataKepler.hpp:180
gnsstk::OrbitDataKepler::A
double A
Semi-major axis (m)
Definition: OrbitDataKepler.hpp:186
SQRT
#define SQRT(x)
Definition: MathBase.hpp:74
gnsstk::SV_ACCURACY_GPS_NOMINAL_INDEX
const double SV_ACCURACY_GPS_NOMINAL_INDEX[]
Definition: GPS_URA.hpp:65
gnsstk::OrbitDataKepler::ecc
double ecc
Eccentricity.
Definition: OrbitDataKepler.hpp:185
gnsstk::OrbitDataKepler::svClockBias
double svClockBias(const CommonTime &when) const
Definition: OrbitDataKepler.cpp:341
gnsstk::Xvt::Healthy
@ Healthy
Satellite is healthy, PVT valid.
Definition: Xvt.hpp:96
gnsstk::NavMessageID::messageType
NavMessageType messageType
Definition: NavMessageID.hpp:97
GPS_URA.hpp
gnsstk::OrbitDataBDS::svRelativity
double svRelativity(const CommonTime &when) const override
Definition: OrbitDataBDS.hpp:75
gnsstk::OrbitDataKepler::OMEGAdot
double OMEGAdot
Rate of Rt ascension (rad/sec)
Definition: OrbitDataKepler.hpp:192
gnsstk::BDSD2NavEph::satH1
bool satH1
Autonomous satellite health flag.
Definition: BDSD2NavEph.hpp:115
example5.oid
oid
Definition: example5.py:29
gnsstk::Xvt::frame
RefFrame frame
reference frame of this data
Definition: Xvt.hpp:156
gnsstk::BDSD2NavEph::aodc
uint8_t aodc
Age of data - clock.
Definition: BDSD2NavEph.hpp:116
gnsstk::NavFit::endFit
CommonTime endFit
Time at end of fit interval.
Definition: NavFit.hpp:55
gnsstk::StringUtils::asString
std::string asString(IonexStoreStrategy e)
Convert a IonexStoreStrategy to a whitespace-free string name.
Definition: IonexStoreStrategy.cpp:46
gnsstk::OrbitDataKepler::Cuc
double Cuc
Cosine latitude (rad)
Definition: OrbitDataKepler.hpp:175
gnsstk::OrbitDataKepler::w
double w
Argument of perigee (rad)
Definition: OrbitDataKepler.hpp:191
gnsstk::PI
const double PI
GPS value of PI; also specified by GAL.
Definition: GNSSconstants.hpp:62
gnsstk::Xvt::v
Triple v
satellite velocity in ECEF Cartesian, meters/second
Definition: Xvt.hpp:152
gnsstk::OrbitDataKepler::Toe
CommonTime Toe
Orbit epoch.
Definition: OrbitDataKepler.hpp:171
gnsstk::OrbitDataKepler::Crs
double Crs
Sine radius (m)
Definition: OrbitDataKepler.hpp:178
gnsstk::RefFrame
Definition: RefFrame.hpp:53
gnsstk::NavData::signal
NavMessageID signal
Source signal identification for this navigation message data.
Definition: NavData.hpp:175
gnsstk::BDSD2NavEph::validate
bool validate() const override
Definition: BDSD2NavEph.cpp:303
gnsstk::SVHealth::Degraded
@ Degraded
Satellite is in a degraded state. Use at your own risk.
gnsstk
For Sinex::InputHistory.
Definition: BasicFramework.cpp:50
gnsstk::CGCS2000Ellipsoid::angVelocity
virtual double angVelocity() const noexcept
Definition: CGCS2000Ellipsoid.hpp:91
std::sin
double sin(gnsstk::Angle x)
Definition: Angle.hpp:144
gnsstk::Xvt::relcorr
double relcorr
relativity correction (standard 2R.V/c^2 term), seconds
Definition: Xvt.hpp:155
gnsstk::OrbitDataKepler::xmitTime
CommonTime xmitTime
Time of transmission of the start of the data.
Definition: OrbitDataKepler.hpp:170
gnsstk::BDSD2NavEph::tgd2
double tgd2
Group delay differential on B2I.
Definition: BDSD2NavEph.hpp:124
gnsstk::OrbitDataKepler::Adot
double Adot
Rate of semi-major axis (m/sec)
Definition: OrbitDataKepler.hpp:188
gnsstk::Xvt::Uninitialized
@ Uninitialized
Health status has not been set.
Definition: Xvt.hpp:90
gnsstk::OrbitDataKepler::M0
double M0
Mean anomaly (rad)
Definition: OrbitDataKepler.hpp:182
gnsstk::Xvt::x
Triple x
Sat position ECEF Cartesian (X,Y,Z) meters.
Definition: Xvt.hpp:151
gnsstk::SVHealth::Unknown
@ Unknown
Health is not known or is uninitialized.
gnsstk::BDSD2NavData::validate
bool validate() const override
Definition: BDSD2NavData.cpp:56
gnsstk::SVHealth::Healthy
@ Healthy
Satellite is in a healthy and useable state.
gnsstk::OrbitDataKepler::dndot
double dndot
Rate of correction to mean motion (rad/sec/sec)
Definition: OrbitDataKepler.hpp:184
gnsstk::BDSD2NavEph::getUserTime
CommonTime getUserTime() const override
Definition: BDSD2NavEph.cpp:310
gnsstk::OrbitDataKepler::Cus
double Cus
Sine latitude (rad)
Definition: OrbitDataKepler.hpp:176
gnsstk::Matrix< double >
CGCS2000Ellipsoid.hpp
gnsstk::ObsID
Definition: ObsID.hpp:82
gnsstk::OrbitDataKepler::Ahalf
double Ahalf
Square Root of semi-major axis (m**.5)
Definition: OrbitDataKepler.hpp:187
gnsstk::NavSatelliteID::sat
SatID sat
ID of satellite to which the nav data applies.
Definition: NavSatelliteID.hpp:169
gnsstk::CommonTime
Definition: CommonTime.hpp:84
gnsstk::WeekSecond::sow
double sow
Definition: WeekSecond.hpp:155
gnsstk::Xvt::clkdrift
double clkdrift
satellite clock drift in seconds/second
Definition: Xvt.hpp:154
gnsstk::NavFit::beginFit
CommonTime beginFit
Time at beginning of fit interval.
Definition: NavFit.hpp:54
gnsstk::Xvt
Definition: Xvt.hpp:60
std::cos
double cos(gnsstk::Angle x)
Definition: Angle.hpp:146
gnsstk::OrbitDataKepler::i0
double i0
Inclination (rad)
Definition: OrbitDataKepler.hpp:190
gnsstk::Xvt::health
HealthStatus health
Health status of satellite at ref time.
Definition: Xvt.hpp:157
gnsstk::OrbitDataKepler::svClockDrift
double svClockDrift(const CommonTime &when) const
Definition: OrbitDataKepler.cpp:351
gnsstk::OrbitDataKepler::Cic
double Cic
Cosine inclination (rad)
Definition: OrbitDataKepler.hpp:179
gnsstk::BDSD2NavEph::getXvt
bool getXvt(const CommonTime &when, Xvt &xvt, const ObsID &=ObsID()) override
Definition: BDSD2NavEph.cpp:64
gnsstk::OrbitDataKepler::Crc
double Crc
Cosine radius (m)
Definition: OrbitDataKepler.hpp:177
gnsstk::BDSD2NavEph::tgd1
double tgd1
Group delay differential on B1I.
Definition: BDSD2NavEph.hpp:123
gnsstk::printTime
std::string printTime(const CommonTime &t, const std::string &fmt)
Definition: TimeString.cpp:64
std
Definition: Angle.hpp:142
gnsstk::BDSD2NavEph::aode
uint8_t aode
Age of data - ephemeris.
Definition: BDSD2NavEph.hpp:117
gnsstk::NavMessageType::Ephemeris
@ Ephemeris
Precision orbits for the transmitting SV.
BDSWeekSecond.hpp
gnsstk::BDSD2NavEph::getAOD
static unsigned getAOD(uint8_t aod)
Definition: BDSD2NavEph.cpp:366
gnsstk::Xvt::Degraded
@ Degraded
Sat is in a degraded state, recommend do not use.
Definition: Xvt.hpp:95
Matrix.hpp
gnsstk::Xvt::clkbias
double clkbias
Sat clock correction in seconds.
Definition: Xvt.hpp:153
gnsstk::BDSD2NavEph::uraIndex
uint8_t uraIndex
4-bit URA index from subframe 1.
Definition: BDSD2NavEph.hpp:122
gnsstk::BDSD2NavEph::fixFit
void fixFit()
Definition: BDSD2NavEph.cpp:318
gnsstk::BDSWeekSecond
Definition: BDSWeekSecond.hpp:56
gnsstk::OrbitDataKepler::health
SVHealth health
SV health status.
Definition: OrbitDataKepler.hpp:173
gnsstk::MAX_MEO_BDS
const long MAX_MEO_BDS
The last ranging code number for BeiDou MEO/IGSO satellites.
Definition: GNSSconstants.hpp:215
gnsstk::SVHealth::Unhealthy
@ Unhealthy
Satellite is unhealthy and should not be used.
gnsstk::OrbitDataKepler::OMEGA0
double OMEGA0
Longitude of ascending node at weekly epoch (rad)
Definition: OrbitDataKepler.hpp:189
gnsstk::BDSD2NavEph::dumpSVStatus
void dumpSVStatus(std::ostream &s) const override
Definition: BDSD2NavEph.cpp:331
gnsstk::CGCS2000Ellipsoid
Definition: CGCS2000Ellipsoid.hpp:58
gnsstk::Xvt::Unhealthy
@ Unhealthy
Sat is marked unhealthy, do not use PVT.
Definition: Xvt.hpp:94
TimeString.hpp
gnsstk::OrbitDataKepler::getXvt
bool getXvt(const CommonTime &when, Xvt &xvt, const ObsID &oid=ObsID()) override=0
gnsstk::BDSD2NavData::sow
uint32_t sow
Seconds of week from word 1-2 of the subframe.
Definition: BDSD2NavData.hpp:71
gnsstk::OrbitDataKepler::dn
double dn
Correction to mean motion (rad/sec)
Definition: OrbitDataKepler.hpp:183


gnsstk
Author(s):
autogenerated on Wed Oct 25 2023 02:40:38