【问题标题】:R binary / decimal conversion confusion - AIS dataR 二进制/十进制转换混淆 - AIS 数据
【发布时间】:2018-09-12 15:42:11
【问题描述】:

我正在使用 AIS(自动识别系统)数据来定位船只。我能够按照this guide 成功解码几乎所有信息位(与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 值与我的二进制字符串的右尾匹配,但我无法弄清楚为什么它与完整的二进制字符串不匹配,或者从这里做什么......

【问题讨论】:

    标签: r binary ais


    【解决方案1】:

    与博文所说的相反,经度是一个有符号整数。但是,它仅使用 28 位,而 R 在内部使用 32 位。因此,您必须自己处理two's compliment conversion。对于设置了最高位的任何数字,您必须减去2^28,例如:

    mine <- "1101001000001001001110010000"
    strtoi(mine, base = 2) - 2^28
    #> [1] -48196720
    

    您可以使用二进制字符串上的substr 或通过查找数字&gt;= 2^27 来识别这些数字。

    顺便说一句,这同样适用于纬度,但修改后它只使用 27 位。

    【讨论】:

    • @user2602640 for latitutude &gt;= 2^26 你必须减去 2^27
    • 非常感谢您的详细解释......对于后代 - 代码 + 解决方案运行良好,但 - 1)仅适用于 AIS 消息类型 1 和 3(例如,类型 18 有不同的位置二进制字符串中的信息)。和 2) 解码 SOG 字段似乎存在问题 - 在线解码器偶尔会显示与此处的输出不同的值...
    猜你喜欢
    • 1970-01-01
    • 2020-06-11
    • 2019-05-06
    • 2018-12-24
    • 1970-01-01
    • 2021-07-29
    • 2023-04-11
    • 2012-06-26
    • 2011-10-11
    相关资源
    最近更新 更多