How to access nested values from Python
11 views (last 30 days)
Show older comments
Hello,
i found this old tutorial about controlling a simulink model from python:
For future reference i copy the code to here (in hopes not to infrige his copyright).
import matlab.engine
import matplotlib.pyplot as plt
class SimulinkPlant:
def __init__(self,modelName = 'plant'):
self.modelName = modelName #The name of the Simulink Model (To be placed in the same directory as the Python Code)
#Logging the variables
self.yHist = 0
self.tHist = 0
def setControlAction(self,u):
#Helper Function to set value of control action
self.eng.set_param('{}/u'.format(self.modelName),'value',str(u),nargout=0)
def getHistory(self):
#Helper Function to get Plant Output and Time History
return self.eng.workspace['output'],self.eng.workspace['tout']
def connectToMatlab(self):
print("Starting matlab")
self.eng = matlab.engine.start_matlab()
print("Connected to Matlab")
#Load the model
self.eng.eval("model = '{}'".format(self.modelName),nargout=0)
self.eng.eval("load_system(model)",nargout=0)
#Initialize Control Action to 0
self.setControlAction(0)
print("Initialized Model")
#Start Simulation and then Instantly pause
self.eng.set_param(self.modelName,'SimulationCommand','start','SimulationCommand','pause',nargout=0)
self.yHist,self.tHist = self.getHistory()
def connectController(self,controller):
self.controller = controller
self.controller.initialize()
def simulate(self):
# Control Loop
while(self.eng.get_param(self.modelName,'SimulationStatus') != ('stopped' or 'terminating')):
#Generate the Control action based on the past outputs
u = self.controller.getControlEffort(self.yHist,self.tHist)
#Set that Control Action
self.setControlAction(u)
#Pause the Simulation for each timestep
self.eng.set_param(self.modelName,'SimulationCommand','continue','SimulationCommand','pause',nargout=0)
self.yHist,self.tHist = self.getHistory()
def disconnect(self):
self.eng.set_param(self.modelName,'SimulationCommand','stop',nargout=0)
self.eng.quit()
class PIController:
def __init__(self):
#Maintain a History of Variables
self.yHist = []
self.tHist = []
self.uHist = []
self.eSum = 0
def initialize(self):
#Initialize the graph
self.fig, = plt.plot(self.tHist,self.yHist)
plt.xlim(0,10)
plt.ylim(0,20)
plt.ylabel("Plant Output")
plt.xlabel("Time(s)")
plt.title("Plant Response")
def updateGraph(self):
# Update the Graph
self.fig.set_xdata(self.tHist)
self.fig.set_ydata(self.yHist)
plt.pause(0.1)
plt.show()
def getControlEffort(self,yHist,tHist):
# Returns control action based on past outputs
self.yHist = yHist
self.tHist = tHist
self.updateGraph()
if(type(self.yHist) == float):
y = self.yHist
else:
y = self.yHist[-1][0]
# Set Point is 10
e = 10-y
self.eSum += e
u = 1*e + 0.001*self.eSum
print(y)
self.uHist.append(u)
return u
plant = SimulinkPlant(modelName="plant")
#Establishes a Connection
plant.connectToMatlab()
#Instantiates the controller
controller = PIController()
plant.connectController(controller)
#Control Loop
plant.simulate()
#Closes Connection to MATLAB
plant.disconnect()
However it seems, that the API changed and Simulink now saves it's data in out.output.
How do i access such nested values from python.
It doesn't work to just write in python:
output = self.eng.workspace['out'].output
0 Comments
Answers (1)
surya venu
on 19 Apr 2024
Hi,
You're right, trying to access "self.eng.workspace['out'].output" directly won't work because it treats 'out' as a key in the workspace dictionary and tries to access another dictionary named 'output' within it.
Here's how you can access the nested values from Python in the given scenario:
Using a Subscript
Since out seems to be a variable in the MATLAB workspace that holds a list or array, you can access its elements using a subscript. Here's the updated code:
output = self.eng.workspace['out'](1)
Hope it helps.
0 Comments
See Also
Categories
Find more on Python Client Programming in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!