Example #1
0
def compare(line1_1, line1_2, line2_1, line2_2, timestamp_min, timestamps, td):
    ts = load.timescale()

    satrec1 = Satrec.twoline2rv(line1_1, line1_2)
    satrec2 = Satrec.twoline2rv(line2_1, line2_2)
    satellite1 = EarthSatellite.from_satrec(satrec1, ts)
    satellite2 = EarthSatellite.from_satrec(satrec2, ts)

    residual = 0
    number_of_measurements = 0
    for s in range(len(timestamps)):
        number_of_measurements += len(timestamps[s])
        for t0 in range(len(timestamps[s])):
            time_step = timestamps[s][t0]

            timestamp1 = timestamp_min + time_step + td[s]

            observing_time = Time(timestamp1, format="unix", scale="utc")
            t = ts.from_astropy(observing_time)

            R1 = satellite1.at(t).position.km
            R2 = satellite2.at(t).position.km

            distance = ((R1[0] - R2[0])**2 + (R1[1] - R2[1])**2 +
                        (R1[2] - R2[2])**2)**0.5
            residual += distance

    return residual / number_of_measurements
Example #2
0
    def __init__(self,
                 whichconst=WGS72,
                 opsmode='i',
                 satnum=5,
                 epoch=None,
                 bstar=2.8098e-05,
                 ndot=6.969196665e-13,
                 nddot=0.0,
                 ecco=0.1859667,
                 argpo=5.7904160274885,
                 inclo=0.5980929187319,
                 mo=0.3373093125574,
                 no_kozai=0.0472294454407,
                 nodeo=6.0863854713832,
                 orientation='sun'):
        self.ts = load.timescale()
        self.t_now = self.ts.now()
        self.t_origin = 2433281.5
        self.t_days_now = self.t_now.ut1

        if epoch == None:
            epoch = (self.t_days_now - self.t_origin) + 0.5
        else:
            epoch = (epoch - self.t_origin) + 0.5

        self.whichconst = whichconst  # gravity model
        self.opsmode = opsmode  # 'a' = old AFSPC mode, 'i' = improved mode
        self.satnum = satnum  # satnum: Satellite number
        self.epoch = epoch  # epoch: days since 1949 December 31 00:00 UT
        self.bstar = bstar  # bstar: drag coefficient (/earth radii)
        self.ndot = ndot  # ndot: ballistic coefficient (revs/day)
        self.nddot = nddot  # nddot: second derivative of mean motion (revs/day^3)
        self.ecco = ecco  # ecco: eccentricity
        self.argpo = argpo  # argpo: argument of perigee (radians)
        self.inclo = inclo  # inclo: inclination (radians)
        self.mo = mo  # mo: mean anomaly (radians)
        self.no_kozai = no_kozai  # no_kozai: mean motion (radians/minute)
        self.nodeo = nodeo  # nodeo: right ascension of ascending node (radians)

        self.satrec = Satrec()
        self.satrec.sgp4init(self.whichconst, self.opsmode, self.satnum,
                             self.epoch, self.bstar, self.ndot, self.nddot,
                             self.ecco, self.argpo, self.inclo, self.mo,
                             self.no_kozai, self.nodeo)
        self.satellite = EarthSatellite.from_satrec(self.satrec, self.ts)
        self.planets = load('de421.bsp')
        self.earth = self.planets['earth']
        self.sun = self.planets['sun']
        self.ssb_satellite = self.earth + self.satellite
        self.orientation = orientation
    return satrec


MINUTES_PER_DAY = 24 * 60
ONE_METER = 1.0 / AU_M
ONE_KM_PER_HOUR = 1.0 * 24.0 / AU_KM
ts = load.timescale(builtin=True)
# TLE
stations_tle = load.tle_file("stations-tle.txt", reload=False)
# XML
tree = ET.parse("stations.xml")
root = tree.getroot()

t0 = ts.utc(2020, 6, 27)
for sat_tle in stations_tle:
    name = sat_tle.name.strip()
    print(name, sat_tle.model.satnum)
    # Find and parse XML twin
    satrec = satrec_from_XML(root, sat_tle.model.satnum)
    sat_xml = EarthSatellite.from_satrec(satrec, ts)
    p_xml = sat_xml.at(t0)
    p_tle = sat_tle.at(t0)
    #print("XML Location", p_xml.position.au)
    #print("TLE location", p_tle.position.au)
    #print()
    #print("XML velocity", p_xml.velocity.au_per_d)
    #print("TLE velocity", p_tle.velocity.au_per_d)
    assert abs(p_xml.position.au - p_tle.position.au).max() < ONE_METER
    assert abs(p_xml.velocity.au_per_d -
               p_tle.velocity.au_per_d).max() < ONE_KM_PER_HOUR
Example #4
0
def satellite_determination(utc_min, utc_max):
    """
    Estimate the identity of spacecraft observed between the unix times <utc_min> and <utc_max>.

    :param utc_min:
        The start of the time period in which we should determine the identity of spacecraft (unix time).
    :type utc_min:
        float
    :param utc_max:
        The end of the time period in which we should determine the identity of spacecraft (unix time).
    :type utc_max:
        float
    :return:
        None
    """

    # Open connection to image archive
    db = obsarchive_db.ObservationDatabase(
        file_store_path=settings['dbFilestore'],
        db_host=installation_info['mysqlHost'],
        db_user=installation_info['mysqlUser'],
        db_password=installation_info['mysqlPassword'],
        db_name=installation_info['mysqlDatabase'],
        obstory_id=installation_info['observatoryId'])

    logging.info("Starting satellite identification.")

    # Count how many images we manage to successfully fit
    outcomes = {
        'successful_fits': 0,
        'unsuccessful_fits': 0,
        'error_records': 0,
        'rescued_records': 0,
        'insufficient_information': 0
    }

    # Status update
    logging.info("Searching for satellites within period {} to {}".format(
        date_string(utc_min), date_string(utc_max)))

    # Open direct connection to database
    conn = db.con

    # Search for satellites within this time period
    conn.execute(
        """
SELECT ao.obsTime, ao.publicId AS observationId, f.repositoryFname, l.publicId AS observatory
FROM archive_observations ao
LEFT OUTER JOIN archive_files f ON (ao.uid = f.observationId AND
    f.semanticType=(SELECT uid FROM archive_semanticTypes WHERE name="pigazing:movingObject/video"))
INNER JOIN archive_observatories l ON ao.observatory = l.uid
INNER JOIN archive_metadata am2 ON ao.uid = am2.observationId AND
    am2.fieldId=(SELECT uid FROM archive_metadataFields WHERE metaKey="web:category")
WHERE ao.obsType=(SELECT uid FROM archive_semanticTypes WHERE name='pigazing:movingObject/') AND
      ao.obsTime BETWEEN %s AND %s AND
      (am2.stringValue='Plane' OR am2.stringValue='Satellite' OR am2.stringValue='Junk')
ORDER BY ao.obsTime
""", (utc_min, utc_max))
    results = conn.fetchall()

    # Display logging list of the images we are going to work on
    logging.info("Estimating the identity of {:d} spacecraft.".format(
        len(results)))

    # Analyse each spacecraft in turn
    for item_index, item in enumerate(results):
        # Fetch metadata about this object, some of which might be on the file, and some on the observation
        obs_obj = db.get_observation(observation_id=item['observationId'])
        obs_metadata = {item.key: item.value for item in obs_obj.meta}
        if item['repositoryFname']:
            file_obj = db.get_file(repository_fname=item['repositoryFname'])
            file_metadata = {item.key: item.value for item in file_obj.meta}
        else:
            file_metadata = {}
        all_metadata = {**obs_metadata, **file_metadata}

        # Check we have all required metadata
        if 'pigazing:path' not in all_metadata:
            logging.info(
                "Cannot process <{}> due to inadequate metadata.".format(
                    item['observationId']))
            continue

        # Make ID string to prefix to all logging messages about this event
        logging_prefix = "{date} [{obs}]".format(
            date=date_string(utc=item['obsTime']), obs=item['observationId'])

        # Project path from (x,y) coordinates into (RA, Dec)
        projector = PathProjection(db=db,
                                   obstory_id=item['observatory'],
                                   time=item['obsTime'],
                                   logging_prefix=logging_prefix)

        path_x_y, path_ra_dec_at_epoch, path_alt_az, sight_line_list_this = projector.ra_dec_from_x_y(
            path_json=all_metadata['pigazing:path'],
            path_bezier_json=all_metadata['pigazing:pathBezier'],
            detections=all_metadata['pigazing:detectionCount'],
            duration=all_metadata['pigazing:duration'])

        # Check for error
        if projector.error is not None:
            if projector.error in outcomes:
                outcomes[projector.error] += 1
            continue

        # Check for notifications
        for notification in projector.notifications:
            if notification in outcomes:
                outcomes[notification] += 1

        # Check number of points in path
        path_len = len(path_x_y)

        # Look up list of satellite orbital elements at the time of this sighting
        spacecraft_list = fetch_satellites(utc=item['obsTime'])

        # List of candidate satellites this object might be
        candidate_satellites = []

        # Check that we found a list of spacecraft
        if spacecraft_list is None:
            logging.info(
                "{date} [{obs}] -- No spacecraft records found.".format(
                    date=date_string(utc=item['obsTime']),
                    obs=item['observationId']))
            outcomes['insufficient_information'] += 1
            continue

        # Logging message about how many spacecraft we're testing
        # logging.info("{date} [{obs}] -- Matching against {count:7d} spacecraft.".format(
        #     date=date_string(utc=item['obsTime']),
        #     obs=item['observationId'],
        #     count=len(spacecraft_list)
        # ))

        # Test for each candidate satellite in turn
        for spacecraft in spacecraft_list:
            # Unit scaling
            deg2rad = pi / 180.0  # 0.0174532925199433
            xpdotp = 1440.0 / (2.0 * pi)  # 229.1831180523293

            # Model the path of this spacecraft
            model = Satrec()
            model.sgp4init(
                # whichconst: gravity model
                WGS72,

                # opsmode: 'a' = old AFSPC mode, 'i' = improved mode
                'i',

                # satnum: Satellite number
                spacecraft['noradId'],

                # epoch: days since 1949 December 31 00:00 UT
                jd_from_unix(spacecraft['epoch']) - 2433281.5,

                # bstar: drag coefficient (/earth radii)
                spacecraft['bStar'],

                # ndot (NOT USED): ballistic coefficient (revs/day)
                spacecraft['meanMotionDot'] / (xpdotp * 1440.0),

                # nddot (NOT USED): mean motion 2nd derivative (revs/day^3)
                spacecraft['meanMotionDotDot'] / (xpdotp * 1440.0 * 1440),

                # ecco: eccentricity
                spacecraft['ecc'],

                # argpo: argument of perigee (radians)
                spacecraft['argPeri'] * deg2rad,

                # inclo: inclination (radians)
                spacecraft['incl'] * deg2rad,

                # mo: mean anomaly (radians)
                spacecraft['meanAnom'] * deg2rad,

                # no_kozai: mean motion (radians/minute)
                spacecraft['meanMotion'] / xpdotp,

                # nodeo: right ascension of ascending node (radians)
                spacecraft['RAasc'] * deg2rad)

            # Wrap within skyfield to convert to topocentric coordinates
            ts = load.timescale()
            sat = EarthSatellite.from_satrec(model, ts)

            # Fetch spacecraft position at each time point along trajectory
            ang_mismatch_list = []
            distance_list = []

            # e, r, v = model.sgp4(jd_from_unix(utc=item['obsTime']), 0)
            # logging.info("{} {} {}".format(str(e), str(r), str(v)))
            tai_utc_offset = 39  # seconds

            def satellite_angular_offset(index, clock_offset):
                # Fetch observed position of object at this time point
                pt_utc = path_x_y[index][3]
                pt_alt = path_alt_az[index][0]
                pt_az = path_alt_az[index][1]

                # Project position of this satellite in space at this time point
                t = ts.tai_jd(jd=jd_from_unix(utc=pt_utc + tai_utc_offset +
                                              clock_offset))

                # Project position of this satellite in the observer's sky
                sight_line = sat - observer
                topocentric = sight_line.at(t)
                sat_alt, sat_az, sat_distance = topocentric.altaz()

                # Work out offset of satellite's position from observed moving object
                ang_mismatch = ang_dist(ra0=pt_az * pi / 180,
                                        dec0=pt_alt * pi / 180,
                                        ra1=sat_az.radians,
                                        dec1=sat_alt.radians) * 180 / pi

                return ang_mismatch, sat_distance

            def time_offset_objective(p):
                """
                Objective function that we minimise in order to find the best fit clock offset between the observed
                and model paths.

                :param p:
                    Vector with a single component: the clock offset
                :return:
                    Metric to minimise
                """

                # Turn input parameters into a time offset
                clock_offset = p[0]

                # Look up angular offset
                ang_mismatch, sat_distance = satellite_angular_offset(
                    index=0, clock_offset=clock_offset)

                # Return metric to minimise
                return ang_mismatch * exp(clock_offset / 8)

            # First, chuck out satellites with large angular offsets
            observer = wgs84.latlon(
                latitude_degrees=projector.obstory_info['latitude'],
                longitude_degrees=projector.obstory_info['longitude'],
                elevation_m=0)

            ang_mismatch, sat_distance = satellite_angular_offset(
                index=0, clock_offset=0)

            # Check angular offset is reasonable
            if ang_mismatch > global_settings['max_angular_mismatch']:
                continue

            # Work out the optimum time offset between the satellite's path and the observed path
            # See <http://www.scipy-lectures.org/advanced/mathematical_optimization/>
            # for more information about how this works
            parameters_initial = [0]
            parameters_optimised = scipy.optimize.minimize(
                time_offset_objective,
                np.asarray(parameters_initial),
                options={
                    'disp': False,
                    'maxiter': 100
                }).x

            # Construct best-fit linear trajectory for best-fitting parameters
            clock_offset = float(parameters_optimised[0])

            # Check clock offset is reasonable
            if abs(clock_offset) > global_settings['max_clock_offset']:
                continue

            # Measure the offset between the satellite's position and the observed position at each time point
            for index in range(path_len):
                # Look up angular mismatch at this time point
                ang_mismatch, sat_distance = satellite_angular_offset(
                    index=index, clock_offset=clock_offset)

                # Keep list of the offsets at each recorded time point along the trajectory
                ang_mismatch_list.append(ang_mismatch)
                distance_list.append(sat_distance.km)

            # Consider adding this satellite to list of candidates
            mean_ang_mismatch = np.mean(np.asarray(ang_mismatch_list))
            distance_mean = np.mean(np.asarray(distance_list))

            if mean_ang_mismatch < global_settings['max_mean_angular_mismatch']:
                candidate_satellites.append({
                    'name':
                    spacecraft['name'],  # string
                    'noradId':
                    spacecraft['noradId'],  # int
                    'distance':
                    distance_mean,  # km
                    'clock_offset':
                    clock_offset,  # seconds
                    'offset':
                    mean_ang_mismatch,  # degrees
                    'absolute_magnitude':
                    spacecraft['mag']
                })

        # Add model possibility for null satellite
        candidate_satellites.append({
            'name': "Unidentified",
            'noradId': 0,
            'distance': 35.7e3 *
            0.25,  # Nothing is visible beyond 25% of geostationary orbit distance
            'clock_offset': 0,
            'offset': 0,
            'absolute_magnitude': None
        })

        # Sort candidates by score - use absolute mag = 20 for satellites with no mag
        for candidate in candidate_satellites:
            candidate['score'] = hypot(
                candidate['distance'] / 1e3,
                candidate['clock_offset'],
                (20 if candidate['absolute_magnitude'] is None else
                 candidate['absolute_magnitude']),
            )
        candidate_satellites.sort(key=itemgetter('score'))

        # Report possible satellite identifications
        logging.info("{prefix} -- {satellites}".format(
            prefix=logging_prefix,
            satellites=", ".join([
                "{} ({:.1f} deg offset; clock offset {:.1f} sec)".format(
                    satellite['name'], satellite['offset'],
                    satellite['clock_offset'])
                for satellite in candidate_satellites
            ])))

        # Identify most likely satellite
        most_likely_satellite = candidate_satellites[0]

        # Store satellite identification
        user = settings['pigazingUser']
        timestamp = time.time()
        db.set_observation_metadata(user_id=user,
                                    observation_id=item['observationId'],
                                    utc=timestamp,
                                    meta=mp.Meta(
                                        key="satellite:name",
                                        value=most_likely_satellite['name']))
        db.set_observation_metadata(
            user_id=user,
            observation_id=item['observationId'],
            utc=timestamp,
            meta=mp.Meta(key="satellite:norad_id",
                         value=most_likely_satellite['noradId']))
        db.set_observation_metadata(
            user_id=user,
            observation_id=item['observationId'],
            utc=timestamp,
            meta=mp.Meta(key="satellite:clock_offset",
                         value=most_likely_satellite['clock_offset']))
        db.set_observation_metadata(user_id=user,
                                    observation_id=item['observationId'],
                                    utc=timestamp,
                                    meta=mp.Meta(
                                        key="satellite:angular_offset",
                                        value=most_likely_satellite['offset']))
        db.set_observation_metadata(
            user_id=user,
            observation_id=item['observationId'],
            utc=timestamp,
            meta=mp.Meta(key="satellite:path_length",
                         value=ang_dist(ra0=path_ra_dec_at_epoch[0][0],
                                        dec0=path_ra_dec_at_epoch[0][1],
                                        ra1=path_ra_dec_at_epoch[-1][0],
                                        dec1=path_ra_dec_at_epoch[-1][1]) *
                         180 / pi))
        db.set_observation_metadata(
            user_id=user,
            observation_id=item['observationId'],
            utc=timestamp,
            meta=mp.Meta(
                key="satellite:path_ra_dec",
                value="[[{:.3f},{:.3f}],[{:.3f},{:.3f}],[{:.3f},{:.3f}]]".
                format(
                    path_ra_dec_at_epoch[0][0] * 12 / pi,
                    path_ra_dec_at_epoch[0][1] * 180 / pi,
                    path_ra_dec_at_epoch[int(path_len / 2)][0] * 12 / pi,
                    path_ra_dec_at_epoch[int(path_len / 2)][1] * 180 / pi,
                    path_ra_dec_at_epoch[-1][0] * 12 / pi,
                    path_ra_dec_at_epoch[-1][1] * 180 / pi,
                )))

        # Satellite successfully identified
        if most_likely_satellite['name'] == "Unidentified":
            outcomes['unsuccessful_fits'] += 1
        else:
            outcomes['successful_fits'] += 1

        # Update database
        db.commit()

    # Report how many fits we achieved
    logging.info("{:d} satellites successfully identified.".format(
        outcomes['successful_fits']))
    logging.info("{:d} satellites not identified.".format(
        outcomes['unsuccessful_fits']))
    logging.info("{:d} malformed database records.".format(
        outcomes['error_records']))
    logging.info("{:d} rescued database records.".format(
        outcomes['rescued_records']))
    logging.info("{:d} satellites with incomplete data.".format(
        outcomes['insufficient_information']))

    # Clean up and exit
    db.commit()
    db.close_db()
    return
Example #5
0
def get_state_sum(r_a, r_p, inc, raan, AoP, tp, bstar, td, station,
                  timestamp_min, timestamps, mode, measurements, meta):

    elevation_min = -30

    # putting in the measurements
    ra = measurements["ra"]
    dec = measurements["dec"]
    el = measurements["el"]
    az = measurements["az"]
    ranging = measurements["range"]
    doppler = measurements["doppler"]
    satellite_pos = measurements["satellite_pos"]

    # preparing the orbit track that is being simulated and used for comparing to the measurements
    #track = np.zeros_like(satellite_pos) # did not work with strange arrays.
    track = []
    for tr in range(len(satellite_pos)):
        track.append(np.zeros_like(satellite_pos[tr]))

    track_az = []
    track_el = []
    for tr in range(len(az)):
        track_az.append(np.zeros_like(az[tr]))
        track_el.append(np.zeros_like(el[tr]))

    track_range = []
    for tr in range(len(ranging)):
        track_range.append(np.zeros_like(ranging[tr]))

    track_doppler = []
    for tr in range(len(doppler)):
        track_doppler.append(np.zeros_like(doppler[tr]))

    track_ra = []
    track_dec = []
    for tr in range(len(ra)):
        track_ra.append(np.zeros_like(ra[tr]))
        track_dec.append(np.zeros_like(dec[tr]))

    # preparing the orbit parameter needed for the simulated orbit
    eccentricity = (r_a - r_p) / (r_a + r_p)
    h_angularmomentuum = np.sqrt(r_p * (1.0 + eccentricity * np.cos(0)) * mu)
    T_orbitperiod = 2.0 * np.pi / mu**2.0 * (h_angularmomentuum /
                                             np.sqrt(1.0 - eccentricity**2))**3

    me = tp * (2.0 * np.pi) / T_orbitperiod * 180.0 / np.pi
    me = zeroTo360(me)
    AoP = zeroTo360(AoP)
    raan = zeroTo360(raan)
    n = 24.0 * 3600.0 / T_orbitperiod

    # preparing the orbit by putting in the orbit parameters
    ts = load.timescale()

    satnum = 0
    epoch = timestamp_min
    ecco = eccentricity
    argpo = AoP
    inclo = inc
    mo = me
    no_kozai = n
    nodeo = raan
    ndot = 0.0
    satrec = get_satrec(satnum,
                        epoch,
                        ecco,
                        argpo,
                        inclo,
                        mo,
                        no_kozai,
                        nodeo,
                        bstar,
                        ndot,
                        nddot=0.0)
    satellite = EarthSatellite.from_satrec(satrec, ts)

    # now for each station s the measurements are being iterated through by its measurements.
    # for each measurement, the orbit state is calculated based on the timestamp t0
    for s in range(len(timestamps)):

        for t0 in range(len(satellite_pos[s])):

            time_step = timestamps[s][t0]

            timestamp1 = timestamp_min + time_step + td[s]

            observing_time = Time(timestamp1, format="unix", scale="utc")
            t = ts.from_astropy(observing_time)

            R1 = satellite.at(t).position.km
            #V1 = satellite.at(t).velocity.km_per_s

            #R = np.array(R1)
            #V = np.array(V1)

            track[s][t0][0] = R1[0]
            track[s][t0][1] = R1[1]
            track[s][t0][2] = R1[2]

            #############

            #if mode == 0:
            #    #state_sum += (R[0] - satellite_pos[s][t0][0]) ** 2 + \
            #    #             (R[1] - satellite_pos[s][t0][1]) ** 2 + \
            #    #             (R[2] - satellite_pos[s][t0][2]) ** 2

        ### station
        if "long" in station[s]:
            gs_long = station[s]["long"]
            gs_lat = station[s]["lat"]
            gs_alt = station[s]["alt"]

            observer = wgs84.latlon(gs_lat, gs_long, gs_alt)
            difference = satellite - observer

        for t0 in range(len(az[s])):
            time_step = timestamps[s][t0]

            timestamp1 = timestamp_min + time_step + td[s]
            if np.abs(td[s]) > 2.0:
                # the system time is expected to be jittery only by a few seconds.
                # so this should be enough and stops the time seach to run amok
                return -np.inf

            observing_time = Time(timestamp1, format="unix", scale="utc")
            t = ts.from_astropy(observing_time)

            topocentric = difference.at(t)
            alt1, az1, distance1 = topocentric.altaz()

            if alt1.degrees >= elevation_min:
                track_az[s][t0] = az1.degrees
                track_el[s][t0] = alt1.degrees
            else:
                #track_az[s][t0] = np.inf
                #track_el[s][t0] = np.inf

                # if one value is not good, then it is already infinity and we can also quit now
                return -np.inf

        for t0 in range(len(ranging[s])):
            time_step = timestamps[s][t0]

            timestamp1 = timestamp_min + time_step + td[s]

            observing_time = Time(timestamp1, format="unix", scale="utc")
            t = ts.from_astropy(observing_time)

            topocentric = difference.at(t)
            alt1, az1, distance1 = topocentric.altaz()

            if alt1.degrees >= elevation_min:
                track_range[s][t0] = distance1.km
            else:
                #track_range[s][t0] = np.inf

                # if one value is not good, then it is already infinity and we can also quit now
                return -np.inf

        for t0 in range(len(doppler[s])):
            time_step = timestamps[s][t0]

            timestamp1 = timestamp_min + time_step + td[s]

            observing_time = Time(timestamp1, format="unix", scale="utc")
            t = ts.from_astropy(observing_time)

            topocentric = difference.at(t)
            alt1, az1, distance1 = topocentric.altaz()
            pointing = topocentric.position.km
            velo = topocentric.velocity.km_per_s
            #angle = np.dot(pointing, velo)
            angle = (pointing[0] * velo[0] + pointing[1] * velo[1] +
                     pointing[2] * velo[2]) / (np.linalg.norm(pointing) *
                                               np.linalg.norm(velo))
            angle = np.arccos(angle)
            range_rate = np.cos(angle) * np.linalg.norm(velo)
            f_0 = meta[s][0]["rf"]["fc"]
            c_speedoflight = 299792.458
            doppler_c = -range_rate * f_0 / c_speedoflight

            if alt1.degrees >= elevation_min:
                track_doppler[s][t0] = doppler_c
            else:
                #track_doppler[s][t0] = np.inf

                # if one value is not good, then it is already infinity and we can also quit now
                return -np.inf

        for t0 in range(len(ra[s])):
            time_step = timestamps[s][t0]

            timestamp1 = timestamp_min + time_step + td[s]

            observing_time = Time(timestamp1, format="unix", scale="utc")
            t = ts.from_astropy(observing_time)

            topocentric = difference.at(t)
            ra1, dec1, distance1 = topocentric.radec()
            alt1, az1, distance2 = topocentric.altaz()

            if alt1.degrees >= elevation_min:
                track_ra[s][t0] = ra1.radians * 180.0 / np.pi
                track_dec[s][t0] = dec1.degrees
            else:
                #track_ra[s][t0] = np.inf
                #track_dec[s][t0] = np.inf

                # if one value is not good, then it is already infinity and we can also quit now
                return -np.inf

    # now we just do a simple Root-mean-square of the measurement positions
    # and the orbit positions based on the simulation
    # but first min-max-rescaling or currently mean.

    # normalization
    rms_sum = 0
    emcee_factor = 10000  # somehow emcee seems to not like rms_sum smaller 1.0, so we artificially boost that up

    satellite_radius = []
    for s in range(len(satellite_pos)):
        if len(satellite_pos[s]) > 0:
            for pos in range(len(satellite_pos[s])):
                satellite_radius.append((satellite_pos[s][pos][0]**2 +
                                         satellite_pos[s][pos][1]**2 +
                                         satellite_pos[s][pos][2]**2)**0.5)

            mean_radius = np.mean(satellite_radius)

            # unfortunately inputs can be ragged arrays, and numpy does not like it.
            # so we iterate through it and use numpy sub-array wise.

            # normalizing with mean radius
            track1 = np.divide(track[s], mean_radius)
            satellite_pos1 = np.divide(satellite_pos[s], mean_radius)

            rms = np.subtract(track1, satellite_pos1)
            rms = np.multiply(rms, emcee_factor)
            rms_sum += np.sum(np.square(rms))

    for s in range(len(az)):
        if len(az[s]) > 0:
            mean_az = np.mean(np.abs(az[s]))
            mean_el = np.mean(np.abs(el[s]))

            # normalizing with mean az
            track_az1 = np.divide(track_az[s], mean_az)
            az1 = np.divide(az[s], mean_az)

            rms = np.subtract(track_az1, az1)
            rms = np.multiply(rms, emcee_factor)
            rms_sum += np.sum(np.square(rms))

            # normalizing with mean el
            track_el1 = np.divide(track_el[s], mean_el)
            el1 = np.divide(el[s], mean_el)

            rms = np.subtract(track_el1, el1)
            rms = np.multiply(rms, emcee_factor)
            rms_sum += np.sum(np.square(rms))

    for s in range(len(ranging)):
        if len(ranging[s]) > 0:
            mean_range = np.mean(ranging[s])

            # normalizing with mean az
            track_range1 = np.divide(track_range[s], mean_range)
            range1 = np.divide(ranging[s], mean_range)

            rms = np.subtract(track_range1, range1)
            rms = np.multiply(rms, emcee_factor)
            rms_sum += np.sum(np.square(rms))

    for s in range(len(doppler)):
        if len(doppler[s]) > 0:

            mean_doppler = np.mean(np.abs(doppler[s]))

            # normalizing with mean az
            track_doppler1 = np.divide(track_doppler[s], mean_doppler)
            doppler1 = np.divide(doppler[s], mean_doppler)

            rms = np.subtract(track_doppler1, doppler1)
            rms = np.multiply(rms, emcee_factor)
            rms_sum += np.sum(np.square(rms))

    for s in range(len(ra)):
        if len(ra[s]) > 0:
            mean_ra = np.mean(np.abs(ra[s]))
            mean_dec = np.mean(np.abs(dec[s]))

            # normalizing with mean az
            track_ra1 = np.divide(track_ra[s], mean_ra)
            ra1 = np.divide(ra[s], mean_ra)

            rms = np.subtract(track_ra1, ra1)
            rms = np.multiply(rms, emcee_factor)
            rms_sum += np.sum(np.square(rms))

            # normalizing with mean el
            track_dec1 = np.divide(track_dec[s], mean_dec)
            dec1 = np.divide(dec[s], mean_dec)

            rms = np.subtract(track_dec1, dec1)
            rms = np.multiply(rms, emcee_factor)
            rms_sum += np.sum(np.square(rms))

    return -0.5 * rms_sum