How to access nested values from Python

11 views (last 30 days)
Franz-Josef Siegemund
Franz-Josef Siegemund on 27 Jan 2021
Answered: surya venu on 19 Apr 2024
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

Answers (1)

surya venu
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.

Tags

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!