def midpt(invoyage):
    '''
    Given an object of :class:`.Voyage` interpolate between alternate reports 
    and compare the 
    interpolated location to the actual location. e.g. take difference between 
    reports 2 and 4 and interpolate to get an estimate for the position at the time 
    of report 3. Then compare the estimated and actual positions at the time of 
    report 3.
    
    :param invoyage: Ship :class:`.Voyage`
    :type invoyage: :class:`.Voyage`
    :return: list of distances from estimated positions in km
    :rtype: list of floats
    
    The calculation linearly interpolates the latitudes and longitudes (allowing for 
    wrapping around the dateline and so on).
    '''    
#    Compute distance from time-proportional position between          
#       outside reported positions to middle reported position.

    nobs = len(invoyage)
    
    midpoint_discrepancies = [None]
    
    for i in range(1, nobs-1):
        
        t0 = invoyage.getvar(i,   'time_diff')
        t1 = invoyage.getvar(i+1, 'time_diff')
        
        if (t0 != None and t1 != None):
            if t0 + t1 != 0:
                fraction_of_time_diff = t0 / (t0 + t1)
            else:
                fraction_of_time_diff = 0.0
        else:
            fraction_of_time_diff = 0.0

        if fraction_of_time_diff > 1.0:
            print fraction_of_time_diff,t0,t1

        estimated_lat_at_midpt, estimated_lon_at_midpt =\
        sph.intermediate_point(invoyage.getvar(i-1, 'LAT'),invoyage.getvar(i-1, 'LON'),
                               invoyage.getvar(i+1, 'LAT'),invoyage.getvar(i+1, 'LON'),
                               fraction_of_time_diff)
        
#      Time-proportional position is at AT3 (N/S) and AN3 (E/W)         
#      Reported mid-point will be at    AT4 (N/S) and AN4 (E/W)         
#      Compute distance between time/prop posn and reported mid-point.  
#        SIDE1 is distance travelled North/South                        
        discrepancy = sph.sphere_distance(invoyage.getvar(i, 'LAT'), 
                                          invoyage.getvar(i, 'LON'),
                                          estimated_lat_at_midpt,
                                          estimated_lon_at_midpt)

        midpoint_discrepancies.append(discrepancy)

    midpoint_discrepancies.append(None)

    return midpoint_discrepancies
Example #2
0
def midpt(invoyage):
    """
    Given an object of :class:`.Voyage` interpolate between alternate reports 
    and compare the 
    interpolated location to the actual location. e.g. take difference between 
    reports 2 and 4 and interpolate to get an estimate for the position at the time 
    of report 3. Then compare the estimated and actual positions at the time of 
    report 3.
    
    :param invoyage: Ship :class:`.Voyage`
    :type invoyage: :class:`.Voyage`
    :return: list of distances from estimated positions in km
    :rtype: list of floats
    
    The calculation linearly interpolates the latitudes and longitudes (allowing for 
    wrapping around the dateline and so on).
    """
    #    Compute distance from time-proportional position between
    #       outside reported positions to middle reported position.

    nobs = len(invoyage)

    midpoint_discrepancies = [None]

    for i in range(1, nobs - 1):

        t0 = invoyage.getvar(i, 'time_diff')
        t1 = invoyage.getvar(i + 1, 'time_diff')

        if t0 is not None and t1 is not None:
            if t0 + t1 != 0:
                fraction_of_time_diff = t0 / (t0 + t1)
            else:
                fraction_of_time_diff = 0.0
        else:
            fraction_of_time_diff = 0.0

        if fraction_of_time_diff > 1.0:
            print(fraction_of_time_diff, t0, t1)

        estimated_lat_at_midpt, estimated_lon_at_midpt = \
            sph.intermediate_point(invoyage.getvar(i - 1, 'LAT'), invoyage.getvar(i - 1, 'LON'),
                                   invoyage.getvar(i + 1, 'LAT'), invoyage.getvar(i + 1, 'LON'),
                                   fraction_of_time_diff)

        #      Time-proportional position is at AT3 (N/S) and AN3 (E/W)
        #      Reported mid-point will be at    AT4 (N/S) and AN4 (E/W)
        #      Compute distance between time/prop posn and reported mid-point.
        #        SIDE1 is distance travelled North/South
        discrepancy = sph.sphere_distance(invoyage.getvar(i, 'LAT'),
                                          invoyage.getvar(i, 'LON'),
                                          estimated_lat_at_midpt,
                                          estimated_lon_at_midpt)

        midpoint_discrepancies.append(discrepancy)

    midpoint_discrepancies.append(None)

    return midpoint_discrepancies
 def test_ship_heading_east_at_60knots_at_latitude60_goes2degrees_in_1hour(self):
     '''
     A ship travelling east at 60 knots will go 2 degrees in 1 hour at 60N
     '''
     km_to_nm = 0.539957
     alat = 60.0
     alon = 0.0
     avs = 60.0/km_to_nm
     ads = 90.0
     timdif = 2.0
     dlat,dlon = tc.increment_position(alat,alon,avs,ads,timdif)
     distance = sph.sphere_distance(alat,alon,alat+dlat,alon+dlon) * km_to_nm
     self.assertAlmostEqual(distance, 60, delta=0.0001)
Example #4
0
def distr2(invoyage):
    """
    Given a list of :class:`.Voyage` , calculate what the 
    distance is between the projected position (based on the reported speed and 
    heading at the current and 
    previous time steps) and the actual position. The calculation proceeds from the 
    final, later observation to the 
    first (in contrast to distr1 which runs in time order)
    
    :param invoyage: List of :class:`.Voyage`
    :type invoyage: :class:`.Voyage`
    :return: list of distances from estimated positions
    :rtype: list of floats
    
    This takes the speed and direction reported by the ship and projects it forwards half a time step, it then projects 
    it forwards another half time step using the speed and direction for the next report, to which the projected
    location is then compared. The distances between the projeted and actual locations is returned
    """
    # Compute difference between actual and expected positions after
    # two observations IN REVERSE ORDER
    # Each vessel travels at its reported speed and direction for
    # half the time interval; the difference (in miles) between
    # the calculated and observed positions is calculatered.

    km_to_nm = 0.539957

    nobs = len(invoyage)

    distance_from_est_location = [None]

    for i in range(nobs - 1, 0, -1):

        if (invoyage.getvar(i, 'vsi') is not None
                and invoyage.getvar(i - 1, 'vsi') is not None
                and invoyage.getvar(i, 'dsi') is not None
                and invoyage.getvar(i - 1, 'dsi') is not None
                and invoyage.getvar(i, 'time_diff') is not None):

            # get increment from initial position - backwards in time
            # means reversing the direction by 180 degrees
            lat1, lon1 = increment_position(
                invoyage.getvar(i, 'LAT'), invoyage.getvar(i, 'LON'),
                invoyage.getvar(i, 'vsi') / km_to_nm,
                invoyage.getvar(i, 'dsi') - 180.,
                invoyage.getvar(i, 'time_diff'))

            lat2, lon2 = increment_position(
                invoyage.getvar(i - 1, 'LAT'), invoyage.getvar(i - 1, 'LON'),
                invoyage.getvar(i - 1, 'vsi') / km_to_nm,
                invoyage.getvar(i - 1, 'dsi') - 180.,
                invoyage.getvar(i, 'time_diff'))

            # apply increments to the lat and lon at i-1
            alatx = invoyage.getvar(i, 'LAT') + lat1 + lat2
            alonx = invoyage.getvar(i, 'LON') + lon1 + lon2

            # calculate distance between calculated position and the second reported position
            discrepancy = sph.sphere_distance(invoyage.getvar(i - 1, 'LAT'),
                                              invoyage.getvar(i - 1, 'LON'),
                                              alatx, alonx)
            distance_from_est_location.append(discrepancy)

        else:
            # in the absence of reported speed and direction set to None
            distance_from_est_location.append(None)

    # that fancy bit at the end reverses the array
    return distance_from_est_location[::-1]
def split_generic_callsign(invoyage):
    '''
    Prototype function to identify when a callsign is being used by multiple ships 
    and to split the observations into pseudo IDs that each represents a different ship
    
    :param invoyage: a voyage object containing marine reports
    :type invoyage: Voyage
    :return: list of separate Voyages that the input Voyage has been split into.
    :return type: Voyage
    
    The function works by comparing consecutive observations in the input lists 
    and calculating the implied speed. If it is greater than 40 knots, a new ship 
    is generated. Each subsequent observation is assigned to the closest ship 
    unless the speed exceed 40 knots. If it does, a new ship is generated. 
    '''

    knots_conversion     = 0.539957
    
    if len(invoyage) <= 0:
        return []
    
    result = [1]
    n_ships = 1

    outvoyages = [ex.Voyage()]
    outvoyages[0].add_report(invoyage.getrep(0))
    
    ntimes = len(invoyage)

    if ntimes > 1:
        for i in range(1, ntimes):
            #calculate speeds from last position for each ship
            speeds = []
            distances = []
            for j in range(0, n_ships):
                
                last_rep = outvoyages[j].last_rep()
                
                speed, distance, course, timediff = invoyage.getrep(i)-last_rep
                
#calc predicted position and distance of new ob from predicted position
                pred_lat, pred_lon = outvoyages[j].predict_next_point(timediff)
                dist = sph.sphere_distance(invoyage.getvar(i, 'LAT'), 
                                           invoyage.getvar(i, 'LON'), 
                                           pred_lat, 
                                           pred_lon)
            
                distances.append(dist)
                if timediff != 0:
                    speeds.append(speed)
                else:
                    speeds.append(10000.)
                                                     
            #if all speeds exceed 40 knots then create new ship
            if min(speeds) > 40.0 / knots_conversion:
                n_ships = n_ships + 1
                voy = ex.Voyage()
                voy.add_report(invoyage.getrep(i))
                outvoyages.append(voy)
                result.append(n_ships)

#else ob is assigned to ship whose predicted location is closest to the ob
            else:
                winner = distances.index(min(distances))
                outvoyages[winner].add_report(invoyage.getrep(i))
                result.append(winner+1)
    
    return outvoyages
Example #6
0
def distr1(invoyage):
    '''
    Given an object of :class:`.Voyage`, 
    calculate what the distance is between the projected position (based on the reported 
    speed and heading at the current and previous time steps) and the actual position. The 
    observations are taken in time order.
    
    :param invoyage: Object of :class:`.Voyage`
    :type invoyage: :class:`.Voyage`
    :return: list of distances from estimated positions
    :rtype: list of floats
    
    This takes the speed and direction reported by the ship and projects it forwards half a 
    time step, it then projects it forwards another half time step using the speed and 
    direction for the next report, to which the projected location 
    is then compared. The distances between the projected and actual locations is returned
    '''
#Compute difference between actual and expected positions after
#two observations.
#Each vessel travels at its reported speed and direction for
#half the time interval; the difference (in miles) between
#the calculated and observed positions is calculatered.
    
    km_to_nm = 0.539957
    
    nobs = len(invoyage)

    distance_from_est_location = [None]

    for i in range(1, nobs):
        
        if (invoyage.getvar(i,   'vsi') != None and 
            invoyage.getvar(i-1, 'vsi') != None and
            invoyage.getvar(i,   'dsi') != None and 
            invoyage.getvar(i-1, 'dsi') != None and 
            invoyage.getvar(i,   'time_diff') != None):

#get increment from initial position
            lat1, lon1 = increment_position(invoyage.getvar(i-1, 'LAT'), 
                                            invoyage.getvar(i-1, 'LON'), 
                                            invoyage.getvar(i-1, 'vsi')/km_to_nm, 
                                            invoyage.getvar(i-1, 'dsi'), 
                                            invoyage.getvar(i,   'time_diff'))

            lat2, lon2 = increment_position(invoyage.getvar(i, 'LAT'), 
                                            invoyage.getvar(i, 'LON'), 
                                            invoyage.getvar(i, 'vsi')/km_to_nm, 
                                            invoyage.getvar(i, 'dsi'), 
                                            invoyage.getvar(i, 'time_diff'))
#apply increments to the lat and lon at i-1            
            alatx = invoyage.getvar(i-1, 'LAT') + lat1 + lat2
            alonx = invoyage.getvar(i-1, 'LON') + lon1 + lon2

#calculate distance between calculated position and the second reported position
            discrepancy = sph.sphere_distance(invoyage.getvar(i, 'LAT'),
                                              invoyage.getvar(i, 'LON'),
                                              alatx, alonx)

            distance_from_est_location.append(discrepancy)

        else:
#in the absence of reported speed and direction set to None
            distance_from_est_location.append(None)
 
    return distance_from_est_location
def distr2(invoyage):
    '''
    Given a list of :class:`.Voyage` , calculate what the 
    distance is between the projected position (based on the reported speed and 
    heading at the current and 
    previous time steps) and the actual position. The calculation proceeds from the 
    final, later observation to the 
    first (in contrast to distr1 which runs in time order)
    
    :param invoyage: List of :class:`.Voyage`
    :type invoyage: :class:`.Voyage`
    :return: list of distances from estimated positions
    :rtype: list of floats
    
    This takes the speed and direction reported by the ship and projects it forwards half a time step, it then projects 
    it forwards another half time step using the speed and direction for the next report, to which the projected location 
    is then compared. The distances between the projeted and actual locations is returned
    '''
#Compute difference between actual and expected positions after
#two observations IN REVERSE ORDER
#Each vessel travels at its reported speed and direction for
#half the time interval; the difference (in miles) between
#the calculated and observed positions is calculatered.

    km_to_nm = 0.539957
    
    nobs = len(invoyage)
    
    distance_from_est_location = [None]
    
    for i in range(nobs-1, 0, -1):
        
        if (invoyage.getvar(i,   'vsi') != None and 
            invoyage.getvar(i-1, 'vsi') != None and
            invoyage.getvar(i,   'dsi') != None and 
            invoyage.getvar(i-1, 'dsi') != None and
            invoyage.getvar(i,   'time_diff') != None):

#get increment from initial position - backwards in time 
#means reversing the direction by 180 degrees
            lat1, lon1 = increment_position(invoyage.getvar(i, 'LAT'), 
                                            invoyage.getvar(i, 'LON'), 
                                            invoyage.getvar(i, 'vsi') / km_to_nm, 
                                            invoyage.getvar(i, 'dsi') - 180.,
                                            invoyage.getvar(i, 'time_diff'))
                                            
            lat2, lon2 = increment_position(invoyage.getvar(i-1, 'LAT'), 
                                            invoyage.getvar(i-1, 'LON'), 
                                            invoyage.getvar(i-1, 'vsi') / km_to_nm, 
                                            invoyage.getvar(i-1, 'dsi') - 180.,
                                            invoyage.getvar(i,   'time_diff'))

#apply increments to the lat and lon at i-1            
            alatx = invoyage.getvar(i, 'LAT') + lat1 + lat2
            alonx = invoyage.getvar(i, 'LON') + lon1 + lon2

#calculate distance between calculated position and the second reported position
            discrepancy = sph.sphere_distance(invoyage.getvar(i-1, 'LAT'), 
                                              invoyage.getvar(i-1, 'LON'), 
                                              alatx, alonx)
            distance_from_est_location.append(discrepancy)

        else:
#in the absence of reported speed and direction set to None
            distance_from_est_location.append(None)

#that fancy bit at the end reverses the array  
    return distance_from_est_location[::-1]