Android Question Solves a formulation of n-D space trilateration problem using a nonlinear least squares optimizer. Input: positions, distances Output: centroid with

mike1967

Active Member
Licensed User
Longtime User
How are your distances determined?

RSSI filtering​

RSSI needs to be (low-pass) filtered to become accurate (try filterFactor=0.1):

filteredRSSI = beacon.RSSI * filterFactor + filteredRSSI * (1.0 - filterFactor)

RSSI to distance (meters)​

Distance in meters can be calculated by txPower and measured RSSI:

double calculateDistance( int txPower, double rssi ) {
if (rssi == 0) return -1.0; // if we cannot determine accuracy, return -1.
double ratio = rssi*1.0/txPower;
if (ratio < 1.0) return pow(ratio,10);
else return (0.89976) * pow(ratio,7.7095) + 0.111;
}

Trilateration​

}

I have also The Trialateration code for 3 Beacons But I Need Trilateration for N Beacons (Rilevated from a scanning functions).

Trilateration​

Trilateration estimates the receivers’s position (using 3 or more) measured distances (meters) to the beacons and the known beacons positions.

float xa = beacon1.locationX;
float ya = beacon1.locationY;
float xb = beacon2.locationX;
float yb = beacon2.locationY;
float xc = beacon3.locationX;
float yc = beacon3.locationY;
float ra = beacon1.filteredDistance;
float rb = beacon2.filteredDistance;
float rc = beacon3.filteredDistance;
float S = (pow(xc, 2.) - pow(xb, 2.) + pow(yc, 2.) - pow(yb, 2.) + pow(rb, 2.) - pow(rc, 2.)) / 2.0;
float T = (pow(xa, 2.) - pow(xb, 2.) + pow(ya, 2.) - pow(yb, 2.) + pow(rb, 2.) - pow(ra, 2.)) / 2.0;
float y = ((T * (xb - xc)) - (S * (xb - xa))) / (((ya - yb) * (xb - xc)) - ((yc - yb) * (xb - xa)));
float x = ((y * (ya - yb)) - T) / (xb - xa);
// now x, y is the estimated receiver position
 
Upvote 0

emexes

Expert
Licensed User
Well, I had a go at using #IF JAVA and those three .java source files, but they depend on an apache math library that I can't figure out how to include.

But the math for multilateration isn't so bad, if you have ok-ish distance measurements.

Given that you've got the source code for the multilateration, I'm wondering if it can be "inlined" using #IF JAVA. I'm no Java expert, but I'll have a poke around, see what I can stir up.

Assuming that you're already capturing the RSSI of the beacons, and applying the above math to convert that distance, I'd be interested in your assessment of:

how good do those distance measurements look in actual real-life use?

B4X:
float ra = beacon1.filteredDistance;
float rb = beacon2.filteredDistance;
float rc = beacon3.filteredDistance;
 
Upvote 0

emexes

Expert
Licensed User
I have also The Trialateration code for 3 Beacons

While you look at how good the RSSI distance estimates are, I figured I'd check out that trilateration calculation.

If you transcribe it to B4X eg:
B4X:
Sub Trilaterate(positions() As Float, distances() As Float) As Float()
    If positions.Length <> 6 Then Log("!!! s/b 3 positions")
 
    Dim xa As Float = positions(0)
    Dim ya As Float = positions(1)
    Dim xb As Float = positions(2)
    Dim yb As Float = positions(3)
    Dim xc As Float = positions(4)
    Dim yc As Float = positions(5)

    If distances.Length <> 3 Then Log("!!! s/b 3 distances")
 
    Dim ra As Float = distances(0)
    Dim rb As Float = distances(1)
    Dim rc As Float = distances(2)
    
    'var S = (Math.pow(xc, 2.) - Math.pow(xb, 2.) + Math.pow(yc, 2.) - Math.pow(yb, 2.) + Math.pow(rb, 2.) - Math.pow(rc, 2.)) / 2.0;
    Dim S As Float = (xc * xc - xb * xb + yc * yc - yb * yb + rb * rb - rc * rc) / 2
 
    'var T = (Math.pow(xa, 2.) - Math.pow(xb, 2.) + Math.pow(ya, 2.) - Math.pow(yb, 2.) + Math.pow(rb, 2.) - Math.pow(ra, 2.)) / 2.0;
    Dim T As Float = (xa * xa - xb * xb + ya * ya - yb * yb + rb * rb - ra * ra) / 2
 
    'var y = ((T * (xb - xc)) - (S * (xb - xa))) / (((ya - yb) * (xb - xc)) - ((yc - yb) * (xb - xa)));
    Dim y As Float = ((T * (xb - xc)) - (S * (xb - xa))) / (((ya - yb) * (xb - xc)) - ((yc - yb) * (xb - xa)))
 
    'var x = ((y * (ya - yb)) - T) / (xb - xa);
    Dim x As Float = ((y * (ya - yb)) - T) / (xb - xa)
 
    Return Array As Float(x, y)
End Sub

and test it with random points eg:
B4X:
Dim Positions(6) As Float = Array As Float(0, 0, 100, 0, 0, 100)

Dim NumBeacons As Int = Positions.Length / 2
If Positions.Length <> NumBeacons * 2 Then Log("!!! odd number of beacons")

Log("Random X,Y" & TAB & "Distances A, B, C" & TAB & TAB & "Reconstructed X,Y")

For Burl = 1 To 10
    Dim X As Float = Rnd(10, 90)
    Dim Y As Float = Rnd(10, 90)

    Dim Distances(NumBeacons) As Float
    For b = 0 To NumBeacons - 1
        Dim dx As Float = X - Positions(b * 2)
        Dim dy As Float = Y - Positions(b * 2 + 1)
        Distances(b) = Sqrt(dx * dx + dy * dy)
    Next

    Dim EstLoc(Positions) As Float = Trilaterate(Positions, Distances)

    Log( _
        X & TAB & _
        Y & TAB & _
        NumberFormat2(Distances(0), 1, 3, 3, False) & TAB & _
        NumberFormat2(Distances(1), 1, 3, 3, False) & TAB & _
        NumberFormat2(Distances(2), 1, 3, 3, False) & TAB & _
        NumberFormat2(EstLoc(0), 1, 4, 4, False) & TAB & _
        NumberFormat2(EstLoc(1), 1, 4, 4, False) _
    )
Next

then it looks like your magic magnificent mathematical incantations do indeed work:
Log output:
Random X,Y      Distances A, B, C                 Reconstructed X,Y
82    47        94.515    50.329    97.637        82.0000    47.0000
88    45        98.838    46.573    103.774       88.0000    45.0000
64    47        79.404    59.203    83.096        64.0000    47.0000
18    86        87.864    118.828   22.804        18.0000    86.0000
40    82        91.236    101.607   43.863        40.0000    82.0000
47    45        65.069    69.527    72.346        47.0000    45.0000
13    46        47.802    98.412    55.543        13.0000    46.0000
25    55        60.415    93.005    51.478        25.0000    55.0000
46    77        89.694    94.048    51.430        46.0000    77.0000
32    50        59.363    84.404    59.363        32.0000    50.0000
 
Last edited:
Upvote 0

mike1967

Active Member
Licensed User
Longtime User
While you look at how good the RSSI distance estimates are, I figured I'd check out that trilateration calculation.

If you transcribe it to B4X eg:
B4X:
Sub Trilaterate(positions() As Float, distances() As Float) As Float()
    If positions.Length <> 6 Then Log("!!! s/b 3 positions")
 
    Dim xa As Float = positions(0)
    Dim ya As Float = positions(1)
    Dim xb As Float = positions(2)
    Dim yb As Float = positions(3)
    Dim xc As Float = positions(4)
    Dim yc As Float = positions(5)

    If distances.Length <> 3 Then Log("!!! s/b 3 distances")
 
    Dim ra As Float = distances(0)
    Dim rb As Float = distances(1)
    Dim rc As Float = distances(2)
     
    'var S = (Math.pow(xc, 2.) - Math.pow(xb, 2.) + Math.pow(yc, 2.) - Math.pow(yb, 2.) + Math.pow(rb, 2.) - Math.pow(rc, 2.)) / 2.0;
    Dim S As Float = (xc * xc - xb * xb + yc * yc - yb * yb + rb * rb - rc * rc) / 2
 
    'var T = (Math.pow(xa, 2.) - Math.pow(xb, 2.) + Math.pow(ya, 2.) - Math.pow(yb, 2.) + Math.pow(rb, 2.) - Math.pow(ra, 2.)) / 2.0;
    Dim T As Float = (xa * xa - xb * xb + ya * ya - yb * yb + rb * rb - ra * ra) / 2
 
    'var y = ((T * (xb - xc)) - (S * (xb - xa))) / (((ya - yb) * (xb - xc)) - ((yc - yb) * (xb - xa)));
    Dim y As Float = ((T * (xb - xc)) - (S * (xb - xa))) / (((ya - yb) * (xb - xc)) - ((yc - yb) * (xb - xa)))
 
    'var x = ((y * (ya - yb)) - T) / (xb - xa);
    Dim x As Float = ((y * (ya - yb)) - T) / (xb - xa)
 
    Return Array As Float(x, y)
End Sub

and test it with random points eg:
B4X:
Dim Positions(6) As Float = Array As Float(0, 0, 100, 0, 0, 100)

Dim NumBeacons As Int = Positions.Length / 2
If Positions.Length <> NumBeacons * 2 Then Log("!!! odd number of beacons")

Log("Random X,Y" & TAB & "Distances A, B, C" & TAB & TAB & "Reconstructed X,Y")

For Burl = 1 To 10
    Dim X As Float = Rnd(10, 90)
    Dim Y As Float = Rnd(10, 90)

    Dim Distances(NumBeacons) As Float
    For b = 0 To NumBeacons - 1
        Dim dx As Float = X - Positions(b * 2)
        Dim dy As Float = Y - Positions(b * 2 + 1)
        Distances(b) = Sqrt(dx * dx + dy * dy)
    Next

    Dim EstLoc(Positions) As Float = Trilaterate(Positions, Distances)

    Log( _
        X & TAB & _
        Y & TAB & _
        NumberFormat2(Distances(0), 1, 3, 3, False) & TAB & _
        NumberFormat2(Distances(1), 1, 3, 3, False) & TAB & _
        NumberFormat2(Distances(2), 1, 3, 3, False) & TAB & _
        NumberFormat2(EstLoc(0), 1, 4, 4, False) & TAB & _
        NumberFormat2(EstLoc(1), 1, 4, 4, False) _
    )
Next

then it looks like your magic magnificent mathematical incantations do indeed work:
Log output:
Random X,Y    Distances A, B, C            Reconstructed X,Y
82    47        94.515    50.329    97.637        82.0000    47.0000
88    45        98.838    46.573    103.774        88.0000    45.0000
64    47        79.404    59.203    83.096        64.0000    47.0000
18    86        87.864    118.828    22.804        18.0000    86.0000
40    82        91.236    101.607    43.863        40.0000    82.0000
47    45        65.069    69.527    72.346        47.0000    45.0000
13    46        47.802    98.412    55.543        13.0000    46.0000
25    55        60.415    93.005    51.478        25.0000    55.0000
46    77        89.694    94.048    51.430        46.0000    77.0000
32    50        59.363    84.404    59.363        32.0000    50.0000
 
Upvote 0

emexes

Expert
Licensed User
I had a bit of an epiphany overnight of a Plan B for estimating a position given a set of ranges from known beacon positions.

Being a converging approach that starts of roughly in the centre of all the beacons, imagines the ranges as being springs or elastic bands between that point and all the beacons, and then calculates the net force on the point depending on whether the spring is longer or shorter than it should be. I'd expect within 10 iterations it'd be a pretty good estimate. Subsequent updates would take even fewer, because you're estimate would be starting from close to the solution, rather than from the "random" centre again.

Using a spring rate that is x² rather than linear might even give a solution of least-squares error rather than least-total-error.

It'll try it out this evening.

I'm intrigued as to whether it could also be used for situations where the actual distance isn't known, but the relative distances are (eg if you had two equal RSSI indicating two equal ranges, and a third RSSI that was a quarter of the other two, indicating the third range was twice the other two).
 
Last edited:
Upvote 0

OliverA

Expert
Licensed User
Longtime User
No inline Java, just some good old-fashioned JavaObject use. See the attached project.

Notes:

1) The AdditionalJar directives have to be made in the Main module
2) Only a B4J implementation, even though used the B4XPages template
3) No error capturing was done
4) No other functions of the library are implemented
5) I included a routine to convert a 1D double array to a 2D double array. There is no neat way to declare a multidimensional array in B4X (that I'm aware of)
6) The Java library also requires/depends upon The Apache Commons Mathematics Library version 3
 

Attachments

  • TriLateration.zip
    10.1 KB · Views: 105
Upvote 0

mike1967

Active Member
Licensed User
Longtime User
I can't see anything there about:

but the robot mower project caught my eye, because we moved house a few months ago and the grass here grows like crazy (1cm per day). :oops:
I am novice to problem , reading documents online the accuracy may be around 1-4 meters but i obtain bad value mostly when i go far from device. Some more stable value using this filter:
KalmanFilter:
Sub KalmanFilter(distance As Double) As Double
    ' Initialize variables
    Dim q As Double = 0.001 ' Process noise
    Dim r As Double =  0.1     ' Measurement noise
    Dim x As Double = 0 ' Initial estimate
    Dim p As Double = 1 ' Initial error estimate
    Dim k As Double ' Kalman gain
   
    ' Prediction
    x = x ' No prediction step in this example
    p = p + q
   
    ' Update
    k = p / (p + r)
    x = x + k * (distance - x)
    p = (1 - k) * p
   
    Return x
End Sub
value for test:
Q = 0.001, R = 0.1
Q = 0.01, R = 0.5
Q = 0.1, R = 1

suggest me by AI.

can someone suggest me something of god?
thanks in advances
 
Upvote 0

emexes

Expert
Licensed User
reading documents online the accuracy may be around 1-4 meters but i obtain bad value

Yeah, I was super-impressed by this result, which is ten-times better than anything I ever got when using BLE iTags as beacons:

1706367678177.png

(from DIY localization using radio frequency beacons | Work-is-Playing )
 
Upvote 0

mike1967

Active Member
Licensed User
Longtime User
Yeah, I was super-impressed by this result, which is ten-times better than anything I ever got when using BLE iTags as beacons:

View attachment 150137
(from DIY localization using radio frequency beacons | Work-is-Playing )
Calculate Distance of iBeacon applyed RSSISmooth and Particle Filter:
Here is a complete example of how to use the routine to calculate the accurate distance to an iBeacon:

```basic4android
' RSSI smoothing
The value of Alpha in the RSSISmooth() function determines the amount of weight given to the current RSSI value compared to the previous RSSI value. A higher Alpha value will give more weight to the current RSSI value, while a lower Alpha value will give more weight to the previous RSSI value.

In general, an Alpha value between 0.5 and 0.8 is a good starting point. An Alpha value less than 0.5 can cause a response that is too slow to the variation of the RSSI, while an Alpha value greater than 0.8 can cause a response that is too sensitive to the variation of the RSSI.

To choose the optimal value of Alpha, you need to run some tests with your data. You can start with an Alpha value of 0.5 and then increase or decrease it based on your test results.

Here are some tips for choosing the value of Alpha:

If the RSSI is relatively stable, a higher Alpha value can be used.
If the RSSI varies rapidly, a lower Alpha value can be used.
If the RSSI is subject to interference, a lower Alpha value can be used.
Sub RSSISmooth(RSSI, Alpha)

     If RSSI < 0 Then
         ' RSSI invalid
         RSSISmooth = RSSI
     Else
         RSSISmooth = (Alpha * RSSI) + ((1 - Alpha) * RSSISmooth)
     End If

     Return RSSISmooth
End Sub

' Particle filter

RSSIThreshold is a variable that is used in the routine to calculate the accurate distance to an iBeacon. This variable determines the minimum RSSI value that will be considered valid for distance calculation.

In general, an RSSIThreshold value between -60 and -80 is a good starting point. An RSSIThreshold value less than -60 may cause some iBeacons to be missed, while an RSSIThreshold value greater than -80 may cause inaccurate distance estimates.

To choose the optimal RSSIThreshold value, you need to run some tests with your data. You can start with an RSSIThreshold value of -60 and then increase or decrease it based on your test results.

Here are some tips for choosing the value of RSSIThreshold:

If the environment in which you are measuring distance is noisy, you can use a higher RSSIThreshold value.
If the iBeacon is placed in a location where it is subject to interference, a higher RSSIThreshold value can be used.
If you need greater accuracy in distance estimation, you can use a lower RSSIThreshold value.

Sub ParticleFilter(RSSI, RssiThreshold, ParticleCount, Alpha)

     ' Create a particle vector
     Dim Particles(ParticleCount) As Particle

     ' Initialize the particles
     For i As Integer = 0 To ParticleCount - 1
         Particles(i).RSSI = RSSI
         Particles(i).Distance = GetDistance(Particles(i).RSSI)
     EndFor

     ' Perform particle update
     For i As Integer = 0 To ParticleCount - 1
         Particles(i).RSSI = RSSISmooth(Particles(i).RSSI, Alpha)
         Particles(i).Distance = GetDistance(Particles(i).RSSI)
     EndFor

     ' Returns the average distance of the particles
     Dim DistanceMean As Double
     DistanceMean = 0
     For i As Integer = 0 To ParticleCount - 1
         DistanceMean = DistanceMean + Particles(i).Distance
     Next
     DistanceMean = DistanceMean / ParticleCount

     Return DistanceMean
End Sub

' Main function

Sub Main()

     ' Settings
     Dim RssiThreshold As Double = -50
     Dim ParticleCount As Integer = 100
     Dim Alpha As Double = 0.7

     ' Read the RSSI value of the iBeacon
     Dim RSSI As Double
     RSSI = InputBox("Enter the RSSI value of the iBeacon: ")

     ' Calculate the accurate distance
     Dim Distance As Double
     Distance = ParticleFilter(RSSI, RssiThreshold, ParticleCount, Alpha)

     ' Display the distance
     MsgBox(Distance)

End Sub
```

This example works like this:

1. The `RSSISmooth()` function is used to apply an RSSI filter to the RSSI value provided by the user.
2. The `ParticleFilter()` function is used to apply a particle filter to the filtered RSSI value.
3. The `GetDistance()` function is used to calculate the distance of the iBeacon in meters based on its RSSI.

To run this example, you need to set the values of the `RssiThreshold`, `ParticleCount`, and `Alpha` variables according to your needs.

Here's an example of how to use the example:

```
Enter the RSSI value of the iBeacon: -60

Distance: 2.4 meters
```

In this example, the iBeacon distance is 2.4 meters. This is more accurate than the distance calculated without applying RSSI smoothing and particle filtering.

Can Someone make a test On this code ?
Generated by AI
 
Last edited:
Upvote 0
Top