Время прочтения: 6 мин.

Используемые определения

Мобильная связь – вид телекоммуникаций, при котором голосовая, текстовая и графическая информация передается на абонентские беспроводные терминалы, не привязанные к определенному месту или территории.

GSM — глобальный стандарт цифровой мобильной сотовой связи с разделением каналов по времени и частоте.

Радиосвязь — способ передачи сообщений на расстояние посредством радиоволн.

СТС – служебное транспортное средство.

Основной и единственный источник данных – выгрузка из автоматизированной системы TRBOnet по событиям СТС, в которой отражены все события по автомобилю, время и координаты регистрации.

Описание алгоритма

Поиск зон, где периодически пропадает связь с СТС по общему списку событий автомобиля – задача не в одно действие. Требуется целая цепочка шагов для достижения цели.

В результате разбора проблемы был составлен алгоритм, позволяющий добиться нужного результата:

  1. Из списка всех событий с СТС на маршруте выделение событий потери и восстановления GSM и радиосвязи.
  2. Определение промежутков, когда не было ни GSM, ни радиосвязи.
  3. Визуализация на карте зон, в которых зафиксированы проблемы со связью с СТС.

Выделение событий

Первым шагом, при анализе информации из выгрузки, необходимо структурировать имеющуюся информацию, а именно:

  • Отсортировать события по времени регистрации;
  • Удалить повторяющиеся сообщения;
  • Разделить данные в разрезе СТС.

Далее нужно выделить связанные события потери и восстановления GSM и радиосвязи.

Ввиду обработки большого объема информации анализ событий проводился с использованием скриптов, разработанных на языке Python.

import pandas as pd
import glob
import datetime as dt

bb = ['AB','BC','CD']
hh = pd.DataFrame(columns = ['B','СТС', 'KOORDS'])
for b in bb:
    print(b)
    gg = pd.DataFrame()       
    for f in glob.glob(r'Path\*' + b + '*.xlsx'):
        print(f)
        gg = gg.append(pd.read_excel(f))
        
    gg = gg.drop_duplicates().reset_index(drop=True)       
    gg = gg.sort_values(['Дата/Время']).reset_index(drop= True)   
    aa = list(set(gg['СТС'].tolist()))
    print(len(aa))
    al = 0
    for a in aa: # Деление событий в разрезе СТС
        al = 0
        temp = gg[gg['СТС'] == a]
        temp = temp.sort_values('Дата/Время').reset_index(drop=True)
        al1 = rad1 = gsm1 = '' # Переменные для сохранения времени потери связи
        rad_k = gsm_k = '' # Переменные для сохранения координат потери связи
        rad = [] # Список пар событий по потере и восстановлению радиосвязи
        gsm = [] # Список пар событий по потере и восстановлению связи GSM
        mar = False # Переменная для отслеживания состояния текущего маршрута

        for i in range(len(temp)):
            if mar:
                if temp['Наименование события'][i] == 'Потеря РАДИО-связи': 
                    rad1 = temp['Дата/Время'][i]
                    rad_k = (temp['Долгота'][i],temp['Широта'][i])
                if temp['Наименование события'][i] == 'Потеря GSM-связи': 
                    gsm1 = temp['Дата/Время'][i]
                    gsm_k = (temp['Долгота'][i],temp['Широта'][i])
                if temp['Наименование события'][i] == 'Восстановление РАДИО-связи': 
                    if rad1 != '':
                        rad.append([rad1,temp['Дата/Время'][i],rad_k,(temp['Долгота'][i],temp['Широта'][i])])
                    rad1 = ''
                    rad_k=''
                if temp['Наименование события'][i] == 'Восстановление GSM-связи': 
                    if gsm1 == '':
                        pass
                    else:
                        gsm.append([gsm1,temp['Дата/Время'][i],gsm_k,(temp['Долгота'][i],temp['Широта'][i])])                        
                    gsm1 = ''
                    gsm_k = ''
                if temp['Наименование события'][i] == 'Завершение маршрута':
                    mar = False
                    if al1 == '':
                        pass
                    else:
                        al = al + (temp['Дата/Время'][i] - al1).seconds
                    al1 = rad1 = gsm1 = rad_k = gsm_k = ''
            else:
                if temp['Наименование события'][i] == 'Старт маршрута' or\
                temp['Наименование события'][i] == 'Назначение СТС на маршрут':
                    mar = True
                    al1 = temp['Дата/Время'][i]
                    al1 = rad1 = gsm1 = rad_k = gsm_k = ''

Выделение периодов полного отсутствия связи

Оборудование для поддержания GSM и радиосвязи в СТС работает независимо друг от друга, вследствие чего и возникновение проблем со связью происходит в разные промежутки времени. Для нахождения периодов полной потери связи с СТС требуется найти все пересечения временных отрезков отсутствия GSM и радиосвязи.

Рис. 1 Взаимное размещение отрезков на прямой

Скрипт для поиска периодов потери связи с СТС:

koord = []
for i in rad:
    for j in gsm: # 
        if i[1] <= j[0]: 
            pass
        else:
            if i[1] <= j[1]:
                if i[0] < j[0]:
                    koord.append([j[2],i[3]])
                else:
                    koord.append([i[2],i[3]])
            else:
                if i[0] >= j[1]:
                    pass
                else:
                    if i[0] >=  j[0]:
                        koord.append([i[2],j[3]])
                    else:
                        koord.append([j[2],j[3]])
        hh = hh.append({'СТС':a,
                        'B':b,
                        'KOORDS':koord},ignore_index=True)

Визуализация отрезков и областей

В качестве инструмента визуализации рассматривались три варианта: Plotly, Folium и Bokeh. Сравнив доступность, простоту и мощность этих библиотек, мой выбор пал на Plotly. Этот инструмент позволяет легко отрисовать карту России и все необходимые объекты – нужные нам отрезки и области.

Скрипт для визуализации:

import numpy as np
import pandas as pd
import random
import plotly
import plotly.graph_objs as go
import plotly.express as px
from plotly.subplots import make_subplots
df = pd.read_excel(r'File.xlsx')
fig = go.Figure(go.Scattermapbox(showlegend=False))
a = []
for i in range(len(df)):
    # Получение пар коорднат (x,y), где была потеряна и восстановлена связь с СТС        
    bb = df['KOORDS'][i].split('(')
    for b in range(1,len(bb)):
        bb[b] = bb[b].split(')')[0]
        bb[b] = bb[b].replace("'","")
        a.append(bb[b].split(', '))
    
for c in range(len(a)):     
    # Добавление на карту отрезков, в которых связь с СТС отсутствовала   
    if c%2==0:
        fig.add_trace(go.Scattermapbox(mode = "markers+lines",
                                       name='1',  
                                       showlegend=True,
                                       lat=[a[c+1][1],a[c][1]],
                                       lon=[a[c+1][0],a[c][0]],
                                       text=list(zip('1','1')),
                                       marker = {'size': 1,'color':'red'}))
        map_center = go.layout.mapbox.Center(lat=56.322075, lon=44.009966)
        fig.update_layout(mapbox_style="carto-positron", mapbox=dict(center=map_center, zoom=2))

В результате выполнения скрипта на карте отображены красные отрезки – участки пути, где пропадала связь с СТС. Области на карте с большим количеством этих отрезков – зоны с частыми проблемами со связью.

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

Требуется разделить список объектов, которые отображаются одновременно. Самое простое решение – разделить исходный файл построчно, но этот вариант не учитывает координаты события, а значит — не подходит.

Для решения этой задачи предложен свой вариант алгоритма:

  1. Определить границы рассматриваемой области путем выявления крайних точек на севере, юге, западе и востоке.
  2. Разбить получившуюся прямоугольную область на несколько зон поменьше. Размер и количество этих зон зависит от величины исходной области и количества отрезков, которые нужно визуализировать.
  3. Для каждой зоны отрисовать все отрезки, которые хотя бы одним концом находятся внутри этой зоны.

Таким образом уменьшается число объектов, единовременно отображенных на карте, но не теряется ни один участок с потерей связи.

Рис. 2 Пример визуализации событий потери связи

Рис. 3 Пример визуализации области с периодическими проблемами связи

Заключение

Мне удалось визуализировать все периоды отсутствия связи с СТС и зафиксировать области, где факты потери связи происходят периодически.

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

Желаю вам всегда оставаться на связи!!!