蓝牙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米内,但会出现凌波微步,从蓝框那里,一下飞到过道。在下篇文章中会将这种杂质进行过滤,
以及使用加权的方法进行改进。
蓝牙RSSI定位入门到精通(4)-指纹法实现_第1张图片

你可能感兴趣的:(室内外定位)