R двоичное / десятичное преобразование путаница - данные AIS - PullRequest
0 голосов
/ 12 сентября 2018

Я работаю с данными АИС (автоматической системы идентификации) для определения местоположения судов. Я смог выполнить это руководство , чтобы успешно декодировать почти весь бит информации (по сравнению с онлайн-декодированием, выполненным здесь ).

Однако у меня возникла проблема с частью долготы. Я думаю , что это связано с тем, что десятичное значение отрицательно, но я не могу понять, что нужно изменить в моем коде, чтобы сделать его правильным.

Версия 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 соответствует правому концу моей двоичной строки, но я не могу понять, почему оно не соответствует полной двоичной строке или что делать отсюда ...

1 Ответ

0 голосов
/ 12 сентября 2018

Вопреки тому, что говорится в сообщении в блоге, долгота - это целое число со знаком .Однако он использует только 28 бит, в то время как R использует 32 бита внутри.Поэтому вы должны справиться с конверсией комплимента себе.Для любого числа с установленным старшим битом необходимо вычесть 2^28, например:

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

. Вы можете идентифицировать эти числа либо с substr в двоичной строке, либо путем поиска чисел >= 2^27.

Кстати, то же самое относится к широте с модификацией, в которой используются только 27 битов.

...