【问题标题】:Reading LabVIEW TCP data (Flattened String / Data Cluster) in Python在 Python 中读取 LabVIEW TCP 数据(扁平化字符串/数据簇)
【发布时间】:2018-01-04 00:19:46
【问题描述】:

在通过 TCP/IP 传输到我的 python 应用程序之前,我有一个 LabVIEW 应用程序将 Doubles 的集群(数组)展平为一个字符串。这样做是因为 TCP/IP 只会传输字符串。

问题在于 python 将字符串读取为一堆无意义的 ASCII 字符,我似乎无法将它们解读回原来的双精度数组。

如何解释 LabVIEW 在展平数据字符串后发送的字符串数据。在谷歌几个小时后,我唯一提示的有用信息是一个名为 pyLFDS 的 PyPI 条目,但它已被删除。

【问题讨论】:

    标签: python tcp double ascii labview


    【解决方案1】:

    LabVIEW 扁平化数据格式在here 中有详细描述。该文档没有明确描述双精度浮点数(DBL 类型)是如何表示的,但通过更多搜索发现this 澄清了它们存储在IEEE 754 format 中。

    但是,以 XML 或 JSON 等标准文本格式发送数据可能会更简单,也更适合未来,LabVIEW 中的内置函数和 Python 中的标准库模块都支持这两种格式。

    如果您可以选择,不使用 LabVIEW 扁平化数据与其他程序交换的另一个原因是扁平化字符串不包含您需要将其转换回原始数据类型的类型描述符 - 您需要了解数据的类型以便对其进行解码。

    【讨论】:

    • 我确实遇到了该页面,但无论出于何种原因都没有发现它解决了我的问题,而且我不清楚双打情况下会发生什么。在某些情况下,例如我的情况,无法修改 LabVIEW 代码。
    • 听起来你已经被你所拥有的东西困住了——很高兴听到你有一些工作。为了让未来的读者受益,我对我的答案进行了更详细的编辑。
    【解决方案2】:

    我想记录问题和解决方案,以便其他人可以避免我浪费在谷歌上寻找解决方案的时间。

    当 LabVIEW 展平数据(在本例中为双精度簇)时,它会将它们简单地作为连接字符串发送,每个双精度均由 8 个字节表示。这被 python 解释为每个双精度 8 个 ASCII 字符,显示为 nonsense in your console

    要返回传输的双精度,您需要依次获取每个 8 字节部分并将 ASCII 字符转换为它们的 ASCII 代码,在 Python 的情况下使用 ord()。 这将为您提供 8 字节的十进制代码(例如 4.8 = [64 19 51 51 51 51 51 51]

    事实证明,LabVIEW 可以处理大多数事情,包括 TCP/IP 传输、Big Endian。除非您使用 Big Endian,否则您可能需要更改它。例如上面的例子将变成[51 51 51 51 51 51 19 64]。我将每个双打都放入一个列表中,因此能够使用list(reversed()) 函数来更改字节序。

    然后您可以将其转换回双精度。示例python代码:

    import struct
    b = bytearray([51,51,51,51,51,51,19,64]) #this is the number 4.8
    value = struct.unpack('d', b)
    
    print(value) #4.8
    

    这对于更有经验的程序员来说可能是显而易见的,但它让我困惑了好几天。我很抱歉使用 stackoverflow 作为平台通过回答我自己的问题来分享这一点,但希望这篇文章可以帮助下一个正在苦苦挣扎的人。

    编辑:请注意,如果您使用的是 Python 2.7.5 之前的版本,那么您可能会发现 struct.unpack() 会失败。使用上面的示例代码替换以下代码对我有用: b = bytes(bytearray([51,51,51,51,51,51,19,64]))

    【讨论】:

      【解决方案3】:

      此代码对我有用。 UDP 服务器接受扁平化的 dbl 数组 x,将 x+1 返回到端口 6503。根据您的需要修改 LabView UDP 客户端。

      import struct
      import socket
      import numpy as np
      
      def get_ip():
          s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
          try:
              # doesn't even have to be reachable
              s.connect(('10.255.255.255', 1))
              IP = s.getsockname()[0]
          except:
              IP = '127.0.0.1'
          finally:
              s.close()
          return IP
      
      #bind_ip = get_ip()
      
      print("\n\n[*] Current ip is %s" % (get_ip()))
      bind_ip = ''
      bind_port = 6502
      
      server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
      server.bind((bind_ip,bind_port))  
      
      print("[*] Ready to receive UDP on %s:%d" % (bind_ip,bind_port))
      
      while True:
          data, address = server.recvfrom(1024)
          print('[*] Received %s bytes from %s:' % (len(data), address))
      
          arrLen = struct.unpack('>i', data[:4])[0]
          print('[*] Received array of %d doubles:' % (arrLen,))
          x = []
          elt = struct.iter_unpack('>d', data[4:])
          while True:
              try:
                  x.append(next(elt)[0])
                  print(x[-1])
              except StopIteration:
                  break
          x = np.array(x)
          y = x+1 # np.sin(x)
          msg = data[:4]
          for item in y:
              msg += struct.pack('>d', item)
          print(msg)
          A = (address[0], 6503)
          server.sendto(msg, A)
          break
      
      server.close()
      print('[*] Server closed')
      print('[*] Done')
      

      LabView UDP 客户端:

      【讨论】:

        【解决方案4】:

        我知道这并不能解决您的问题,因为您提到您无法修改 LabVIEW 代码。但是,我希望对在 LabVIEW 中通过 TCP 传输字符串数据的常见方式有所了解。

        可以控制通过Write TCP发送的数据字符串的字节顺序。我建议使用Flatten To String Function,因为它可以让您在展平数据时选择要使用的字节顺序; big-endian(未连接时默认)、native(使用主机的字节顺序)或 little-endian。

        我见过的另一种常见技术是使用Type Cast Function。这样做会将数字转换为大端字符串。当您在网络的另一端阅读它时,这当然会令人困惑,因为大多数其他内容都是小端的,因此您需要进行一些字节交换。

        一般来说,如果您不确定代码是什么样子,假设它来自 LabVIEW 代码,它将是大端的。

        nekomatic 的回答很好。在可用时使用标准文本格式始终是一个不错的选择。

        【讨论】:

          猜你喜欢
          • 2020-09-10
          • 1970-01-01
          • 1970-01-01
          • 2011-02-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-12-16
          • 2023-03-10
          相关资源
          最近更新 更多