map-sense.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. // components/map-sense.js
  2. const innerAudioContext = wx.createInnerAudioContext();
  3. import http from '../../utils/http';
  4. import {promisify,BeaconUtils} from '../../utils/util';
  5. let openBluetoothAdapter = promisify(wx.openBluetoothAdapter)
  6. let startBeaconDiscovery = promisify(wx.startBeaconDiscovery)
  7. import { CDN_URL, CONNECT_STATUS, STATUS_TEXT, API_BASE_URL } from '../../config/index';
  8. const STATUS_PIC = {
  9. '0': 'default',
  10. '1': 'loading',
  11. '2': 'success',
  12. '3': 'fail'
  13. };
  14. // 选择6档
  15. const TXPOWER = 0
  16. // 距离经验值(调试所得)
  17. const N = 14
  18. let AveLength = 10
  19. Component({
  20. /**
  21. * 组件的属性列表
  22. */
  23. properties: {
  24. },
  25. /**
  26. * 组件的初始数据
  27. */
  28. data: {
  29. status: "0",
  30. cdn_url: CDN_URL,
  31. connect_status: CONNECT_STATUS,
  32. status_text: STATUS_TEXT,
  33. status_pic: STATUS_PIC,
  34. targetObj: {},
  35. audio_address: {},
  36. api_base_url: API_BASE_URL,
  37. // 是否是扫码播放
  38. isScanPlay: false,
  39. cdn_url:CDN_URL,
  40. classfiy:{}
  41. },
  42. /**
  43. * 组件的方法列表
  44. */
  45. methods: {
  46. openBluetooth(cb) {
  47. openBluetoothAdapter().then(res=>{
  48. cb(res)
  49. },()=>{
  50. wx.showToast({
  51. title: '请打开蓝牙',
  52. icon: 'error',
  53. duration: 2000
  54. })
  55. })
  56. },
  57. toHandle() {
  58. let aveArr = []
  59. this.openBluetooth(()=>{
  60. startBeaconDiscovery({uuids: ['FDA50693-A4E2-4FB1-AFCF-C6EB07647825']}).then((res)=>{
  61. wx.onBeaconUpdate(data=>{
  62. //打印最新收集到的信号
  63. console.log('beacon',data.beacons)
  64. // 需要收集十组数据,索引号最大的组是最旧的
  65. if (aveArr.length > AveLength) {
  66. // aveArr[0] = data.beacons
  67. //当超过十组时,应该将索引号大的组淘汰掉
  68. aveArr.pop()
  69. }
  70. aveArr.unshift(data.beacons) //在队列前面插入
  71. // console.log('aveArr',aveArr);
  72. let all = []
  73. aveArr.forEach(item => {
  74. // console.log(aveArr.length,item)
  75. all = all.concat(item)
  76. });
  77. // classfiy = {10003:[{},{},···],10002:[{},{},···],10001:[{},{},···]}
  78. // console.log('all',all)
  79. let classfiy = BeaconUtils.classification(all,'major')
  80. let accuracyList = {} // 存放处理后的accuary
  81. // let dataArr = [] //记录各信标的信号收集数目
  82. Object.keys(classfiy).forEach(key=>{
  83. //每个major的AveLength个元素数组,元素为rssi
  84. let arr = classfiy[key].map(item=>{
  85. return item.rssi
  86. })
  87. //每个major的rssi平均值
  88. // console.log(key,'rssi',arr)
  89. let ave = BeaconUtils.arrayAverage(arr)
  90. // console.log('ave',ave)
  91. //计算平均差
  92. let meanDeviation = BeaconUtils.getMeanDeviation(arr,ave);
  93. // console.log('meanDeviation',meanDeviation)
  94. //计算各rssi的高斯模糊权重
  95. let guassionArr = [];
  96. for(let i = 0; i < arr.length; ++i){
  97. // console.log('guassionArr ele',BeaconUtils.getOneGuassionArray(arr.length,i,meanDeviation))
  98. // 返回的可能是空数组
  99. guassionArr.push(BeaconUtils.getOneGuassionArray(arr.length,i,meanDeviation));
  100. }
  101. // console.log('guassionArr',guassionArr)
  102. //计算高斯模糊后的rssi值
  103. let rssiArr = []; //模糊后的rssi数组
  104. for(let i = 0; i < arr.length; ++i){
  105. let sum = 0;
  106. for(let j = 0; j <arr.length; ++j){
  107. sum += guassionArr[i][j] * arr[j]
  108. }
  109. rssiArr.push(sum);
  110. // console.log('sum',sum)
  111. }
  112. // console.log('rssiArr',rssiArr);
  113. //时间加权后求rssi平均值
  114. let aveOnTime = BeaconUtils.arrayAverage(rssiArr.slice(Math.floor(0,1)).concat(rssiArr));
  115. // console.log('aveOnTime',aveOnTime)
  116. //测距
  117. classfiy[key].forEach(item=>{
  118. item.accuracy = BeaconUtils.calculateAccuracy(TXPOWER,aveOnTime,N)
  119. if(!accuracyList[key]){
  120. //如果还没有对应的“信标号”
  121. accuracyList[key] = [item.accuracy]
  122. }
  123. accuracyList[key].push(item.accuracy)
  124. // console.log('item',item)
  125. })
  126. // dataArr.push(classfiy[key].length)
  127. })
  128. // console.log(classfiy['10001'])
  129. // console.log(classfiy['10002'])
  130. // console.log(classfiy['10003'])
  131. console.log(classfiy)
  132. // 筛选器,筛选出配对的一组信标
  133. let aveAccuracys = new Map() //信标的平均距离,用于判断是否在范围内
  134. let matchSigns = [] //匹配的信号
  135. let prologue = ['1000110002'] //序厅
  136. let annexHall = ['1000310004'] //附厅
  137. let mainHall = ['1000510006'] //主厅
  138. let area = [prologue,annexHall,mainHall]
  139. const R = 3.8 //设定范围半径
  140. Object.keys(accuracyList).forEach(key=>{
  141. let aveAccuracy = BeaconUtils.arrayAverage(accuracyList[key])
  142. if(aveAccuracy < R){
  143. aveAccuracys.set(key,aveAccuracy)
  144. }
  145. })
  146. //理想情况下只有两个信标的信号,刚好匹配为一组
  147. //判断编号是奇数偶数
  148. let result = ''
  149. for(let key of aveAccuracys.keys()){
  150. let num = parseInt(key)
  151. if(num % 2 == 0){
  152. if(aveAccuracys.has(String(num - 1))){
  153. num--
  154. result = key + num
  155. break
  156. }
  157. }else if(aveAccuracys.has(String(num + 1))){
  158. num++
  159. result = key + num
  160. break
  161. }
  162. }
  163. console.log('result',result);
  164. for(let i = 0; i < area.length; ++i){
  165. if(area[i].includes(result)){
  166. console.log(i)
  167. }
  168. }
  169. // 计算方差
  170. //计算平均数
  171. // let x = BeaconUtils.arrayAverage(dataArr)
  172. // let variance = BeaconUtils.getVariance(dataArr,x)
  173. //打印收集到各种信号数目的方差
  174. // console.log('txPower=',TXPOWER," 方差:",BeaconUtils.repeat('--',Math.floor(variance)))
  175. // 定位
  176. // 将三个信标构成直角三角形,其中10002号信标为直角,10001号为基点
  177. // 根据挡位设定相邻顶点信标的距离,5档,设边长为10m
  178. // let sideLength = 5
  179. // let distance1,distance2,distance3 //分别对应游客到信标10001,1002,10003的距离
  180. // distance1 = BeaconUtils.arrayAverage(accuracyList['10001'])
  181. // distance2 = BeaconUtils.arrayAverage(accuracyList['10002'])
  182. // distance3 = BeaconUtils.arrayAverage(accuracyList['10003'])
  183. // let px = (Math.pow(2.8,2) - Math.pow(distance2,2) + Math.pow(distance1,2)) / (2.8 * 2)
  184. // let py = (Math.pow(5.6,2) - Math.pow(distance3,2) + Math.pow(distance2,2)) / (5.6 * 2)
  185. // console.log('px',px,' py',py)
  186. this.setData({
  187. classfiy,
  188. status:'2'
  189. })
  190. })
  191. }).catch(()=>{
  192. wx.showToast({
  193. title: '连接失败',
  194. icon: 'error',
  195. duration: 500
  196. })
  197. })
  198. })
  199. },
  200. stopBeaconDiscovery() {
  201. var that = this;
  202. console.log('这是取消连接')
  203. wx.showToast({
  204. title: '取消连接成功',
  205. icon: 'error',
  206. duration: 1000
  207. })
  208. wx.stopBeaconDiscovery({})
  209. // 取消连接 停止播放音乐 目标对象置为{} 设置为第一次进入
  210. innerAudioContext.stop();
  211. that.setData({
  212. status: '0',
  213. targetObj: {}
  214. })
  215. },
  216. // 扫一扫
  217. toScanCode() {
  218. var that = this;
  219. that.setData({
  220. isScanPlay: true
  221. })
  222. wx.scanCode({
  223. success(res) {
  224. console.log('success', res)
  225. console.log('result', res['result'])
  226. console.log('innerAudioContext', innerAudioContext)
  227. that.setData({ targetObj: {} })
  228. innerAudioContext.autoplay = true;
  229. innerAudioContext.src = res['result']
  230. innerAudioContext.loop = true;
  231. innerAudioContext.play();
  232. },
  233. fail: function (res) {
  234. console.log('fail innerAudioContext', innerAudioContext)
  235. that.setData({
  236. isScanPlay: false
  237. })
  238. innerAudioContext.play();
  239. return;
  240. },
  241. complete(){
  242. // console.log()
  243. that.setData({
  244. isScanPlay: false
  245. })
  246. }
  247. })
  248. },
  249. getAudios() {
  250. http.get('/api/web/getAudioIndex')
  251. .then(res => {
  252. let { data } = res,target = {};
  253. data.forEach(item => {
  254. switch (item.type) {
  255. case 1:
  256. target['10001'] = `${this.data.api_base_url}/data/${item.audio}`;
  257. break;
  258. case 2:
  259. target['10002'] = `${this.data.api_base_url}/data/${item.audio}`;
  260. break;
  261. case 3:
  262. target['10003'] = `${this.data.api_base_url}/data/${item.audio}`;
  263. break;
  264. default:
  265. break
  266. }
  267. })
  268. this.setData({
  269. audio_address: target
  270. })
  271. })
  272. }
  273. },
  274. lifetimes:{
  275. attached: function () {
  276. innerAudioContext.stop();
  277. //获取语音
  278. this.getAudios();
  279. var that = this;
  280. // wx.onAccelerometerChange(function (e) {
  281. // console.log('手机咚咚咚给')
  282. // if (Math.abs(e.x) > 1.1 && Math.abs(e.y) > 1.1) {
  283. // //         wx.showToast({ title: "摇一摇" })
  284. // } else if (Math.abs(e.x) > 0.07 && Math.abs(e.y) > 0.02 && that.data.status === '2') {
  285. // // 扫一扫播放的话 移动无效
  286. // if (that.data.isScanPlay) return;
  287. // that.startBeaconDiscovery()
  288. // } else {
  289. // //         wx.showToast({ title: "静止" })
  290. // }
  291. // }),
  292. innerAudioContext.onEnded(() => {
  293. console.log('播放结束了')
  294. if (this.data.isScanPlay) {
  295. innerAudioContext.stop()
  296. this.setData({ isScanPlay: false })
  297. this.targetObj = {}
  298. console.log('innerAudioContext', innerAudioContext)
  299. if (this.data.status == 2) {
  300. console.log(2222222222222222)
  301. this.startBeaconDiscovery()
  302. }
  303. }
  304. })
  305. },
  306. detached: function () {
  307. innerAudioContext.stop();
  308. innerAudioContext.destroy();
  309. wx.stopBeaconDiscovery({})
  310. this.setData({status:"0"})
  311. }
  312. }
  313. })