R二进制/十进制转换混乱-AIS数据
R binary / decimal conversion confusion - AIS data
我正在使用 AIS(自动识别系统)数据来定位船只。我能够关注 this guide to decode almost all the bit of information successfully (when compared to online decoding done here)。
但是,我 运行 遇到了经度部分的问题。我 认为 它与小数值为负有关,但我无法弄清楚要在我的代码中更改什么才能使其正确。
TLDR 版本:如何从二进制字符串 1101001000001001001110010000 得到十进制值 -48196720(或 48196720)?
完整版:
玩具数据:
library(dplyr)
library(tidyr)
library(stringr)
# choose an example - two strings are provided.
# The first string shows the issue with the longitude,
# whereas the second string (where longitude is positive) has no issue
s <- "15E3tB001;J@BLPaK5j7qFA406;d"
# s <- "133m@ogP00PD;88MD5MTDww@2D7k"
### for input into the online decoder - use these:
# !AIVDM,1,1,,A,14eG;o@034o8sd<L9i:a;WF>062D,0*7D
# !AIVDM,1,1,,A,133m@ogP00PD;88MD5MTDww@2D7k,0*46
temp <- data.frame(V6 = s) %>%
# splitting the AIS info into separate characters
mutate(char_split = str_split(V6,pattern=""))
temp$Text <- apply(temp, 1, function(x) paste(unlist(x$char_split), collapse = ","))
temp <- temp %>%
select(-char_split) %>%
# and then into separate columns
separate(Text, into = paste0("v", 1:43, sep = ""), sep = ",", fill = "right")
ASCII <- temp %>%
select(v1:v43)
# translating to ASCII
ASCII <- apply(ASCII, c(1, 2), function(x) utf8ToInt(x))
# translating to 6-bit
ASCII <- apply(ASCII, c(1, 2), function(x) ifelse(x <= 88, x - 48, x - 48 - 8))
一旦数据为 ASCII,需要转换为二进制
# making binary
Binary <- apply(ASCII, c(1, 2), function(x){ paste(rev(as.integer(intToBits(x))[1:6]), collapse = "")})
# pasting all the binary info into a single string
temp$Binary <- apply(Binary, 1, function(x) paste(x, collapse = "" ))
temp <- temp %>%
select(V6, Binary) %>%
# selecting bits of the single binary string,
#and translating back to decimal, as per the guide
mutate(MMSI = strtoi(substr(Binary, 9, 38), base = 2),
SOG = strtoi(substr(Binary, 50, 60), base = 2)/10,
Accuracy = strtoi(substr(Binary, 61, 61), base = 2),
Lon = strtoi(substr(Binary, 62, 89), base = 2)/600000,
Lat = strtoi(substr(Binary, 90, 116), base = 2)/600000,
COG = strtoi(substr(Binary, 117, 128), base = 2)/10,
Heading = strtoi(substr(Binary, 129, 137), base = 2))
输出:
select(temp, -Binary, -V6)
当我与在线解码器进行比较时,除经度外,一切都匹配。在解码器中,结果是 80.3278667(尽管它实际上是 -80.3278667),而我的是 367.0646。试图对此进行逆向工程,我查看了 temp$Binary
:
的相关子字符串
mine <- substr(temp$Binary, 62, 89)
RevEng <- -80.3278667 * 600000
binaryLogic:::as.binary(as.integer(RevEng), signed = FALSE)
mine
所以看起来 RevEng 值与我的二进制字符串的右端尾部匹配,但我无法弄清楚为什么它与完整的二进制字符串不匹配,或者从这里开始做什么...
与博客 [=23=] 告诉您的相反,经度是一个 有符号 整数。但是,它仅使用 28 位,而 R 在内部使用 32 位。因此,您必须自己处理 two's compliment conversion。对于设置了最高位的任何数字,您必须减去 2^28
,例如:
mine <- "1101001000001001001110010000"
strtoi(mine, base = 2) - 2^28
#> [1] -48196720
您可以在二进制字符串上使用 substr
或通过查找数字 >= 2^27
.
来识别这些数字
顺便说一句,这同样适用于纬度,只是它只使用 27 位。
我正在使用 AIS(自动识别系统)数据来定位船只。我能够关注 this guide to decode almost all the bit of information successfully (when compared to online decoding done here)。
但是,我 运行 遇到了经度部分的问题。我 认为 它与小数值为负有关,但我无法弄清楚要在我的代码中更改什么才能使其正确。
TLDR 版本:如何从二进制字符串 1101001000001001001110010000 得到十进制值 -48196720(或 48196720)?
完整版:
玩具数据:
library(dplyr)
library(tidyr)
library(stringr)
# choose an example - two strings are provided.
# The first string shows the issue with the longitude,
# whereas the second string (where longitude is positive) has no issue
s <- "15E3tB001;J@BLPaK5j7qFA406;d"
# s <- "133m@ogP00PD;88MD5MTDww@2D7k"
### for input into the online decoder - use these:
# !AIVDM,1,1,,A,14eG;o@034o8sd<L9i:a;WF>062D,0*7D
# !AIVDM,1,1,,A,133m@ogP00PD;88MD5MTDww@2D7k,0*46
temp <- data.frame(V6 = s) %>%
# splitting the AIS info into separate characters
mutate(char_split = str_split(V6,pattern=""))
temp$Text <- apply(temp, 1, function(x) paste(unlist(x$char_split), collapse = ","))
temp <- temp %>%
select(-char_split) %>%
# and then into separate columns
separate(Text, into = paste0("v", 1:43, sep = ""), sep = ",", fill = "right")
ASCII <- temp %>%
select(v1:v43)
# translating to ASCII
ASCII <- apply(ASCII, c(1, 2), function(x) utf8ToInt(x))
# translating to 6-bit
ASCII <- apply(ASCII, c(1, 2), function(x) ifelse(x <= 88, x - 48, x - 48 - 8))
一旦数据为 ASCII,需要转换为二进制
# making binary
Binary <- apply(ASCII, c(1, 2), function(x){ paste(rev(as.integer(intToBits(x))[1:6]), collapse = "")})
# pasting all the binary info into a single string
temp$Binary <- apply(Binary, 1, function(x) paste(x, collapse = "" ))
temp <- temp %>%
select(V6, Binary) %>%
# selecting bits of the single binary string,
#and translating back to decimal, as per the guide
mutate(MMSI = strtoi(substr(Binary, 9, 38), base = 2),
SOG = strtoi(substr(Binary, 50, 60), base = 2)/10,
Accuracy = strtoi(substr(Binary, 61, 61), base = 2),
Lon = strtoi(substr(Binary, 62, 89), base = 2)/600000,
Lat = strtoi(substr(Binary, 90, 116), base = 2)/600000,
COG = strtoi(substr(Binary, 117, 128), base = 2)/10,
Heading = strtoi(substr(Binary, 129, 137), base = 2))
输出:
select(temp, -Binary, -V6)
当我与在线解码器进行比较时,除经度外,一切都匹配。在解码器中,结果是 80.3278667(尽管它实际上是 -80.3278667),而我的是 367.0646。试图对此进行逆向工程,我查看了 temp$Binary
:
mine <- substr(temp$Binary, 62, 89)
RevEng <- -80.3278667 * 600000
binaryLogic:::as.binary(as.integer(RevEng), signed = FALSE)
mine
所以看起来 RevEng 值与我的二进制字符串的右端尾部匹配,但我无法弄清楚为什么它与完整的二进制字符串不匹配,或者从这里开始做什么...
与博客 [=23=] 告诉您的相反,经度是一个 有符号 整数。但是,它仅使用 28 位,而 R 在内部使用 32 位。因此,您必须自己处理 two's compliment conversion。对于设置了最高位的任何数字,您必须减去 2^28
,例如:
mine <- "1101001000001001001110010000"
strtoi(mine, base = 2) - 2^28
#> [1] -48196720
您可以在二进制字符串上使用 substr
或通过查找数字 >= 2^27
.
顺便说一句,这同样适用于纬度,只是它只使用 27 位。