TransferFunctionToStateSpace.py 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. import numpy as np
  2. import csv
  3. # Read data containing de coëfficients of the numerator and denominator of a transfer function.
  4. def ReadData(filepath):
  5. with open(filepath, 'r') as file:
  6. AllData = list(csv.reader(file, delimiter=';'))
  7. num = [float(i) for i in AllData[0]]
  8. denom = [float(i) for i in AllData[1]]
  9. # We fill coëfficients for the highest powers with zeros
  10. # if one of the list contains less elements than the other.
  11. if len(num) > len(denom):
  12. for i in range(len(denom), len(num)):
  13. denom.append(0)
  14. else:
  15. for i in range(len(num), len(denom)):
  16. num.append(0)
  17. return num, denom
  18. #[1] These methods convert a transfer function to a state-space model in controller canonical form
  19. # using the method described by Smith, J.O., Introduction to Digital Filters.
  20. # [Online] http://ccrma.stanford.edu/~jos/filters/, Sept. 2005, online book. Accessed in April 2020.
  21. # We extract a delay-free path to find the feedthrough gain
  22. # used as the direct-path coëfficient in the state-space model
  23. def ExtractDelayFreePath(num, denom):
  24. if num[0] == 0:
  25. return num, denom
  26. else:
  27. for i in range(len(num) - 1):
  28. num[i] = num[i] - num[-1] * denom[i]
  29. return num, denom
  30. # We construct the state-space matrices from the transfer function.
  31. def FillMatrices(num, denom):
  32. order = len(num) - 1
  33. A = np.zeros((order, order))
  34. B = np.zeros(order)
  35. C = np.zeros(order)
  36. D = num[0]
  37. # We construct a model in the controller canonical form defined in [1].
  38. for i in range(order):
  39. A[0][i] = -denom[order - i - 1]
  40. if i > 0:
  41. A[i][i-1] = 1
  42. C[i] = num[order - i - 1]
  43. B[0] = 1
  44. return A, B, C, D
  45. # Converts a transfer function to state-space model.
  46. def ConvertToStateSpace(num=None, denom=None, filepath=None):
  47. if filepath != None:
  48. num, denom = ReadData(filepath)
  49. if num.all() == None or denom.all() == None:
  50. print("Numerator or denominator not assigned.")
  51. num, denom = ExtractDelayFreePath(num, denom)
  52. return FillMatrices(num, denom)