• 【原创】大叔案例分享(4)定位分析--见证scala的强大


    一 场景分析

    定位分析广泛应用,比如室外基站定位,室内蓝牙beacon定位,室内wifi探针定位等,实现方式是三点定位 Trilateration

    理想情况

     

    这种理想情况要求3个基站‘同时’采集‘准确’的距离信息,

    实际情况

    • 3个基站采集数据的时间是分开的;
    • 采集数据的距离不准确;

    解决方法是:

    • 增加基站数量,即增加采集数据的密度和数量;
    • 不采用一个时间点的数据,而采用一个时间段的数据计算,比如5s内可能只有1个基站的数据,但是30s内可能会有超过3个基站的数据;
    • 在误差范围内,采用数学方法迭代收敛,找出概率上最有可能的未知点的坐标;

    得到未知点坐标之后再结合时间可以做更多应用:轨迹图,热力图等,比如

    二 问题抽象

    已知条件

    • n个点位置坐标:(x1, y1), (x2, y2), (x3, y3), ..., (xn, yn)
    • 未知点到n个点距离:d1, d2, d3, ..., dn

    求解

    • 未知点位置坐标(x, y)

    方程

     

    解法

    上面的方程是n个2次方程,

    1)首先尝试将次数降低,逐个用方程组中第i-1个方程减去第i个方程得到新方程,这样n个2次方程转换为n-1个1次方程,

    2)得到n-1个1次方程(线性方程)之后,问题转换为一元线性回归问题:

    即平面中有n个观察点(x1, y1), (x2, y2), ..., (xn, yn),需要找到一条直线Y=aX+b,计算常数a和常数b使得n个观察点到直线的距离(误差)平方和最小(注意原始问题中的未知点坐标就是这里的常数a和常数b);

    一元线性回归模型可以利用最小二乘法(最小平方法)求得最优解,即最小二乘解;最小二乘法详见:https://www.cnblogs.com/barneywill/p/10217349.html

    问题模型简化

    (x1, y1, d1)
    (x2, y2, d2)
    ...
    (xn, yn, dn)
    ->
    (x, y)

    三 统计示例

    输入
    (1.0, 1.0, 1.0)
    (2.0, 0.0, 1.0)
    (2.0, 2.0, 1.0)

    输出
    (2.0,1.0)

    四 代码实现

    scala核心代码

    scala

      /**
        * @param datas Array(x_coordinates, y_coordinates, distance)
        * @return (x_coordinates, y_coordinates)
        */
      def detect(datas : Array[(Double, Double, Double)]) : (Double, Double) = {
        if (datas == null || datas.isEmpty) (0, 0)
        else if (datas.length == 1) return (datas.head._1, datas.head._2)
        else if (datas.length == 2) return ((datas.head._1 + datas.last._1) / 2, (datas.head._2 + datas.last._2) / 2)
        else {
          var data = Array[Array[Double]]()
          //X + (y_1 - y_i)/(x_1 - x_i)Y = (sq(d_i) - sq(d_1) + sq(x_1) + sq(y_1) - sq(x_i) - sq(y_i))/2(x_1 - x_i)
          for (i <- 1 to (datas.length - 1)) data = data :+ Array((datas.head._2 - datas.apply(i)._2) / (datas.head._1 - datas.apply(i)._1), (Math.pow(datas.apply(i)._3, 2) - Math.pow(datas.head._3, 2) + Math.pow(datas.head._1, 2) + Math.pow(datas.head._2, 2) - Math.pow(datas.apply(i)._1, 2) - Math.pow(datas.apply(i)._2, 2))  / 2 / (datas.head._1 - datas.apply(i)._1))
          val regression = new SimpleRegression
          regression.addData(data)
          (regression.getIntercept, regression.getSlope)
        }
      }

    测试运行

          println(detect(Array((1.0, 1.0, 1.0))))
          println(detect(Array((1.0, 1.0, 1.0), (2.0, 2.0, 1.0))))
          println(detect(Array((1.0, 1.0, 1.0), (2.0, 0.0, 1.0), (2.0, 2.0, 1.0))))
          println(detect(Array((1.0, 1.0, 1.0), (2.0, 0.0, 1.0), (2.0, 3.0, 1.0))))
          println(detect(Array((1.0, 1.0, 1.0), (2.0, 0.0, 1.0), (2.0, 3.0, 1.0), (2.0, 3.0, 1.0), (20.0, 30.0, 1.0))))

    输出

    (1.0,1.0)
    (1.5,1.5)
    (2.0,1.0)
    (2.5,1.5)
    (7.728915662650602,3.3674698795180724)

    五 半径图效果

    实际数据的半径图示例:

    半径图中黑色点表示基站位置,每个基站都有一个或两个圆圈,其中两个圆圈使用数据里的最大距离和最小距离绘制的;红色点表示根据算法定位出来的设备位置;

  • 相关阅读:
    关于js判断鼠标移入元素的方向--解释
    angularJs的学习笔记(一):angularJs的filter是根据value属性值来过滤的
    虚拟机设置网络连接
    [转载]23个经典JDK设计模式
    Ubuntu 17.04 开启 TCP BBR 拥塞控制算法
    解决DIGITALOCEAN后台被墙的两个方法
    远程访问服务器上的MySQL数据库,发现root远程连接不上
    jsp获取properties配置文件中的属性值
    去除底部“自豪地采用 WordPress”版权信息----最后附最新版的删除方法!!
    改91云linux服务器一键测试脚本(去除上传测试文件代码)
  • 原文地址:https://www.cnblogs.com/barneywill/p/10193601.html
Copyright © 2020-2023  润新知