Select to view content in your preferred language

How to determine location of transmitter from points with position and strengt?

958
4
Jump to solution
06-01-2022 05:20 AM
HenningSagen
Emerging Contributor

Hi, I have a table with lat/long and signal strength. I have walked the perimeter of my estate and trying to predict where my WIFI-transmitter is placed within the perimeter.

All the tools just highlights the strongest point on the perimeter or something like it. I want to use the combined set to predict where the transmitter is within the perimeter.

How can I make ArcGIS predict where the transmitter is located?

 

0 Kudos
1 Solution

Accepted Solutions
JohannesLindner
MVP Frequent Contributor

Is there a way I could program my own script without too much effort? 

The most effortless way is running the tools manually, then going to the Geoprocessing history and copying the commands into a Python script:

 

JohannesLindner_0-1655188631930.pngJohannesLindner_1-1655188671541.png

 

I found another way that might help you:

  1. Calculate the distance of your measured points to the transmitter.
  2. Generate buffers around the points, based on that distance.
  3. Get the intersection points of all the buffers
    1. In a perfect world without measuring uncertainties and without signal absorption in walls, all circles around your points with a radius of the calculated distance would intersect in a single point, the transmitter (and in many other points, but they would all have that common point).
    2. In our more imperfect world, the highest density of intersections should still be close to the transmitter.
  4. Create a heat map of the intersection points.
  5. Analyze that heat map like in my original answer.

 

Just to show how you could create your own script, I'll run the tools manually and then copy/paste the Python commands from the history here. Note that I'm using memory paths for intermediate results. This means they are only stored in RAM and thus will be gone when I close ArcGIS. The advantage is that this way is much faster than saving on disk.

 

My input data, area is ~ 250m x 250m, signal strength is calculated using the formulas from the links below plus a little noise.

JohannesLindner_2-1655189546680.png

 

Calculate the distance of your measured points to the transmitter. In this thread and this wiki page, you can find formulas to convert signal strength to distance to the transmitter.

 

arcpy.management.CalculateField("points", "Distance", "dist(!DoubleField!)", "PYTHON3", """def dist(fspl):
    k = -27.55
    f = 2413
    pot = (fspl - k - 20 * math.log10(f)) / 20
    return math.pow(10, pot)""", "TEXT", "NO_ENFORCE_DOMAINS")

 

 

Create buffers around the points based on the calculated distance.

 

arcpy.analysis.Buffer(r"memory\points", r"memory\circles", "Distance", "FULL", "ROUND", "NONE", None, "PLANAR")

 

JohannesLindner_3-1655190073666.png

 

Intersect the buffers with themselves, specify point output.

 

arcpy.analysis.Intersect(r"memory\circles #", r"memory\circle_intersections", "ALL", None, "POINT")

 

JohannesLindner_4-1655190184271.png

 

Create a heat map of these intersections (Point Density). Play with the Output cell size and Neighbourhood parameters, they massively influence the result.

 

out_raster = arcpy.sa.PointDensity("circle_intersections", "NONE", 1, "Circle 5 CELL", "SQUARE_METERS"); out_raster.save(r"memory\heatmap")

 

JohannesLindner_5-1655190326831.png

 

The area with the most intersections of the buffers should be near the transmitter. Create Contour lines to find this area.

 

arcpy.ddd.Contour("heatmap", r"memory\contours", 1, 0, 1, "CONTOUR", None)

 

JohannesLindner_6-1655190515143.png

 

That's pretty busy. Let's zoom in.

JohannesLindner_7-1655190654493.png

Slightly over 5m off, not too shabby!

 

Let's create an ouput feature class (saved on disc), showing the most probable transmitter locations.

 

# get the raster values as points
arcpy.conversion.RasterToPoint("heatmap", r"memory\raster_values", "Value")

# delete all points where grid_value != max(grid_value)
# it would be easier to use the arcpy.da.SearchCursor and UpdateCursor for this (or do it manually in the attribute table)
# but we're pretending we don't know Python and want to create a script, so let's do it with tools.
arcpy.management.CalculateField("raster_values", "IsMax", """if($feature.grid_code == 0) {
    return 0
}
var max_grid_code = Max($featureset, "grid_code")
return $feature.grid_code == max_grid_code""", "ARCADE", '', "TEXT", "NO_ENFORCE_DOMAINS") 
# 400k points take a really long time...

# 1/2 hour later: well, I'm going to use the Cursors...
# this is how you would procee with tools:
arcpy.management.SelectLayerByAttribute("raster_values", "NEW_SELECTION", "IsMax = '1'")
arcpy.management.DeleteFeatures("raster_values")

# And this is using cursors
grid_codes = [row[0] for row in arcpy.da.SearchCursor("memory/raster_values", ["grid_code"], "grid_code > 0")]
max_grid_code = max(grid_codes)
with arcpy.da.UpdateCursor("memory/raster_values", ["grid_code"], f"grid_code < {max_grid_code}") as cursor:
    for row in cursor:
        cursor.deleteRow()
# that took like 10 seconds...

# save the result on disc
save_path = "TransmitterLocations"  # Save in the project's default gdb
arcpy.management.CopyFeatures(r"memory\raster_values", save_path)

 

 

JohannesLindner_9-1655193383727.png

 

 


Have a great day!
Johannes

View solution in original post

4 Replies
JohannesLindner
MVP Frequent Contributor

One possible way: Interpolate a raster of signal strength. Your elongated point distribution might make this not really exact, it would be better if you had some points in between.

 

My input (signal strength as inverse distance to the source plus some random noise)

JohannesLindner_0-1654157651712.png

Interpolate a raster, eg using IDW (Spatial Analyst)—ArcGIS Pro | Documentation

JohannesLindner_1-1654157835965.png
(you can already see that this might not show the actual source, due to the point distribution)

 

You can use this raster to guess the source spot. You can also analyse it further:

 

Contour (Spatial Analyst)—ArcGIS Pro | Documentation

JohannesLindner_2-1654158103143.png

 

Raster to Point (Conversion)—ArcGIS Pro | Documentation, sort by value field, delete all but highest

JohannesLindner_3-1654158327110.png

 

Here's the same process with a more random point distribution. The calculated source point (red x) is much closer to the actual source:

JohannesLindner_4-1654159385910.png

 


Have a great day!
Johannes
HenningSagen
Emerging Contributor

Sorry for my very late reply. I thank you for your time and effort in helping me here. I have been testing this for some time now, with different datasets. But I can not get it right. It is close, but not close enough to put the "center" in the right property. This is probably due to my lack of experience.

A predictive tool, where you could define the max strength of the sender could maybe do the trick. Is there a way I could program my own script without too much effort? 

0 Kudos
JohannesLindner
MVP Frequent Contributor

Is there a way I could program my own script without too much effort? 

The most effortless way is running the tools manually, then going to the Geoprocessing history and copying the commands into a Python script:

 

JohannesLindner_0-1655188631930.pngJohannesLindner_1-1655188671541.png

 

I found another way that might help you:

  1. Calculate the distance of your measured points to the transmitter.
  2. Generate buffers around the points, based on that distance.
  3. Get the intersection points of all the buffers
    1. In a perfect world without measuring uncertainties and without signal absorption in walls, all circles around your points with a radius of the calculated distance would intersect in a single point, the transmitter (and in many other points, but they would all have that common point).
    2. In our more imperfect world, the highest density of intersections should still be close to the transmitter.
  4. Create a heat map of the intersection points.
  5. Analyze that heat map like in my original answer.

 

Just to show how you could create your own script, I'll run the tools manually and then copy/paste the Python commands from the history here. Note that I'm using memory paths for intermediate results. This means they are only stored in RAM and thus will be gone when I close ArcGIS. The advantage is that this way is much faster than saving on disk.

 

My input data, area is ~ 250m x 250m, signal strength is calculated using the formulas from the links below plus a little noise.

JohannesLindner_2-1655189546680.png

 

Calculate the distance of your measured points to the transmitter. In this thread and this wiki page, you can find formulas to convert signal strength to distance to the transmitter.

 

arcpy.management.CalculateField("points", "Distance", "dist(!DoubleField!)", "PYTHON3", """def dist(fspl):
    k = -27.55
    f = 2413
    pot = (fspl - k - 20 * math.log10(f)) / 20
    return math.pow(10, pot)""", "TEXT", "NO_ENFORCE_DOMAINS")

 

 

Create buffers around the points based on the calculated distance.

 

arcpy.analysis.Buffer(r"memory\points", r"memory\circles", "Distance", "FULL", "ROUND", "NONE", None, "PLANAR")

 

JohannesLindner_3-1655190073666.png

 

Intersect the buffers with themselves, specify point output.

 

arcpy.analysis.Intersect(r"memory\circles #", r"memory\circle_intersections", "ALL", None, "POINT")

 

JohannesLindner_4-1655190184271.png

 

Create a heat map of these intersections (Point Density). Play with the Output cell size and Neighbourhood parameters, they massively influence the result.

 

out_raster = arcpy.sa.PointDensity("circle_intersections", "NONE", 1, "Circle 5 CELL", "SQUARE_METERS"); out_raster.save(r"memory\heatmap")

 

JohannesLindner_5-1655190326831.png

 

The area with the most intersections of the buffers should be near the transmitter. Create Contour lines to find this area.

 

arcpy.ddd.Contour("heatmap", r"memory\contours", 1, 0, 1, "CONTOUR", None)

 

JohannesLindner_6-1655190515143.png

 

That's pretty busy. Let's zoom in.

JohannesLindner_7-1655190654493.png

Slightly over 5m off, not too shabby!

 

Let's create an ouput feature class (saved on disc), showing the most probable transmitter locations.

 

# get the raster values as points
arcpy.conversion.RasterToPoint("heatmap", r"memory\raster_values", "Value")

# delete all points where grid_value != max(grid_value)
# it would be easier to use the arcpy.da.SearchCursor and UpdateCursor for this (or do it manually in the attribute table)
# but we're pretending we don't know Python and want to create a script, so let's do it with tools.
arcpy.management.CalculateField("raster_values", "IsMax", """if($feature.grid_code == 0) {
    return 0
}
var max_grid_code = Max($featureset, "grid_code")
return $feature.grid_code == max_grid_code""", "ARCADE", '', "TEXT", "NO_ENFORCE_DOMAINS") 
# 400k points take a really long time...

# 1/2 hour later: well, I'm going to use the Cursors...
# this is how you would procee with tools:
arcpy.management.SelectLayerByAttribute("raster_values", "NEW_SELECTION", "IsMax = '1'")
arcpy.management.DeleteFeatures("raster_values")

# And this is using cursors
grid_codes = [row[0] for row in arcpy.da.SearchCursor("memory/raster_values", ["grid_code"], "grid_code > 0")]
max_grid_code = max(grid_codes)
with arcpy.da.UpdateCursor("memory/raster_values", ["grid_code"], f"grid_code < {max_grid_code}") as cursor:
    for row in cursor:
        cursor.deleteRow()
# that took like 10 seconds...

# save the result on disc
save_path = "TransmitterLocations"  # Save in the project's default gdb
arcpy.management.CopyFeatures(r"memory\raster_values", save_path)

 

 

JohannesLindner_9-1655193383727.png

 

 


Have a great day!
Johannes
HenningSagen
Emerging Contributor

Thank you again for you effort and time.

This time the results are much better. I have some learning to do regarding Python in ArcGis. But I managed somehow to replicate your procedure.

0 Kudos