Skip to content

frequency_response() returns incorrect response  #860

@NilsLG

Description

@NilsLG

Hey,
I'm currently running version 0.9.2 and face some issues with the frequency_response() function with rather complex TransferFunctions. In my minimal working example, I create a MIMO system from state-space matrices with 24 in- and 18 outputs. In the next step, I extracted two transfer functions (H&P) and performed a simple calculation with both to create a new TF (Hcl). Using frequency_response() function on both the original TFs I get the expected result. For the new TF Hcl however, the response looks very messy in magnitude as well as in phase.

To get a short time fix, I took the frequency response of the original functions, converted magnitude and phase into a complex number and redid the calculation, which returned a the expected form of Hcl, as seen in the plot below.

image

The code i used is the following:

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import control

# Importing State-Space matrices and check if dimensions are correct
ssAspoiler = np.loadtxt(open('ssA_spoiler.csv', 'rb'), delimiter=',')
ssB = np.loadtxt(open('ssB.csv', 'rb'), delimiter=',')
ssC = np.loadtxt(open('ssC.csv', 'rb'), delimiter=',')
ssD = np.loadtxt(open('ssD.csv', 'rb'), delimiter=',')

print('dim(A) =', np.shape(ssAspoiler))
print('dim(B) =', np.shape(ssB))
print('dim(C) =', np.shape(ssC))
print('dim(D) =', np.shape(ssD))

# Define Frequency Array
Frequency_Array = np.linspace(0.1, 100, int(1e5))
Omega_Array = Frequency_Array * (2*np.pi)

# Create State-Space System 
sys = control.StateSpace(ssAspoiler, ssB, ssC, ssD)
TF = control.ss2tf(sys)

# Choose in- and outputs
i1 = 0
i2 = 6
o = 12

# Extract TFs from State-Space System
H = control.TransferFunction(TF.num[o][i1], TF.den[o][i1])
P = control.TransferFunction(TF.num[o][i2], TF.den[o][i2])

# Calculating (closed loop) TF from existing TF's 
Hcl = H / (1 + P)

# Compute frequency_response() of all TF from above
mag_H, phase_H, _ = control.frequency_response(H, Omega_Array)
mag_P, phase_P, _ = control.frequency_response(P, Omega_Array)
mag_Hcl, phase_Hcl, _ = control.frequency_response(Hcl, Omega_Array)

# Try different way to get proper frequency response of Hcl
P_comp = mag_P * np.exp(1j*phase_P)
H_comp = mag_H * np.exp(1j*phase_H)

Hcl_comp = (H_comp) / (1 + P_comp)

# Plot frequency responses
plt.figure(dpi = 150, figsize = (10, 6))
plt.loglog(Frequency_Array, mag_Hcl, color = 'k', label = 'Hcl from frequency_reponse()')
plt.loglog(Frequency_Array, np.abs(Hcl_comp), linewidth = .75, color = 'r', label = 'Hcl from complex calcs')
plt.loglog(Frequency_Array, mag_H, label = 'H', linewidth = .75)
plt.loglog(Frequency_Array, mag_P, label = 'P', linewidth = .75)
plt.grid(True, which = 'both')
plt.xlabel('Frequency [Hz]')
plt.ylabel('Magnitude')
plt.legend(loc = 'lower left')
plt.show()

Since I want to use control.feedback() later on as well, this problem is especially problematic, since it also appears there.
Unfortunately, I can't pinpoint where this problem originates from, so I am hoping you might understand the reasons behind that. For completeness, I also attached the .txt files with the state-space matrices.

EDIT: I should mention, that I don't see this kind of behaviour for simple transfer functions.

ssD.csv
ssC.csv
ssB.csv
ssA_spoiler.csv

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions