Binary Files Parser resulted from the script Logger from CFRS - Rfeye Node Equipament
Project description
RFPY
Este módulo tem como objetivo o processamento e extração otimizada de dados dos arquivos
.bin
de monitoramento do espectro provenientes do script Logger executados nas estações de Monitoramento CRFS RFeye Node. Para tal utilizamos as várias funcionalidades da biblioteca fastcore, que expande e otimiza as estruturas de dados da linguagem python.
import warnings
with warnings.catch_warnings():
warnings.simplefilter("ignore")
from pprint import pprint
import rfpy
from rfpy.parser import *
from fastcore.xtras import Path
Instalação
pip install rfpy
Como utilizar
Abaixo mostramos as funcionalidades principais dos módulos, utilizando-os dentro de algum outro script ou REPL
Precisamos necessariamente de um diretório de entrada, contendo um ou mais arquivos .bin
e um diretório de saída no qual iremos salvar os arquivos processados.
Mude os caminhos abaixo para suas pastas locais caso for executar o exemplo.
Ao utilizar o script process_bin
, as pastas entrada
e saída
esses serão repassadas como parâmetros na linha de comando.
VERBOSE = True
entrada = Path(r'D:\OneDrive - ANATEL\Backup_Rfeye_SP\RPO\PMEC2020\Ribeirao_Preto_SP\SLMA')
saida = Path(r'C:\Users\rsilva\Downloads\saida')
Leitura de Arquivos
No módulo parser.py
, há funções auxiliares para lidar com os arquivos .bin
, pastas e para processar tais arquivos em formatos úteis. Nesse caso utilizaremos a função get_files
que busca de maneira recursiva arquivos de dada extensão, inclusive links simbólicos se existirem
O caráter recursivo e a busca em links, recurse
e followlinks
simbólicos pode ser desativados por meio dos parâmetros e opcionalmente pode ser varrido somente o conjunto de pastas indicado em folders
#show_doc(get_files)
arquivos = get_files(entrada, extensions=['.bin']) ; arquivos
O Objeto retornado
L
é uma extensão da lista python com funcionalidades adicionais, uma delas como podemos ver é que a representação da lista impressa mostra o comprimento da lista. Esse objeto pode ser usado de maneira idêntica à uma lista em python e sem substituição desta.
Temos 255 arquivos bin na pasta entrada. Podemos filtrar por pasta também
arquivos_bin = get_files(entrada, extensions=['.bin'], folders='tmp') ; arquivos_bin
Nesse caso dentro da pasta 'tmp' há somente 1 arquivo .bin
bin_file = arquivos_bin[0] ; bin_file.name
Processamento dos blocos
A função seguinte parse_bin
recebe um arquivo .bin
e mapeia os blocos contidos nele retornando um dicionário que tem como chave o tipo de bloco e os valores como uma lista com os blocos extraídos sequencialmente.
%%time
map_bin = parse_bin(bin_file)
block.keys()
Exceto o primeiro bloco, que é simplesmente ignorado, os demais blocos são conhecidos e tratados individualmente.
block[63]
block[40]
Temos nesse arquivo 6605 blocos do tipo 63 - Bloco contendo dados de espectro.
bloco = block[63][0]
pprint([d for d in dir(bloco) if not d.startswith('_')])
Esses são os atributos do Bloco de Espectro acima do tipo 63. Todos podem ser acessados por meio da notação .
bloco.data_points
bloco.start_mega
bloco.stop_mega
bloco.level_offset
O bloco se comporta como um objeto python do tipo lista.
Podemos selecionar items da lista, é retornado uma tupla com a frequência em MHz
e o nível medido em dBm / dBuV/m
for freq, nível in bloco:
print(freq, nível)
break
Podemos iterar as medidas num loop
len(bloco)
Esse é o mesmo valor do atributo data_points
Metadados
A função seguinte extrai os metadados META
definidos no cabeçalho do arquivo parser.py
e retorna um DataFrame.
%%time
meta = export_bin_meta(block)
meta.tail(10)
meta.info()
Os metadados de um arquivo .bin
de cerca de 100MB
ocupa somente 226KB
meta.to_feather(saida / 'file_a.fth')
Frequência e Nível
A função seguinte extrai as frequências e nível num formato de Tabela Dinâmica:
- Colunas: Frequências (MHz)
- Índice: Números de Bloco
- Valores: Níveis (dBm ou dBuV/m)
block[24].attrgot('thread_id')
%%time
levels = export_bin_level(block) ; levels.head()
levels.info()
Essa matriz com mais de 98 milhões de valores ocupa somente 187.1MB
de memória
Caso o parâmetro pivoted = False
é retornada a versão tabular empilhada. No entanto o processamento é mais lento tendo em vista a redundância de dados que é adicionada.
Os tipos de dados a seguir são os automaticamente retornados pelo numpy
/ pandas
no momento de criação da matriz
dtypes = {'Block_Number': 'int32', 'Frequency(MHz)': 'float64', 'Nivel(dBm)': 'float64'}
%%time
levels = export_bin_level(block, pivoted=False, dtypes=dtypes) ; levels.head()
levels.info()
Esse formato de dados é extremamente redundante, repete-se o conjunto de blocos e frequências a cada bloco existente, por isso ocupa 1.8GB
de memória.
O número de bloco pode ser perfeitamente armazenado como um int16
, a frequência como um float32
e os níveis, dado termos somente 1 casa decimal, podem ser armazenados como float16
dtypes = {'Block_Number': 'int16', 'Frequency(MHz)': 'float32', 'Nivel(dBm)': 'float32'}
%%time
levels = export_bin_level(block, pivoted=False, dtypes=dtypes) ; levels.head()
levels.info()
Reduzimos de 1.8GB
para 748.2MB
sem perda de informação.
No entanto, como não vamos fazer cálculos com essa matriz, somente extraí-la e armazená-la no momento, podemos manipular e salvar os valores em float32
como category
do pandas que ocupa o mesmo espaço próximo de um int16
nesse caso, isso irá economizar bastante espaço tendo em vista o número fixo de frequências.
dtypes = {'Block_Number': 'int16', 'Frequency(MHz)': 'category', 'Nivel(dBm)': 'float16'}
%%time
levels = export_bin_level(block, pivoted=False, dtypes=dtypes) ; levels.head()
levels.info()
Reduzimos assim de 1.8GB
para 561.9MB
sem perda de informação nos dados. Qualquer redução adicional implica numa transformação dos dados ou perda de precisão.
%%time
levels.to_feather(saida / 'file_b.fth')
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for rfpye-0.0.5-cp37-cp37m-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 887d9ab2795d4f6bf476f260206c49deda0c09b62167d42c84a966180007f653 |
|
MD5 | 5aa6309a0b938618b9a185ed0dc16815 |
|
BLAKE2b-256 | 8c9956ffdb366a9d022733adbc666ea180f078c431b67af8e8d120680fdfdccf |