Python 机器学习求解 PDE 学习项目——PINN 求解二维 Poisson 方程

news2024/9/20 22:22:20

本文使用 TensorFlow 1.15 环境搭建深度神经网络(PINN)求解二维 Poisson 方程:

模型问题

− Δ u = f in  Ω , u = g on  Γ : = ∂ Ω . \begin{align} -\Delta u &= f \quad & \text{in } \Omega,\\ u & =g \quad & \text{on } \Gamma:=\partial \Omega. \end{align} Δuu=f=gin Ω,on Γ:=Ω.
其中 Ω = [ X a , X b ] × [ Y a , Y b ] \Omega = [X_a,X_b]\times[Y_a,Y_b] Ω=[Xa,Xb]×[Ya,Yb] 是一个二维矩形区域, Δ u = u x x + u y y , g \Delta u = u_{xx}+u_{yy}, g Δu=uxx+uyy,g 是边界条件给定的函数,可以非零.

在这里插入图片描述

代码展现

二维PINN 与一维的整体框架是类似的,只是数据的维度升高了,完整代码及其注释如下:

# PINN 求解 2D Poisson 方程
import tensorflow as tf
print(tf.__version__)
import os
#tensorflow-intel automatically set the TF_ENABLE_ONEDNN_OPTS=1
#os.environ['TF_ENABLE_ONEDNN_OPTS'] = '0'
# Here, TF_ENABLE_ONEDNN_OPTS=0 should be above import tensorflow as tf
import tensorflow as tf
import numpy as np
import time
import matplotlib.pyplot as plt
import scipy.io
import math
# 定义数据集类,用于生成训练所需的数据
class Dataset:
    def __init__(self, x_range, y_range, N_res, N_bx, N_by, Nx, Ny, xa, xb, ya, yb):
        self.x_range = x_range  # x 轴范围
        self.y_range = y_range  # y 轴范围
        self.N_res = N_res  # 方程残差点数量
        self.N_bx = N_bx  # x 方向边界条件点数量
        self.N_by = N_by  # y 方向边界条件点数量
        self.Nx = Nx  # x 方向网格数量
        self.Ny = Ny  # y 方向网格数量
        self.xa = xa  # x 方向左边界
        self.xb = xb  # x 方向右边界
        self.ya = ya  # y 方向下边界
        self.yb = yb  # y 方向上边界

    # 定义边界条件函数
    # 可以求解非齐次 Dirichlet 边界条件
    def bc(self, X_b):
        U_bc = Exact(self.xa, self.xb, self.ya, self.yb)
        u_bc = U_bc.u_exact(X_b)
        return u_bc

    # 生成数据:残差点和边界条件点
    def build_data(self):
        x0, x1 = self.x_range
        y0, y1 = self.y_range

        Xmin = np.hstack((x0, y0))
        Xmax = np.hstack((x1, y1))

        ## 如果使用均匀网格,代码如下:
        """
        x_ = np.linspace(x0, x1, self.Nx).reshape((-1, 1))
        y_ = np.linspace(y0, y1, self.Ny).reshape((-1, 1))
        x, y = np.meshgrid(x_, y_)
        x = np.reshape(x, (-1, 1))
        y = np.reshape(y, (-1, 1))
        xy = np.hstack((x, y))
        X_res_input = xy
        """

        ## 为方程生成随机残差点
        x_res = x0 + (x1 - x0) * np.random.rand(self.N_res, 1)
        y_res = y0 + (y1 - y0) * np.random.rand(self.N_res, 1)
        X_res_input = np.hstack((x_res, y_res))

        # 生成 x = xa, xb 的边界条件点
        y_b = y0 + (y1 - y0) * np.random.rand(self.N_by, 1)
        x_b0 = x0 * np.ones_like(y_b)
        x_b1 = x1 * np.ones_like(y_b)
        X_b0_input = np.hstack((x_b0, y_b))
        X_b1_input = np.hstack((x_b1, y_b))

        # 生成 y = ya, yb 的边界条件点
        x_b = x0 + (x1 - x0) * np.random.rand(self.N_bx, 1)
        y_b0 = y0 * np.ones_like(x_b)
        y_b1 = y1 * np.ones_like(x_b)
        Y_b0_input = np.hstack((x_b, y_b0))
        Y_b1_input = np.hstack((x_b, y_b1))
        
        return X_res_input, X_b0_input, X_b1_input, Y_b0_input, Y_b1_input, Xmin, Xmax

# 定义精确解类,用于计算精确解
class Exact:
    def __init__(self, xa, xb, ya, yb):
        self.xa = xa  # x 方向左边界
        self.xb = xb  # x 方向右边界
        self.ya = ya  # y 方向下边界
        self.yb = yb  # y 方向上边界

    # 精确解函数
    def u_exact(self, X):
        x = X[:, 0:1]
        y = X[:, 1:2]

        u = np.sin(2 * np.pi * x  ) * np.sin(2 * np.pi * y )
        return u

class Train:
    def __init__(self, train_dict):
        self.train_dict = train_dict  # 训练数据
        self.step = 0  # 训练步数

    # 打印训练损失
    def callback(self, loss_value):
        self.step += 1
        if self.step % 200 == 0:
            print(f'Loss: {loss_value:.4e}')

    # 使用 Adam 和 L-BFGS 优化器进行训练
    def nntrain(self, sess, u_pred, loss, train_adam, train_lbfgs):
        n = 0
        max_steps = 1000
        loss_threshold = 4.0e-4
        current_loss = 1.0
        while n < max_steps and current_loss > loss_threshold:
            n += 1
            u_, current_loss, _ = sess.run([u_pred, loss, train_adam], feed_dict=self.train_dict)
            # 每2^n步打印一次损失并绘制结果  
            if math.isclose(math.fmod(math.log2(n), 1), 0, abs_tol=1e-9): 
                print(f'Steps: {n}, loss: {current_loss:.4e}')

        train_lbfgs.minimize(sess, feed_dict=self.train_dict, fetches=[loss], loss_callback=self.callback)

class DNN:
    def __init__(self, layer_sizes, Xmin, Xmax):
        self.layer_sizes = layer_sizes  # 每层的节点数
        self.Xmin = Xmin  # 输入范围最小值
        self.Xmax = Xmax  # 输入范围最大值
    
    # 初始化神经网络的权重和偏置
    def hyper_initial(self):
        num_layers = len(self.layer_sizes)
        weights = []
        biases = []
        for l in range(1, num_layers):
            in_dim = self.layer_sizes[l-1]
            out_dim = self.layer_sizes[l]
            std = np.sqrt(2 / (in_dim + out_dim))
            weight = tf.Variable(tf.random_normal(shape=[in_dim, out_dim], stddev=std))
            bias = tf.Variable(tf.zeros(shape=[1, out_dim]))
            weights.append(weight)
            biases.append(bias)
        return weights, biases

    # 构建前馈神经网络
    def fnn(self, X, weights, biases):
        A = 2.0 * (X - self.Xmin) / (self.Xmax - self.Xmin) - 1.0  # 归一化输入
        num_layers = len(weights)
        for i in range(num_layers - 1):
            A = tf.tanh(tf.add(tf.matmul(A, weights[i]), biases[i]))  # 隐藏层激活函数
        Y = tf.add(tf.matmul(A, weights[-1]), biases[-1])  # 输出层
        return Y
    
    # 构建用于求解 Poisson 方程的神经网络
    def pdenn(self, x, y, weights, biases):
        u = self.fnn(tf.concat([x, y], 1), weights, biases)  # 前馈网络输出
        u_x = tf.gradients(u, x)[0]  # u 对 x 的一阶导数
        u_xx = tf.gradients(u_x, x)[0]  # u 对 x 的二阶导数
        u_y = tf.gradients(u, y)[0]  # u 对 y 的一阶导数
        u_yy = tf.gradients(u_y, y)[0]  # u 对 y 的二阶导数
        
        # 源项函数
        rhs_func = 8 * np.pi**2 * tf.sin(2 * np.pi * x  ) * tf.sin(2 * np.pi * y )

        # 残差项
        residual = -(u_xx + u_yy) - rhs_func

        return residual

def compute_errors(u_pred, u_exact):
    """
    计算数值解与精确解之间的 L2 误差和最大模误差
    :param u_pred: 数值解
    :param u_exact: 精确解
    :return: L2 误差和最大模误差
    """
    # 计算 L2 误差
    L2_error = np.sqrt(np.mean((u_pred - u_exact) ** 2))
    
    # 计算最大模误差
    max_error = np.max(np.abs(u_pred - u_exact))
    
    return L2_error, max_error

# 检查保存路径是否存在,如果不存在则创建
save_path = './Output'
if not os.path.exists(save_path):
    os.makedirs(save_path)

# 定义保存和绘图类
class SavePlot:
    def __init__(self, session, x_range, y_range, num_x_points, num_y_points, xa, xb, ya, yb):
        self.x_range = x_range  # x 轴范围
        self.y_range = y_range  # y 轴范围
        self.num_x_points = num_x_points  # x 方向上的测试点数量
        self.num_y_points = num_y_points  # y 方向上的测试点数量
        self.session = session  # TensorFlow 会话
        self.xa = xa  # x 方向左边界
        self.xb = xb  # x 方向右边界
        self.ya = ya  # y 方向下边界
        self.yb = yb  # y 方向上边界

    # 保存并绘制预测和精确解
    def save_and_plot(self, u_pred, x_res_train, y_res_train):
        # 生成测试点
        x_test = np.linspace(self.x_range[0], self.x_range[1], self.num_x_points).reshape((-1, 1))
        y_test = np.linspace(self.y_range[0], self.y_range[1], self.num_y_points).reshape((-1, 1))
        x_test_grid, y_test_grid = np.meshgrid(x_test, y_test)
        x_test_grid = np.reshape(x_test_grid, (-1, 1))
        y_test_grid = np.reshape(y_test_grid, (-1, 1))
        
        # 创建测试字典
        test_feed_dict = {x_res_train: x_test_grid, y_res_train: y_test_grid}
        
        # 在测试网格上进行预测
        u_test = self.session.run(u_pred, feed_dict=test_feed_dict)
        u_test = np.reshape(u_test, (y_test.shape[0], x_test.shape[0]))
        u_test = np.transpose(u_test)

        # 保存预测结果到文件
        np.savetxt(os.path.join(save_path, 'u_pred.txt'), u_test, fmt='%e')

        # 绘制预测结果并保存图片
        plt.imshow(u_test, cmap='rainbow', aspect='auto')
        plt.colorbar()
        plt.title('Numerical Solution')
        plt.xlabel('X-axis')
        plt.ylabel('Y-axis')
        plt.savefig(os.path.join(save_path, 'u_pred.png'))
        plt.show()
        plt.close()

        # 计算并保存精确解
        exact_solution = Exact(self.xa, self.xb, self.ya, self.yb)
        u_exact = exact_solution.u_exact(np.hstack((x_test_grid, y_test_grid)))
        u_exact = np.reshape(u_exact, (y_test.shape[0], x_test.shape[0]))
        u_exact = np.transpose(u_exact)
        np.savetxt(os.path.join(save_path, 'u_exact.txt'), u_exact, fmt='%e')

        # 绘制精确解并保存图片
        plt.imshow(u_exact, cmap='rainbow', aspect='auto')
        plt.colorbar()
        plt.title('Exact Solution')
        plt.xlabel('X-axis')
        plt.ylabel('Y-axis')
        plt.savefig(os.path.join(save_path, 'u_exact.png'))
        plt.show()
        plt.close()

下面是主程序:

import os
import tensorflow as tf
import numpy as np
import time
import matplotlib.pyplot as plt

# 设置随机种子以确保可重复性
np.random.seed(1234)
tf.set_random_seed(1234)

def main():
    # 定义计算域范围
    x_range = [-0.5, 1.5]
    y_range = [-1.0, 1.0]
    
    # 网格点数量
    num_x_points = 101
    num_y_points = 101
    
    # 残差点和边界点数量
    num_residual_points = 8000
    num_boundary_x_points = 100
    num_boundary_y_points = 100
    
    # 边界范围
    xa = x_range[0]
    xb = x_range[1]
    ya = y_range[0]
    yb = y_range[1]

    # 创建数据集对象
    data = Dataset(x_range, y_range, num_residual_points, num_boundary_x_points, num_boundary_y_points, num_x_points, num_y_points, xa, xb, ya, yb)
    
    # 生成数据
    X_res, X_b0, X_b1, Y_b0, Y_b1, Xmin, Xmax = data.build_data()

    # 定义神经网络的层结构
    layers = [2] + 5 * [40] + [1]

    # 定义输入占位符
    x_res_train = tf.placeholder(shape=[None, 1], dtype=tf.float32)
    y_res_train = tf.placeholder(shape=[None, 1], dtype=tf.float32)
    X_x_b0_train = tf.placeholder(shape=[None, 1], dtype=tf.float32)
    X_y_b0_train = tf.placeholder(shape=[None, 1], dtype=tf.float32)
    X_x_b1_train = tf.placeholder(shape=[None, 1], dtype=tf.float32)
    X_y_b1_train = tf.placeholder(shape=[None, 1], dtype=tf.float32)
    Y_x_b0_train = tf.placeholder(shape=[None, 1], dtype=tf.float32)
    Y_y_b0_train = tf.placeholder(shape=[None, 1], dtype=tf.float32)
    Y_x_b1_train = tf.placeholder(shape=[None, 1], dtype=tf.float32)
    Y_y_b1_train = tf.placeholder(shape=[None, 1], dtype=tf.float32)

    # 创建物理信息神经网络(PINN)
    pinn = DNN(layers, Xmin, Xmax)
    weights, biases = pinn.hyper_initial()

    # 预测解
    u_pred = pinn.fnn(tf.concat([x_res_train, y_res_train], 1), weights, biases)

    # 计算残差
    f_pred = pinn.pdenn(x_res_train, y_res_train, weights, biases)

    # 边界条件预测 (x = xa, xb)
    u_x_b0_pred = pinn.fnn(tf.concat([X_x_b0_train, X_y_b0_train], 1), weights, biases)
    u_x_b1_pred = pinn.fnn(tf.concat([X_x_b1_train, X_y_b1_train], 1), weights, biases)

    # 边界条件预测 (y = ya, yb)
    u_y_b0_pred = pinn.fnn(tf.concat([Y_x_b0_train, Y_y_b0_train], 1), weights, biases)
    u_y_b1_pred = pinn.fnn(tf.concat([Y_x_b1_train, Y_y_b1_train], 1), weights, biases)

    # 定义损失函数
    loss = 0.1 * tf.reduce_mean(tf.square(f_pred)) + \
           tf.reduce_mean(tf.square(u_x_b0_pred)) + \
           tf.reduce_mean(tf.square(u_x_b1_pred)) + \
           tf.reduce_mean(tf.square(u_y_b0_pred)) + \
           tf.reduce_mean(tf.square(u_y_b1_pred))

    # 定义优化器
    train_adam = tf.train.AdamOptimizer(0.0008).minimize(loss)
    train_lbfgs = tf.contrib.opt.ScipyOptimizerInterface(loss,
                                                         method="L-BFGS-B",
                                                         options={'maxiter': 10000 ,
                                                                  'ftol': 1.0 * np.finfo(float).eps})

    # 创建 TensorFlow 会话
    session = tf.Session()
    session.run(tf.global_variables_initializer())
    
    # 创建训练字典
    train_feed_dict = {x_res_train: X_res[:, 0:1], y_res_train: X_res[:, 1:2], 
                       X_x_b0_train: X_b0[:, 0:1], X_y_b0_train: X_b0[:, 1:2],
                       X_x_b1_train: X_b1[:, 0:1], X_y_b1_train: X_b1[:, 1:2], 
                       Y_x_b0_train: Y_b0[:, 0:1], Y_y_b0_train: Y_b0[:, 1:2], 
                       Y_x_b1_train: Y_b1[:, 0:1], Y_y_b1_train: Y_b1[:, 1:2]}

    # 创建训练模型
    model = Train(train_feed_dict)
    
    # 记录训练时间
    start_time = time.perf_counter()
    model.nntrain(session, u_pred, loss, train_adam, train_lbfgs)
    stop_time = time.perf_counter()
    print('训练时间为 %.3f 秒' % (stop_time - start_time))

    # 保存预测数据和图像
    num_test_x_points = 101
    num_test_y_points = 101
    data_saver = SavePlot(session, x_range, y_range, num_test_x_points, num_test_y_points, xa, xb, ya, yb)
    data_saver.save_and_plot(u_pred, x_res_train, y_res_train)

    
        # 计算误差
    x_test = np.linspace(x_range[0], x_range[1], num_test_x_points).reshape((-1, 1))
    y_test = np.linspace(y_range[0], y_range[1], num_test_y_points).reshape((-1, 1))
    x_t, y_t = np.meshgrid(x_test, y_test)
    x_t = np.reshape(x_t, (-1, 1))
    y_t = np.reshape(y_t, (-1, 1))
    test_dict = {x_res_train: x_t, y_res_train: y_t}
    u_test_pred = session.run(u_pred, feed_dict=test_dict)  # 预测在均匀网格上的解
    Exact_sln = Exact(xa, xb, ya, yb)
    u_test_exact = Exact_sln.u_exact(np.hstack((x_t, y_t)))

    # 计算误差
    L2_error, max_error = compute_errors(u_test_pred, u_test_exact)
    print('L2 Error: %.6e' % L2_error)
    print('Max Error: %.7e' % max_error)
    
    
if __name__ == '__main__':
    main()

程序中已经写好了详细的注释,关于优化器与 TF 会话(session) 的相关知识请各位移步 TensorFlow 优化器使用。另外建议读者对比阅读我之前总结的一维PINN 算法的实现 ,理解一维二维的本质不同,更高维的 PDE 求解也就不在话下了。

运行结果

在这里插入图片描述
在这里插入图片描述
效果不错!

-----------------------------------------------------------------------------------------------
本专栏目标从简单的一维 Poisson 方程,到对流扩散方程,Burges 方程,到二维,三维以及非线性方程,发展方程,积分方程等等,所有文章包含全部可运行代码。请持续关注!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1943852.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【vue前端项目实战案例】之Vue仿饿了么App

本文将介绍一款仿“饿了么”商家页面的App。该案例是基于 Vue2.0 Vue Router webpack ES6 等技术栈实现的一款外卖类App&#xff0c;适合初学者进行学习。 项目源码下载链接在文章末尾 1 项目概述 该项目是一款仿“饿了么”商家页面的外卖类App&#xff0c;主要有以下功能…

electron 网页TodoList工具打包成win桌面应用exe

参考&#xff1a; electron安装&#xff08;支持win、mac、linux桌面应用&#xff09; https://blog.csdn.net/weixin_42357472/article/details/140643624 TodoList工具 https://blog.csdn.net/weixin_42357472/article/details/140618446 electron打包过程&#xff1a; 要将…

RabbitMQ入门详解

前言 本篇文章将详细介绍rabbitmq的基本概念知识&#xff0c;以及rabbitmq各个工作模式在springboot中如何使用。 文章目录 介绍 简介 RabbitMQ 核心 生产者与消费者 Exchange Queue 工作模式 简单模式 工作队列模式 发布订阅模式 路由模式 主题模式 SpringBoot中…

uniapp从入坑到出土(2-初始化你的uniapp项目)

第2章:《初始化你的uniapp项目》 2.1 Vite:点燃魔法的火种魔法准备:环境搭建魔法施展:项目创建魔法测试:运行项目2.2 Vue CLI vs Vite:构建项目的魔法对决2.3 uniapp项目结构初探2.4 创建你的第一个uniapp页面创建你的第一个uniapp页面**魔法代码**(`pages/index/index.…

最新快乐二级域名分发系统重置版v1.7源码-最新美化版+源码+可对接支付

源码简介&#xff1a; 最新快乐二级域名分发系统重置版v1.7源码&#xff0c;它是最新美化版源码可对接支付。 快乐二级域名分发系统重置版v1.7源码&#xff0c;简单快捷、功能强大的控制面板。系统稳定长久&#xff0c;控制面板没任何广告&#xff0c;让网站更实用方便。 最…

ubuntu22.04 安装 NVIDIA 驱动

目录 目录 1、事前问题解决 2、安装 3、卸载 1、事前问题解决 在安装完ubuntu之后&#xff0c;如果进入ubuntu出现黑屏情况&#xff0c;一般就是nvidia驱动与linux自带的不兼容&#xff0c;可以通过以下方式解决&#xff1a; 1、启动电脑&#xff0c;进入引导菜单&#x…

PHP预约推拿按摩小程序系统源码

&#x1f486;‍♀️轻松享受&#xff0c;揭秘“预约推拿按摩小程序”的便捷之道&#x1f4f1; &#x1f308; 开篇&#xff1a;告别繁琐&#xff0c;一键预约舒适时光&#xff01; 在这个快节奏的生活中&#xff0c;找到片刻的宁静与放松成为了我们的奢望。而“预约推拿按摩…

探索BPMN—工作流技术的理论与实践|得物技术

一、前言 19世纪70年代&#xff0c;流程管理思想萌芽阶段。 怎样提高工作效率&#xff1f; 泰勒&#xff1a;标准化个人操作流程 亨利福特&#xff1a;规定标准时间定额 标准化、精简化、通用化、专业化。 20世纪70年代&#xff0c;工作流技术起源于办公自动化领域的研究。由于…

minio 服务docker配置

用minio docker配置了一个服务&#xff0c;分享链接始终是127.0.01开始的&#xff0c; 改成docker的host的ip则提示签名不匹配&#xff0c; 好在这个文件主要是用来下载的&#xff0c;所以可以通过设置bucket的匿名访问权限来实现下载&#xff1b; 这样不需要后面的地址参数就…

GeoHash原理介绍以及在redis中的应用

GeoHash将二维信息编码成了一个一维信息。降维后有三个好处&#xff1a; 编码后数据长度变短&#xff0c;利于节省存储。利于使用前缀检索当分割的足够细致,能够快速的对双方距离进行快速查询 GeoHash是一种地址编码方法。他能够把二维的空间经纬度数据编码成一个字符串。 1…

网站漏洞扫描软件Burp suite和Xray安装应用及联合使用

目录 1、网站漏洞扫描软件应用-Burp suite 01 burp 扫描工具使用介绍&#xff1a; 02 burp 扫描工具安装过程&#xff1a; 1&#xff09;获取扫描工具程序包 2&#xff09;安装部署扫描工具 3&#xff09;bp安装完毕的基础设置&#xff1a; 3.1&#xff09;抓取浏览器访…

CSS怎么实现镜像效果?

实现镜像效果&#xff08;包含动画&#xff09; 需求分析 创建一个可以接收任意内容的 Vue 组件&#xff0c;并在其下方显示该内容的镜像。镜像效果应包括垂直翻转和渐变透明效果&#xff0c;以模拟真实的倒影。支持动画效果&#xff0c;使内容和镜像同步运动。组件应具有高可…

Redis从入门到超神-(四)Redis实现分布式锁原理

引言 什么是分布式锁&#xff1f; 分布式锁是分布式系统中用于控制多个进程或线程对共享资源的访问的一种机制。在分布式系统中&#xff0c;由于存在多个服务实例或节点&#xff0c;它们可能会同时尝试访问或修改同一份数据或资源。如果没有适当的同步机制&#xff0c;就可能导…

装机基础知识,不被坑,纯小白级别

装机基础知识&#xff0c;不被坑&#xff0c;纯小白级别 CPU主要是英特尔和AMD1&#xff0c;AMDyes2 &#xff0c;英特尔老大哥牙膏厂3&#xff0c;CPU参数 显卡主要是NVidia和AMD1&#xff0c;gtx系列2&#xff0c;rtx系列3&#xff0c;AMD的rx系列显卡4&#xff0c;显卡参数问…

PLC通过IGT-SER系列智能网关快速实现WebService接口调用案例

IGT-SER系列智能网关支持PLC设备数据对接到各种系统平台&#xff0c;包括SQL数据库&#xff0c;以及MQTT、HTTP协议的数据服务端&#xff1b;通过其边缘计算功能和脚本生成的工具软件&#xff0c;非常方便快速实现PLC、智能仪表与WebService服务端通信。 本文是通过智能网关读取…

SpringSecurity如何正确的设置白名单

在SpringSecurity中,往往需要对部分接口白名单访问,而大部分在使用Security中就有一个误区,那就是免鉴权访问和白名单的区别。 大部分的Security文章包括官方文档给出免鉴权访问都是使用.permitAll()去对相应路径进行免鉴权访问,但实际上这仅仅只表示该资源不需要相应的权限访问…

交易积累-BIAS

BIAS&#xff08;乖离率&#xff09;是股票交易中常用的一种技术分析指标&#xff0c;用于衡量股票当前价格与其某一移动平均线之间的偏离程度。它的计算简单&#xff0c;易于理解和应用&#xff0c;因此在投资者和交易者中相当流行。 计算公式&#xff1a; BIAS的计算公式是&…

高效部署Modbus转MQTT网关:Modbus RTU、Modbus TCP转MQTT

钡铼Modbus转MQTT网关&#xff0c;简而言之&#xff0c;就是通过将Modbus协议&#xff08;包括Modbus RTU和Modbus TCP&#xff09;的数据转换为MQTT协议的数据格式&#xff0c;从而实现设备数据的上传和云端控制指令的下发。这一转换过程使得设备能够与基于MQTT协议的云平台进…

Linux_实现UDP网络通信

目录 1、实现服务器的逻辑 1.1 socket 1.2 bind 1.3 recvfrom 1.4 sendto 1.5 服务器代码 2、实现客户端的逻辑 2.1 客户端代码 3、实现通信 结语 前言&#xff1a; 在Linux下&#xff0c;实现传输层协议为UDP的套接字进行网络通信&#xff0c;网络层协议为IPv4&am…

Spring Boot集成Spire.doc实现对word的操作

1.什么是spire.doc? Spire.Doc for Java 是一款专业的 Java Word 组件&#xff0c;开发人员使用它可以轻松地将 Word 文档创建、读取、编辑、转换和打印等功能集成到自己的 Java 应用程序中。作为一款完全独立的组件&#xff0c;Spire.Doc for Java 的运行环境无需安装 Micro…