NMEA0183-AIS数据解析
public class AisParser { public void ParseNmeaMessage() { String nmeaMessage = "!AIVDM,1,1,,B,16:Erk00008PI@h>EMB7R4E@049T,0*04"; if (isValidChecksum(nmeaMessage)) { parseNmeaMessage(nmeaMessage); } else { System.out.println("校验和验证失败"); } } // 校验NMEA消息的校验和 private boolean isValidChecksum(String nmeaMessage) { int asteriskIndex = nmeaMessage.indexOf('*'); if (asteriskIndex == -1 || asteriskIndex + 3 != nmeaMessage.length()) { return false; } String checksumString = nmeaMessage.substring(asteriskIndex + 1); int checksum = Integer.parseInt(checksumString, 16); String dataToCheck = nmeaMessage.substring(1, asteriskIndex); int calculatedChecksum = 0; for (char ch : dataToCheck.toCharArray()) { calculatedChecksum ^= ch; } return calculatedChecksum == checksum; } // 解析NMEA消息 private void parseNmeaMessage(String nmeaMessage) { if (nmeaMessage.startsWith("!AIVDM") || nmeaMessage.startsWith("!AIVDO")) { String[] parts = nmeaMessage.split(","); String payload = parts[5]; parsePayload(payload); } } // 解析PayLoad数据 private void parsePayload(String payload) { String binaryPayload = convertSixBitAsciiToBinary(payload); int messageType = Integer.parseInt(binaryPayload.substring(0, 6), 2); System.out.println("消息类型: " + messageType); switch (messageType) { case 1: case 2: case 3: parseDynamicData(binaryPayload); break; case 5: parseStaticData(binaryPayload); break; default: System.out.println("不支持的消息类型: " + messageType); } } // 转换6位ASCII到二进制字符串 private String convertSixBitAsciiToBinary(String payload) { StringBuilder binaryString = new StringBuilder(); for (char c : payload.toCharArray()) { int value = c - 48; if (value > 40) value -= 8; String binaryChar = String.format("%6s", Integer.toBinaryString(value)).replace(' ', '0'); binaryString.append(binaryChar); } return binaryString.toString(); } // 解析动态数据 private void parseDynamicData(String binaryPayload) { int mmsi = Integer.parseInt(binaryPayload.substring(8, 38), 2); int navigationStatus = Integer.parseInt(binaryPayload.substring(38, 42), 2); float speedOverGround = Integer.parseInt(binaryPayload.substring(50, 60), 2) / 10.0f; int longitude = Integer.parseInt(binaryPayload.substring(61, 89), 2) - 180000000; int latitude = Integer.parseInt(binaryPayload.substring(89, 116), 2) - 90000000; System.out.println("MMSI: " + mmsi); System.out.println("导航状态: " + navigationStatus); System.out.println("对地速度: " + speedOverGround + " 节"); System.out.println("经度: " + (longitude / 600000.0) + " 度"); System.out.println("纬度: " + (latitude / 600000.0) + " 度"); } // 解析静态数据 private void parseStaticData(String binaryPayload) { int mmsi = Integer.parseInt(binaryPayload.substring(8, 38), 2); String vesselName = convertBinaryToString(binaryPayload.substring(112, 232)); int shipType = Integer.parseInt(binaryPayload.substring(232, 240), 2); int dimensionToBow = Integer.parseInt(binaryPayload.substring(240, 249), 2); System.out.println("MMSI: " + mmsi); System.out.println("船名: " + vesselName); System.out.println("船型: " + shipType); System.out.println("船首到船长距离: " + dimensionToBow + " 米"); } // 将二进制字符串转换为ASCII字符串 private String convertBinaryToString(String binary) { StringBuilder text = new StringBuilder(); for (int i = 0; i < binary.length(); i += 6) { String byteString = binary.substring(i, i + 6); int charCode = Integer.parseInt(byteString, 2); if (charCode <= 31) { charCode += 64; } text.append((char) charCode); } return text.toString().trim(); } }