plant.py
# Copyright (c) 2016 Konstantinos G. Papdopoulos. All rights reserved.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v1.0 which accompanies this distribution,
# and is available at http://www.eclipse.org/legal/epl-v10.html
from collections import defaultdict
from scipy.interpolate import pade
import control
import logging
import math
import matplotlib
import matplotlib.pyplot as plt
import random
class Plant:
"""
Controlled process
"""
"""
Creates a Test run object
"""
def __init__(self, args):
"""
Initializes the appropriate test component objects according to the
test_type and the test configuration json object, in order to prepare
the test for running
:param args:
:param json_conf:
:param test_type:
:type args:
:type json_conf:
:type test_type: str
"""
tzi, tpj, plantGp = self.create_plant(args)
def create_plant(self, args):
"""Creates the controlled process determined by the user input
Plant creation supports poles (max:5), zeros (max:5), time delay
:param poles
:param zeros
:param time_delay
:param user_defined_plant
:
:type
:type
:type
:type
"""
kp = random.random();
zerosOrder = args.zeros
polesOrder = args.poles
time_delay = args.time_delay
zeros = self.zerosRandomGeneration(zerosOrder)
poles = self.polesRandomGeneration(polesOrder)
tzi = self.tziDictCreate(zeros, zerosOrder)
tpj = self.tpjDictCreate(poles, polesOrder)
# time delay generation
# --------------------------------------------------------------------------
timeDelay = 100.0*random.random()
# Sort poles and zeros to identify dominant pole and dominant zeros
# ----------------------------------------------------------------------
numGp = self.createZerosCoefficients(zerosOrder, tzi)
denGp = self.createPolesCoefficients(polesOrder, tpj);
kpnumGp = [i * kp for i in numGp]
plantGp = control.tf(kpnumGp,denGp);
Gd = self.createTimeDelayPlant(timeDelay)
Gp = control.series(plantGp, Gd)
print(plantGp)
print(Gd)
print(Gp)
(T , yout) = control.step_response(plantGp)
self.plotStepResponse(T, yout, kp)
return tzi, tpj, plantGp
def tziDictCreate(self, zeros, zerosOrder):
"""
"""
zerosSorted = [];
zerosSorted = sorted(zeros, reverse=True)
tzi = {}; tzi_names = [];
if int(zerosOrder) > 0:
tzi_names = ['tz'+str(i+1) for i in range(int(zerosOrder))]
for i in range(len(tzi_names)):
tzi[tzi_names[i]] = zerosSorted[i]
return tzi
def tpjDictCreate(self, poles, polesOrder):
"""
"""
polesSorted = [];
polesSorted = sorted(poles, reverse=True)
tpj = {}; tpj_names = [];
if int(polesOrder) > 0:
tpj_names = ['tp'+str(j+1) for j in range(int(polesOrder))]
for j in range(len(tpj_names)):
tpj[tpj_names[j]] = polesSorted[j]
return tpj
def polesRandomGeneration(self, polesOrder):
"""
"""
poles = [];
# poles generation
# --------------------------------------------------------------------------
for i in range(int(polesOrder)):
if polesOrder == 0:
poles = [0]
else:
poles.append(random.random())
return poles
def zerosRandomGeneration(self, zerosOrder):
"""
"""
# zeros generation
# --------------------------------------------------------------------------
zeros = [];
for j in range(int(zerosOrder)):
if zerosOrder == 0:
zeros = [0]
else:
zeros.append(random.random())
return zeros
def createTimeDelayPlant(self, timeDelay):
"""
"""
n1 = 0
n2 = 0
n3 = pow(timeDelay,3) / 6
if timeDelay != 0:
n1 = timeDelay
n2 = pow(timeDelay,2) / 2.0
n3 = pow(timeDelay,3) / 6.0
e_exp = [1.0, 1.0/math.factorial(1.0),
(1.0/math.factorial(2)) * pow(timeDelay,2),
(1.0/math.factorial(3)) * pow(timeDelay,3),
(1.0/math.factorial(4)) * pow(timeDelay,4),
(1.0/math.factorial(5)) * pow(timeDelay,5)]
padeApproximationOrder = 20
numGd, denGd = control.pade(timeDelay, padeApproximationOrder)
Gd = control.tf(numGd, denGd)
return Gd
def createZerosCoefficients(self, zerosOrder, tzi):
"""
"""
q0 = 1 ;
print('tzi-dictionary:',tzi)
print('---------------------------------------------------------------')
q0 = 1
print('---------------------------------------------------------------')
print('---------------------------------------------------------------')
q1 = 0
q1 = sum(tzi.values());
print('---------------------------------------------------------------')
q2 = 0
for i in range(int(zerosOrder)):
for j in range(int(zerosOrder)):
if (i != j) and (i < j):
print('i:',i+1,'j:',j+1);
q2 = tzi['tz'+str(i+1)]*tzi['tz'+str(j+1)] + q2
print('q2->',q2)
print('---------------------------------------------------------------')
q3 = 0
for i in range(int(zerosOrder)):
for j in range(int(zerosOrder)):
for k in range(int(zerosOrder)):
if (i != j != k != i) and (i < j < k):
print('i:',i+1,'j:',j+1,'k:',k+1);
q3 = tzi['tz'+str(i+1)] * tzi['tz'+str(j+1)] * \
tzi['tz'+str(k+1)] + q3
print('q3->',q3)
print('---------------------------------------------------------------')
q4 = 0
for i in range(int(zerosOrder)):
for j in range(int(zerosOrder)):
for k in range(int(zerosOrder)):
for l in range(int(zerosOrder)):
if (i != j != k != l != i) and (i < j < k < l):
print('i:',i+1,'j:',j+1,'k:',k+1,'l:',l+1);
q4 = tzi['tz'+str(i+1)] * tzi['tz'+str(j+1)] * \
tzi['tz'+str(k+1)] * tzi['tz'+str(l+1)] + q4
print('q4->',q4)
print('tzi-dictionary:', tzi)
print('---------------------------------------------------------------')
numGp = [q4, q3, q2, q1, q0];
return numGp
def createPolesCoefficients(self, polesOrder, tpj):
"""
"""
pGp0 = 1
print('---------------------------------------------------------------')
pGp1 = 0
pGp1 = sum(tpj.values());
print('---------------------------------------------------------------')
pGp2 = 0
for i in range(int(polesOrder)):
for j in range(int(polesOrder)):
if (i != j) and (i < j):
print('i:',i+1,'j:',j+1);
pGp2 = tpj['tp'+str(i+1)]*tpj['tp'+str(j+1)] + pGp2
print('pGp2->',pGp2)
print('---------------------------------------------------------------')
pGp3 = 0
for i in range(int(polesOrder)):
for j in range(int(polesOrder)):
for k in range(int(polesOrder)):
if (i != j != k != i) and (i < j < k):
print('i:',i+1,'j:',j+1,'k:',k+1);
pGp3 = tpj['tp'+str(i+1)]*tpj['tp'+str(j+1)] * \
tpj['tp'+str(k+1)] + pGp3
print('pGp3->',pGp3)
print('---------------------------------------------------------------')
pGp4 = 0
for i in range(int(polesOrder)):
for j in range(int(polesOrder)):
for k in range(int(polesOrder)):
for l in range(int(polesOrder)):
if (i != j != k != l != i) and (i < j < k < l):
print('i:',i+1,'j:',j+1,'k:',k+1,'l:',l+1);
pGp4 = tpj['tp'+str(i+1)]*tpj['tp'+str(j+1)] * \
tpj['tp'+str(k+1)]*tpj['tp'+str(l+1)] + pGp4
print('pGp4->',pGp4)
print('---------------------------------------------------------------')
pGp5 = 0
for i in range(int(polesOrder)):
for j in range(int(polesOrder)):
for k in range(int(polesOrder)):
for l in range(int(polesOrder)):
for m in range(int(polesOrder)):
if (i != j != k != l != m != i) and (i < j < k < l < m):
print('i:',i+1,'j:',j+1,'k:',k+1,'l:',l+1,'m:',m+1);
pGp5 = tpj['tp'+str(i+1)]*tpj['tp'+str(j+1)] * \
tpj['tp'+str(k+1)]*tpj['tp'+str(l+1)] * \
tpj['tp'+str(m+1)] + pGp5
print('pGp5->',pGp5)
print('---------------------------------------------------------------')
print('pGp0->',pGp0)
print('pGp1->',pGp1)
print('pGp2->',pGp2)
print('pGp3->',pGp3)
print('pGp4->',pGp4)
print('pGp5->',pGp5)
denGp = [pGp5, pGp4, pGp3, pGp2, pGp1, pGp0];
return denGp
def plantRandom(self, args):
"""
"""
alpha = 0.1
pass
def plantDetermined(self, args):
"""
"""
pass
def plantAlpha(self, args):
pass
def plotStepResponse(self, T, yout, kp):
""" The method takes the vector of a step response in T, yout form plus the
dc gain kp at steady state and plot on Figure with the step response plus a
straight horizontal line based in kp
"""
kpLine = [1] * len(T)
fig, ax = plt.subplots()
ax.plot(T, yout)
kpLine = [i * kp for i in kpLine]
ax.plot(T, kpLine)
ax.set(xlabel='time (s)', ylabel='$y_{out}$',
title='Plant $G_p$ Open Loop step response')
ax.legend([ 'step response','dc-gain: kp:' + str(format(kp, '.2f'))])
plt.grid(color='k', linestyle='-.', linewidth=0.1)
plt.show()
def plantEstimation(self, poles,zeros,time_delay,user_defined_plant):
"""The method takes the real plant as an input and returns the settling
time of the plant's step response, the estimated DC gain (plant's steady
state gain, an estimation of the plant's unmodelled dynamics and the
plant transfer function [first order mode] based on the step response
measurements). All above measurements will be used as an input for
initializing the automatic tuning algorith,
Plant creation supports poles (max:5), zeros (max:5), time delay
:param poles
:param zeros
:param time_delay
:param user_defined_plant
:
:type
:type
:type
:type
"""
pass
def plantNormalize(self):
"""The method takes the real plant as an input and returns the settling
time of the plant's step response, the estimated DC gain (plant's steady
state gain, an estimation of the plant's unmodelled dynamics and the
plant transfer function [first order mode] based on the step response
measurements). All above measurements will be used as an input for
initializing the automatic tuning algorithm,
Plant creation supports poles (max:5), zeros (max:5), time delay
Plant creation supports poles (max:5), zeros (max:5), time delay
:param poles
:param zeros
:param time_delay
:param user_defined_plant
:
:type
:type
:type
:type
"""
pass