蓝牙RSSI定位入门到精通(4)-指纹法实现

下篇文章蓝牙RSSI定位入门到精通(5)-卡尔曼滤波
https://blog.csdn.net/qq_35651984/article/details/82793612

指纹的实现

接上篇文章,指纹的实现是在线阶段(实际测坐标)也就是回归问题,如何用特征rssi来获得坐标的问题。可以通过knn算法来实现。
1,计算距离(可以通过欧几里得度量计算)
2,选择距离最小的k个点(这里k=1)


获得在线的rssi

将获得的string进行截取,放入容器rssi中保存

QStringList qstlist_rss=string.split("&");
                    QList<QString>::iterator itrss=qstlist_rss.begin();
                    QList<QString>::iterator itrss_end=qstlist_rss.end();
                    for(int i=0;itrss!=itrss_end;itrss++,i++)
                    {
                          QString string_rss=*itrss;
                          rssi[i]=string_rss.toFloat();//存储在线的rssi
                          ui->label->setText(QString("rssi:%1:%2:%3").arg(rssi[0]).arg(rssi[1]).arg(rssi[2]));
                    }

获得离线的rssi

如果离线的容器为空,将文件中的离线数据读出来

 if(qstr_list.empty())
                    {
                      QFile file_in(".\\ku.txt");
                      if(file_in.open(QIODevice::ReadOnly|QIODevice::Text))
                      {
                             QTextStream text_in(&file_in);

                             while(!text_in.atEnd())
                             {
                                 qstr_list<<text_in.readLine();
                             }
                             file_in.close();
                      }
                    }

通过迭代器,获得多个类块的各rssi保存在rssi_li中

QList<QString>::iterator it=qstr_list.begin();//指纹库
                    QList<QString>::iterator it_end=qstr_list.end();
                    for(;it!=it_end;it++)
                    {//一个区域的指纹
                           QString str;
                           QStringList qlist;
                           QVector<float> rssi_li(3);//离线的三个rssi
                           str=*it;
                           ui->label->setText(str);
                           qlist=str.split("&");//存储各个信标的rssi

                           QList<QString>::iterator iter=qlist.begin()+1;//第一个为坐标跳过
                           QList<QString>::iterator iter_end=qlist.end();
                           ui->label->setText(*iter);
                           for(int i=0;iter!=iter_end;iter++,i++)
                           {
                               rssi_li[i]= QString(*iter).toFloat();


                           }

KNN算法

1,获得每个信标到待测点的距离
2,通过距离进行排序
3,找到前k(5)个最近的距离
4,通过5个距离的类判断比例最大的,为最近的分类
5,距离最近且为最近的类选择为坐标

创建KNN类和knn_date类

knn_date中保存每个位置的坐标距离和所属的类,在KNN中实例化对象

class Knn
{
public:
    。。。。。。。
private:
    Knn_Date date[42];
};
class Knn_Date
{
public:
,,,,,,
private:
    char region;
    QString coordinate;
    double distance=1000;

初始化knn类

目的将距离,分类,坐标的值写入,利于排序和查找
构造函数中初始化分类和坐标

Knn::Knn()
{
    date[0].setregion('A');
     date[0].setcoordinate("2,3");
    date[1].setregion('A');
     date[1].setcoordinate("3,3");
    date[2].setregion('A');
     date[2].setcoordinate("2,4");
    date[3].setregion('A');
     date[3].setcoordinate("3,4");

      date[4].setregion('B');
      date[4].setcoordinate("4,3");
      date[5].setregion('B');
      。。。。。。

date_init中获得距离

void Knn::knn_init(QString coordinate,double distance)
{
    for(int i=0;i<42;i++)
    {
        if(date[i].getcoordinate()==coordinate)
        {
             date[i].setdistance(distance);
        }
    }
}

数据进行排序

void Knn::knn_sort()//冒泡排序
{
    for(int i=0;i<42;i++)
    {
        for(int t=i;t<42-1;t++)
        {
            if(date[t].getdistance()>date[t+1].getdistance())
            {
                Knn_Date x=date[t];
                date[t]=date[t+1];
                date[t+1]=x;
            }
        }
    }
}

计算获得坐标

QString Knn::knn_result()
{
    int i[11]={0,0,0,0,0,0,0,0,0,0,0};//对应/a/b/c/d/e/分类的的个数
    char max=' ';//最优的分类
    for(int t=0;t<5;t++)
    {
        switch(date[t].getregion())
        {
        case 'A':
            if(++i[0]>=3)//5个,过半就是该类
            {max='A';}
                 break;
        case 'B':
        。。。。。。
         for(int t=0;t<5;t++)
    {
        if(date[t].getregion()==max)//从最近的距离开始,找到第一个是max类的坐标
            return date[t].getcoordinate();
    }
    return NULL;

使用knn

获得一组在线rssi和n组离线rssi后,循环n次每次计算一次欧式距离

//欧式距离
                               Knn *k=new Knn();
                               。。。。。。
                               double a=qAbs(rssi[0]-rssi_li[0]);
                               double b=qAbs(rssi[1]-rssi_li[1]);
                               double c=qAbs(rssi[2]-rssi_li[2]);
                               double d=pow(a,2)+pow(b,2)+pow(c,2);
                               double distance=sqrt(d);
                                   ok=qlist.front()+1;
                                   k->knn_init(ok,distance);
                                                                }
                           }
                    }
                   k->knn_sort();
                    ok=k->knn_result();

画运动轨迹

回归

通过最短的距离可以得到对应的坐标(ok),将ok通过信号发送到画图界面

                    ui->label->setText(QString("你的坐标是%1").arg(ok));
                    send_sig();

定义,发送send信号

public:
    explicit Widget(QWidget *parent = 0);
    operation();
    ~Widget();
    void send_sig()
    {
        emit send(ok);
    }
 signals:
    void send(const QString & ok);

槽函数接收

接收ok后,保存在vector,并刷新绘图事件

public:
    explicit Show(QWidget *parent = 0);
    ~Show();
    void rec(const QString & ok)
    {
         int x=ok.mid(0,ok.indexOf("*")).toDouble()-1;
         int y=ok.mid(ok.indexOf("*")+1,3).toDouble()-1;
         vector_x<<x;
         vector_y<<y;
         update();

    }

在main中connect处理信号与槽(qt5)

int main(int argc, char *argv[])
{
    w.move(500,400);
    Show w1;
    w1.move(530+w.geometry().width(),400);
    w1.setMaximumSize(450,450);
    w1.setMinimumSize(450,450);
    w1.setWindowTitle("移动轨迹图");
    w1.show();
    w.show();
QObject::connect(&w,&Widget::send,&w1,&Show::rec);

绘图事件

添加画笔画家绘制网格,背景图,并将vector中保存的坐标绘制出来

void Show::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    QPen pen(Qt::black,3);
    QPen pen_1(Qt::blue,1,Qt::DotLine, Qt::RoundCap, Qt::RoundJoin);
    painter.setPen(pen);
    painter.drawRect(0,0,this->width(),this->height());
    painter.setPen(pen_1);
    //网格
    for(int i=this->width()/50;i>0;i--)//每个框50
    {
            painter.drawLine(QPoint(i*50,0),QPoint(i*50,this->height()));
    }
    for(int t=this->height()/50;t>0;t--)
    {
          painter.drawLine(QPoint(0,t*50),QPoint(this->width(),t*50));
    }
    QBrush brush(QColor(0, 0, 255), Qt::Dense4Pattern);

if(!vector_x.empty()&&!vector_y.empty())
{
    for(int i=0;i<vector_x.size();i++)
    {
        painter.setBrush(brush);
        painter.drawRect(vector_x[i]*50,vector_y[i]*50,50,50);
    }
painter.drawPixmap(vector_x.back()*50,vector_y.back()*50,50,50,QPixmap("://2.jpg"));
}

效果图&总结

精确度在2-3米内,但会出现凌波微步,从蓝框那里,一下飞到过道。在下篇文章中会将这种杂质进行过滤,
以及使用加权的方法进行改进。
效果图

  • 8
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
### 回答1: 蓝牙(RSSI)室内定位是一种基于蓝牙信号强度(RSSI)和距离的室内定位技术,可以在室内环境中实现精确的位置跟踪服务。目前,Android平台提供了许多用于蓝牙定位的API和工具,开发人员可以使用这些工具来实现室内定位功能。 在实现蓝牙(RSSI)室内定位之前,需要先进行站点调查和信号质量测试。站点调查可以用于确定信标放置的位置、数量和信号范围等因素。信号质量测试可以确定信标的信号强度和覆盖范围,以便更好的设计和优化蓝牙定位系统。 在Android平台中,可以使用BluetoothAdapter API来扫描周围的蓝牙设备,获取设备的RSSI值和MAC地址等信息。一旦获取了RSSI值,就可以通过算计算出设备与信标之间的距离和位置信息,并将其显示在用户界面上。具体的算可以使用基于信号强度指数的方,例如Path Loss和Trilateration的方来进行定位计算。 需要注意的是,蓝牙(RSSI)室内定位技术也存在一些挑战和限制。例如,信号强度受环境因素的影响,如环境噪声和干扰等,这可能会导致定位精度不是特别高。此外,室内定位需要多个信标进行多点定位,成本也会相应增加。 总之,在Android开发中,使用蓝牙(RSSI)室内定位技术可以实现室内定位和位置跟踪功能,为商业和社会提供更多可能性。 ### 回答2: 在Android开发中,可以通过蓝牙RSSI(接收信号强度指数)数据实现室内定位RSSI是指接收到的信号强度,通过测量不同位置的RSSI值,就能够确定设备的位置。 首先需要获取设备的蓝牙信号强度值,这可以通过蓝牙扫描获取。然后建立一个基站位置数据库,将不同位置的蓝牙信号强度值记录下来。当需要定位时,就可以通过比对当前设备的蓝牙信号强度值和基站位置数据库中的信号强度值,来确定设备所处的位置。 室内定位的精度受到多种因素影响,比如墙体厚度、金属物体等会影响信号强度。因此在开发中需要进行精细的调试和优化。同时,蓝牙定位也有一些局限性,如需要用户开启蓝牙蓝牙信号强度值容易受到干扰等。 总之,蓝牙RSSI室内定位是一种比较成熟的技术,在Android开发中也有较多的应用场景,但仍需要开发者进行精细的调试和优化,来提高室内定位的精度和性能。 ### 回答3: 蓝牙RSSI室内定位,是指通过蓝牙信号强度指示(RSSI)来确定物体或设备在室内的具体位置。这种方适用于室内定位、追踪和导航等场景,但是有其限制:比如,受到干扰等外部环境因素的影响,精准度往往难以达到预期。 对于Android开发来说,实现蓝牙RSSI室内定位需要使用蓝牙模块,并结合相关的定位,如三角定位指纹定位等。一般步骤如下: 1.获取蓝牙设备的RSSI值。通过将扫描到的蓝牙设备进行连接,获取其信号强度值。 2.建立基站地图。在室内设定多个基站,获取它们的位置信息,并记录其强度值。 3.计算物体位置。结合已知的基站位置和它们的强度值,使用相关算计算物体位置及其误差范围。 4.优化算。如增加基站数量、调整基站位置等,提升室内定位精确度。 Android开发中,需要使用一些相关技术包和类库,如蓝牙适配器、手动操作权限等,较为复杂。值得注意的是,该技术需要有精确的物理地图、较多的基站数量以及较强的数据处理能力,因此在应用中的实际场景时需要谨慎考虑。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

工农村贴膜小哥

我倒是要看看是那个憨憨在给我打

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值