SIMULINK与PYTHON之间使用TCP通讯传输浮点型数组数据

文章介绍了如何在PyTorch模型训练后,通过TCP协议与MATLAB进行数据交换,包括服务器端的代码实现、数据格式转换和Simulink中的S-Function模块设计,以及测试中数据的发送与接收过程。
摘要由CSDN通过智能技术生成

01 介绍

        因为在pytorch中训练的模型需要使用carsim与matlab进行联合仿真验证,所以设计了如下程序进行TCP数据传输。

02 服务器端代码设计

        导入的相关库如下:

import socket
import struct
import numpy as np
import time
import gc

        创建了TCP服务器端的类,代码如下:

class TCPServer:
    def __init__(self, ip, port, backlog=5, buffer_size=1024 * 8):
        self.ip = ip
        self.port = port
        self.backlog = backlog
        self.buffer_size = buffer_size
        self.server_socket = None
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.server_socket.bind((self.ip, self.port))
        self.server_socket.listen(self.backlog)
        self.connection, self.address = self.server_socket.accept()

    def start_send(self, data):
        # connection, address = self.server_socket.accept()

        # 将数据发送到服务器
        data_bytes = selected_data.tobytes()  # 将数据转换为字节流
        self.connection.sendall(data_bytes)
        print("发送成功")
        time.sleep(0.00001)

        # print(data)
        return True

    def start_read(self):
        #connection, address = self.server_socket.accept()

        while True:
            time.sleep(0.001)
            # 接收来自客户端的数据
            data_bytes = self.connection.recv(24320)  # 假设数据大小是40x(76)*8

            if len(data_bytes) == 24320:
                # 计算字节流中包含的双精度浮点数数量
                num_double_values = len(data_bytes) // 8

                # 解析字节流为双精度浮点数
                double_values = []
                for i in range(num_double_values):
                    start_index = i * 8
                    end_index = start_index + 8
                    double_bytes = data_bytes[start_index:end_index]
                    double_value = struct.unpack('d', double_bytes)[0]
                    double_values.append(double_value)

                # 使用列表推导来将每个元素除以1000,并将结果存储为NumPy数组
                received_data = np.array(double_values) / 1000

                # 将数组重塑为40x76的形状
                received_data = received_data.reshape(76, 40)
                received_data = received_data.T
                #self.server_socket.close()

                # 在此处可以处理接收到的数据,例如打印或其他操作
                print(received_data, "正在读取")
                break
        return received_data

    def stop(self):
        if self.server_socket:
            self.server_socket.close()

主程序代码设置了while循环进行接收和发送。代码如下:

if __name__ == "__main__":
    server1 = TCPServer('127.0.0.1', 22)

    num = 1
    while True:
        print(num)
        msg = server1.start_read()
        server1.stop()
        server2 = TCPServer('127.0.0.1', 23)
        time.sleep(0.1)
        # 读取CSV文件
        data = np.genfromtxt('vehcile_features.csv', delimiter=',')
        # 提取第二列到倒数第二列的前40行数据
        selected_data = data[0:40, 1:-1]
        selected_data = selected_data.T
        # 显示提取的数据
        print(selected_data)
        # 将数据乘以1000
        selected_data = selected_data * 1000
        server2.start_send(selected_data)
        num = num + 1
        time.sleep(0.005)
        server2.stop()
        server1 = TCPServer('127.0.0.1', 22)
        gc.collect()

03 Simulink端S-function模块设计

        因为只是个demo文件,所以将Simulink设置如下所示:

        以上使用零阶保持器将采样频率限制在10Hz,设置一级S-Function进行TCP通讯。设计代码如下:

function [sys, x0, str, ts, simStateCompliance] = TCPSimulink(t, x, u, flag)
%STORECARSIMDATASFUNCTION Custom MATLAB S-Function for storing Carsim data
%   This S-Function takes input 'u' containing Carsim model output parameters
%   and performs some calculations to store the data in Trajectory_data.

switch flag
    case 0
        [sys, x0, str, ts, simStateCompliance] = mdlInitializeSizes();
    case 3
        sys = mdlOutputs(t, x, u);
    case 9
        sys = mdlTerminate(t, x, u);
    otherwise
        sys = [];
end

function [sys, x0, str, ts, simStateCompliance] = mdlInitializeSizes()
% Initialize sizes, initial conditions, and sample times
%import java.net.Socket;
%import java.io.OutputStream;
%import java.io.DataOutputStream;

sizes = simsizes;
sizes.NumContStates = 0;
sizes.NumDiscStates = 0;
sizes.NumOutputs = 1;
sizes.NumInputs = 1; % One input, which is the Carsim data
sizes.DirFeedthrough = 1;
sizes.NumSampleTimes = 1;

sys = simsizes(sizes);
x0 = [];% 有状态的要初始化
str = [];
ts = [0 0];  % 一步为零或者-1
clc

% Specify the block simStateCompliance
simStateCompliance = 'UnknownSimState';

function sys = mdlOutputs(t, x, u)%模型输出
% Calculate and store the data

persistent Order historyData lastTimeStep currentTimeStep Trajectory_data last_historyData

if ~isempty(Trajectory_data)
    Order = 0;
end

%% 远程主机为localhost,即本地主机,要连接的目的端口为22,作为客户机使用
client1=tcpip('127.0.0.1',22,'NetworkRole','client');
client2=tcpip('127.0.0.1',23,'NetworkRole','client');
%% 设置接收和发送缓存区的最大容量,这里设置的是1000*1000*8,也就是一个1000*1000的double类型的数组大小
client1.InputBuffersize=27000;
client1.OutputBuffersize=27000;
client2.InputBuffersize=27000;
client2.OutputBuffersize=27000;

%% 向服务器发送数据
%% 打开连接,寻找目的服务器,如果未找到,报错



% 读取CSV文件
data = readmatrix('vehcile_features.csv');
% 提取第二列到倒数第二列的前40行数据
Trajectory_data = data(1:40, 2:end-1);
% 显示提取的数据
% disp(Trajectory_data);            


Trajectory_data = Trajectory_data * 1000;
client1.timeout = 2;  % 增加超时时间
client2.timeout = 2;  % 增加超时时间


fopen(client1);
% 将数据发送到服务器
data_bytes = typecast(Trajectory_data(:), 'uint8');  % 将数据转换为字节流
fwrite(client1, data_bytes);
disp('发送数据成功!!');

fclose(client1);

fopen(client2);
condition = 1;
while(condition)

    pause(0.01)
   

    received_bytes = fread(client2, 24320, 'uint8');  % 假设数据类型是uint8 , 24640 = 40*77*8
    
    if ~isempty(received_bytes)
        % 将字节流转换为双精度浮点数
        received_data = typecast(uint8(received_bytes), 'double');
        disp('接收数据成功!!');
        % 将数据重新形状为40x76
        received_data = reshape(received_data, 40,76 );
        % 如果需要,将数据缩小1000倍
        Predict_data = received_data / 1000;
        Order = Order + 1;
        condition = 0;
        fclose(client2);
        % pause(0.005)
       
        break
       
    else
        %加一段等待时间
        pause(0.025)
    end
end



      
sys = [condition];

function sys=mdlGetTimeOfNextVarHit(t,x,u)%计算下一个采样时间点

sampleTime = 0.1;    %  Example, set the next hit to be one second later.
sys = t + sampleTime;

function sys = mdlTerminate(t, x, u)
% Perform end of simulation tasks

sys = [];

04 通讯程序测试结果展示

        服务器端和客户端部分打印结果:

发送成功
98
[[3.88000011 3.         1.82000005 ... 0.         0.         3.        ]
 [3.88000011 3.         1.82000005 ... 0.         0.         3.        ]
 [3.88000011 3.         1.82000005 ... 0.         0.         3.        ]
 ...
 [3.88000011 3.         1.82000005 ... 0.         0.         3.        ]
 [3.88000011 3.         1.82000005 ... 0.         0.         3.        ]
 [3.88000011 3.         1.82000005 ... 0.         0.         3.        ]] 正在读取
[[       nan 3.88000011 3.88000011 ... 3.88000011 3.88000011 3.88000011]
 [       nan 3.         3.         ... 3.         3.         3.        ]
 [       nan 1.82000005 1.82000005 ... 1.82000005 1.82000005 1.82000005]
 ...
 [       nan 0.         0.         ... 0.         0.         0.        ]
 [       nan 0.         0.         ... 0.         0.         0.        ]
 [       nan 3.         3.         ... 3.         3.         3.        ]]
发送成功
99
[[3.88000011 3.         1.82000005 ... 0.         0.         3.        ]
 [3.88000011 3.         1.82000005 ... 0.         0.         3.        ]
 [3.88000011 3.         1.82000005 ... 0.         0.         3.        ]
 ...
 [3.88000011 3.         1.82000005 ... 0.         0.         3.        ]
 [3.88000011 3.         1.82000005 ... 0.         0.         3.        ]
 [3.88000011 3.         1.82000005 ... 0.         0.         3.        ]] 正在读取
[[       nan 3.88000011 3.88000011 ... 3.88000011 3.88000011 3.88000011]
 [       nan 3.         3.         ... 3.         3.         3.        ]
 [       nan 1.82000005 1.82000005 ... 1.82000005 1.82000005 1.82000005]
 ...
 [       nan 0.         0.         ... 0.         0.         0.        ]
 [       nan 0.         0.         ... 0.         0.         0.        ]
 [       nan 3.         3.         ... 3.         3.         3.        ]]
发送成功
100
[[3.88000011 3.         1.82000005 ... 0.         0.         3.        ]
 [3.88000011 3.         1.82000005 ... 0.         0.         3.        ]
 [3.88000011 3.         1.82000005 ... 0.         0.         3.        ]
 ...
 [3.88000011 3.         1.82000005 ... 0.         0.         3.        ]
 [3.88000011 3.         1.82000005 ... 0.         0.         3.        ]
 [3.88000011 3.         1.82000005 ... 0.         0.         3.        ]] 正在读取
[[       nan 3.88000011 3.88000011 ... 3.88000011 3.88000011 3.88000011]
 [       nan 3.         3.         ... 3.         3.         3.        ]
 [       nan 1.82000005 1.82000005 ... 1.82000005 1.82000005 1.82000005]
 ...
 [       nan 0.         0.         ... 0.         0.         0.        ]
 [       nan 0.         0.         ... 0.         0.         0.        ]
 [       nan 3.         3.         ... 3.         3.         3.        ]]
发送数据成功!!
接收数据成功!!
发送数据成功!!
接收数据成功!!
发送数据成功!!
接收数据成功!!
发送数据成功!!
接收数据成功!!

05 注意事项

  1. 本TCP通讯程序使用了两个通道进行数据传输;
  2. 传输的数据是40*76的浮点型数据,其中matlab和python的行列之间需要转置才能保证数据相同;
  3. 在程序中的延时都是为了能够将通讯连接准确开闭;
  4. 在传输数据中,都是将浮点型转化为字节流传输的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值