Понижение частоты дискретизации GPS

Моя цель - понизить мои данные на каждые 100 м и получить первую и последнюю строку.

Моя проблема в том, что я получаю намного меньше строк, чем должен, когда я понижаю разрешение, и я не знаю, как получить последнюю строку.

Надеюсь, я достаточно ясен, чтобы кто-то понял

To make this
Line 20130904_0848.nmea
$GPGGA,111936.00,5849.37538,N,01739.88263,,E,2,09,00.9,00004.43,M,0024.87,M,007,0734*42
$GPGGA,111936.00,5849.37548,N,01739.88240,,E,2,09,00.9,00004.43,M,0024.87,M,007,0734*44
$GPGGA,111936.00,5849.37556,N,01739.88216,,E,2,09,00.9,00004.43,M,0024.87,M,007,0734*48
$GPGGA,111936.00,5849.37569,N,01739.88193,,E,2,09,00.9,00004.43,M,0024.87,M,007,0734*4a
$GPGGA,111936.00,5849.37581,N,01739.88171,,E,2,09,00.9,00004.43,M,0024.87,M,007,0734*40
$GPGGA,111936.00,5849.69118,N,01739.89674,,E,2,09,00.9,00004.43,M,0024.87,M,007,0734*4c
EOL 

Line 20130904_0926.nmea
$GPGGA,111936.00,5849.67569,N,01739.98426,,E,2,09,00.9,00004.43,M,0024.87,M,007,0734*45
$GPGGA,111936.00,5849.67593,N,01739.98453,,E,2,09,00.9,00004.43,M,0024.87,M,007,0734*42
$GPGGA,111936.00,5849.67616,N,01739.98479,,E,2,09,00.9,00004.43,M,0024.87,M,007,0734*44
....

Look like this

Line 20081002-1119.nmea
58.853952   13.309779   0.00
58.853907   13.310688   101.15
58.853858   13.311593   100.72
58.853811   13.312498   100.62
58.853764   13.313402   100.59
58.853752   13.313660   28.70

EOL

Line 20081002-1119.nmea
58.853952   13.309779   0.00
58.853907   13.310688   101.15
58.853858   13.311593   100.72
58.853811   13.312498   100.62
58.853764   13.313402   100.59
...

Это мой код до сих пор

from math import sin, cos, sqrt, atan2, radians

coord=[]
coord1=None
def distance(coord1,coord2): #Haversin
    lat1,lon1=coord1
    lat2,lon2=coord2
    dlat = radians(lat2-lat1)
    dlon = radians(lon2-lon1)
    a = sin(dlat/2) * sin(dlat/2)
    + cos(radians(lat1))*cos(radians(lat2))*sin(dlon/2)*sin(dlon/2)
    c = 2 *atan2(sqrt(a),sqrt(1-a))
    s = (6367*c)*1000 #meter
    return s

# with open as data will close itself after reading each line. so you don't need to close it yourself

with open('asko_nav_2013.nmea', 'r') as indata:         #making a indata and outdata, r stands for reading(readcapabilities
    with open('asko_nav_out.txt', 'w') as outdata:      #w stands for write write to a new file(open for writing-you can change things)


        while True:
            line = indata.readline()
            if not line:
                break
            if line.startswith('EOL'):  #if the line starts with EOL(end of line) it writes it in the output
                outdata.writelines("EOL")
                coord1=None
            elif line.startswith('Line'): 
                LineID=line
                outdata.writelines('\n%s' %LineID)
            elif line.startswith('$GPGGA'):  #when the fist line starts with $GPGGA it splits the columns
                data=line.split(",")        #the for loop reads the file line by line



            # Importing only coordinates from asko input file (Row 2 and 4)

                # Converting the coordinates from DDMM.MMMM to DD.DDDDDD
                LAT=(data[2])
                LAT_D=LAT[0:2]               
                LATID=float(LAT_D)

                LAT_M=LAT[2:]
                LATM=float(LAT_M)
                LATIM = float(LATM) / 60.0

                latitude=(LATID + LATIM)                  

                LON=(data[4])
                LON_D=LON[1:3]
                LONGD=float(LON_D)

                LON_M=LON[3:]
                LONM=float(LON_M)
                LONGM = float(LONM) / 60.0

                longitude=(LONGD + LONGM)

                if coord1 is None:

                # The first time through the loop "coord1" is None
                    outdata.writelines('%0.6f\t%0.6f\t%s \n'%(latitude,longitude,0))
                    coord1=(latitude,longitude)
                else:
                    coord2=(latitude,longitude)
                    dist=distance(coord1,coord2)

                    if dist <100:
                        continue
                    outdata.writelines('%0.6f\t%0.6f\t%f\n' % (latitude,longitude,dist))
                    coord1=coord2

person Cecilia Nilsson    schedule 13.11.2015    source источник
comment
Я максимально улучшил отступ и убрал все ваши > в начале строки, как будто вы взяли это из списка рассылки. Не могли бы вы улучшить отступы, потому что вы единственный, кто знает, какие блоки куда принадлежат.   -  person Torxed    schedule 13.11.2015
comment
Думаю, да, я не могу сказать, но выглядит нормально, ваши комментарии, я думаю, с отступом на одну строку слева. Но самая важная часть — это блоки кода, скажем, if: и т. д.   -  person Torxed    schedule 13.11.2015


Ответы (2)


Ваш код можно немного реорганизовать, чтобы сделать его более понятным. Вам нужно добавить дополнительную запись всякий раз, когда отображается EOL для случая, когда расстояние меньше 100 м:

from math import sin, cos, sqrt, atan2, radians    

def distance(coord1, coord2): #Haversin
    lat1,lon1=coord1
    lat2,lon2=coord2
    dlat = radians(lat2-lat1)
    dlon = radians(lon2-lon1)
    a = sin(dlat/2) * sin(dlat/2)
    + cos(radians(lat1))*cos(radians(lat2))*sin(dlon/2)*sin(dlon/2)
    c = 2 *atan2(sqrt(a),sqrt(1-a))
    s = (6367*c)*1000 #meter
    return s

def get_coordinates(data):
    # Importing only coordinates from asko input file (Row 2 and 4)
    # Converting the coordinates from DDMM.MMMM to DD.DDDDDD

    LAT = (data[2])
    LAT_D = LAT[0:2]               
    LATID = float(LAT_D)

    LAT_M = LAT[2:]
    LATM = float(LAT_M)
    LATIM = float(LATM) / 60.0

    latitude = (LATID + LATIM)                  

    LON = (data[4])
    LON_D = LON[1:3]
    LONGD = float(LON_D)

    LON_M = LON[3:]
    LONM = float(LON_M)
    LONGM = float(LONM) / 60.0

    longitude = (LONGD + LONGM)

    return (latitude, longitude)


coord1 = None

# with open as data will close itself after reading each line. so you don't need to close it yourself

with open('asko_nav_2013.nmea', 'r') as indata, open('asko_nav_out.txt', 'w') as outdata:
    for line in indata:
        if line.startswith('EOL'):  #if the line starts with EOL(end of line) it writes it in the output
            if dist < 100:
                outdata.write('%0.6f\t%0.6f\t%f\n' % (latitude, longitude, dist))
            outdata.write("\nEOL\n")
            coord1 = None   # Reset the first coordinate
        elif line.startswith('Line'): 
            outdata.write('\n%s' % line)
        elif line.startswith('$GPGGA'):  #when the fist line starts with $GPGGA it splits the columns
            data=line.split(",")        #the for loop reads the file line by line
            latitude, longitude = get_coordinates(data)

            if coord1:
                coord2 = (latitude, longitude)
                dist = distance(coord1, coord2)

                if dist >= 100:
                    outdata.write('%0.6f\t%0.6f\t%f\n' % (latitude, longitude, dist))
                    coord1 = coord2         
            else:
                # The first time through the loop "coord1" is None
                outdata.write('%0.6f\t%0.6f\t0.0 \n' % (latitude, longitude))
                coord1 = (latitude, longitude)

Для вашего ввода это создает следующий выходной файл:

Line 20130904_0848.nmea
58.822923   17.664710   0.0 
58.828186   17.664946   584.888514

EOL

Line 20130904_0926.nmea
58.827928   17.666404   0.0 
58.827936   17.666413   0.870480

EOL

Вам также необходимо сбросить coord1 всякий раз, когда обнаруживается EOL, чтобы убедиться, что 0 снова отображается для первой записи.

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

person Martin Evans    schedule 13.11.2015
comment
Спасибо за реорганизацию, она очень нужна :D Расстояния должны быть около 100 м, кроме первой и последней. Первый должен быть 0 (это так), а последний должен быть только последним в строке. что мне нужна помощь, чтобы получить - person Cecilia Nilsson; 13.11.2015
comment
Каков ожидаемый результат для строки 20130904_0848.nmea? - person Martin Evans; 13.11.2015
comment
Я получаю последнюю известную линию и каждые 100 м - спасибо ‹ 3, но я добираюсь до нескольких, каждые 100 м должны давать намного больше, чем на самом деле. - person Cecilia Nilsson; 13.11.2015
comment
Может быть проблема с вашей функцией расстояния, я не проверял логику этого. - person Martin Evans; 13.11.2015
comment
Может быть? но я не могу найти другой способ сделать это :/ - person Cecilia Nilsson; 13.11.2015

Решение второй проблемы, связанной с меньшим количеством строк результатов, чем ожидалось: вы предоставляете слишком мало информации о характере вашей проблемы и входных данных, которые вы обрабатываете. Выборка вашего ввода «каждые 100 м» может означать что-то другое, если ваши входные данные отбираются из траектории, по которой движется движущийся объект, особенно если движение не является чисто линейным.

Представьте, что ваши входные данные описывают координаты, полученные путем измерения GPS-координат через равные промежутки времени при движении по окружности с радиусом меньше, скажем, 15 м. Тогда независимо от того, сколько точек данных предоставляет ваш ввод, вывод для предлагаемого вами решения никогда не будет длиннее двух строк, потому что никакие две точки вдоль этой кривой не могут иметь абсолютное расстояние более 100 м. Это может объяснить, почему вы видите меньше строк в выводе, чем ожидалось.

Если вы хотите сэмплировать входные данные через каждые 100 м пройденного, вам придется суммировать все расстояния между входными семплами, начиная с последней точки, выбранной для выходных данных, и использовать это вместо dist. Модифицируя реорганизованный код Мартина, это можно было бы сделать так (некоторые строки для краткости опущены):

coord1 = None
coord_last = None  # holds coordinate of last input sample
dist = 0.0         # total distance travelled since coord1
# [...]
with open('asko_nav_2013.nmea', 'r') as indata, open('asko_nav_out.txt', 'w') as outdata:
    for line in indata:
    # [...]
            if coord1:
                coord2 = (latitude, longitude)
                delta = distance(coord_last, coord2)
                dist += delta
                coord_last = coord2

                if dist >= 100:
                    outdata.write('%0.6f\t%0.6f\t%f\n' % (latitude, longitude, dist))
                    coord1 = coord2
                    dist = 0.0
            else:
                # The first time through the loop "coord1" is None
                outdata.write('%0.6f\t%0.6f\t0.0 \n' % (latitude, longitude))
                coord1 = (latitude, longitude)
                coord_last = coord1
                dist = 0.0
person omahdi    schedule 13.11.2015
comment
Теперь данных немного больше, но не так много, как я надеялся, но все же больше, чем раньше, так что большое спасибо :D - person Cecilia Nilsson; 13.11.2015
comment
Не могли бы вы немного пояснить, почему, по вашему мнению, в выходных данных должно быть больше точек данных? Было бы очень полезно, если бы вы предоставили более конкретную информацию о том, как ваши данные были получены (движущееся транспортное средство?), почему вы намерены уменьшить количество выборок (визуализация?) и по какой метрике вы определяете размер вывода как удовлетворительный. - person omahdi; 14.11.2015
comment
Да, конечно! Это с лодки, которая составляла карту морского дна. Данные должны использоваться в QGIS для создания карты :) понижение частоты дискретизации сделано, потому что имеется около 70 000 строк данных, поэтому 200, которые я получаю после понижения частоты дискретизации, немного меньше - person Cecilia Nilsson; 14.11.2015
comment
Спасибо, что прояснили это. Тогда вас в первую очередь не интересуют временные ряды, и в этом случае вам следует игнорировать мое предложение выше. Вы, вероятно, захотите изучить что-то вроде передискретизации данных с неравномерным интервалом в обычную сетку в Python. Я полагаю, что в QGIS тоже есть фильтры передискретизации. Просто выбрасывать измерения кажется пустой тратой времени, особенно. если вы не знаете, следовала ли лодка по обычной траектории поиска (может помочь визуализировать это!) - person omahdi; 17.11.2015