Aula 04 - Estruturas de Repetição, Laços Determinados e Indeterminados

Navegação Rápida

Metadados da Aula

  • Área: 06 Computação e Telecomunicações
  • Carga Horária Equivalente: 4 horas-aula teóricas e práticas
  • Pré-requisitos: Aula 03 - Estruturas Condicionais
  • Palavras-chave: Laço Determinado (for), Laço Indeterminado (while), Protocolo de Iteração, Invariante de Laço, Newton-Raphson, Convergência Quadrática, True RMS, Cláusula else em Laços

📌 Sumário da Aula

  1. 🧭 1. Contextualização e Objetivos de Aprendizagem
  2. 📋 2. Sumário Executivo dos Tópicos
  3. ⚡ 3. Fundamentação Teórica e Modelagem Matemática
  4. 🖼️ 4. Diagrama Técnico Integrado
  5. 💻 5. Implementação Prática em Engenharia Elétrica
  6. 📝 6. Banco de Questões de Fixação e Concursos Auditados
  7. 📚 7. Referências Bibliográficas e Normas Técnicas

🧭 1. Contextualização e Objetivos de Aprendizagem

O poder transformador da computação em engenharia manifesta-se plenamente quando a máquina executa tarefas matemáticas repetitivas com velocidade e exatidão imunes à fadiga humana. Seja na integração numérica de equações diferenciais de transitórios eletromagnéticos, no processamento discreto de sinais amostrados por conversores A/D a dezenas de milhares de vezes por segundo, ou na convergência de sistemas de equações algébricas não-lineares em redes elétricas de grande porte, as estruturas de repetição constituem o motor primário dos algoritmos de simulação e controle.

Esta aula aprofunda a teoria e a prática dos laços de repetição (laços determinados for e laços indeterminados while). Analisa o formalismo lógico de prova de programas através da técnica de Invariantes de Laço, disseca a dedução analítica e a taxa de convergência quadrática do método de Newton-Raphson, e demonstra a implementação computacional do cálculo do valor eficaz verdadeiro (True RMS) em sinais distorcidos por harmônicas.

Ao término desta aula, o engenheiro será capaz de:

  • Selecionar e implementar a estrutura de repetição ótima (for com geradores range() ou while com sentinelas de segurança), dominando as instruções de controle break, continue e a cláusula else.
  • Formular e demonstrar formalmente a corretude de um laço de repetição através das três etapas da prova de Invariante de Laço (Inicialização, Manutenção e Terminação).
  • Desenvolver solvers iterativos de raízes e sistemas de equações não-lineares baseados em Newton-Raphson com proteção rigorosa contra singularidades derivadas e limites de iteração máxima.
  • Projetar algoritmos discretos de integração numérica temporal para medição digital de grandezas elétricas True RMS e potências segundo as normas IEEE 1459.

📋 2. Sumário Executivo dos Tópicos

  • Protocolo de Iteração em Python: Mecanismo subjacente aos laços for. Objetos iteráveis implementam o método __iter__(), retornando um iterador que avança sequencialmente via __next__() até emitir a exceção StopIteration.
  • Gerador range(start, stop, step): Estrutura imutável de progressão aritmética com consumo de memória estritamente constante , independente da quantidade de elementos gerados.
  • Laço Indeterminado while: Executa iterativamente enquanto a proposição de controle permanecer verdadeira. Exige obrigatoriamente mecanismos de garantia de término (critério de convergência e sentinela de iterações máximas).
  • Invariante de Laço: Propriedade lógica invariável no tempo comprovada por indução matemática: verdadeira na Inicialização (pré-iteração), conservada na Manutenção (iteração ) e garantidora da corretude na Terminação.
  • Método de Newton-Raphson: Algoritmo numérico de aproximação tangencial derivado da expansão em Série de Taylor de 1ª ordem: . Apresenta convergência de ordem quadrática ().
  • Cálculo Numérico True RMS: Quadratura média temporal discreta: , computando com exatidão componentes fundamentais e todo o espectro harmônico.

⚡ 3. Fundamentação Teórica e Modelagem Matemática

3.1 Mecanismo de Iteração em Python: for, while e o Protocolo de Iteração

Em Python, a instrução for não é meramente um contador numérico incrementado em registrador como em C ou Assembly (for(int i=0; i<N; i++)). Trata-se de um construto de alto nível governado pelo Protocolo de Iteração (Iterator Protocol).

3.1.1 O Tipo range e Eficiência de Memória

A função range(início, fim, passo) retorna um objeto de sequência aritmética imutável:

Diferente de construir uma lista de 10 milhões de inteiros (list(range(10_000_000))), que consumiria cerca de de memória RAM no Heap, o objeto range armazena exclusivamente três inteiros de 64 bits (start, stop, step), computando cada valor sob demanda em tempo e consumo de memória invariante de .

3.1.2 Instruções de Salto e a Cláusula else em Laços

  1. break: Interrompe prematuramente a execução do laço mais interno, saltando para a primeira instrução externa.
  2. continue: Aborta a iteração corrente e avança imediatamente para o teste condicional do próximo ciclo.
  3. Cláusula else acoplada ao laço: Recurso sintático exclusivo do Python. O bloco else associado a um for ou while executa se e somente se o laço terminar naturalmente (esgotamento do iterável ou condição tornada falsa). Se o laço for interrompido por um break, o bloco else é ignorado.

3.2 Prova Formal de Corretude: A Teoria da Invariante de Laço

Para validar que um algoritmo iterativo produz resultados matematicamente corretos em sistemas de alta criticidade (como telecomando de subestações e cálculos de proteção), utiliza-se o método axiomático formulado por C. A. R. Hoare: a Invariante de Laço (Loop Invariant).

Uma invariante de laço é uma asserção lógica sobre as variáveis do programa que deve ser verdadeira em cada iteração do ciclo. A prova formal exige três etapas rigorosas por indução matemática:

Aplicação: Demonstração da Acumulação de Perdas Joule

Considere o algoritmo que calcula a perda Joule total em ramos de um alimentador elétrico:

Código Python sob análise:

3.3.2 Dedução da Ordem de Convergência Quadrática

Seja a raiz exata da função () e o erro absoluto na iteração . Expandindo em torno de :

Reescrevendo a equação de recorrência multiplicada por :

Substituindo :

Consequência Prática da Convergência Quadrática

A relação significa que o erro na iteração subsequente é proporcional ao quadrado do erro anterior. Se em uma determinada iteração o erro for , na iteração seguinte será , e na subsequente . O número de dígitos significativos corretos dobra a cada iteração do laço. Em contrapartida, se a derivada , o quociente explode e o algoritmo diverge, exigindo guardas de proteção de software.


3.4 Discretização Numérica e Cálculo de Valor Eficaz True RMS

Em instrumentação eletrônica e sistemas digitais de proteção, o cálculo do valor eficaz (Root Mean Square - RMS) de uma forma de onda de tensão ou corrente periódica contínua de período é formalmente definido por:

Quando o sinal é digitalizado por um conversor analógico-digital (ADC) que captura amostras discretas uniformemente espaçadas por no intervalo temporal :

A integral contínua é aproximada numericamente pela quadratura discreta de Riemann (Regra do Ponto Médio / Retangular):

Como , a formulação computacional direta do True RMS Discreto resulta em:

Analogamente, a Potência Ativa Média () absorvida pela carga ao longo de um ciclo é a média temporal do produto das amostras instantâneas de tensão e corrente:


🖼️ 4. Diagrama Técnico Integrado

O diagrama técnico a seguir sintetiza os fundamentos das estruturas de repetição: à esquerda, os paradigmas operacionais dos laços for e while com o formalismo de prova da invariante de laço; à direita, a dinâmica de convergência quadrática do método numérico de Newton-Raphson aplicado à engenharia de potência:


💻 5. Implementação Prática em Engenharia Elétrica

5.1 Solver Não-Linear de Newton-Raphson com Salvaguardas de Divergência

O código a seguir implementa um solver numérico de raízes em Python 3 utilizando o método de Newton-Raphson. A rotina integra verificação de singularidade de derivada (), tolerância absoluta e relativa no resíduo, e limite máximo de iterações com cláusula else no laço while:

"""
Solver Numerico de Newton-Raphson para Sistemas Nao-Lineares.
Equipado com protecao de singularidade de derivada e convergencia estrita.
"""
 
import math
from typing import Callable, Tuple
 
 
def resolver_newton_raphson(
    funcao_f: Callable[[float], float],
    funcao_df: Callable[[float], float],
    estimativa_inicial_x0: float,
    tolerancia: float = 1e-9,
    max_iteracoes: int = 100,
) -> Tuple[float, int, bool]:
    """
    Localiza a raiz de f(x) = 0 utilizando o algoritmo de Newton-Raphson.
 
    Retorna:
        Tuple contendo: (raiz_calculada, total_iteracoes, convergiu_flag).
    """
    xk = estimativa_inicial_x0
    iteracao = 0
 
    print(f"{'Iteracao':<10} | {'x_k':<18} | {'f(x_k)':<18} | {'Passo Delta_x':<18}")
    print("-" * 72)
 
    while iteracao < max_iteracoes:
        fx = funcao_f(xk)
        dfx = funcao_df(xk)
 
        # 1. Salvaguarda contra derivada nula ou excessivamente proxima de zero
        if abs(dfx) < 1e-14:
            print(f"[ALERTA CRITICO] Derivada nula (f'(x) = {dfx:.2e}) na iteracao {iteracao}! Abortando.")
            return xk, iteracao, False
 
        # 2. Calculo do passo de correcao de Newton: Delta_x = f(x) / f'(x)
        delta_x = fx / dfx
        xk_proximo = xk - delta_x
 
        print(f"{iteracao:<10} | {xk:<18.10f} | {fx:<18.10e} | {delta_x:<18.10e}")
 
        # 3. Criterio de parada conjugado: variacao do passo e residuo da funcao
        if abs(delta_x) < tolerancia and abs(fx) < tolerancia:
            print("-" * 72)
            print(f"[CONVERGENCIA ATINGIDA] Raiz localizada em {iteracao + 1} iteracoes.")
            return xk_proximo, iteracao + 1, True
 
        xk = xk_proximo
        iteracao += 1
    else:
        # Clausula else do while: executada se o laco atingir max_iteracoes sem convergir
        print("-" * 72)
        print(f"[FALHA DE CONVERGENCIA] Limite maximo de {max_iteracoes} iteracoes excedido.")
        return xk, iteracao, False
 
 
def main():
    # Exemplo em Engenharia Eletrica: Calculo da Tensao de Barra em PU
    # Equacao de fluxo de carga simplificada: f(V) = V^3 - 0.2*V - 1.05 = 0
    # Derivada analitica: f'(V) = 3*V^2 - 0.2
    f_tensao = lambda v: (v ** 3) - 0.2 * v - 1.05
    df_tensao = lambda v: 3.0 * (v ** 2) - 0.2
 
    print("========================================================================")
    print("      CALCULO DE TENSAO DE BARRA DE CARGA VIA NEWTON-RAPHSON            ")
    print("========================================================================")
    v_raiz, passos, sucesso = resolver_newton_raphson(
        funcao_f=f_tensao,
        funcao_df=df_tensao,
        estimativa_inicial_x0=1.0, # Estimativa tipica inicial "Flat Start" (1.0 pu)
        tolerancia=1e-8,
        max_iteracoes=20
    )
 
    if sucesso:
        print(f"Tensao Final de Operacao da Barra: V = {v_raiz:.8f} pu")
    print("========================================================================\n")
 
 
if __name__ == "__main__":
    main()

5.2 Analisador Numérico Discreto de Grandezas True RMS com Harmônicas

A rotina a seguir simula a aquisição em tempo real de uma onda de corrente industrial distorcida por retificadores a tiristor (contendo fundamental de , de 3ª harmônica e de 5ª harmônica), calculando as grandezas True RMS e a Distorção Harmônica Total ():

"""
Analisador Digital True RMS e Distorcao Harmonica Total (THD).
Implementacao orientada a processamento discreto de sinais amostrados.
"""
 
import math
 
 
def analisar_sinal_digitalizado(
    frequencia_rede_hz: float,
    num_amostras_por_ciclo: int,
    i_fundamental_pico: float,
    i_h3_pico: float,
    i_h5_pico: float,
    defasagem_graus: float = 30.0,
):
    periodo_s = 1.0 / frequencia_rede_hz
    dt = periodo_s / num_amostras_por_ciclo
    omega = 2.0 * math.pi * frequencia_rede_hz
    phi_rad = math.radians(defasagem_graus)
 
    # Acumuladores numericos para os lacos de integracao
    soma_v2 = 0.0
    soma_i2 = 0.0
    soma_potencia_inst = 0.0
 
    tensao_pico = 311.127 # Equivalente a 220 V eficazes
 
    for k in range(num_amostras_por_ciclo):
        t = k * dt
 
        # Sinal senoidal puro de tensao de alimentacao da rede
        v_k = tensao_pico * math.sin(omega * t)
 
        # Corrente distorcida com harmonicas impares tipicas de eletronica de potencia
        i_k = (
            i_fundamental_pico * math.sin(omega * t - phi_rad)
            + i_h3_pico * math.sin(3.0 * omega * t - (3.0 * phi_rad))
            + i_h5_pico * math.sin(5.0 * omega * t - (5.0 * phi_rad))
        )
 
        # Quadratura e produto instantaneo
        soma_v2 += v_k ** 2
        soma_i2 += i_k ** 2
        soma_potencia_inst += v_k * i_k
 
    # Calculo das medias discretas de True RMS
    v_rms_true = math.sqrt(soma_v2 / num_amostras_por_ciclo)
    i_rms_true = math.sqrt(soma_i2 / num_amostras_por_ciclo)
    potencia_ativa_p = soma_potencia_inst / num_amostras_por_ciclo
    potencia_aparente_s = v_rms_true * i_rms_true
    fator_potencia_real = potencia_ativa_p / potencia_aparente_s
 
    # Calculo analitico de THD da corrente
    i1_rms = i_fundamental_pico / math.sqrt(2.0)
    i_harmonicas_rms = math.sqrt((i_h3_pico / math.sqrt(2.0))**2 + (i_h5_pico / math.sqrt(2.0))**2)
    thd_corrente_percent = (i_harmonicas_rms / i1_rms) * 100.0
 
    return {
        "amostras_totais": num_amostras_por_ciclo,
        "v_rms_true": v_rms_true,
        "i_rms_true": i_rms_true,
        "potencia_ativa_w": potencia_ativa_p,
        "potencia_aparente_va": potencia_aparente_s,
        "fator_potencia_real": fator_potencia_real,
        "thd_corrente_percent": thd_corrente_percent,
    }
 
 
def main():
    # Ensaio com 512 amostras por ciclo (taxa de 30.72 kHz para 60 Hz)
    laudo = analisar_sinal_digitalizado(
        frequencia_rede_hz=60.0,
        num_amostras_por_ciclo=512,
        i_fundamental_pico=100.0, # 70.71 A rms fundamental
        i_h3_pico=25.0,           # 25% de 3a harmonica
        i_h5_pico=15.0,           # 15% de 5a harmonica
        defasagem_graus=25.84     # cos(25.84°) ~= 0.90
    )
 
    print("=================================================================")
    print("      ANALISADOR DISCRETO DE QUALIDADE DE ENERGIA (TRUE RMS)     ")
    print("=================================================================")
    print(f"Total de Amostras por Ciclo  : {laudo['amostras_totais']}")
    print(f"Tensao Eficaz True RMS       : {laudo['v_rms_true']:>10.2f} V")
    print(f"Corrente Eficaz True RMS     : {laudo['i_rms_true']:>10.2f} A")
    print(f"Distorcao Harmonica Total THD: {laudo['thd_corrente_percent']:>10.2f} %")
    print("-----------------------------------------------------------------")
    print(f"Potencia Ativa Media (P)     : {laudo['potencia_ativa_w']:>10.2f} W")
    print(f"Potencia Aparente Total (S)  : {laudo['potencia_aparente_va']:>10.2f} VA")
    print(f"Fator de Potencia Real (FP)  : {laudo['fator_potencia_real']:>10.4f}")
    print("=================================================================")
 
 
if __name__ == "__main__":
    main()

📝 6. Banco de Questões de Fixação e Concursos Auditados

Questão 01 — Análise de Convergência Quadrática de Newton-Raphson em Fluxo de Potência

(Petrobras — Engenharia de Sistemas de Potência — Adaptada)
Em um estudo de planejamento elétrico, a equação não-linear escalar que determina a tensão da barra é: Um algoritmo computacional baseado no método de Newton-Raphson é inicializado com uma estimativa plana (flat start) de .
a) Calcule os valores numéricos de e exibidos nas duas primeiras iterações do laço.
b) Calcule os erros absolutos , e sabendo que a raiz exata é .
c) Demonstre que a taxa de redução de erro obedece estritamente à constante de convergência quadrática .

💡 Resolução Analítica Passo a Passo:

a) Cálculo das Iterações de Recorrência: A derivada da função é: A fórmula de recorrência é:

  • Iteração 0 1 ():

  • Iteração 1 2 ():

b) Cálculo dos Erros Absolutos: Com a raiz exata :

c) Comprovação da Constante de Convergência Quadrática: Calculando a constante teórica de erro assintótico: Aplicando a equação teórica :

  • Para :
  • Para : A demonstração comprova que os erros calculados satisfazem rigorosamente a relação quadrática assintótica de Newton-Raphson.

Questão 02 — Prova Formal de Invariante de Laço em Algoritmo de Busca MPPT

(Marinha do Brasil — Corpo de Engenheiros / Eletrônica)
Em sistemas fotovoltaicos, algoritmos de rastreamento do ponto de máxima potência (Maximum Power Point Tracking - MPPT) varrem amostras de tensão e corrente de painéis solares para identificar o ponto ótimo operacional. Considere o algoritmo a seguir que identifica a potência máxima em um vetor amostrado:

def buscar_potencia_maxima(vetor_potencias):
    p_max = vetor_potencias[0]
    for i in range(1, len(vetor_potencias)):
        # Assercao da Invariante: p_max == max(vetor_potencias[0 : i])
        if vetor_potencias[i] > p_max:
            p_max = vetor_potencias[i]
    return p_max

Formule e prove formalmente a invariante de laço nas três etapas clássicas de Hoare (Inicialização, Manutenção e Terminação).

💡 Resolução Analítica Passo a Passo:

Definição da Invariante de Laço ():
No início de cada iteração do laço for indexada por , a variável local p_max contém o valor máximo estrito dentre todos os elementos contidos no subarray anterior:

  • 1. Inicialização:
    Antes da primeira iteração do laço, temos . O subarray considerado é formado exclusivamente pelo elemento de índice 0: .
    Como a linha imediatamente anterior inicializou p_max = vetor_potencias[0], temos trivialmente . Logo, a invariante é verdadeira na inicialização.

  • 2. Manutenção:
    Assuma por hipótese indutiva que a invariante é verdadeira antes da iteração com índice . Ou seja, .
    Durante a iteração , o corpo do laço avalia o elemento :

    • Se , p_max é atualizado para , tornando-se o maior elemento do conjunto ampliado ;
    • Se , p_max permanece inalterado, conservando a condição de ser o maior elemento do conjunto ampliado .
      Portanto, ao final da iteração (e antes da iteração ), temos rigorosamente . A invariante é preservada na manutenção.
  • 3. Terminação:
    O laço encerra quando o índice atinge , onde . Substituindo na invariante: Como o intervalo compreende todos os elementos do vetor amostrado, a instrução return p_max entrega o valor máximo absoluto global da potência com garantia matemática de corretude.


Questão 03 — Semântica da Cláusula else em Laços de Varredura de Faltas Elétricas

(ENADE — Engenharia de Computação / Controle)
Considere o seguinte trecho de código projetado para diagnosticar sobrecorrente em um alimentador trifásico com 10 sensores de monitoramento:

def diagnosticar_alimentador(sensores_corrente, limite_i):
    for sensor in sensores_corrente:
        if sensor.leitura_amperes > limite_i:
            print(f"FALTA DETECTADA no sensor {sensor.id}! Disparo acionado.")
            break
    else:
        print("ALIMENTADOR SEGURO: Nenhuma sobrecorrente detectada em nenhum sensor.")

a) Explique a função semântica da cláusula else após o bloco for em Python e descreva em que circunstâncias ela é executada.
b) Se a cláusula else for removida e a mensagem print("ALIMENTADOR SEGURO...") for simplesmente tabulada fora do laço for, qual erro de lógica grave ocorrerá quando houver uma falta elétrica real?

💡 Resolução Analítica Passo a Passo:

a) Semântica da Cláusula else em Laços:
No modelo de execução da linguagem Python, a cláusula else vinculada a um laço (for ou while) atua como uma cláusula de sucesso da varredura completa sem interrupção.
Ela é executada se e somente se o laço esgotar todos os itens da sequência iterável sem ter executado nenhuma instrução break. Se qualquer sensor reportar corrente superior a limite_i, a linha break é acionada: o laço é abortado imediatamente e o bloco else associado é ignorado. Portanto, a mensagem "ALIMENTADOR SEGURO" só será emitida se todos os 10 sensores tiverem sido avaliados e nenhum tiver apresentado sobrecorrente.

b) Erro Lógico por Remoção Incorreta:
Se a palavra-chave else: for suprimida e a instrução print("ALIMENTADOR SEGURO...") for posicionada diretamente após o término do bloco for:

# CODIGO COM ERRO GRAVE DE ENGENHARIA:
for sensor in sensores_corrente:
    if sensor.leitura_amperes > limite_i:
        print(f"FALTA DETECTADA no sensor {sensor.id}!")
        break
print("ALIMENTADOR SEGURO: Nenhuma sobrecorrente detectada.") # Executa SEMPRE!

Quando ocorrer uma sobrecorrente real no sensor 3, a instrução break interromperá o laço. O interpretador prosseguirá para a próxima linha do script, imprimindo a mensagem de que o sistema está seguro logo após emitir o alarme de falta! O operador do supervisório receberá informações contraditórias simultâneas no log de eventos, gerando confusão operacional em momento crítico de manobra. A cláusula else elimina a necessidade de criar variáveis sentinela do tipo booleano (falta_encontrada = False).


📚 7. Referências Bibliográficas e Normas Técnicas

  1. HOARE, C. A. R. An Axiomatic Basis for Computer Programming. Communications of the ACM, v. 12, n. 10, p. 576-580, 1969.
  2. BURDEN, Richard L.; FAIRES, J. Douglas. Numerical Analysis. 9. ed. Boston: Cengage Learning, 2011.
  3. CHAPRA, Steven C.; CANALE, Raymond P. Métodos Numéricos para Engenharia. 7. ed. Porto Alegre: AMGH, 2016.
  4. IEEE Std 1459-2010: IEEE Standard Definitions for the Measurement of Electric Power Quantities Under Sinusoidal, Nonsinusoidal, Balanced, or Unbalanced Conditions. New York: IEEE, 2010.
  5. KNUTH, Donald E. The Art of Computer Programming, Volume 1: Fundamental Algorithms. 3. ed. Boston: Addison-Wesley, 1997.
  6. PYTHON SOFTWARE FOUNDATION. The Python Language Reference: Compound Statements (The while and for statements). Python 3.12 Documentation, 2024.