【问题标题】:Controlling a matlab script (Pause, Reset)控制 matlab 脚本(暂停、重置)
【发布时间】:2011-07-03 12:40:27
【问题描述】:

我正在尝试创建一个由外部 VBA 脚本控制的 matlab 脚本(m 文件)。

对于一定数量的循环,matlab 脚本每次都应执行相同的操作(即使参数更改,但在这种情况下不是问题)。 如果我没看错,我可以像这样在 VBA 中使用 matlab funktions:http://www.mathworks.de/help/techdoc/matlab_external/f135590.html#f133975

我的主要问题是如何实现这个问题的matlab部分......目前我的控制部分看起来像这样:

start.m:

run = 1;
reset = 0;
while run ~= 0     % Loop until external reset of 'run' to '0'
    if reset ~= 0
        doReset();   % Reset the parameters for the processing
        reset = 0;
        disp('I did a reset');
    end

    disp('I am processing');
    doProcess();
    pause(1)
end
disp('I am done');

重置部分在通过脚本更改值时工作得很好,但是当我手动尝试将“运行”或“重置”的值更改为工作区中的任何其他值时,什么也没有发生……我的脚本没有'不要中止,重置也没有 - 如果它有效...... 在我看来,脚本无法识别工作区中的任何更改?!

稍后变量 'run' 和 'reset' 将由 VBA 脚本设置或取消设置。 为什么我不能手动中止循环,有什么合理的理由吗?

感谢您的建议!

你好,波斯克伦

编辑:

似乎脚本在开始之前加载了一次变量,并且在运行时不再加载...是否有可能显式访问工作区变量?

编辑 2:

我目前使用 Matlab 2010b,没有额外的工具箱

编辑 3:

我发现,Matlab 中有几个“工作区”或 RAM。如果我的函数正在运行,则变量存储在“base”(?)工作区中,这不是您可以单击并更改每个值的 matlab 工作区。所以我必须访问这个不祥的“基地”空间并将“运行”标志更改为零。

【问题讨论】:

  • r.e.编辑 3:没有什么不祥的,函数有自己的变量堆栈,工作空间另一个(你不希望用户函数改变你的工作空间变量,反之亦然!)。如果您需要跨工作区和用户函数全局访问变量,请在工作区和您使用的任何函数中使用 global 关键字,即 global run -- mathworks.com/help/techdoc/matlab_prog/f0-38052.html#f0-38470 -- 这是假设你的循环没有阻塞外部接口...
  • @Edit 3:有这样一个函数:assigning非常不推荐。
  • @Juhl:为什么这个功能非常不推荐?我认为没有任何反对意见 O.o
  • 它的行为方式与全局变量几乎相同,并且通过在 others 工作空间中声明变量更进一步。如果您正在破解,使用它没问题,但是在将它用于大型程序等时我会意识到它。

标签: matlab loops controls


【解决方案1】:

我认为您的问题只是您的循环阻止了外部接口的执行。循环运行时,您无法访问其他接口。

我想做类似的事情——允许外部程序(Ruby 或其他 matlab 实例)控制 matlab 循环。迄今为止最灵活的解决方案是使用 UDP。有一个很棒的工具箱叫做 PNET for matlab,我认为 VB 也必须有一个套接字库。我只是在两边都开一个UDP端口,用简单的文本命令来控制和反馈。

obj.conn = pnet('udpsocket', 9999);
command = '';
while run ~= 0
    nBytes = pnet(obj.conn, 'readpacket');
    if nBytes > 0
        command = pnet(obj.conn, 'read', nBytes, 'string');
    end
    switch command
        case '--reset--'
            doReset();   % Reset the parameters for the processing
            reset = 0;
            disp('I did a reset');
        case '--abort--'
            run = 0;
            disp('Going to abort');
        case '--echo--'
            pnet(obj.conn, 'write', '--echo--');
            pnet(obj.conn, 'writepacket', remoteAddress, remotePort);
    end
    doProcess();
end

这样我可以构建自己的可扩展控制界面,而不必担心循环阻塞,它可以跨平台和跨语言工作,可以在机器内或跨网络工作。

更新: 要在两个 UDP 客户端之间进行通信,您需要设置两个免费的 UDP 端口,它们都是客户端(这个例子都是在 matlab 中,假设 obj 这里是一个结构,在我的例子中,它是一个我包装 pnet 功能的类):

obj = struct();
obj.success = 0;
obj.client1Port = 9999;
obj.client2Port = 9998;
obj.client1Address = '127.0.0.1';
obj.client2Address = '127.0.0.1';
obj.conn1 = pnet('udpsocket', obj.client1Port);
obj.conn2 = pnet('udpsocket', obj.client2Port);

pnet(obj.conn1, 'write', '--echo--')
pnet(obj.conn1, 'writepacket', obj.client2Address, obj.client2Port);

nBytes = pnet(obj.conn2, 'readpacket');
if nBytes > 0
    command = pnet(obj.conn2, 'read', nBytes, 'string');
    if regexpi(command,'--echo--')
        obj.success = obj.success+1;
        fprintf('Client 2 recieved this message: %s\n',command);
        pnet(obj.conn2, 'write', '--echo--')
        pnet(obj.conn2, 'writepacket', obj.client1Address, obj.client1Port);
    end
end

nBytes = pnet(obj.conn1, 'readpacket');
if nBytes > 0
    command = pnet(obj.conn1, 'read', nBytes, 'string');
    if regexpi(command,'--echo--')
        obj.success = obj.success+1;
        fprintf('Client 1 got this back: %s\n',command);
    end
end

if obj.success == 2
    fprintf('\nWe both sent and received messages!\n');
end

【讨论】:

  • 哇,这真是太棒了。你能告诉我,我在哪里可以找到 PNET 库?似乎 Mathworks 在任何地方都没有那些完整的工具箱,但一些非官方的工具箱已经准备好加载......你能告诉我你正在使用哪个工具箱吗?
  • 是的,我使用的是 pnet,它已经从心理物理学工具箱预编译(适用于 Win、OS X 和 Linux):PTB,你可以下载它并解压目录,或者抓取 svn here -- 工具箱本身已找到 here -- 您可以使用 TCP(可靠但开销更大)或 UDP(无连接且更快); UDP 更容易设置。
  • 请注意,如果您有仪器控制工具箱documented here,您也可以直接在 Matlab 中使用 UDP。我非常更喜欢 PNET,因为您不仅可以发送简单的数据类型,甚至还可以发送 matlab oop 对象,否则这些对象几乎不可能通过网络进行序列化和发送(matlab 本身的弱点)。还有一个matlab java接口替代PNEThere
  • 嗨,谢谢,我下载了正确的文件...我将它们解压缩到我的循环脚本所在的目录中。您能否指出,第二个脚本必须是什么样子为了发送正确的命令(例如--abort--)?我对此不以为然(即使使用 matlab 的第二个实例):/
  • 我添加了一个你需要做的例子,你必须打开两个免费的 UDP 端口作为客户端,然后在它们之间发送。伪代码比我描述的更清楚!
【解决方案2】:

您的脚本是脚本 m 文件还是函数?

如果它是一个函数,您将失去工作区变量的范围,这就是它不起作用的原因。我会把你的代码变成这样的函数:

  function processRun(run,reset)
    while run ~= 0     % Loop until external reset of 'run' to '0'
      if reset ~= 0
        doReset;   % Reset the parameters for the processing
        reset = 0;
        disp('I did a reset');
      end

      disp('I am processing');
      [run,reset]  =  doProcess;
      pause(1)
    end

然后,您可以在每次从 VBA 调用函数时设置 run 和 reset 的值。

如果您有脚本,请尝试从顶部删除运行和重置行,并在运行脚本之前在工作区中设置它们的值。我认为您正在通过运行脚本文件来覆盖您的工作区值。

【讨论】:

  • 代码本身就是一个m文件的全部内容。我在理解你的代码方面有一点问题......如果我没看错,我必须调用函数 processRun(...) 一次?然后我可以在工作区中更改我的值?
  • 如果您没有函数定义,我认为您可能会覆盖脚本中的工作区变量。请参阅我对原始答案的修改。
  • 在我看来,reset 变量被重置为 0 当且仅当由于某种原因它在上次检查和当前检查之间的时间跨度内更改为 1。那个原因是你的 VBA 脚本,我认为没有逻辑问题。对我来说是个谜。
  • 谢谢,这是有道理的。我唯一遇到的麻烦是如何在脚本由 run=1 作为参数启动时暂停(在此重置后然后恢复)...
【解决方案3】:

对不起,我没有足够的代表发表评论,所以我会在这里引用它:

@Adam Leadbetter:谢谢,这是有道理的。我唯一遇到的麻烦是如何在脚本以 run=1 作为参数启动时暂停(在此重置后然后恢复)... – poeschlorn 2 月 25 日 7:17

如果您想在 reset 设置为 1 后跳出循环,然后等待循环再次继续一次 run = 1,这与重新开始几乎相同?

function processRun()
run = 1;
while run ~= 1
   run = doProcess();
end

如果doProcess() 返回0,那么函数processRun() 将结束(就像您希望重置时的行为一样),下次调用processRun 时,它会重新开始,并带有“重置”/默认值.

还是我错过了什么?

【讨论】:

  • 如果你错过了什么,那我也是!我认为你在这里展示的是一种比我添加的函数包装更以 Matlab 为中心的代码方式。
  • 嘿 Juhl,您的代码绝对清晰,但我不相信您能解决我的问题。在这种情况下,doProcess() 需要获取用于中止脚本或返回“0”的任何标准。该标准必须来自外部来源。我的问题是如何访问外部中断。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-13
  • 2020-04-06
  • 2015-02-12
  • 2019-06-12
相关资源
最近更新 更多