定位实验
题目:基于WIFI位置指纹的室内定位实验成员:
2012年12月
一、实验题目
实验题目
基于Wifi 位置指纹的室内定位实验
实验要求
学习android平台使用、android编程、android环境下wifi 设备查看操作。实验内容
利用最少数目的wifi 热点设备,能够实时地对手机进行定位。
二、实验目的
目前全球定位系统(GPS ,Global Positioning System )是获取室外环境位置信息通过实施项目的最常用方式。但由于卫星信号容易受到各种障碍物遮挡,GPS/APGS 等卫星定位技术并不适用于室内或高楼林立的场合,目前无线室内定位技术迅速发展,已成为GPS 的有力补充。了解智能手机如何利用Wifi 热点设备信号强度进行室内定位。
三、实验原理
1.Android 系统架构简介
Android系统架构见图,它建立于Linux内核之上,包含了各种设备驱动和管理模块,囊括了非常齐全的类库和框架,包括轻量级数据库SQLite 、浏览器Webkit 等。整个系统建立在Dalvik 虚拟机上,应用程序使用Java 语言编写。Android 系统提供了丰富的框架(活
动管理、位置管理等)来管理系统的软、硬件资源,整合了常用的应用程序(联系人、电话本等),并开放了很全面的 API 供用户使用,整个平台具有良好的开放性和扩展性。
2.采用基于射频指纹的定位方法
移动终端需要获得周围AP的RSSI指纹特征,Android 系统提供的接口可以很方便地实现这一功能。
3.定位算法
由于室内环境复杂,WiFi无线信号具有较强的时变无线信号传播衰减模型难以很好的表征距离与信号强度间的映射关系,采用基于射频指纹匹配定位方法,它具有较好的定位鲁棒性。指纹匹配方式定位算法建立在实验数据基础上,它主要包括离线训练和在线定位两个阶段,其中离线训练阶段的任务是建立射频信号强度向量和客户端位置间的一一对应关系,形成一个指纹库(radio map),定位阶段则使用实时采集的信号强度向量去匹配训练阶段构建的指纹库,从而获得目标的位置估计。
4.本次实验所采用的基本原理和基本思想如下:
当手机程序初次运行时,会创建一个数据库,数据库中包含两个表,一个记录用户所采集的地点信息,另一个表记录每个之前所记录的地点信
息所对应的wifi信息,为一对多的关系。
手持手机设备采集指纹信息,即地点信息,指纹信息会存入之前创建的
数据库中,即把输入的地点名称录入表1中,并对此地点的wifi进行
扫描,将满足一定要求的wifi信息,每个wifi SSID+地点名称作为一
个记录存进表2中。
采集的指纹信息越多,定位就会越准确。
定位时,先扫描得到所在地点的wifi信息列表,然后与数据库中每一个地点所拥有的wifi信息进行匹配,若待定位地点的wifi信息绝大部分
都在数据库中某一地点的wifi信息列表中(允许存在一定的误差),则
可以认为当前地点就是数据库中的那一个地点,于是输出那一个地点的
名称,完成定位。
四、实验流程
1.首先在手机上面打开应用程序:如图1
图1
2. 然后添加指纹信息,运行效果图如下图2和图3:
图2 图3
重复此过程,直到数据库中有一定的数量的指纹信息
3. 进入到查询界面,如图4:
图4
4.查询当前所在的位置,结果如图5所示:
图5
五、个人工作及总结
本次实验我主要负责程序中关于指纹数据库初始化模块和查询用户当前位置模块。
在指纹数据库初始化模块中,主要任务是建立如下结构的表1:wifi和表2:location:
表一:
ID Wifi_SSID Location_ID
表二:
Location_ID Location_name
其中表一和表二通过Location_ID进行关联,建表的目的是存储location 信息及其对应的wifi列表信息,一个location信息对应多个wifi信息。
在查询用户当前位置模块中,主要是进行待定位地点wifi列表信息与数据库中已经存在地点的wifi列表信息进行匹配。在此过程中用一个数
组wificount[]保存匹配的wifi个数,wificount[i]代表待定位地点
wifi列表信息与数据库表二中location_ID为i的地点所拥有的wifi
列表信息匹配的wifi个数。
最初实验只有两者个数完全一样时才输出此地点,但是在实际操作运行
时总是没有匹配的信息输出。后来经过分析和查相关的资料,发现生活
中很多wifi信号不是很稳定,并且wifi信号受外界环境的影响较大,
手机就算是在同一地点所收到的wifi信号变化也会很大,于是考虑允
许wificount[i]有一定的误差,但是多少范围内的误差即能尽大可能的
不影响定位的误差,又可以实现定位?后来经过测试,当wificount[i]
左右变化不超过3的时候可以满足一般性要求,实现定位。
通过本次实验,知道了wifi定位的基本原理,并且在实际中给予实现;熟悉了安卓开发的一般性步骤,提升了自己的能力。同时发现,此安卓程序存在诸多问题和可以改进的地方,如采集指纹信息的时候必须人为操作,可以设置一个定时器,周期性的进行采集。
六、附录:实验代码
1.程序运行主入口:
//程序运行的主入口
package com.example.w4;
import java.util.List;
import https://www.wendangku.net/doc/f613901944.html,.wifi.ScanResult;
import https://www.wendangku.net/doc/f613901944.html,.wifi.WifiInfo;
import https://www.wendangku.net/doc/f613901944.html,.wifi.WifiManager;
import android.os.Bundle;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
public static int locationnum=0;
public static int wifinum[]=new int[100];
public TextView text1,text2,text3,text4,text5;
@Override
//创建
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(https://www.wendangku.net/doc/f613901944.html,yout.activity_main);
DBHelper source=new DBHelper(this);
SQLiteDatabase db =source.getWritableDatabase();
Button locationaddbutton =(Button)findViewById(R.id.locationaddbutton);
Button searchbutton =(Button)findViewById(R.id.searchbutton);
locationaddbutton.setOnClickListener(new AddButtonClickListener());
searchbutton.setOnClickListener(new
SearchButtonClickListener());
text1=(TextView)findViewById(R.id.text1);
text1.setText(R.string.hello_world);
}
//“输入当前地点的位置”按钮的动作监听器
public class AddButtonClickListener implements OnClickListener{ @Override
public void onClick(View v) {
locationnum++;
Intent intent =new Intent(MainActivity.this,Add.class);
startActivity(intent);
}
}
//“查询当前所在的位置”按钮的动作监听器
public class SearchButtonClickListener implements OnClickListener{ @Override
public void onClick(View v) {
Intent intent =new Intent(MainActivity.this,Search.class);
startActivity(intent);
}
}
}
2.指纹数据库初始化模块:
//创建一个空的数据库,初始化数据库
package com.example.w4;
import android.content.Context;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.widget.Toast;
public class DBHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION =1;
private static final String DATABASE_NAME ="wifilocation.db";
private Context m_context;
private static final String WIFI_CREATE_DDL = "CREATE TABLE WIFI (_ID INTERGER PRIMARY KEY,WIFI_SSID TEXT,WIFI_LEVEL INTEGER,WIFI_LOCATION INTERGER);";
private static final String LOCATION_CREATE_DDL ="CREATE TABLE
LOCATION(_ID INTERGER PRIMARY KEY,LOCATION_DESCRIPTION TEXT);";
//Wifi表,地点id,wifi的ssid,level,查询时按照groupby 地点id,//location表地点id,地点描述,两表通过id建立联系
private static final String WIFI_DELETE_DDL ="DROP TABLE IF EXISTS WIFI;";
private static final String LOCATION_DELETE_DDL ="DROP TABLE IF EXISTS LOCATION";
public DBHelper(Context context) {//对象的构造函数
super(context,DATABASE_NAME, null, DATABASE_VERSION);
m_context=context;// TODO Auto-generated constructor stub }
@Override
//执行SQL语句以创建表
public void onCreate(SQLiteDatabase db) {
Toast.makeText(m_context,"creat
db",Toast.LENGTH_LONG).show();// TODO Auto-generated method stub db.execSQL(WIFI_CREATE_DDL);
db.execSQL(LOCATION_CREATE_DDL);
}
@Override
public void onUpgrade(SQLiteDatabase db, int lolVersion, int newVersion) {//两个表的更新,当version变化时会更新(调试时用)Toast.makeText(m_context, "upgrade db", Toast.LENGTH_LONG).show();
db.execSQL(WIFI_DELETE_DDL);
db.execSQL(WIFI_CREATE_DDL);
db.execSQL(LOCATION_DELETE_DDL);
db.execSQL(LOCATION_CREATE_DDL);
}
}
3.采集并添加指纹信息模块:
//增加指纹库,往数据库中增加指纹信息
package com.example.w4;
import java.util.List;
import android.app.Activity;
import android.content.ContentValues;
import android.database.sqlite.SQLiteDatabase;
import https://www.wendangku.net/doc/f613901944.html,.wifi.ScanResult;
import https://www.wendangku.net/doc/f613901944.html,.wifi.WifiManager;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class Add extends Activity{
public static StringBuffer save;//保存的location信息都在其中
//“输入当前地点的位置”按钮动作监听器
public class SubmitListener implements OnClickListener{
@Override
//点击按钮之后将wifi SSID信息存入指纹数据库中
public void onClick(View v) {
EditText desc =(EditText)(Add.this).findViewById(R.id.desc);
DBHelper helper=new DBHelper(Add.this);
SQLiteDatabase db =helper.getWritableDatabase();
WifiManager wifimanager = (WifiManager)getSystemService(WIFI_SERVICE);
wifimanager.startScan();
List
int i=0;
String[] ssid=new String[25];
for(ScanResult scanResult:scanResults){
//信息添加到数据库中
ContentValues args =new ContentValues();
if(wifimanager.calculateSignalLevel(scanResult.level,100)>20){//这里将level>20的认为是比较稳定的wifi站点
args.put("WIFI_SSID",scanResult.SSID.toString());
long rowid =db.insert("WIFI", null, args);
args.put("WIFI_LEVEL",wifimanager.calculateSignalLevel(scanResult.lev el,100));
long rowid2 =db.insert("WIFI", null, args);
i++;
}
}
Toast.makeText(Add.this, "One record insert,there are "+i+"wifi at here",Toast.LENGTH_LONG).show();
MainActivity.wifinum[MainActivity.locationnum]=i;//几号地点有几个wifi站点
db.close();
}
}
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(https://www.wendangku.net/doc/f613901944.html,yout.add);
Button submitButton =(Button)findViewById(R.id.submit);
submitButton.setOnClickListener(new SubmitListener());
}
}
4.查询用户当前位置模块:
//查询用户当前位置
package com.example.w4;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import https://www.wendangku.net/doc/f613901944.html,.wifi.ScanResult;
import https://www.wendangku.net/doc/f613901944.html,.wifi.WifiManager;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
public class Search extends Activity{
public int[] wificount=new int[100]; //与数据库中数据相匹配wifi 的数量
public int[] levelcount=new int[100];
//“查询当前所在的位置”按钮动作监听器
public class SearchListener implements OnClickListener{
private String sqllistarray;
@Override
public void onClick(View v) {
DBHelper helper=new DBHelper(Search.this);
SQLiteDatabase db =helper.getReadableDatabase(); //db是之前创建和输入指纹信息的数据库
WifiManager wifimanager = (WifiManager)getSystemService(WIFI_SERVICE);
List
List
for(int i=1;i<=MainActivity.locationnum;i++){
Cursor cursor =db.query("WIFI",new String[]{"_ID","WIFI_SSID","WIFI_LEVEL","WIFI_LOCATION"},"WHERE
WIFI_LOCATION=1",null,null,null,null);
try{
if(cursor.moveToFirst()){
do{
String sqlresult =cursor.getString(1);//如果结果出错尝试修改
sqllist.add(sqlresult);
}while(cursor.moveToNext()); //对数据库中某一个location中wifi信息进行遍历,然后加入到sqlresult变量中
}
}finally {
cursor.close();
}
sqllistarray=sqllist.toString();
db.close();
wifimanager.startScan();
for(ScanResult scanResult:scanResults){ //对扫描到每一个wifi信息,如果存在于sqlresult中,wifilocation变量加一
if(sqllistarray.indexOf(scanResult.SSID)!=-1)
wificount[i]++;//第i个location有这些个wifi数与所存地点的wifi匹配
if(wificount[i]>=MainActivity.wifinum[i]-3&&wificount[i]<=MainAct ivity.wifinum[i]+3) //如果匹配的wifi数量在一定范围之内,则输出对应的location信息
{Toast.makeText(Search.this, "The location id="+i,Toast.LENGTH_LONG).show();
break;
}
}
}
}
}
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(https://www.wendangku.net/doc/f613901944.html,yout.search);
Button searchButton =(Button)findViewById(R.id.search);
searchButton.setOnClickListener(new SearchListener());
}
}