|
33 | 33 | import numpy as np |
34 | 34 |
|
35 | 35 | import gnss_lib_py.utils.constants as consts |
| 36 | +from gnss_lib_py.parsers.navdata import NavData |
36 | 37 |
|
37 | 38 | EPSILON = 1e-7 |
38 | 39 |
|
@@ -467,3 +468,81 @@ def ecef_to_el_az(rx_pos, sv_pos): |
467 | 468 | el_az[:,1][el_az[:,1] < 0] += 360 |
468 | 469 |
|
469 | 470 | return el_az |
| 471 | + |
| 472 | +def add_el_az(navdata, receiver_state, inplace=False): |
| 473 | + """Adds elevation and azimuth to NavData object. |
| 474 | +
|
| 475 | + Parameters |
| 476 | + ---------- |
| 477 | + navdata : gnss_lib_py.parsers.navdata.NavData |
| 478 | + Instance of the NavData class. Must include ``gps_millis`` as |
| 479 | + well as satellite ECEF positions as ``x_sv_m``, ``y_sv_m``, |
| 480 | + ``z_sv_m``, ``gnss_id`` and ``sv_id``. |
| 481 | + receiver_state : gnss_lib_py.parsers.navdata.NavData |
| 482 | + Either estimated or ground truth receiver position in ECEF frame |
| 483 | + in meters as an instance of the NavData class with the |
| 484 | + following rows: ``x_*_m``, ``y_*_m``, ``z_*_m``, ``gps_millis``. |
| 485 | + inplace : bool |
| 486 | + If false (default) will add elevation and azimuth to a new |
| 487 | + NavData instance. If true, will add elevation and azimuth to the |
| 488 | + existing NavData instance. |
| 489 | +
|
| 490 | + Returns |
| 491 | + ------- |
| 492 | + data_el_az : gnss_lib_py.parsers.navdata.NavData |
| 493 | + If inplace is True, adds ``el_sv_deg`` and ``az_sv_deg`` to |
| 494 | + the input navdata and returns the same object. |
| 495 | + If inplace is False, returns ``el_sv_deg`` and ``az_sv_deg`` |
| 496 | + in a new NavData instance along with ``gps_millis`` and the |
| 497 | + corresponding satellite and receiver rows. |
| 498 | +
|
| 499 | + """ |
| 500 | + |
| 501 | + # check for missing rows |
| 502 | + navdata.in_rows(["gps_millis","x_sv_m","y_sv_m","z_sv_m", |
| 503 | + "gnss_id","sv_id"]) |
| 504 | + receiver_state.in_rows(["gps_millis"]) |
| 505 | + |
| 506 | + # check for receiver_state indexes |
| 507 | + rx_idxs = receiver_state.find_wildcard_indexes(["x_*_m","y_*_m", |
| 508 | + "z_*_m"],max_allow=1) |
| 509 | + |
| 510 | + sv_el_az = None |
| 511 | + for timestamp, _, navdata_subset in navdata.loop_time("gps_millis"): |
| 512 | + |
| 513 | + pos_sv_m = navdata_subset[["x_sv_m","y_sv_m","z_sv_m"]].T |
| 514 | + |
| 515 | + # find time index for receiver_state NavData instance |
| 516 | + rx_t_idx = np.argmin(np.abs(receiver_state["gps_millis"] - timestamp)) |
| 517 | + |
| 518 | + pos_rx_m = receiver_state[[rx_idxs["x_*_m"][0], |
| 519 | + rx_idxs["y_*_m"][0], |
| 520 | + rx_idxs["z_*_m"][0]], |
| 521 | + rx_t_idx].reshape(1,-1) |
| 522 | + |
| 523 | + timestep_el_az = ecef_to_el_az(pos_rx_m, pos_sv_m) |
| 524 | + |
| 525 | + if sv_el_az is None: |
| 526 | + sv_el_az = timestep_el_az.T |
| 527 | + else: |
| 528 | + sv_el_az = np.hstack((sv_el_az,timestep_el_az.T)) |
| 529 | + |
| 530 | + if inplace: |
| 531 | + navdata["el_sv_deg"] = sv_el_az[0,:] |
| 532 | + navdata["az_sv_deg"] = sv_el_az[1,:] |
| 533 | + return navdata |
| 534 | + |
| 535 | + data_el_az = NavData() |
| 536 | + data_el_az["gps_millis"] = navdata["gps_millis"] |
| 537 | + data_el_az["gnss_id"] = navdata["gnss_id"] |
| 538 | + data_el_az["sv_id"] = navdata["sv_id"] |
| 539 | + data_el_az["x_sv_m"] = navdata["x_sv_m"] |
| 540 | + data_el_az["y_sv_m"] = navdata["y_sv_m"] |
| 541 | + data_el_az["z_sv_m"] = navdata["z_sv_m"] |
| 542 | + data_el_az[rx_idxs["x_*_m"][0]] = receiver_state[rx_idxs["x_*_m"][0]] |
| 543 | + data_el_az[rx_idxs["y_*_m"][0]] = receiver_state[rx_idxs["y_*_m"][0]] |
| 544 | + data_el_az[rx_idxs["z_*_m"][0]] = receiver_state[rx_idxs["z_*_m"][0]] |
| 545 | + data_el_az["el_sv_deg"] = sv_el_az[0,:] |
| 546 | + data_el_az["az_sv_deg"] = sv_el_az[1,:] |
| 547 | + |
| 548 | + return data_el_az |
0 commit comments