terça-feira, 28 de julho de 2026

Resolvendo uma EDO fornecida pelo usuário com RK-6

Janela principal do script.

Neste script, o usuário escreve a equação diferencial (EDO) em uma caixa de edição de texto. Após clicar no botão 'RUN', os parâmetros de entrada são analisados e se estiver tudo certo, a equação é resolvida numericamente usando o método de Runge-Kutta de 6a. ordem. O resultado é mostrado graficamente em uma nova janela. Depois disso, o usuário tem a opção de editar a EDO e calcular uma nova solução ou 'fechar' (sair) do programa. Esse script apresenta dois diferenciais:

  1. a equação é dinamicamente analisada;
  2. é usado o método de Runge-Kutta de 6a. ordem. 

Em geral, para resolver uma EDO, é usado o método de RK de 4a. ordem. Exemplos de saída:

Exemplo de saída 1.

 
Exemplo 2.


Exemplo de erro, o valor de h deve ser positivo.
 
Código Scilab:
// ===============================================
// rk4_gui.sce
//
// Resolve numericamente uma Equacao Diferencial Ordinaria de 1a ordem
//         dy/dt = f(t,y)
// pelo metodo de Runge-Kutta de 4a ordem (RK-6), com uma interface
// grafica onde o usuario informa:
//    - a equacao diferencial f(t,y)  (ex: -2*y + t)
//    - o instante inicial t0
//    - o valor inicial y0
//    - o tempo final de integracao tf
//    - o passo de integracao h
//
// Ao clicar em "RUN", a solucao numerica e calculada e plotada dentro
// da propria janela.
//
// COMO USAR:
//   1) Abra este arquivo no SciNotes (editor do Scilab).
//   2) Execute (Executar > Executar sem eco no Scilab, ou tecla F5),
//      ou no console digite:  exec('rk6_gui.sce', -1)
//   3) A janela sera aberta. Edite os campos e clique em RUN.
//
// EXEMPLOS DE EQUACOES QUE PODEM SER DIGITADAS (use as variaveis t e y):
//   -2*y + t          -> equacao linear
//   y                 -> crescimento exponencial (dy/dt = y)
//   -0.5*y            -> decaimento exponencial
//   y*(1-y)           -> equacao logistica
//   -y + sin(t)       -> oscilador amortecido forcado
//   t^2 - y           -> nao-linear simples
//
// OBSERVACAO: o programa resolve EDOs escalares de 1a ordem da forma
// dy/dt = f(t,y). Sistemas de equacoes e EDOs de ordem superior nao
// sao suportados nesta versao.
// =========================================================

// -------------------------------------------------------------------
// Funcao que monta a interface grafica (janela, campos, botoes, eixo)
// -------------------------------------------------------------------
function rk6_gui()

    f = figure('figure_name', 'EDO - Método de RK-6a. Dr. Aquino.', ...
                'position', [80, 60, 340, 630], ...
                'background', [0.95 0.95 0.95], ...
                'menubar', 'none', ...
                'toolbar', 'none', ...
                'resize', 'off');

    // ---- Painel esquerdo: entradas do usuario ----
    uicontrol(f, 'style', 'frame', 'position', [10, 10, 320, 610]);

    uicontrol(f, 'style', 'text', ...
              'string', 'Parâmetros do Metodo RK-6a.', ...
              'position', [20, 590, 300, 25], ...
              'fontsize', 11, 'fontweight', 'bold', ...
              'horizontalalignment', 'center');
              
        uicontrol(f, 'style', 'text', ...
              'string', 'Prof. Dr. Francisco J. A. de Aquino.', ...
              'position', [20, 570, 300, 25], ...
              'fontsize', 11, 'fontweight', 'bold', ...
              'horizontalalignment', 'center');

    uicontrol(f, 'style', 'text', 'string', 'dy/dt = f(t, y)  :', ...
              'position', [20, 550, 300, 20], 'horizontalalignment', 'left');
              
    edit_eq = uicontrol(f, 'style', 'edit', 'string', '-y/2 + 2*exp(-t/2)*cos(2*t)', ...
              'position', [20, 525, 300, 25]);

    uicontrol(f, 'style', 'text', ...
              'string', '(use t e y; funções: sin, cos, exp, sqrt, log,...)', ...
              'position', [20, 503, 300, 18], 'fontsize', 10, ...
              'horizontalalignment', 'left');

    uicontrol(f, 'style', 'text', 'string', 'Instante inicial  t0 :', ...
              'position', [20, 465, 170, 20], 'horizontalalignment', 'left');
              
    edit_t0 = uicontrol(f, 'style', 'edit', 'string', '0', ...
              'position', [200, 465, 120, 25]);

    uicontrol(f, 'style', 'text', 'string', 'Valor inicial     y0 :', ...
              'position', [20, 425, 170, 20], 'horizontalalignment', 'left');
    edit_y0 = uicontrol(f, 'style', 'edit', 'string', '0', ...
              'position', [200, 425, 120, 25]);

    uicontrol(f, 'style', 'text', 'string', 'Tempo final       tf :', ...
              'position', [20, 385, 170, 20], 'horizontalalignment', 'left');
              
    edit_tf = uicontrol(f, 'style', 'edit', 'string', '10', ...
              'position', [200, 385, 120, 25]);

    uicontrol(f, 'style', 'text', 'string', 'Passo de integracao h :', ...
              'position', [20, 345, 170, 20], 'horizontalalignment', 'left');
              
    edit_h = uicontrol(f, 'style', 'edit', 'string', '0.01', ...
              'position', [200, 345, 120, 25]);

    btn_run = uicontrol(f, 'style', 'pushbutton', 'string', 'RUN', ...
              'position', [20, 280, 135, 42], ...
              'fontsize', 12, 'fontweight', 'bold', ...
              'callback', 'rk6_run_callback()');

    btn_clear = uicontrol(f, 'style', 'pushbutton', ...
              'string', 'Limpar grafico/Sair', ...
              'position', [165, 280, 155, 42], ...
              'fontsize', 12, 'fontweight', 'bold', ...
              'callback', 'close');

    txt_status1 = uicontrol(f, 'style', 'text', 'string', '', ...
              'position', [20, 45, 300, 50], ...
              'horizontalalignment', 'left', 'fontsize', 12, ...
              'background', [1 1 1]);
              
    txt_status2 = uicontrol(f, 'style', 'text', 'string', '', ...
              'position', [20, 105, 300, 50], ...
              'horizontalalignment', 'left', 'fontsize', 12, ...
              'background', [1 1 1]);
              
    txt_status3 = uicontrol(f, 'style', 'text', 'string', '', ...
              'position', [20, 165, 300, 50], ...
              'horizontalalignment', 'left', 'fontsize', 12, ...
              'background', [1 1 1]);
          
    txt_status4 = uicontrol(f, 'style', 'text', 'string', '', ...
              'position', [20, 225, 300, 50], ...
              'horizontalalignment', 'left', 'fontsize', 12, ...
              'background', [1 1 1]);

    btn_sobre = uicontrol(f, 'style', 'pushbutton', 'string', 'Sobre', ...
              'position', [120, 15, 100, 22], ...
              'fontweight', 'bold',...
              'callback', 'b_sobre');
              
    // Guarda os handles dos controles no userdata da figura,
    // para que o callback consiga acessa-los depois
    handles = struct('eq', edit_eq, 't0', edit_t0, 'y0', edit_y0, ...
                      'tf', edit_tf, 'h', edit_h, ... 
                      'status1', txt_status1,...
                      'status2', txt_status2,...
                      'status3', txt_status3,...
                      'status4', txt_status4);
    f.userdata = handles;
    f.tag = 'RK4_GUI';
endfunction

// ----- Sobre
function b_sobre()
    // Buttons labels + "modal" replaces title
    msg = ["Este Script em Scilab resolve uma EDO de 1a. ordem usando RK-6."
           "A EDO precisa estar em um formato legível."
           " "
           "Script desenvolvido pelo prof. Dr. Francisco Aquino,"
           "Departamento de Telemática - IFCE."];
    messagebox(msg, "Sobre este script", "modal", "info", ["OK"])
endfunction

// -------------------------------------------------------
// Callback do botao RUN: le os parametros, 
// resolve a EDO com RK-6
// e plota o resultado
// --------------------------------------------------------
function rk6_run_callback()

    f = gcf();
    handles = f.userdata;

    eq_str = handles.eq.string;

    t0 = evstr(handles.t0.string);
    y0 = evstr(handles.y0.string);
    tf = evstr(handles.tf.string);
    h  = evstr(handles.h.string);

    // --- validacao basica das entradas ---
    if isempty(t0) | isempty(y0) | isempty(tf) | isempty(h) then
        messagebox('Preencha todos os campos numericos.', 'Erro de entrada', 'error');
        return;
    end
    if h <= 0 then
        messagebox('O passo h deve ser um numero positivo.', 'Erro de entrada', 'error');
        return;
    end
    if h > 0.5 then
        messagebox('O passo h deve ser um numero menor que 0.5.', 'Erro de entrada', 'error');
        return;
    end
    if tf <= t0 then
        messagebox('O tempo final tf deve ser maior que t0.', 'Erro de entrada', 'error');
        return;
    end

    // --- monta dinamicamente a funcao f_user(t,y) a partir do texto digitado ---
    erro_eq = %f;
    try
        deff('dydt = f_user(t,y)', 'dydt = ' + eq_str);
        teste = f_user(t0, y0);   // chamada de teste para forcar avaliacao
        if ~isreal(teste) | isnan(teste) then
            erro_eq = %t;
        end
    catch
        erro_eq = %t;
    end

    if erro_eq then
        messagebox('Equacao invalida. Use somente as variaveis t e y ' + ...
                    '(ex: -2*y + t , sin(t)-y^2 , y*(1-y) ).', ...
                    'Erro na equacao', 'error');
        return;
    end

    // --- metodo de Runge-Kutta de 6a ordem ---
    n = floor((tf - t0) / h); // número de pontos
    tt = zeros(1, n+1); // vetor de tempo
    yy = zeros(1, n+1); // resposta/solução da EDO
    tt(1) = t0; // valores iniciais
    yy(1) = y0; // valores iniciais

    t = t0;
    y = y0;
    for i = 1:n
      K1 = f_user(t, y);
      K2 = f_user(t + h/9, y + K1*h/9);
      K3 = f_user(t + h/6, y + (K1 + 3*K2)*h/24);
      K4 = f_user(t + h/3, y + (K1 - 3*K2 + 4*K3)*h/6);
      K5 = f_user(t + h/2, y + (-5*K1 + 27*K2 - 24*K3 + 6*K4)*h/8);
      K6 = f_user(t + 2*h/3, y + (221*K1 - 981*K2 + 867*K3 - 102*K4 + K5)*h/9);
      K7 = f_user(t + 5*h/6, y + (-183*K1 + 678*K2 - 472*K3 - 66*K4 + 80*K5 + 3*K6)*h/48);
      K8 = f_user(t + h, y + (716*K1 - 2079*K2 + 1002*K3 + 834*K4 - 454*K5 - 9*K6 + 72*K7)*h/82);
    
      y = y + h*(41*K1 + 216*K3 + 27*K4 + 272*K5 + 27*K6 + 216*K7 + 41*K8)/840;
      t = t + h;

      tt(i+1) = t;
      yy(i+1) = y;
   end

    // --- atualiza a caixa de status ---
    linha1 = ' Passos calculados: ' + string(n)+ '. ';
    linha2 = ' Instante final atingido: t = ' + string(tt($))+ '. ';
    linha3 = ' y(tf) = ' + string(yy($));
    [ymax, tmax] = max(yy);
    tmax = tt(tmax);
    linha4 = ' y(max) = '+string(ymax)+', tmax = '+string(tmax);
    handles.status2.string = linha3;
    handles.status3.string = linha2;
    handles.status4.string = linha1;
    handles.status1.string = linha4;
    
    // --- plota o resultado em uma nova janela ---
    figure;
    plot(tt, yy, 'b-','thickness',2);
    xlabel('tempo','fontsize',4);
    ylabel('y(t)','fontsize',4);
    title('dy/dt = ' + eq_str + '   --  (RK-6,  h = ' + string(h) + ')',...
    'fontsize',4,'color','blue');
    xgrid;
    // Obtém o handle da figura atual
    fig = gcf();
    set(fig, 'background', 8);

endfunction

// --------------------------------------------
// Lanca a interface ao executar o script
// --------------------------------------------
clc; close; // limpa o console e fecha alguma janela
rk6_gui();
 
**********************************
****************
******
***
 *

Nenhum comentário:

Postar um comentário