pid_base.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. from core.utils import *
  2. import os
  3. '''
  4. base discrete/takahashi PID controller
  5. '''
  6. class BasePID:
  7. def __init__(self, target, clip_min, clip_max, controller_type, kp=0, ki=0, kd=0, dt=1, Kc=0, Ti=0, Td=0, Ts=0, debug=False, type='base', swap_error_fn=False):
  8. self.Kp = kp # discrete pid kp
  9. self.Ki = ki # discrete pid ki
  10. self.Kd = kd # discrete pid kd
  11. self.T = dt # discrete pid frequency time.
  12. self.Ti = Ti # takahashi ti
  13. self.Td = Td # takahashi td
  14. self.Ts = Ts # takahashi ts
  15. self.Kc = Kc # takahashi kc
  16. self.target = target # pid set point, target
  17. self.prev_feedback = 0
  18. self.feedback_hist = [0, 0]
  19. self.output_hist = [0]
  20. self.error_hist = [0, 0]
  21. self.debug=debug
  22. self.clip_min = clip_min
  23. self.clip_max = clip_max
  24. self.controller_type = CONTROLLER_TYPE_DISCRETE
  25. self.swap_error_fn = swap_error_fn
  26. self.type = type
  27. def continuous_pid(self, feedback):
  28. ret = (self.Kp * self.proportional(feedback)) + (self.Ki * self.integral(feedback)) + (self.Kd * self.derivative(feedback))
  29. self.feedback_hist+=[feedback]
  30. self.prev_feedback=feedback
  31. return ret
  32. def discrete_pid(self, feedback, debug=True):
  33. k1 = self.Kp + self.Ki + self.Kd
  34. k2 = -1 * self.Kp - 2 * self.Kd
  35. k3 = self.Kd
  36. err = self.proportional(feedback)
  37. ret = self.output_hist[-1] + k1 * err + k2 * self.error_hist[-1] + k3 * self.error_hist[-2]
  38. self.error_hist+=[err]
  39. self.feedback_hist+=[feedback]
  40. return ret
  41. def zero_feedback_hist(self):
  42. count = 0
  43. length = len(self.feedback_hist)
  44. for i in range(0,length):
  45. if self.feedback_hist[length-(i+1)]==0:
  46. count+=1
  47. else:
  48. return count
  49. return count
  50. def takahashi(self, feedback, debug=True):
  51. err = self.proportional(feedback)
  52. ret = self.output_hist[-1] + self.Kc * (self.feedback_hist[-1] - feedback + self.Ts * err/ self.Ti + self.Td / self.Ts * (2*self.feedback_hist[-1] - feedback - self.feedback_hist[-2]))
  53. self.error_hist+=[err]
  54. self.feedback_hist+=[feedback]
  55. return ret
  56. def pid_clipped(self, feedback, debug=True):
  57. pid_value = None
  58. if self.controller_type == CONTROLLER_TYPE_TAKAHASHI:
  59. pid_value = self.takahashi(feedback, debug)
  60. elif self.controller_type == CONTROLLER_TYPE_DISCRETE:
  61. pid_value = self.discrete_pid(feedback, debug)
  62. else:
  63. pid_value = self.continuous_pid(feedback)
  64. if pid_value <= self.clip_min:
  65. pid_value = self.clip_min
  66. if pid_value >= self.clip_max:
  67. pid_value = self.clip_max
  68. if self.integral(feedback) == 0 and len(self.feedback_hist) >=3 and self.feedback_hist[-1] == 0 and self.feedback_hist[-2] == 0 and self.feedback_hist[-3] == 0:
  69. pid_value = 0.9**self.zero_feedback_hist()
  70. self.output_hist+=[pid_value]
  71. return pid_value
  72. def error(self, feedback):
  73. if self.swap_error_fn:
  74. # maintain positive proportional gains
  75. return self.target - feedback
  76. else:
  77. return feedback - self.target
  78. def proportional(self, feedback):
  79. return self.error(feedback)
  80. def integral(self, feedback):
  81. return sum(self.feedback_hist[-10:]) + feedback
  82. def derivative(self, feedback):
  83. return (self.error(self.prev_feedback) - self.error(feedback)) / self.T
  84. def write_feedback(self, feedback_hist_file):
  85. if len(self.feedback_hist)==0:
  86. return
  87. buf = ''
  88. buf+=str(self.feedback_hist[0])
  89. buf+=','
  90. for i in self.feedback_hist[1:]:
  91. buf+=str(i)+','
  92. with open(feedback_hist_file, "w+") as f:
  93. f.write(buf)
  94. def write_fval(self, output_hist_file):
  95. if len(self.output_hist)==0:
  96. return
  97. buf = ''
  98. buf+=str(self.output_hist[0])
  99. buf+=','
  100. for i in self.output_hist[1:]:
  101. buf+=str(i)+','
  102. with open(output_hist_file, "w+") as f:
  103. f.write(buf)
  104. def write(self, feedback_hist_file='_feedback.hist', output_hist_file='_output.hist'):
  105. self.write_feedback('log' + os.sep + self.type+feedback_hist_file)
  106. self.write_fval('log'+ os.sep + self.type+output_hist_file)
  107. def acc(self):
  108. return sum(np.array(self.feedback_hist)==1)/float(len(self.feedback_hist))
  109. def acc_percentage(self):
  110. return self.acc() * 100