下篇文章蓝牙RSSI定位入门到精通(5)-卡尔曼滤波
https://blog.csdn.net/qq_35651984/article/details/82793612
接上篇文章,指纹的实现是在线阶段(实际测坐标)也就是回归问题,如何用特征rssi来获得坐标的问题。可以通过knn算法来实现。
1,计算距离(可以通过欧几里得度量计算)
2,选择距离最小的k个点(这里k=1)
将获得的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]));
}
如果离线的容器为空,将文件中的离线数据读出来
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();
}
1,获得每个信标到待测点的距离
2,通过距离进行排序
3,找到前k(5)个最近的距离
4,通过5个距离的类判断比例最大的,为最近的分类
5,距离最近且为最近的类选择为坐标
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()
{
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;
获得一组在线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米内,但会出现凌波微步,从蓝框那里,一下飞到过道。在下篇文章中会将这种杂质进行过滤,
以及使用加权的方法进行改进。