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();
|