Aula 01 - Algoritmos, Representação e Estrutura Básica de Programas em Python
Navegação Rápida
📍 Disciplina: 01 Lógica de Programação | 🗺️ Área: 06 Computação e Telecomunicações | 🏠 Hub Principal
Metadados da Aula
- Área: 06 Computação e Telecomunicações
- Carga Horária Equivalente: 4 horas-aula teóricas e práticas
- Pré-requisitos: Nenhum (Fundamento Formativo Inicial de Computação)
- Palavras-chave: Algoritmos, Critérios de Knuth, Arquitetura de Von Neumann, Gargalo de Barramento, CPython, AST, Bytecode, Máquina Virtual Baseada em Pilha, PEP 8, Coletor de Lixo
📌 Sumário da Aula
- 🧭 1. Contextualização e Objetivos de Aprendizagem
- 📋 2. Sumário Executivo dos Tópicos
- ⚡ 3. Fundamentação Teórica e Modelagem Matemática
- 🖼️ 4. Diagrama Arquitetural Integrado
- 💻 5. Implementação Prática em Engenharia Elétrica
- 📝 6. Banco de Questões de Fixação e Concursos Auditados
- 📚 7. Referências Bibliográficas e Normas Técnicas
🧭 1. Contextualização e Objetivos de Aprendizagem
A engenharia moderna assenta-se sobre a capacidade de modelar fenômenos físicos contínuos e traduzi-los em procedimentos lógicos discretos executáveis por máquinas digitais. Da simulação de transitórios eletromagnéticos ao despacho ótimo de usinas hidrelétricas e eólicas, a programação computacional deixou de ser uma ferramenta de suporte para tornar-se a espinha dorsal da análise de sistemas de potência, instrumentação eletrônica e telecomunicações.
Esta aula inaugural estabelece as bases conceituais rigorosas da ciência da computação aplicadas à Engenharia Elétrica. Analisa o conceito formal de algoritmo sob os critérios clássicos de Donald Knuth, disseca a arquitetura física de Von Neumann e seus limites termodinâmicos e de barramento, compara as abordagens de representação algorítmica e aprofunda o modelo interno de funcionamento do interpretador de referência do ecossistema Python moderno (CPython 3).
Ao término desta aula, o engenheiro será capaz de:
- Definir e validar formalmente um algoritmo com base nos 5 critérios fundamentais de Knuth (Finitude, Definição, Entradas, Saídas e Efetividade).
- Analisar quantitativamente o impacto do gargalo de Von Neumann na taxa de transferência de dados (bandwidth) entre CPU e memória primária em sistemas de aquisição em tempo real.
- Modelar processos decisórios de proteção e controle utilizando a simbologia gráfica normatizada ANSI/ISO.
- Compreender a anatomia interna do CPython, distinguindo as etapas de análise léxica, geração de Árvore Sintática Abstrata (AST), compilação para bytecode (
.pyc) e avaliação na máquina virtual baseada em pilha (PVM). - Escrever programas em Python 3 estritamente aderentes às normas técnicas do guia de estilo PEP 8.
📋 2. Sumário Executivo dos Tópicos
- Conceito de Algoritmo: Conjunto finito e ordenado de instruções não ambíguas que transformam dados de entrada em resultados computáveis em tempo finito.
- Critérios de Knuth: Finitude (), Definição (ausência de ambiguidade semântica), Entradas (), Saídas () e Efetividade (passos realizáveis em papel por um operador humano).
- Modelo de Von Neumann: CPU integrada (UC, ULA e Registradores rápidos), barramentos compartilhados de dados e instruções, memória RAM linearmente endereçada e subsistema de E/S.
- Gargalo de Von Neumann: Assimetria de velocidade: enquanto a CPU opera em GHz ( por ciclo), o acesso à DRAM consome dezenas de nanossegundos (), limitando o throughput global pela largura do barramento .
- CPython 3 Virtual Machine: Modelo híbrido interpretado/compilado. O código-fonte
.pyé convertido em bytecode armazenado em cache (__pycache__/*.pyc) e avaliado pela máquina virtual baseada em pilha (ceval.c). - Gerenciamento de Memória: Alocação dinâmica de objetos em Heap baseada em contagem de referências (Reference Counting) assistida por coletor de lixo cíclico (Generational GC).
⚡ 3. Fundamentação Teórica e Modelagem Matemática
3.1 Formalismo Matemático de Algoritmos e Critérios de Knuth
Em ciência da computação e matemática discreta, um algoritmo é formalmente definido como uma tupla:
Onde:
- é o conjunto de possíveis estados de entrada (Inputs);
- é o conjunto de possíveis estados de saída (Outputs);
- é o conjunto de estados internos do sistema de computação;
- é a função de transição de estado da máquina;
- é a função de mapeamento de saída.
Segundo Donald Knuth (The Art of Computer Programming, Vol. 1), qualquer formulação algorítmica válida deve satisfazer obrigatoriamente a cinco postulados fundamentais:
Em sistemas elétricos de potência e automação, o descumprimento do critério de Finitude (gerando um loop infinito de processamento em uma rotina de proteção de transformador) provoca a falha de abertura de disjuntores durante um curto-circuito franco, resultando em catástrofe patrimonial e riscos à vida humana.
3.2 Arquitetura de Von Neumann, Hierarquia de Memória e Gargalo de Barramento
Proposta pelo matemático John von Neumann em 1945, a arquitetura canônica de computadores digitais estabelece a premissa de que dados e instruções de programa compartilham o mesmo espaço físico de endereçamento e os mesmos barramentos de comunicação.
3.2.1 O Ciclo de Instrução da CPU
A execução sequencial de qualquer programa obedece ciclicamente a três micro-operações temporizadas:
- Busca (Fetch): A UC coloca o conteúdo do registrador Contador de Programa () no barramento de endereços. A memória primária lê o endereço e disponibiliza a instrução no barramento de dados. A instrução é carregada no Registrador de Instruções (), e o é incrementado:
- Decodificação (Decode): A lógica combinacional da UC analisa o código de operação (opcode) contido em , identificando os sinais de controle necessários e os operandos em registradores ou memória.
- Execução (Execute): A ULA efetua a operação algébrica ou booleana requerida, escrevendo o resultado no acumulador ou disparando desvios condicionais de fluxo.
3.2.2 Modelagem Matemática do Gargalo de Von Neumann (Von Neumann Bottleneck)
Como os dados e as instruções trafegam pelo mesmo barramento físico compartilhado, a CPU é forçada a intercalar o acesso à memória para buscar a instrução subsequente e para ler/escrever os operandos de dados.
A largura de banda máxima teórica de transferência de um barramento síncrono () é dada por:
Onde é a frequência de clock do barramento (em Hz) e é a largura do barramento em bytes ().
Se uma instrução típica de computação científica consome de CPU a (), mas o tempo de latência de acesso aleatório à memória RAM DDR4 é de , a CPU permanece ociosa esperando a chegada dos dados por:
Para mitigar esse abismo temporal, a engenharia de computadores implementa a Hierarquia de Memória piramidal:
3.3 Notações Formais: Linguagem Natural, Pseudocódigo e Fluxogramas ANSI
Para representar formalmente o fluxo de um algoritmo antes da implementação computacional, a engenharia utiliza três níveis progressivos de abstração:
- Descrição Narrativa (Linguagem Natural): Expressa as etapas em vernáculo (português ou inglês). Possui alta intuitividade, porém sofre de ambiguidade semântica inerente e ausência de rigor estrutural.
- Pseudocódigo (Português Estruturado / Algol-like): Emprega palavras-chave padronizadas (
INÍCIO,FIM,SE...ENTÃO...SENÃO,ENQUANTO...FAÇA) com regras estritas de atribuição e tipagem, servindo como modelo direto para codificação. - Fluxograma ANSI/ISO (Norma ANSI X3.5 / ISO 5807): Representação gráfica normalizada bidimensional que evidencia visualmente bifurcações condicionais e laços de iteração:
3.4 O Pipeline de Execução do CPython 3: Tokenizador, AST, Bytecode e VM
O Python padrão, mantido pela Python Software Foundation, é implementado na linguagem C e formalmente denominado CPython. Diferente de linguagens puramente compiladas para código nativo (como C, C++ ou Rust) e de linguagens puramente interpretadas linha a linha em tempo real (como o antigo BASIC), o CPython adota uma arquitetura híbrida baseada em compilação para bytecode:
3.4.1 Fases do Pipeline
- Tokenização (Lexing): O módulo
tokenizedivide o fluxo de caracteres de entrada em blocos atômicos chamados tokens (NAME,NUMBER,OP,NEWLINE,INDENT,DEDENT). Em Python, o controle de blocos de escopo é realizado sintaticamente pelo recuo de margem (off-side rule), onde o tokenizador emite explicitamente eventosINDENTeDEDENT. - Construção da AST (Parsing): A partir do Python 3.9, utiliza-se o analisador sintático formal PEG (Parsing Expression Grammar), que constrói a Árvore Sintática Abstrata (Abstract Syntax Tree), verificando a correção gramatical da estrutura.
- Compilação para Bytecode: A AST é compilada para uma sequência linear de opcodes independentes da CPU subjacente. Esse resultado é armazenado em disco no diretório especial
__pycache__/<script>.cpython-312.pyc, dotado de cabeçalho contendo o número mágico da versão e o timestamp do arquivo-fonte para evitar recompilações desnecessárias. - Execução na PVM (Python Virtual Machine): O laço central de despacho (implementado na função
_PyEval_EvalFrameDefaultno arquivoceval.c) atua como uma máquina baseada em pilha (stack machine):- Instruções como
LOAD_NAMEempilham referências de objetos no topo da pilha; - Instruções aritméticas como
BINARY_OPdesempilham os dois operandos superiores, invocam os métodos internos em C correspondentes (ex.:nb_add) e empilham o ponteiro do objeto resultante; - Instruções como
STORE_NAMEdesempilham o valor e gravam seu endereço no mapa local de variáveis.
- Instruções como
3.4.2 Gerenciamento Automático de Memória: Contagem de Referências e GC
Em CPython, toda variável é um ponteiro para uma estrutura de dados genérica em C denominada PyObject:
// Estrutura conceitual basica de qualquer objeto Python em C (object.h)
typedef struct _object {
_PyObject_HEAD_EXTRA
Py_ssize_t ob_refcnt; // Contador de referencias ativas
struct _typeobject *ob_type; // Ponteiro para o tipo de dado (int, float, etc.)
} PyObject;O mecanismo primário de coleta de memória é a Contagem de Referências (Reference Counting):
- Sempre que uma variável recebe um objeto (
a = 10), o campoob_refcntdo objeto é incrementado em 1. - Quando o nome sai de escopo ou é reatribuído (
a = None),ob_refcnté decrementado em 1. - No instante exato em que
ob_refcnt == 0, a memória do objeto é imediatamente desalocada pelo gerenciador de memóriaPyObject_Free().
Para resolver o problema das referências circulares (quando o objeto A aponta para o objeto B e o objeto B aponta de volta para A, mantendo ob_refcnt >= 1 mesmo quando ambos são inacessíveis pelo programa), o CPython integra um segundo subsistema: o Coletor de Lixo Geracional (Generational Garbage Collector), que divide os objetos em três gerações () e executa algoritmos de detecção de ciclos baseados em grafos de alcançabilidade.
🖼️ 4. Diagrama Arquitetural Integrado
O diagrama técnico completo a seguir sintetiza as duas metades complementares da execução computacional: à esquerda, o modelo físico de Von Neumann (CPU, barramentos e memória primária); à direita, o pipeline de tradução do CPython 3 que converte código-fonte legível em bytecode avaliado pela máquina virtual:
💻 5. Implementação Prática em Engenharia Elétrica
5.1 Script Padronizado PEP 8: Diagnóstico e Balanço de Potências em Regime Permanente
O programa a seguir ilustra a estrutura profissional de um script em Python 3 aplicado à Engenharia Elétrica. O código calcula o triângulo de potências (aparente , ativa , reativa ) e diagnostica a conformidade do fator de potência () segundo os limites da Resolução Normativa ANEEL nº 1.000/2021 ( indutivo ou capacitivo):
"""
Modulo de Diagnostico Energetico e Calculo do Triangulo de Potencias.
Em conformidade rigorosa com a norma PEP 8, este script realiza a leitura
de parametros eletricos senoidais em regime permanente, valida coercoes
de tipos e emite relatorio de conformidade regulatoria.
"""
import math
import sys
def calcular_potencias(tensao_rms: float, corrente_rms: float, defasagem_graus: float) -> dict[str, float]:
"""
Calcula as grandezas do triangulo de potencias senoidais.
Parametros:
tensao_rms (float): Tensao eficaz de linha em Volts [V].
corrente_rms (float): Corrente eficaz de linha em Amperes [A].
defasagem_graus (float): Angulo phi de defasagem tensao-corrente em graus [°].
Valores positivos indicam carga indutiva (corrente atrasada).
Retorna:
dict[str, float]: Dicionario contendo S (VA), P (W), Q (VAr) e FP (adimensional).
"""
# Conversao da defasagem angular para radianos
phi_rad = math.radians(defasagem_graus)
# Potencia Aparente: S = V_rms * I_rms
potencia_s = tensao_rms * corrente_rms
# Fator de Potencia: FP = cos(phi)
fator_potencia = math.cos(phi_rad)
# Potencia Ativa: P = S * cos(phi)
potencia_p = potencia_s * fator_potencia
# Potencia Reativa: Q = S * sin(phi)
potencia_q = potencia_s * math.sin(phi_rad)
return {
"tensao_v": tensao_rms,
"corrente_a": corrente_rms,
"defasagem_graus": defasagem_graus,
"potencia_aparente_va": potencia_s,
"potencia_ativa_w": potencia_p,
"potencia_reativa_var": potencia_q,
"fator_potencia": abs(fator_potencia),
}
def emitir_laudo_regulatorio(resultados: dict[str, float]) -> None:
"""
Gera relatorio formatado no terminal com base nas resolucoes da ANEEL.
"""
limite_aneel = 0.92
fp = resultados["fator_potencia"]
is_conforme = fp >= limite_aneel
print("========================================================")
print(" LAUDO DE DIAGNOSTICO ENERGETICO - SUBESTACAO ")
print("========================================================")
print(f"Tensao Eficaz de Entrada : {resultados['tensao_v']:>10.2f} V")
print(f"Corrente Eficaz de Carga : {resultados['corrente_a']:>10.2f} A")
print(f"Defasagem Angular (Phi) : {resultados['defasagem_graus']:>10.2f} graus")
print("--------------------------------------------------------")
print(f"Potencia Aparente (S) : {resultados['potencia_aparente_va']:>10.2f} VA")
print(f"Potencia Ativa (P) : {resultados['potencia_ativa_w']:>10.2f} W")
print(f"Potencia Reativa (Q) : {resultados['potencia_reativa_var']:>10.2f} VAr")
print(f"Fator de Potencia (FP) : {fp:>10.4f}")
print("--------------------------------------------------------")
if is_conforme:
status = "[CONFORME] Sistema operando dentro da meta regulatoria da ANEEL."
else:
status = "[ALERTA] FP inferior a 0.92! Risco de faturamento por energia reativa exedente."
print(status)
print("========================================================\n")
def main() -> None:
"""Funcao principal de execucao e orquestracao."""
print("Inicializando Algoritmo de Analise Eletrica...")
# Parametros de ensaio de uma carga industrial trifasica equivalente monofasica
v_nominal = 220.0 # Volts
i_carga = 45.5 # Amperes
defasagem_angulo = 36.87 # Graus (cos(36.87°) ~= 0.80 indutivo)
laudo = calcular_potencias(v_nominal, i_carga, defasagem_angulo)
emitir_laudo_regulatorio(laudo)
if __name__ == "__main__":
main()5.2 Inspeção de Bytecode com o Módulo dis
O módulo embutido dis do Python permite desmontar funções e inspecionar diretamente os opcodes gerados para a máquina virtual de pilha do CPython:
import dis
def somar_correntes(i_ramo1, i_ramo2):
i_total = i_ramo1 + i_ramo2
return i_total
print("Desmontagem em Bytecode da Funcao somar_correntes:")
dis.dis(somar_correntes)Saída típica gerada pelo desmontador:
2 0 LOAD_FAST 0 (i_ramo1)
2 LOAD_FAST 1 (i_ramo2)
4 BINARY_OP 0 (+)
8 STORE_FAST 2 (i_total)
3 10 LOAD_FAST 2 (i_total)
12 RETURN_VALUEAnálise: As instruções LOAD_FAST buscam referências dos argumentos locais e as empilham; BINARY_OP executa a soma matemática via C-API e empilha o resultado; STORE_FAST transfere o resultado para a variável local i_total, e RETURN_VALUE retorna a referência no topo da pilha para o chamador.
📝 6. Banco de Questões de Fixação e Concursos Auditados
Questão 01 — Determinismo Temporal: Compilação Estática C vs CPython VM em Relés de Proteção
(Petrobras — Engenharia de Equipamentos / Eletrônica — Adaptada)
Em sistemas elétricos de alta tensão, relés de proteção digital microprocessados executam a função ANSI 50 (sobrecorrente instantânea), cujo tempo de disparo total não pode ultrapassar (menos de 1 ciclo em ) para evitar explosões de transformadores de potência.
Um engenheiro propõe substituir o firmware nativo em C compilado diretamente para código de máquina ARM Cortex-M7 por um script em Python executado pelo interpretador padrão CPython embarcado.
a) Explique as razões arquiteturais pelas quais o CPython não atende aos requisitos de sistemas de tempo real estrito (hard real-time).
b) Diferencie a execução do C compilado e do CPython sob o ponto de vista de determinismo temporal e latência de coletor de lixo (garbage collector).
💡 Resolução Analítica Passo a Passo:
a) Incompatibilidade com Sistemas Hard Real-Time:
Um sistema de tempo real estrito (hard real-time) exige garantia matemática de cumprimento de prazos temporais (deadlines). A falha em atender ao prazo de é considerada uma falha catastrófica total do sistema.
O interpretador CPython é inadequado por três fatores fundamentais:
- Sobrecarga de Interpretação da VM: O laço
ceval.cadiciona camadas de busca e decodificação de bytecode intermediário em memória para cada instrução, aumentando o tempo de resposta em ordens de magnitude em comparação com código de máquina nativo; - Ausência de Determinismo Temporal (Jitter): Em CPython, a alocação dinâmica contínua de memória fragmenta o Heap e dispara o Coletor de Lixo (Garbage Collector) de forma assíncrona. Durante as coletas de geração 2 (), o interpretador pausa a execução do programa (Stop-the-World pause) para percorrer grafos de ponteiros circulares. Essa pausa pode durar de dezenas a centenas de milissegundos, ultrapassando fatalmente o limite de ;
- Travamento Global do Interpretador (GIL): O GIL serializa a execução de threads, impedindo a preempção determinística de interrupções por hardware de alta prioridade.
b) C Compilado versus CPython:
- C Compilado: O compilador (ex.:
gcc-arm-none-eabi) traduz o código estaticamente para código de máquina puro binário. Cada instrução consome um número fixo e conhecido de ciclos de clock (latência determinística por instrução a ). Não há coletor de lixo automático nem abstração de máquina virtual em tempo de execução; a memória é estática ou gerenciada deterministicamente na pilha (Stack). - CPython: Executa bytecode sobre uma máquina virtual genérica em C com despacho dinâmico de métodos e resolução tardia de tipos. A alocação de qualquer variável numérica envolve a criação de estruturas pesadas de objetos no Heap e posterior reciclagem pelo GC, gerando dispersão estatística inaceitável no tempo de resposta do relé.
Questão 02 — Análise de Vazão e Gargalo de Von Neumann em Aquisição de Unidades Fasoriais (PMU)
(Operador Nacional do Sistema Elétrico - ONS / Engenharia de Sistemas)
Uma Unidade de Medição Fasorial (PMU - Phasor Measurement Unit) instalada em uma subestação de amostra as grandezas elétricas a uma taxa de . Cada pacote de dados fasoriais conforme a norma IEEE C37.118 contém de telemetria.
Considere que um concentrador de dados de fasores (PDC) centralizado recebe os dados de distribuídas. Os dados trafegam pela memória RAM através de um barramento de sistema compartilhado de 64 bits () operando a uma frequência de clock efetiva de .
a) Calcule a taxa total contínua de dados gerada pelas subestações em megabytes por segundo ().
b) Determine a largura de banda máxima teórica do barramento de memória e a fração percentual de ocupação do barramento exclusivamente pelo fluxo de entrada de dados.
c) Sob o modelo de Von Neumann, explique por que a taxa de dados real sustentável da CPU é substancialmente inferior à largura de banda teórica calculada.
💡 Resolução Analítica Passo a Passo:
a) Taxa Total de Dados das PMUs:
Cada PMU gera de dados a uma frequência de . A taxa de geração individual é:
Para o conjunto de :
b) Largura de Banda do Barramento e Ocupação Percentual:
A largura de banda máxima teórica do barramento () é:
A ocupação teórica mínima gerada pela injeção direta dos dados das PMUs é:
c) Efeito do Gargalo de Von Neumann na Prática:
Embora o fluxo de entrada ocupe apenas da largura de banda bruta do barramento, na arquitetura de Von Neumann o barramento de sistema não é dedicado unicamente ao tráfego de dados de entrada da placa de rede.
Para cada pacote fasorial recebido:
- O controlador DMA lê os dados e escreve na memória RAM primária (tráfego de barramento);
- A CPU busca as instruções do software PDC na mesma RAM para decodificar o frame IEEE C37.118 (tráfego de barramento);
- A CPU lê os bytes do pacote da RAM para os registradores internos (tráfego de barramento);
- A CPU efetua as validações trigonométricas de limites e escreve o pacote consolidado em outra região de memória para gravação em banco de dados ou retransmissão ao ONS (tráfego de barramento).
A cada acesso intercalado entre leitura de instruções e movimentação de dados, ocorrem penalidades de latência de linha de cache (cache miss), chaveamento de barramento e arbitragem de memória, multiplicando por mais de 10 vezes a demanda real sobre o barramento e gerando estados de espera (wait states) que reduzem drasticamente o throughput útil.
Questão 03 — Gerenciamento de Memória, Ciclo de Coleta de Lixo e sys.getrefcount()
(ENADE — Ciência da Computação / Engenharia da Computação)
Considere o seguinte trecho de código executado no interpretador CPython 3 padrão:
import sys
class SensorTensao:
def __init__(self, tag):
self.tag = tag
s1 = SensorTensao("PT-01")
print(sys.getrefcount(s1)) # Linha A
s2 = s1
print(sys.getrefcount(s1)) # Linha B
del s1
print(sys.getrefcount(s2)) # Linha Ca) Indique os valores inteiros exibidos no console nas linhas A, B e C, justificando formalmente cada resultado com base no funcionamento do ob_refcnt do CPython.
b) Explique por que a chamada sys.getrefcount(x) sempre reporta uma unidade a mais em relação ao número aparente de referências declaradas no código do usuário.
💡 Resolução Analítica Passo a Passo:
a) Valores Exibidos e Mecânica de Contagem:
- Linha A (Exibe 2):
O objetoSensorTensao("PT-01")é instanciado no Heap. A variávels1passa a apontar para ele (). No entanto, ao invocarsys.getrefcount(s1), o parâmetro formal da própria função recebe uma referência temporária para o objeto enquanto a função executa na pilha de chamadas, incrementando temporariamente o contador para: - Linha B (Exibe 3):
A linhas2 = s1cria uma nova referência de variável apontando para o mesmíssimo objeto na memória (s1es2compartilham a mesma identidadeid()). O contador persistente sobe para 2. Ao passars1parasys.getrefcount(), soma-se a referência temporária do argumento, resultando em: - Linha C (Exibe 2):
O comandodel s1não destrói o objeto diretamente; ele apenas desconecta o identificadors1do objeto e decrementa seu contador em 1 ( retorna para 1, poiss2ainda aponta para ele). Na linha C, passamoss2como argumento desys.getrefcount(), somando temporariamente 1 referência:
b) A Referência Adicional da Chamada de Função:
Em CPython, a passagem de parâmetros para qualquer função é realizada por atribuição de ponteiro de objeto (call-by-object-reference). Quando o identificador x é colocado dentro dos parênteses de sys.getrefcount(x), a função getrefcount cria um parâmetro local em seu frame de execução que aponta para o mesmo objeto. Consequentemente, o contador ob_refcnt contido no cabeçalho PyObject é incrementado em 1 no momento da chamada e decrementado em 1 logo após a finalização da função, fazendo com que o valor medido internamente seja sempre rigorosamente , onde é o número de referências externas ativas.
📚 7. Referências Bibliográficas e Normas Técnicas
- KNUTH, Donald E. The Art of Computer Programming, Volume 1: Fundamental Algorithms. 3. ed. Boston: Addison-Wesley, 1997.
- TANENBAUM, Andrew S.; AUSTIN, Todd. Organização Estruturada de Computadores. 6. ed. São Paulo: Pearson, 2013.
- HENNESSY, John L.; PATTERSON, David A. Computer Architecture: A Quantitative Approach. 6. ed. Cambridge: Morgan Kaufmann, 2017.
- LUTZ, Mark. Learning Python: Powerful Object-Oriented Programming. 5. ed. Sebastopol: O’Reilly Media, 2013.
- VAN ROSSUM, Guido; WARSAW, Barry; COGHLAN, Nick. PEP 8 – Style Guide for Python Code. Python Enhancement Proposals, 2001 (revisado continuamente).
- ANEEL. Resolução Normativa nº 1.000, de 7 de dezembro de 2021: Estabelece as Regras de Prestação do Serviço Público de Distribuição de Energia Elétrica. Brasília: ANEEL, 2021.
- IEEE Std C37.118.1-2011: IEEE Standard for Synchrophasor Measurements for Power Systems. New York: IEEE, 2011.