Metadata-Version: 2.1
Name: rfpye
Version: 0.0.5
Summary: Binary Files Parser resulted from the script Logger from CFRS - Rfeye Node Equipament
Home-page: https://github.com/ronaldokun/rfpy/tree/master/
Author: Ronaldo Batista
Author-email: ronaldokun@gmail.com
License: Apache Software License 2.0
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 <a href='https://fastcore.fast.ai/basics.html'>fastcore</a>, que expande e otimiza as estruturas de dados da linguagem python. 
        
        
        ```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.
        
        ```python
        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` 
        
        ```python
        #show_doc(get_files)
        ```
        
        ```python
        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
        
        ```python
        arquivos_bin = get_files(entrada, extensions=['.bin'], folders='tmp') ; arquivos_bin
        ```
        
        Nesse caso dentro da pasta 'tmp' há somente 1 arquivo `.bin`
        
        ```python
        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.
        
        ```python
        %%time
        map_bin = parse_bin(bin_file)
        ```
        
        ```python
        block.keys()
        ```
        
        Exceto o primeiro bloco, que é simplesmente ignorado, os demais blocos são conhecidos e tratados individualmente.
        
        ```python
        block[63]
        ```
        
        ```python
        block[40]
        ```
        
        Temos nesse arquivo 6605 blocos do tipo 63 - Bloco contendo dados de espectro.
        
        ```python
        bloco = block[63][0]
        ```
        
        ```python
        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 `.`
        
        ```python
        bloco.data_points
        ```
        
        ```python
        bloco.start_mega
        ```
        
        ```python
        bloco.stop_mega
        ```
        
        ```python
        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` 
        
        ```python
        for freq, nível in bloco:
            print(freq, nível)
            break
        ```
        
        Podemos iterar as medidas num loop
        
        ```python
        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.
        
        ```python
        %%time
        meta = export_bin_meta(block)
        meta.tail(10)
        ```
        
        ```python
        meta.info()
        ```
        
        Os metadados de um arquivo `.bin` de cerca de `100MB` ocupa somente `226KB`
        
        ```python
        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)
        
        ```python
        block[24].attrgot('thread_id')
        ```
        
        ```python
        %%time
        levels = export_bin_level(block) ; levels.head()
        ```
        
        ```python
        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
        
        ```python
        dtypes = {'Block_Number': 'int32', 'Frequency(MHz)': 'float64', 'Nivel(dBm)': 'float64'}
        ```
        
        ```python
        %%time
        levels = export_bin_level(block, pivoted=False, dtypes=dtypes) ; levels.head()
        ```
        
        ```python
        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`
        
        ```python
        dtypes = {'Block_Number': 'int16', 'Frequency(MHz)': 'float32', 'Nivel(dBm)': 'float32'}
        ```
        
        ```python
        %%time
        levels = export_bin_level(block, pivoted=False, dtypes=dtypes) ; levels.head()
        ```
        
        ```python
        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.
        
        ```python
        dtypes = {'Block_Number': 'int16', 'Frequency(MHz)': 'category', 'Nivel(dBm)': 'float16'}
        ```
        
        ```python
        %%time
        levels = export_bin_level(block, pivoted=False, dtypes=dtypes) ; levels.head()
        ```
        
        ```python
        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.
        
        ```python
        %%time
        levels.to_feather(saida / 'file_b.fth')
        ```
        
Keywords: spectrum monitoring
Platform: UNKNOWN
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Natural Language :: Portuguese
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Requires-Python: >=3.6
Description-Content-Type: text/markdown
