加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

S-Function实现simulink仿真与Vc通信

(2012-12-22 13:38:25)
标签:

simulink仿真与vc通信

s-function

socket通信

udp实现simulink通信

udp

分类: 程序开发

 S-Function实现simulink仿真与Vc通信

 

背景:在使用simulink仿真和其他语言编写的仿真模块合作时,总存在两种语言模块的数据交互的问题,本文考虑使用S-Function构建一个单独的通信模块,将该模块添加到simulink模型中,实现仿真数据的交互。

Matlabsimulink仿真有提供一个用户自定义模块,该模块可以用多种编程语言来实现,本文介绍:使用C++Socket通信来编写代码,实现和Vc的交互。

下面介绍VC++用户自定义模块的实现方法

1、在模型中添加用户自定义模块

该模块位于SimulinkUser-Define Function下的S-Function模块

2、添加模块对应的函数名,双击模块,在弹出窗口S-function name后面输入要定义的函数名,

3、编写模块对应的函数代码,函数代码要求有固定的格式,如下(可以参考simulinkdemo中的代码):(限于篇幅,只贴部分关键代码,完整源代码请看后续链接中的UseFunc.cpp和UseFunc.h)


// Function: mdlStart =======================================================
// Abstract:
//   This function is called once at start of model execution. If you
//   have states that should be initialized once, this is the place
//   to do it.
#define MDL_START
static void mdlStart(SimStruct *S)
{
    // Store new C++ object in the pointers vector
    DoubleAdder *da  = new DoubleAdder();
    ssGetPWork(S)[0] = da;

    UseFun_StartSock(S);
}

// Function: mdlOutputs =======================================================
// Abstract:
//   In this function, you compute the outputs of your S-function
//   block.
static void mdlOutputs(SimStruct *S, int_T tid)
{
    // Retrieve C++ object from the pointers vector
    DoubleAdder *da = static_cast<</FONT>DoubleAdder *>(ssGetPWork(S)[0]);
   
   
// Get data addresses of I/O
    InputRealPtrsType  u = ssGetInputPortRealSignalPtrs(S,0);
               real_T *y = ssGetOutputPortRealSignal(S, 0);

    int InputNum = ssGetInputPortWidth(S, 0);
    for(int i=0;i<</FONT>InputNum;i++)
    {
        y[i] = *u[i];
    }

    UseFun_SentData(S, y, InputNum);
}

// Function: mdlTerminate =====================================================
// Abstract:
//   In this function, you should perform any actions that are necessary
//   at the termination of a simulation.  For example, if memory was
//   allocated in mdlStart, this is the place to free it.
static void mdlTerminate(SimStruct *S)
{
    // Retrieve and destroy C++ object
    DoubleAdder *da = static_cast<</FONT>DoubleAdder *>(ssGetPWork(S)[0]);
    delete da;

    UseFun_CloseSock(S);
}

void UseFun_StartSock(SimStruct *S)
{
    int iResult;
    WSADATA wsaData;

    SOCKET *pSendSocket = new SOCKET;
    *pSendSocket = INVALID_SOCKET;

    sockaddr_in *pRecvAddr = new sockaddr_in;

    unsigned short Port = 27015;
   
    printf
("Start socket communication, please wait...\n");

    //----------------------
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != NO_ERROR) {
        printf("WSAStartup failed with error: %d\n", iResult);
        return ;
    }

    //---------------------------------------------
    // Create a socket for sending data
    *pSendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (*pSendSocket == INVALID_SOCKET) {
        printf("socket failed with error: %ld\n", WSAGetLastError());
        WSACleanup();
        return ;
    }

    //---------------------------------------------
    // Set up the RecvAddr structure with the IP address of
    // the receiver (in this example case "192.168.1.1")
    // and the specified port number.
    pRecvAddr->sin_family = AF_INET;
    pRecvAddr->sin_port = htons(Port);
    pRecvAddr->sin_addr.s_addr = inet_addr("127.0.0.1");

    ssGetPWork(S)[1] = pSendSocket;
    ssGetPWork(S)[2] = pRecvAddr;
}

void UseFun_SentData(SimStruct *S, const real_T *data, int DataNum)
{
    int iResult;

    char SendBuf[1024]={'\0'};
    int BufLen = 1024;

    SOCKET
*pSendSocket    = static_cast<</FONT>SOCKET *>(ssGetPWork(S)[1]);
    sockaddr_in *pRecvAddr = static_cast<</FONT>sockaddr_in *>(ssGetPWork(S)[2]);

    if (*pSendSocket == SOCKET_ERROR) {
        printf("SOCKET_ERROR error: %d\n", WSAGetLastError());
        closesocket(*pSendSocket);
        WSACleanup();
        return ;
    }

    //---------------------------------------------
    // Send a datagram to the receiver
    //printf("Sending a datagram to the receiver...\n");
    int ValidateBufLen = 0;
   
for(int i=0;i<</FONT>DataNum;i++)
    {
        ValidateBufLen = strlen(SendBuf);
        sprintf(SendBuf+ValidateBufLen, "%g;", data[i]);
    }

    iResult = sendto(*pSendSocket,
        SendBuf, BufLen, 0, (SOCKADDR *)pRecvAddr, sizeof(sockaddr_in));
}

void UseFun_CloseSock(SimStruct *S)
{
    SOCKET *pSendSocket    = static_cast<</FONT>SOCKET *>(ssGetPWork(S)[1]);
    sockaddr_in *pRecvAddr = static_cast<</FONT>sockaddr_in *>(ssGetPWork(S)[2]);

    //---------------------------------------------
    // When the application is finished sending, close the socket.
    printf("Finished socket communication, Closing socket.\n");

    if (closesocket(*pSendSocket) == SOCKET_ERROR)
    {
        printf("closesocket failed with error: %d\n", WSAGetLastError());
    }
    //---------------------------------------------
    // Clean up and quit.

    WSACleanup();

    delete pSendSocket;
    pSendSocket = NULL;

    delete pRecvAddr;
    pRecvAddr = NULL;
}

示例程序实现将输入直接输出,并将输入数据通过socket采UDP协议将数据发送到网络上

4、编译C++代码,在matlab中编译,需要先通过matlab命令行设置matlabmex编译器,方法如下:

http://s14/mw690/6f83fdb4gx6DieivDoV0d&690

选择VS2005编译器,然后使用mex 命令来编译代码,命令格式:mex cppfile(模块对应的代码的文件名),编译成功会有相应的提示

5、编译成功会产生一个后缀为mexw32mex程序,有了这个程序,用户自定义模块就可以工作了 

 

 

附:

Demo说明:两个正弦输入信号经过mux模块集束成一个输入数组,经过自定义模块,最后到达Scope模块显示。在自定义模块(UseFunc)中,通过Socket采用UDP将输入数据发送到某个端口。

1、simulink模型图示(模型文件请看后续链接中的DemoTest.mdl)

http://s12/mw690/6f83fdb4gx6DieqjWjhdb&690
 

2、运行效果图: 

http://s2/mw690/6f83fdb4gx6DieuIFqxd1&690


 

3、通过辅助程序,收到上面自定义模型发出来的数据如下

http://s15/mw690/6f83fdb4gx6DieV5WlUde&690 

说明:分号前为第一个正弦输入信号的数据,分号后为第二个正弦输入信号的数据

 

接收端程序代码:(完整源代码请看后续链接中的SocketServer.cpp)
int _tmain(int argc, _TCHAR* argv[])
{
    int iResult = 0;

    WSADATA wsaData;

    SOCKET RecvSocket;
    sockaddr_in RecvAddr;

    unsigned short Port = 27015;

    char RecvBuf[1024];
    int BufLen = 1024;

    sockaddr_in SenderAddr;
    int SenderAddrSize = sizeof (SenderAddr);

    //-----------------------------------------------
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != NO_ERROR) {
        wprintf(L"WSAStartup failed with error %d\n", iResult);
        return 1;
    }
    //-----------------------------------------------
    // Create a receiver socket to receive datagrams
    RecvSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (RecvSocket == INVALID_SOCKET) {
        wprintf(L"socket failed with error %d\n", WSAGetLastError());
        return 1;
    }
    //-----------------------------------------------
    // Bind the socket to any address and the specified port.
    RecvAddr.sin_family = AF_INET;
    RecvAddr.sin_port = htons(Port);
    RecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    iResult = bind(RecvSocket, (SOCKADDR *) & RecvAddr, sizeof (RecvAddr));
    if (iResult != 0) {
        wprintf(L"bind failed with error %d\n", WSAGetLastError());
        return 1;
    }
    //-----------------------------------------------
    // Call the recvfrom function to receive datagrams
    // on the bound socket.
    wprintf(L"Receiving datagrams...\n");
    iResult = 0;
    int RecvNum = 0;
    while(RecvNum <</FONT> 100)
    {
        memset(RecvBuf,0,BufLen);
        iResult = recvfrom(RecvSocket,
            RecvBuf, BufLen, 0, (SOCKADDR *) & SenderAddr, &SenderAddrSize);

        if (iResult == SOCKET_ERROR)
        {
            wprintf(L"recvfrom failed with error %d\n", WSAGetLastError());
            break;
        }
        printf("recv dada: %s \n", RecvBuf);
        RecvNum++;
    }

    //-----------------------------------------------
    // Close the socket when finished receiving datagrams
    wprintf(L"Finished receiving. Closing socket.\n");
    iResult = closesocket(RecvSocket);
    if (iResult == SOCKET_ERROR) {
        wprintf(L"closesocket failed with error %d\n", WSAGetLastError());
        return 1;
    }

    //-----------------------------------------------
    // Clean up and exit.
    wprintf(L"Exiting.\n");
    WSACleanup();

    return 0;
}

 

完整源代码参见:S-Function实现simulink仿真与Vc通信的源代码

0

阅读 收藏 喜欢 打印举报/Report
后一篇:Matlab画足球
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有