Exemplo n.º 1
0
class MatlabConnector(object):
    def __init__(self):
        self.started = False
        self.matlab = None
        self.quarc = True
        self.external = True
        self.build = True
        self.external = self.quarc & self.external
        self.build = self.quarc & self.build
        self.commandBuilder = CommandBuilder()

    def connect(self):
        if self.matlab == None:
            names = matlab.engine.find_matlab()
            if not names:
                # self.matlab = matlab.engine.start_matlab()  # use matlab.engine.start_matlab('-desktop') for debug
                try:
                    future = matlab.engine.start_matlab(
                        async=True)  # use async=True in old versions
                except:
                    future = matlab.engine.start_matlab(
                        background=True)  # use background=True for async
                self.matlab = future.result()
                print("Opened new MATLAB session")
            else:
                # self.matlab = matlab.engine.connect_matlab(names[0])  # TODO: Control which shared session connect to?
                try:
                    future = matlab.engine.connect_matlab(names[0], async=True)
                except:
                    future = matlab.engine.connect_matlab(names[0],
                                                          background=True)
                self.matlab = future.result()
                print("Connected to existing MATLAB session: " + names[0])

    def stop(self):
        self._stop(self.model['name'])

    def disconnect(self):
        self._stop(self.model['name'])
        self._close_system(self.model['name'])
        self._exitThis()

    def set(self, variables, values):
        if isinstance(variables, list):
            size = len(variables)
            for i in range(size):
                try:
                    name, value = variables[i], values[i]
                    tomodelworkspace = self.commandBuilder.to_model_workspace(
                        name, value)
                    try:
                        self.matlab.eval(tomodelworkspace,
                                         async=True,
                                         nargout=0)
                    except:
                        self.matlab.eval(tomodelworkspace,
                                         background=True,
                                         nargout=0)
                except:
                    pass
        else:
            try:
                name, value = variables, values
                tomodelworkspace = self.commandBuilder.to_model_workspace(
                    name, value)
                try:
                    self.matlab.eval(tomodelworkspace, async=True, nargout=0)
                except:
                    self.matlab.eval(tomodelworkspace,
                                     background=True,
                                     nargout=0)
            except:
                pass
        self._update(self.model['name'])

    def get(self, variables):
        future_value = {}
        variables_names = []
        variables_values = []
        if self.external:
            data = self.qtcpc.read(variables)
            for name in variables:
                try:
                    variables_names.append(name)
                    variables_values.append(data[name])
                except:
                    pass
        else:
            for name in variables:
                try:
                    if name == "SimulationTime":
                        try:
                            future_value[name] = self.matlab.get_param(
                                self.model['name'], name, background=True)
                        except:
                            future_value[name] = self.matlab.get_param(
                                self.model['name'], name, async=True)
                    else:
                        try:
                            future_value[name] = self.matlab.eval(
                                name + '.InputPort(1).Data', background=True)
                        except:
                            future_value[name] = self.matlab.eval(
                                name + '.InputPort(1).Data', async=True)
                except:
                    pass
            for name in variables:
                try:
                    variables_names.append(name)
                    if name == "SimulationTime":
                        variables_values.append(future_value[name].result())
                    else:
                        variables_values.append(future_value[name].result())
                except:
                    pass
        return np.array([variables_names, variables_values]).tolist()

    def open(self, path):
        """"
        Open a Simulink model
        """
        try:
            dirname = os.path.dirname(path)
            filename = os.path.basename(path)
            modelname = os.path.splitext(filename)[0]
            self.model = {
                'path': dirname,
                'file': filename,
                'name': modelname,
            }
            version = self.matlab.version('-release')
            if version >= '2018b':
                self.matlab.eval('Simulink.sdi.setAutoArchiveMode(false);',
                                 nargout=0)
                self.matlab.eval('Simulink.sdi.setArchiveRunLimit(0);',
                                 nargout=0)
            self._load(self.model)
            self._settime(self.model['name'])
            self._getmodelworkspace(self.model['name'])
            self._buildandconnect(self.model['name'])  # for quarc only
        except:
            print("Could not open simulink model " + path)

    def close_system(self):
        self._close_system(self.model['name'])

    def exit(self):
        self._exitThis()

    def _load(self, model):
        version = self.matlab.version('-release')
        self.matlab.cd(model['path'])
        autosavedfile = model['file'] + '.autosave'
        cachedfile = model['file'] + 'c'
        if version >= '2017b':
            if self.matlab.isfile(autosavedfile):
                self.matlab.delete(autosavedfile, nargout=0)
            if self.matlab.isfile(cachedfile):
                self.matlab.delete(cachedfile, nargout=0)
        else:
            if self.matlab.exist(autosavedfile, 'file') == 2:
                self.matlab.delete(autosavedfile, nargout=0)
            if self.matlab.exist(cachedfile, 'file') == 2:
                self.matlab.delete(cachedfile, nargout=0)
        if version >= '2018b':
            if not self.matlab.slreportgen.utils.isModelLoaded(model['name']):
                self.matlab.load_system(model['file'])
        else:
            self.matlab.load_system(model['file'])
        print("Loaded Simulink model")

    def _getmodelworkspace(self, model):
        getmodelworkspace = self.commandBuilder.get_model_workspace(model)
        self.matlab.eval(getmodelworkspace, nargout=0)

    def _settime(self, model):
        self.matlab.set_param(model, "StartTime", "0", nargout=0)
        self.matlab.set_param(model, "StopTime", "inf", nargout=0)
        self.matlab.set_param(model, 'SolverType', 'Fixed-step', nargout=0)
        if not self.external:
            self.matlab.set_param(model, 'FixedStep', '0.06', nargout=0)

    def start(self):
        if self.quarc:
            if self.external:
                self.matlab.qc_set_simulation_mode(self.model['name'],
                                                   'external',
                                                   nargout=0)
            else:
                self.matlab.qc_set_simulation_mode(self.model['name'],
                                                   'normal',
                                                   nargout=0)
            self.matlab.qc_start_model(self.model['name'],
                                       async=True,
                                       nargout=0)
        else:
            try:
                self.matlab.qc_set_simulation_mode(self.model['name'],
                                                   'normal',
                                                   nargout=0)
            except:
                pass
            self.matlab.set_param(self.model['name'],
                                  "SimulationCommand",
                                  "start",
                                  async=True,
                                  nargout=0)
        self.started = True

    def creatertos(self, readables):
        if self.external:
            self.qtcpc = QuarcTCPClient(18000)
            self.qtcpc.config(
                ['double'] *
                len(readables))  # TODO: Add support for other data types
        else:
            for readable in readables:
                if readable != "SimulationTime":
                    try:
                        self.matlab.eval(readable + "=get_param('" +
                                         self.model['name'] + "/" + readable +
                                         "', 'RuntimeObject');",
                                         async=True,
                                         nargout=0)
                    except:
                        self.matlab.eval(readable + "=get_param('" +
                                         self.model['name'] + "/" + readable +
                                         "', 'RuntimeObject');",
                                         background=True,
                                         nargout=0)

    def _pause(self, model):
        self.matlab.set_param(model, "SimulationCommand", "pause", nargout=0)

    def ispaused(self):
        return self.matlab.get_param(self.model['name'], "SimulationStatus")

    def _buildandconnect(self, model):
        self.matlab.set_param(model, 'AccelVerboseBuild', 'off', nargout=0)
        self.matlab.save_system(model, nargout=0)
        try:
            if self.external:
                if self.build:
                    self.matlab.qc_build_model(model, nargout=0)
                    print("Quarc model has been built")
                if not self.matlab.qc_is_model_loaded(model):
                    self.matlab.qc_download_model(model, nargout=0)
                    print("Quarc model downloaded in target")
                    self.matlab.qc_load_model(model, nargout=0)
                    print("Quarc model loaded in target")
                self.matlab.qc_connect_model(model, nargout=0)
                print("Simulink model connected to quarc target")
        except:
            pass

    def _update(self, model):
        if self.external:
            try:
                self.matlab.qc_update_model(model, async=True, nargout=0)
            except:
                self.matlab.qc_update_model(model, background=True, nargout=0)
        else:
            try:
                self.matlab.set_param(model,
                                      "SimulationCommand",
                                      "update",
                                      async=True,
                                      nargout=0)
            except:
                self.matlab.set_param(model,
                                      "SimulationCommand",
                                      "update",
                                      background=True,
                                      nargout=0)

    def resume(self):
        try:
            self.matlab.set_param(self.model['name'],
                                  "SimulationCommand",
                                  "continue",
                                  async=True,
                                  nargout=0)
        except:
            self.matlab.set_param(self.model['name'],
                                  "SimulationCommand",
                                  "continue",
                                  background=True,
                                  nargout=0)

    def _stop(self, model):
        if self.external:
            self.qtcpc.close()
            self.matlab.qc_stop_model(model)
            self.matlab.qc_connect_model(model, nargout=0)
        else:
            self.matlab.set_param(model,
                                  "SimulationCommand",
                                  "stop",
                                  nargout=0)
        self.started = False

    def _close_system(self, model):
        self.matlab.close_system(model)

    def _exitThis(self):
        self.qtcpc.close()
        self.matlab.quit()