【数字孪生】利用Pythonnet包Unity调用Scipy库中的RBF代理模型

Motivation

搞过数字孪生的都知道,在数字孪生当中比较有价值的是代理模型这一块。这是因为有限元仿真往往比较耗时,难以达到根据边界条件的变化实时进行变化。那么用已经仿真好的数据训练代理模型则是一个替代的方案。 在代理模型这一块比较常用的有POD(SVD)矩阵降维和RBF(径向基函数)等,还有各式各样的mlp、cnn等神经网络(其实RBF也可以写成神经网络)。在Unity当中也有Barricuda库能够调用转换成ONNX格式的神经网络模型(TensorFlow、Torch等)。
一旦涉及到神经网络的训练,一方面需要一些深度学习的基础,会涉及到调参,又因为有限元仿真数据具有其特殊性,有些位置可能数值特别小但非常关键,mlp的loss已经降到足够小了,但可能误差很轻易就会达到200%往上,导致这一块往往会消耗大量的时间还不一定能调出能接受的结果。

在实际研究中发现像Python的Scipy库当中其实已经有了RBF的实现方式,而且代码写的非常规范,很轻易就能实现超高精度的插值,精度等级可以达到(e-26),即便有限元仿真数据很小都应该能够满足要要求。然而,在转换Scipy数据库关于RBF插值预测的源代码时发现其中有一部分使用了Cython编写的dll动态链接库,这就使得很难在Unity当中使用C#重新改写Scipy当中的源代码实现过程。如果能用Unity调用Python的Scipy库进行计算并交互也是一个非常巧妙的解决方案。

解决方案

用pythonnet包在unity当中实现Python代码的调用。

Pythonnet是一个Python的扩展模块,允许Python与.NET框架进行交互。它提供了一个双向的桥梁,使得你可以在Python中调用.NET代码,也可以在.NET中调用Python代码。这对于那些希望在Python和.NET之间进行集成的开发人员来说非常有用。Pythonnet允许你在Python中调用.NET类、方法和属性,并且可以在Python中处理.NET对象。使用Pythonnet,你可以利用.NET框架的强大功能,比如.NET库、C#代码等,与Python的灵活性和易用性相结合。这在跨平台开发和混合语言开发方面特别有用,因为它让Python和.NET之间的交互变得非常方便。

放一张调试成功的图片,视频放在B站了,感兴趣可以点击移步过去看看。
在这里插入图片描述

操作过程需要注意的点

python当中需要进行的操作

1、在自己的python环境中,pip install pythonnet.
2、确认pythonnet安装的环境目录,并设置其为环境变量

Unity当中需要进行的操作

1、找到pythonnet安装环境当中的动态链接库 Python.Runtime.dll 并将其放在unity当中的asset/plugins路径下.
2、找到Microsoft.CSharp.dll并将其放在Unity的asset/plugiins路径下.

部分源代码放上供参考:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Python.Runtime;
using System;
using UnityEngine.UI;


public class RBFInterpolater : MonoBehaviour
{
    public Slider framecontrol;
    // Python环境路径和Python DLL路径
    private string pythonHome = @"F:\Python\Python39";
    private string pythonPath = @"F:\Python\Python39;F:\Python\Python39\Lib\site-packages";
    private string pythonDLLPath = @"F:\Python\Python39\python39.dll";
    // Python引擎初始化标志
    private bool pythonInitialized = false;

    Mesh mesh;
    // Start is called before the first frame update
    void Start()
    {
        // 检查Python引擎是否已初始化
        if (!PythonEngine.IsInitialized)
        {
            // 设置Python环境变量
            Environment.SetEnvironmentVariable("PYTHONHOME", pythonHome);
            Environment.SetEnvironmentVariable("PYTHONPATH", pythonPath);

            // 设置Python DLL路径
            Runtime.PythonDLL = pythonDLLPath;

            // 初始化Python引擎
            PythonEngine.Initialize();
            pythonInitialized = true;
            Debug.Log("Python engine has been initialized!");
        }

     }
        modelColorInit(framecontrol.value);
    }
    private void modelColorInit(float sliderValue)
    {
        List<float> currentPysicData = new List<float>();
        // 使用Python插值器进行计算
        using (Py.GIL())
        {
            dynamic np = Py.Import("numpy");
            dynamic sci_in = Py.Import("scipy.interpolate");

            // 加载数据
            dynamic X = np.array(new float[,] { { 12 }, { 13 }, { 14 }, { 15 }, { 16 }, { 17 }, { 18 } });
            dynamic Y = np.load(@"E:\science_research\code repo\VScode\zhongchuan\data\numpy\interpolated_acc.npy", allow_pickle: true);
            Debug.Log("Data has been loaded!");

            // 创建RBF插值器
            dynamic rbf = sci_in.RBFInterpolator(X, Y, kernel: "gaussian", epsilon: 1.0);
            Debug.Log("RBF Interpolator has been trained!");

            // 使用RBF插值器进行计算
            dynamic x = np.array(new float[,] { { sliderValue } });
            dynamic result = rbf(x);
            Debug.Log("The case of speed = " + sliderValue + " has been calculated!");
            Debug.Log(result.ToString());

            // 将result转换为List<float>
            foreach (var item in result[0])
            {
                currentPysicData.Add((float)item);
            }
        }
    }

 
    private void OnDestroy()
    {
        // 在销毁时关闭Python引擎
        if (pythonInitialized)
        {
            PythonEngine.Shutdown();
        }
     }


}


猜你喜欢

转载自blog.csdn.net/weixin_44815129/article/details/139156498