Repository: sympy/sympy (python)

Issue:
Symbolic conversion of transfer function to state-space model looks incorrect

I'm trying out the new [control module](https://docs.sympy.org/latest/modules/physics/control/lti.html) and a bit puzzled by the output of this symbolic conversion of a transfer function to a continuous-time state-space model:

```python
import sympy
from sympy.physics.control.lti import StateSpace, TransferFunction

s, K, T1 = sympy.symbols('s, K, T1')
G = TransferFunction(K, T1 * s + 1, s)
print(G)
Gss = G.rewrite(StateSpace)
print(Gss)
```

Output:
```none
TransferFunction(K, T1*s + 1, s)
StateSpace(Matrix([[-1/T1]]), Matrix([[1]]), Matrix([[K]]), Matrix([[0]]))
```

When I simulated this I got a steady-state gain 3 times higher than K. So I would have expected for example, the C matrix to be `Matrix([[K/T1]])` not `Matrix([[K]])`, or some similar adjustment to the B matrix.

If I plug some numbers into Python Control I get a result consistent with my expectation:
```python
import control as con

K = 2
T1 = 3
G = con.tf(K, [T1, 1])
print(G)
Gss = con.ss(G)
print(Gss)
```

Output:
```none
<TransferFunction>: sys[14]
Inputs (1): ['u[0]']
Outputs (1): ['y[0]']


   2
-------
3 s + 1

<StateSpace>: sys[14]
Inputs (1): ['u[0]']
Outputs (1): ['y[0]']
States (1): ['x[0]']

A = [[-0.33333333]]

B = [[1.]]

C = [[0.66666667]]

D = [[0.]]

```

I'm using `sympy.__version__` 1.13.0


Patch:
diff --git a/.mailmap b/.mailmap
index 068c7812cbbe..00397fbf108e 100644
--- a/.mailmap
+++ b/.mailmap
@@ -343,6 +343,8 @@ Anjul Kumar Tyagi <anjul.ten@gmail.com>
 Ankit Agrawal <aaaagrawal@iitb.ac.in>
 Ankit Kumar Singh <ankitdiswar10@gmail.com>
 Ankit Raj Pandey <pandeyan@grinnell.edu> Ankit Pandey <pandeyan@grinnell.edu>
+Annamalai N <srirammount@gmail.com> Annamalai <91740832+RaMathuZen@users.noreply.github.com> 
+Annamalai N <srirammount@gmail.com> ramathuzen <srirammount@gmail.com>
 Ansh Mishra <anshmishra471@gmail.com>
 Anshul Sharma <anshulsharma4605@gmail.com>
 Anthony Scopatz <scopatz@gmail.com>
diff --git a/sympy/physics/control/lti.py b/sympy/physics/control/lti.py
index f402b44adf25..864cd29351fa 100644
--- a/sympy/physics/control/lti.py
+++ b/sympy/physics/control/lti.py
@@ -1456,13 +1456,29 @@ def _StateSpace_matrices_equivalent(self):
 
         num_coeffs = num_poly.all_coeffs()
         den_coeffs = den_poly.all_coeffs()
+
+        if n == 0:
+            return (
+                Matrix([zeros(1)]),
+                Matrix([zeros(1)]),
+                Matrix([zeros(1)]),
+                Matrix([num_coeffs[0] / den_coeffs[0]]),
+            )
+
+        if self.num == self.den:
+            return (
+                Matrix([zeros(1)]), Matrix([zeros(1)]), Matrix([zeros(1)]), Matrix([1])
+            )
+
         diff = n - num_poly.degree()
         num_coeffs = [0]*diff + num_coeffs
 
         a = den_coeffs[1:]
-        a_mat = Matrix([[(-1)*coefficient/den_coeffs[0] for coefficient in reversed(a)]])
-        vert = zeros(n-1, 1)
-        mat = eye(n-1)
+        a_mat = Matrix(
+            [[(-1) * coefficient / den_coeffs[0] for coefficient in reversed(a)]]
+        )
+        vert = zeros(n - 1, 1)
+        mat = eye(n - 1)
         A = vert.row_join(mat)
         A = A.col_join(a_mat)
 
@@ -1472,11 +1488,11 @@ def _StateSpace_matrices_equivalent(self):
         i = n
         C = []
         while(i > 0):
-            C.append(num_coeffs[i] - den_coeffs[i]*num_coeffs[0])
+            C.append(num_coeffs[i]/den_coeffs[0] - den_coeffs[i]*num_coeffs[0]/(den_coeffs[0]**2))
             i -= 1
         C = Matrix([C])
 
-        D = Matrix([num_coeffs[0]])
+        D = Matrix([num_coeffs[0]/den_coeffs[0]])
 
         return A, B, C, D
 


Test patch:
diff --git a/sympy/physics/control/tests/test_lti.py b/sympy/physics/control/tests/test_lti.py
index 2b867a323f33..87ea26921d4a 100644
--- a/sympy/physics/control/tests/test_lti.py
+++ b/sympy/physics/control/tests/test_lti.py
@@ -25,7 +25,7 @@
     TransferFunctionMatrix, MIMOSeries, MIMOParallel, MIMOFeedback, StateSpace,
     DiscreteStateSpace, create_state_space, gbt, bilinear, forward_diff,
     backward_diff, phase_margin, gain_margin)
-from sympy.testing.pytest import raises
+from sympy.testing.pytest import raises, XFAIL
 from sympy.logic.boolalg import false, true
 
 from math import isclose
@@ -38,6 +38,35 @@
 TF1 = TransferFunction(1, s**2 + 2*zeta*wn*s + wn**2, s)
 TF2 = TransferFunction(k, 1, s)
 TF3 = TransferFunction(a2*p - s, a2*s + p, s)
+TF4 = TransferFunction(k*s + p, tau*s + 1, s)
+TF5 = TransferFunction(k, p, s)
+TF6 = TransferFunction(k*s + p, k*s + p, s)
+
+
+@XFAIL
+def test_state_space_rewrite_from_pr_27651():
+    c0, c1, c2 = symbols('c0, c1, c2', real=True)
+    a0, a1, a2, a3 = symbols('a0, a1, a2, a3', real=True)
+    d = symbols('d', real=True)
+    s = symbols('s')
+    t = TransferFunction(d, 1, s) + TransferFunction(c2*s**2 + c1*s**1 + c0,
+                                                     s**4 + a3*s**3 + a2*s**2 +
+                                                     a1*s**1 + a0, s)
+    expected = StateSpace(
+        Matrix([[0,   1,   0,   0],
+                [0,   0,   1,   0],
+                [0,   0,   0,   1],
+                [-a0, -a1, -a2, -a3]]),
+        Matrix([[0],
+                [0],
+                [0],
+                [1]]),
+        Matrix([[c0, c1, c2, 0]]),
+        Matrix([[d]]))
+
+    # The call to Parallel.doit() is not working correctly.
+    assert t.rewrite(StateSpace).doit() == expected
+    assert t.rewrite(StateSpace).doit() == t.doit().rewrite(StateSpace)
 
 
 def test_create_transfer_function():
@@ -3485,6 +3514,21 @@ def test_conversion():
                    Matrix([[0]]))
     assert SS.rewrite(TransferFunction)[0][0] == TF1
 
+    SS1 = TF4.rewrite(StateSpace)
+    assert SS1 == \
+        StateSpace(Matrix([[-1/tau]]), Matrix([[1]]), Matrix([[-k/tau**2 + p/tau]]),
+                   Matrix([[k/tau]]))
+    assert SS1.rewrite(TransferFunction)[0][0] == TF4
+
+    SS2 = TF5.rewrite(StateSpace)
+    assert SS2 == \
+        StateSpace(Matrix([[0]]), Matrix([[0]]), Matrix([[0]]), Matrix([[k/p]]))
+    assert SS2.rewrite(TransferFunction)[0][0] == TF5
+
+    SS3 = TF6.rewrite(StateSpace)
+    assert SS3 == \
+        StateSpace(Matrix([[0]]), Matrix([[0]]), Matrix([[0]]), Matrix([[1]]))
+
     # TransferFunction cannot be converted to DiscreteStateSpace
     raises(TypeError, lambda: TF1.rewrite(DiscreteStateSpace))