const mysql = require('../utils/mysql_db') const numbers = require('../utils/numbers') async function Locating() { try { //首先获取已计算生成的非法电台目录 let sql = `SELECT id,frequency,confirm FROM fm_t_illegal_radio;`; let result = await mysql.query(sql); let map_illegal_radio = {}; for (let i = 0; i < result.length; i++) { map_illegal_radio[result[i].frequency] = result[i]; } //获取扫描记录中所有非法电台记录 用以计算 sql = ` SELECT frequency, signal_strength, lon, lat, max(upload_time) AS upload_time FROM fm_t_scan_record a LEFT JOIN fm_t_task_record b ON a.task_record_id = b.id WHERE result <> '0' AND result <> '1' AND signal_strength IS NOT NULL AND lon IS NOT NULL AND lat IS NOT NULL GROUP BY frequency, device_lgid ;`; result = await mysql.query(sql); let map_data = {}; for (let i = 0; i < result.length; i++) { if (map_data[result[i].frequency]) { map_data[result[i].frequency].push(result[i]); } else { map_data[result[i].frequency] = [result[i]]; } } //依次计算每个非法电台的位置 for (let freq in map_data) { if (map_illegal_radio[freq] && map_illegal_radio[freq].confirm == "已确认") { continue; //如果电台信息已经经过确认,则不再计算 } let data = map_data[freq]; let xy = []; let dis = []; for (let i = 0; i < data.length; i++) { xy.push([data[i].lon, data[i].lat]); dis.push(getDistanceByRSS(data[i].signal_strength)); //计算距离 } let location = equationSolving(xy, dis); //求解坐标 if (!location) { continue; } //保存计算结果到数据库 if (map_illegal_radio[freq]) { sql = `UPDATE fm_t_illegal_radio SET lon=${location[0][0]}, lat=${location[1][0]}, time=NOW() WHERE id=${map_illegal_radio[freq].id};`; } else { sql = `INSERT INTO fm_t_illegal_radio (frequency,lon,lat,confirm,time,detail) VALUES(${freq}, ${location[0][0]}, ${location[1][0]}, '待确认', NOW(), '平台计算');`; } result = await mysql.query(sql); } return true; } catch (err) { return false; } } //通过接收信号强度近似计算电台距离 便于计算返回值单位转为 度 function getDistanceByRSS(rss) { let dis = -0.0236 * rss - 2.0394; //距离近似计算公式 return dis > 0 ? dis : 0; } //求解距离方程组 得到电台坐标 //xy为n x 2 的矩阵,表示n个已知点的坐标 //dis为n个已知点到未知点的距离 function equationSolving(xy, dis) { try { if (dis.length == 1) { let theta = Math.random() * Math.PI; return [ [xy[0][0] + dis * Math.cos(theta)], [xy[0][1] + dis * Math.sin(theta)] ]; } else if (dis.length == 2) { //仅粗略计算,直接返回 中点 ------ 待改进 return [ [0.5 * (xy[0][0] + xy[1][0])], [0.5 * (xy[0][1] + xy[1][1])] ]; } else { let n = dis.length; let A = []; let b = []; const c = dis[n - 1] * dis[n - 1] - xy[n - 1][0] * xy[n - 1][0] - xy[n - 1][1] * xy[n - 1][1]; for (let i = 0; i < n - 1; i++) { A.push([2 * (xy[i][0] - xy[n - 1][0]), 2 * (xy[i][1] - xy[n - 1][1])]); b.push([xy[i][0] * xy[i][0] + xy[i][1] * xy[i][1] - dis[i] * dis[i] + c]); } let AT = [ numbers.matrix.getCol(A, 0), numbers.matrix.getCol(A, 1) ]; let X = numbers.matrix.multiply( numbers.matrix.multiply( numbers.matrix.inverse(numbers.matrix.multiply(AT, A)), AT), b); return X; } } catch (err) { return null; } } Locating();