PointPerfect Localized Distribution

Overview

The PointPerfect service provides correction messages for the whole continent when you subscribe to the continental level data topics (e.g. pp/ip/eu) as explained in the PointPerfect Service description. Normally, the service requires a data bandwidth of 2400 bits per second for the continental streams. However, for applications with limited data bandwidth and connectivity plans, a localized version of the PointPerfect service is also available. The localized PointPerfect transmits significantly less data compared to the continental streams,  reducing it by up to 70% of the bandwidth used by the continental streams.

PointPerfect Localized System Architecture

In the localized PointPerfect architecture, the correction data is spread across multiple nodes and delivered through individual node MQTT Topics. Unlike the continental level approach, where a device subscribes to the continental level topic, in the localized approach, device subscribes to the localized node topic based on its location. Each localized node topic distributes the correction messages for that particular location. In the upcoming section, we will get understanding of the nodes. 

Nodes

Nodes are locations for which SPARTN correction streams are generated to enable a highly precise positioning solution. Each node is named according to its location, and this name is used to access the localized SPARTN data through the corresponding localized node topic. The data transmitted through each node is optimized based on its location, which greatly reduces the amount of bandwidth. This optimization process filters out unnecessary data that is not relevant to the user, ensuring that the remaining corrections are for the node's location as explained in the image below. The dynamic users moving throughout the region, need to transition to different nodes, to continuously and seamlessly access the SPARTN correction streams. 

Tiles 

The distribution of node information within the coverage areas is facilitated through the use of tiles in the service. The tiles layout is designed based on a pre-defined algorithm similar to a "GeoHash". Each tile is named based on its location and zoom level, which determines its specific location and size. Each tile contains a set of nodes that are relevant to a user located within that tile. This may include nodes outside the tile boundaries to support users on dynamic platforms.

In the image shared below, the triangles represents nodes and the yellow rectangle is a tile. The number of nodes in a tile depends on the zoom level. 

Service Access

The localized PointPerfect is accessible in two ways:

Service to Device 

In a service to device (S2D) architecture, the device selects the localized node topic to subscribe based on its location. This ensures that the device receives relevant localized data. The image shared below is an example architecture for a service to device distribution of localized data. 

After provisiong the device, i.e. obtaining the client credentials from the Thingstream portal as explained in the Point Perfect Getting Started guide, the device needs to calculate the tile location. You can find an example on how to calculate tile in the sample python script available at Thingstream Downloads PointPerfect.

Once you have calculated the tile location, connect the device to the PointPerfect MQTT Endpoint (pp.services.u-blox.com) using the client credentials and subscribe to the node dictionary topic (tile topic) for the calculated tile. The structure for the Tile topic is as follows:

pp/ip/{tile}/dict

e.g.: pp/ip/L2N6125E02625/dict

In the above topic, we insert the tile calculated based on device latitude and longitude coordinates and zoom level.  The tile topic  provides the the location-specific metadata including the list of all the nodes in that tile and the node correction service endpoint. The message is encapsulated in a JSON structure in the following format:

 
{"tile":"L2N6125E02625","nodeprefix":"pp/ip/L2N6125E02625/","nodes":["N5900E02400","N5900E02500","N5900E02600","N5900E02700","N6100E02400","N6100E02500","N6100E02600","N6100E02700","N6100E02800","N6200E02400","N6200E02500","N6200E02600","N6200E02700","N6200E02800","N6300E02400","N6300E02500","N6300E02600","N6300E02700","N6300E02800"],"endpoint":"pp-eu.services.u-blox.com"}


Once the device has received  list of the nodes,  connect to the Correction MQTT  endpoint and subscribe to the nearest Node topic based on the device position.
This node topic provides the localized correction data. The structure for the Node topic is as follows:

pp/{subscription}/{tile}/{node}

For instance, if the nearest node from the provided JSON example is N5900E02400, subscribe to the following topic

pp/ip/L2N6125E02625/N5900E02400

Once the device has subscribed to the nearest node topic, it will start receiving the localized corrections.

Notes:

Service to Service 

In service to service (S2S), the user is responsible for distribution of localized corrections data and requires additional configuration at the user backend to redistribute the service data to the devices.

To access the service via service to service approach, please contact us at support@thingstream.io 

Python sample script: PointPerfect MQTT Client 

To evaluate PointPerfect localized version with an MQTT Client built-in your host application, you may please refer to PointPerfect MQTT Client sample python script available in the Thingstream Downloads PointPerfect section to get started. 

Pseudo code for Tile calculation

The psedo code for Tile calculation is shared below for reference:

function GetTileTopic(lat, lon, level):

    delta = LevelToDelta(level)

    dh = "N"

    bh = "E"

    if lat < 0:

        dh = "S"

    if lon < 0:

        bh = "W"

    llat = floor(lat / delta) * delta

    llon = floor(lon / delta) * delta

    clat = llat + (delta / 2)

    clon = llon + (delta / 2)

    clat = round(clat * 100)

    clon = round(clon * 100)

    slat = abs(clat)

    slon = abs(clon)

    topic = "L" + level + dh + format(slat, "0000") + bh + format(slon, "00000")

    return topic


function LevelToDelta(level):

    if level is in Level2Delta:

        return Level2Delta[level]

    return 10.0


Level2Delta = {

    0: 10.0,

    1: 5.0,

    2: 2.5

}

Note: The pseudocode provided above represents a high-level representation of the code and may need further modification to fit the specific programming language or environment you are working with.