前言
最近公司在研发室内定位的产品,作为后端工程师天然也开始了UWB定位算法的钻研。
协定
解析
依据协定内容,咱们能够简略编写工具类,疾速解析
private static byte[] getSHA1Digest(String data) throws IOException { byte[] bytes = null; try { MessageDigest md = MessageDigest.getInstance("SHA-1"); bytes = md.digest(data.getBytes("UTF-8")); } catch (GeneralSecurityException gse) { throw new IOException(gse); } return bytes; } /** * 二进制转十六进制字符串 * * @param bytes * @return */ private static String byte2hex(byte[] bytes) { StringBuilder sign = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { String hex = Integer.toHexString(bytes[i] & 0xFF); if (hex.length() == 1) { sign.append("0"); } sign.append(hex.toUpperCase()); } return sign.toString(); } /** * 将16进制转换为二进制 * * @param hexStr * @return */ public static byte[] parseHexStr2Byte(String hexStr) { if (hexStr.length() < 1) { return null; } byte[] result = new byte[hexStr.length() / 2]; for (int i = 0; i < hexStr.length() / 2; i++) { int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16); int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16); System.out.println("字节位:" + (byte) (high * 16 + low)); result[i] = (byte) (high * 16 + low); } System.out.println(new String(result)); return result; } /** * 十六进制字符串转二进制字符串 * * @param hexStr 十六进制字符串 * @return 二进制字符串 */ public static String hexToBin(String hexStr) { String hexToBinStr = ""; try { hexToBinStr = Long.toBinaryString(Long.valueOf(hexStr, 16)); } catch (NumberFormatException e) { e.printStackTrace(); } return hexToBinStr; } /** * 十六进制字符串转十进制 * * @param hexStr 十六进制字符串 * @return 二进制字符串 */ public static int hexToTen(String hexStr) { BigInteger lngNum = new BigInteger(hexStr, 16); return lngNum.intValue(); } public static void main(String[] args) { String payload = "mc0f00000663000005a300000512000004cbffffffffffffffffffffffffffffffff095fc100146fb7a0:022be"; String hexStr = payload.substring(2, 4); String mask = hexToBin(hexStr); System.out.println("音讯头,固定为 mc:" + mask); String range = payload.substring(4, 68); System.out.println("基站A0-A8:" + range); System.out.println(range.length()); // 1:通过渠道获取imei // 2:通过imei获取该设施绑定的室内地图,通过地图找到地图x,y,z轴坐标 List<BaseStation> stationList = new ArrayList<>(); for (int i = 0; i < mask.length(); i++) { String result = mask.substring(mask.length() - 1 - i, mask.length() - i); if (result.equals("1")) { Double rawDistance = Double.valueOf(hexToTen(range.substring(i * 8, (i + 1) * 8))) / 1000; System.out.println("标签到A" + i + "的间隔:" + rawDistance); BaseStation baseStation = new BaseStation(); baseStation.setImei("imei"); baseStation.setRawDistance(rawDistance); stationList.add(baseStation); } } // baseStationService.calculate(stationList); }
UWB定位算法编写
BaseStation.java
package com.bbzn.device.client.dataobject;import lombok.Getter;import lombok.NoArgsConstructor;import lombok.Setter;import lombok.ToString;import java.io.Serializable;import java.util.Date;@Getter@Setter@ToString@NoArgsConstructorpublic class BaseStation implements Serializable { private Long id; /** * 室内定位X轴 */ private Integer xAxis; /** * 室内定位Y轴 */ private Integer yAxis; /** * 室内定位Z轴 */ private Integer zAxis; /** * 设施imei号 */ private String imei; /** * 状态 0 默认 1 禁用 2 失常 */ private Integer status; /** * 创立工夫 */ private Date createTime; /** * 更新工夫 */ private Date updateTime; /** * 获取的间隔 */ private Double rawDistance; private static final long serialVersionUID = 1L;}
计算定位坐标:
/** * 计算定位坐标 * * @param bases 接管到的一组基站对象列表(此处列表中的基站该当是id各异的) * @return 返回定位坐标 */ @Override public Location calculate(List<BaseStation> bases) { Location location = new Location(); int baseNum = bases.size(); /*间隔数组*/ double[] distanceArray = new double[baseNum]; String[] ids = new String[baseNum]; int j = 0; /*取得基站id*/ for (BaseStation baseHeight : bases) { ids[j] = baseHeight.getId().toString(); distanceArray[j] = UwbMathUtils.getDistance(baseHeight.getZAxis(),baseHeight.getRawDistance()); j++; } int disArrayLength = distanceArray.length; double[][] a = new double[baseNum - 1][2]; double[][] b = new double[baseNum - 1][1]; /*数组a初始化*/ for (int i = 0; i < 2; i++) { a[i][0] = 2 * (bases.get(i).getXAxis() - bases.get(baseNum-1).getXAxis()); a[i][1] = 2 * (bases.get(i).getYAxis() - bases.get(baseNum-1).getYAxis()); } /*数组b初始化*/ for (int i = 0; i < 2; i++) { b[i][0] = Math.pow(bases.get(i).getXAxis(), 2) - Math.pow(bases.get(baseNum-1).getXAxis(), 2) + Math.pow(bases.get(i).getYAxis(), 2) - Math.pow(bases.get(baseNum-1).getYAxis(), 2) + Math.pow(distanceArray[disArrayLength - 1], 2) - Math.pow(distanceArray[i], 2); } /*将数组封装成矩阵*/ Matrix b1 = new Matrix(b); Matrix a1 = new Matrix(a); /*求矩阵的转置*/ Matrix a2 = a1.transpose(); /*求矩阵a1与矩阵a1转置矩阵a2的乘积*/ Matrix tmpMatrix1 = a2.times(a1); Matrix reTmpMatrix1 = tmpMatrix1.inverse(); Matrix tmpMatrix2 = reTmpMatrix1.times(a2); /*两头后果乘以最初的b1矩阵*/ Matrix resultMatrix = tmpMatrix2.times(b1); double[][] resultArray = resultMatrix.getArray(); location.setX(resultArray[0][0]); location.setY(resultArray[1][0]); /*设置定位后果的工夫戳*/ Timestamp ts = new Timestamp(System.currentTimeMillis());// location.setTimeStamp(ts); return location; }
Location.java
@Getter@Setter@ToString@NoArgsConstructorpublic class Location implements Serializable { private static final long serialVersionUID = 1L; /*x轴坐标*/// private Double xAxis; /*x轴坐标*/ private Double x; /*y轴坐标*/// private Double yAxis; /*y轴坐标*/ private Double y; /*工夫戳*/// private Timestamp timeStamp; private String imei;}