Search code examples
mathoctavesympysymbolic-math

How to tell GNU Octave Symbolic (SymPy) to have one variable with only scalar 1?


I'm using GNU Octave with Symbolic (SymPy) and I want all s^2 should have scalar 1.

% Load packet
pkg load symbolic

% Symbolic
syms Vin Vout dVout ddVout R C Rf R1

A = 1 + Rf/R1;
eq = Vin == Vout/A + R*C*1/A*dVout + R*(C*1/A*dVout + C*((1/A*dVout + R*C*1/A*ddVout)- dVout));

% More symbolic
syms U s Y
eq2 = subs(eq, {Vin, Vout, dVout, ddVout}, {U, Y, Y*s, Y*s^2});
eq3 = expand(eq2);

% Transfer function G = Y/U
G = simplify(solve(eq3, Y)/U)

Output:

G = (sym)

                  R1 + Rf
  ----------------------------------------
   2  2     2
  C *R *R1*s  + 2*C*R*R1*s - C*R*Rf*s + R1

If you run that code above, you will get a transfer function G of second order. But it's not on the second order standard form.

The standard form requries that s^2 have a scalar one. Then I can compute the rest of greek letters.

enter image description here

Question:

Is it possible in GNU Octave Symbolic (SymPy) to tell that s^2 should have scalar 1?


Solution

  • With symbolic computations there are many ways to achieve the same simplification. Having said that, I'm not familiar with Octave. Looking at the symbolic package documentation it appears that it lacks many many Sympy's function that are exposed on Python. However, by looking at the package source code, it is relatively quick to implement them. So, we are going to implement a couple of them:

    pkg load symbolic
    
    function y = collect(expr, t)
    % Collects common powers of a term in an expression.
    
      cmd = 'return sp.collect(*_ins),';
    
      y = pycall_sympy__ (cmd, expr, t);
    
    end
    
    function [num, den] = fraction(expr)
    % Returns a pair with expression’s numerator and denominator.
    
      cmd = 'return sp.fraction(*_ins),';
    
      y = pycall_sympy__ (cmd, expr);
      num = y{1,1}
      den = y{1,2}
    
    end
    

    Now we can apply them to our use case:

    % retrieve the numerator and denominator of G
    [num, den] = fraction(G)
    % num = (sym) R₁ + Rf
    % den = (sym)
    % 
    %    2  2     2
    %   C ⋅R ⋅R₁⋅s  + 2⋅C⋅R⋅R₁⋅s - C⋅R⋅Rf⋅s + R₁
    
    % Let's modify the denominator
    den_mod = collect(expand(den / (C^2 * R^2 * R1)), s)
    % In the previous command:
    % 1. we divide "den" by (C^2 * R^2 * R1)
    % 2. we expand the expression so that the division gets executed term by term.
    %    At this points, the term containing "s^2" will have a coefficient of 1.
    % 3. we collect the terms having a common "s".
    % Output:
    % den_mod = (sym)
    % 
    %    2     ⎛ 2      Rf  ⎞     1
    %   s  + s⋅⎜─── - ──────⎟ + ─────
    %          ⎝C⋅R   C⋅R⋅R₁⎠    2  2
    %                           C ⋅R
    %
    
    % Now we simply reconstruct G. Since we divided "den" by (C^2 * R^2 * R1)
    % we also have to divide "num" by the same amount
    G_mod = num / (C^2 * R^2 * R1) / den_mod
    % G_mod = (sym)
    % 
    %                   R₁ + Rf
    %   ────────────────────────────────────────
    %    2  2    ⎛ 2     ⎛ 2      Rf  ⎞     1  ⎞
    %   C ⋅R ⋅R₁⋅ ⎜s  + s⋅⎜─── - ──────⎟ + ─────⎟
    %            ⎜       ⎝C⋅R   C⋅R⋅R₁⎠    2  2⎟
    %            ⎝                        C ⋅R ⎠