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

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

− Δ u = f in  Ω , u = 0 on  Γ : = ∂ Ω . \begin{align} -\Delta u &= f \quad & \text{in } \Omega,\\ u & =0 \quad & \text{on } \Gamma:=\partial \Omega. \end{align} Δuu=f=0in Ω,on Γ:=Ω.
其中 Ω = [ X a , X b ] \Omega = [X_a,X_b] Ω=[Xa,Xb] 是一段区间,一维情况 Δ u = u x x \Delta u = u_{xx} Δu=uxx.

在这里插入图片描述

完整代码及其注释如下:

import tensorflow as tf
#print(tf.__version__)
import numpy as np  
import math
# def is_log2_close_to_int(n, eps=1e-9):  
#     log_n = math.log2(n)  
#     return math.isclose(math.fmod(log_n, 1), 0, abs_tol=eps)  # 定义Exact类,用于计算精确解  
class Exact:  def __init__(self, xa, xb):  # 初始化类,接受两个参数xa和xb,代表区间的两个端点  self.xa = xa  # 区间左端点  self.xb = xb  # 区间右端点  def u_exact(self, X):  # 计算并返回精确解u(X)  # 这里使用正弦函数作为精确解,其频率与区间长度(xb-xa)有关  u = np.sin(2*np.pi*X / (self.xb - self.xa))  return u  # 定义Dataset类,用于生成数据  
class Dataset:  def __init__(self, x_range, N_res, N_b, xa, xb):  # 初始化类,接受多个参数  self.x_range = x_range  # 区间范围,例如[0, 1]  self.N_res = N_res      # 内部节点数,用于构建内部网格  self.N_b = N_b          # 边界条件点数(通常这里N_b为2,因为有两个边界)  self.xa = xa            # 区间左端点  self.xb = xb            # 区间右端点  def bc(self, X_b):  # 计算并返回边界条件上的精确解  # 创建一个Exact对象,用于计算精确解  U_bc = Exact(self.xa, self.xb)  u_bc = U_bc.u_exact(X_b)  # 计算边界条件X_b上的精确解  return u_bc  def build_data(self):  # 构建并返回数据集,包括内部网格点、边界网格点和区间端点  x0 = self.x_range[0]  # 区间左端点  x1 = self.x_range[1]  # 区间右端点  # 区间端点(最小值和最大值)  Xmin = np.array([[x0]])  Xmax = np.array([[x1]])  # 构建内部网格点  # 可以选择使用均匀网格或随机网格  ## For the equation, you can choose using the uniform mesh"""N = self.N_resX_res_input = np.linspace(x0, x1, N).reshape((-1, 1))"""# 这里展示了如何使用随机网格  X_res_input = x0 + (x1-x0)*np.random.rand(self.N_res,1)  # 生成N_res个在[x0, x1]区间内的随机点  # 边界网格点(在这个例子中,我们手动指定了边界点)  X_b0_input = np.array([[x0]])  # 左边界点  X_b1_input = np.array([[x1]])  # 右边界点  # 返回构建的数据集  return X_res_input, X_b0_input, X_b1_input, Xmin, Xmaxdef calculate_errors(sess, x_res_train, u_pred, x_t, u_e):  """  计算并打印L2范数和最大模范数的误差。  """  u_pred_vals = sess.run(u_pred, feed_dict={x_res_train: x_t})  error_l2 = np.linalg.norm(u_pred_vals - u_e, ord=2) / np.linalg.norm(u_e, ord=2)  error_max = np.max(np.abs(u_pred_vals - u_e)) / np.max(np.abs(u_e))  print(f"L2 Error: {error_l2:.8f}")  print(f"Max Error: {error_max:.8f}")  

神经网络及其训练过程所需要的函数定义:

import tensorflow as tf  
import numpy as np  
import time  
import matplotlib.pyplot as plt  class Train:  def __init__(self, train_dict):  """  初始化Train类。  Args:  train_dict (dict): 用于训练的feed_dict,包含训练数据和其他必要的TensorFlow变量。  """  self.train_dict = train_dict  self.step = 0  # 初始化训练步数计数器  def callback(self, loss_):  """  回调函数,用于在LBFGS优化器每次迭代后打印损失。  Args:  loss_ (float): 当前迭代的损失值。  """  self.step += 1  if math.isclose(math.fmod(math.log2(self.step), 1), 0, abs_tol=1e-9): print('Loss: %.3e' % (loss_))  def nntrain(self, sess, u_pred, loss, test_dict, u_e, x_t, train_adam, train_lbfgs):  """  执行神经网络训练。  Args:  sess (tf.Session): TensorFlow会话。  u_pred (tf.Tensor): 预测值的Tensor。  loss (tf.Tensor): 损失函数的Tensor。  test_dict (dict): 用于测试的feed_dict。  u_e (np.array): 精确解的数值数组。  x_t (np.array): 测试点或网格点的x坐标数组。  train_adam (tf.Operation): Adam优化器的TensorFlow操作。  train_lbfgs (LBFGSOptimizer 或类似): 用于精细调整的LBFGS优化器。  Returns:  None  """  n = 0  # 初始化迭代计数器  nmax = 10000  # 最大迭代次数  loss_c = 1.0e-4  # 收敛条件:当损失小于此值时停止训练  loss_ = 1.0  # 初始化损失值  while n < nmax and loss_ > loss_c:  n += 1  # 使用Adam优化器进行训练  u_, 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('Steps: %d, loss: %.3e' % (n, loss_))  # 在测试集上评估模型  u_test = sess.run(u_pred, feed_dict=test_dict)  # 绘制精确解和预测解的对比图  plt.cla()  # 清除之前的图表  plt.plot(x_t, u_e, 'bo', markersize=0.4, label='Exact solution')  plt.plot(x_t, u_test, 'rv', markersize=0.4, label='PINN solution')  plt.legend()  plt.show()  plt.pause(0.1)  # 暂停一段时间以便观察图表  # 使用LBFGS优化器进行精细调整  train_lbfgs.minimize(sess, feed_dict=self.train_dict, fetches=[loss], loss_callback=self.callback)
 import tensorflow as tf  
import numpy as np  class DNN:  """  深度神经网络类,用于构建和训练神经网络。  """  def __init__(self, layer_size, Xmin, Xmax):  """  初始化DNN类。  Args:  layer_size (list): 网络各层的神经元数量。  Xmin (numpy.ndarray): 输入数据的最小值。  Xmax (numpy.ndarray): 输入数据的最大值。  """  self.size = layer_size  self.Xmin = Xmin  self.Xmax = Xmax  def hyper_initial(self):  """  初始化网络的权重和偏置。  Returns:  tuple: 包含权重和偏置的列表。  """  L = len(self.size)  Weights = []  Biases = []  for l in range(1, L):  in_dim = self.size[l-1]  out_dim = self.size[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, W, b):  """  前馈神经网络的前向传播。  Args:  X (tf.Tensor): 输入数据。  W (list): 权重列表。  b (list): 偏置列表。  Returns:  tf.Tensor: 网络的输出。  """  A = 2.0*(X - self.Xmin)/(self.Xmax - self.Xmin) - 1.0  # 归一化和缩放输入  L = len(W)  for i in range(L-1):  A = tf.tanh(tf.add(tf.matmul(A, W[i]), b[i]))  # 应用激活函数和线性变换  u = tf.add(tf.matmul(A, W[-1]), b[-1])  # 输出层  return u  def pdenn(self, x, W, b):  """  计算物理驱动的神经网络残差(无边界条件)。  Args:  x (tf.Tensor): 输入数据。  W (list): 权重列表。  b (list): 偏置列表。  Returns:  tf.Tensor: 残差f。  """  u = self.fnn(x, W, b)  u_x = tf.gradients(u, x)[0]  u_xx = tf.gradients(u_x, x)[0]  rhf = np.pi**2 * tf.sin(np.pi*x)  # 右侧手边项  f = -u_xx - rhf  # 计算残差  return f  def fnn_BC(self, X, W, b):  """  应用边界条件的前馈神经网络。  Args:  X (tf.Tensor): 输入数据。  W (list): 权重列表。  b (list): 偏置列表。  Returns:  tf.Tensor: 应用边界条件后的输出。  """  Xmax = self.XmaxXmin = self.Xminu = self.fnn(X, W, b)ua = self.fnn(tf.cast(Xmin, tf.float32), W, b)ub = self.fnn(tf.cast(Xmax, tf.float32), W, b)K = tf.subtract(ub, ua)/(Xmax[0,0] - Xmin[0,0])c = tf.subtract(ua, Xmin*K)u = tf.subtract(u, tf.add(tf.matmul(X, K), c))return udef pdenn_BC(self, x, W, b):  """  计算物理驱动的神经网络残差(带边界条件)。  Args:  x (tf.Tensor): 输入数据。  W (list): 权重列表。  b (list): 偏置列表。  Returns:  tf.Tensor: 残差f。  """  u = self.fnn_BC(x, W, b)u_x = tf.gradients(u, x)[0]u_xx = tf.gradients(u_x, x)[0]rhf = np.pi**2 * tf.sin(np.pi*x)f = -u_xx - rhfreturn fdef fnn_BC2(self, X, W, b):  """  另一种应用边界条件的方法(示例)。  Args:  X (tf.Tensor): 输入数据。  W (list): 权重列表。  b (list): 偏置列表。  Returns:  tf.Tensor: 应用边界条件后的输出。  """  Xmax = self.XmaxXmin = self.Xminu = self.fnn(X, W, b)u = (X-Xmax)*(X-Xmin) * ureturn udef pdenn_BC2(self, x, W, b):  """  使用另一种边界条件计算物理驱动的神经网络残差。  Args:  x (tf.Tensor): 输入数据。  W (list): 权重列表。  b (list): 偏置列表。  Returns:  tf.Tensor: 残差f。  """  u = self.fnn_BC2(x, W, b)u_x = tf.gradients(u, x)[0]u_xx = tf.gradients(u_x, x)[0]rhf = np.pi**2 * tf.sin(np.pi*x)f = -u_xx - rhfreturn f

画图:

# 导入必要的库  
import tensorflow as tf  # TensorFlow库,用于构建和训练神经网络  
import numpy as np  # NumPy库,用于处理数值数据  
import matplotlib.pyplot as plt  # Matplotlib库,用于绘图  
import os  # os库,用于与操作系统交互,如文件路径操作  # 设置保存结果的路径  
savepath='./Output'  
if not os.path.exists(savepath):  os.makedirs(savepath)  # 如果路径不存在,则创建该路径  # 定义一个类SavePlot,用于保存预测结果并绘制图形  
class SavePlot:  def __init__(self, sess, x_range, N, xa, xb):  # 初始化函数,设置类的属性  self.x_range = x_range  # 预测时x的范围  self.N = N  # 预测时x的样本数  self.sess = sess  # TensorFlow会话,用于执行TensorFlow操作  self.xa = xa  # 精确解计算时可能需要的参数a  self.xb = xb  # 精确解计算时可能需要的参数b  def saveplt(self, u_pred, x_res_train):  # 在给定范围内生成均匀的x点  x_t = np.linspace(self.x_range[0], self.x_range[1], self.N).reshape((-1, 1))  # 构建feed_dict,用于在TensorFlow会话中执行u_pred  test_dict = {x_res_train: x_t}  # 使用TensorFlow会话执行u_pred,得到预测结果  u_test = self.sess.run(u_pred, feed_dict=test_dict)  # 将预测结果保存到文件  np.savetxt('./Output/u_pred', u_test, fmt='%e')  # 计算并保存精确解  Exact_sln = Exact(self.xa, self.xb)  u_e = Exact_sln.u_exact(x_t)  np.savetxt('./Output/u_e', u_e, fmt='%e')  # 计算并打印预测误差  err_ = np.linalg.norm(u_test - u_e)/np.linalg.norm(u_e)  print(err_)  # 绘制精确解和预测解的对比图  plt.plot(x_t, u_e, 'bo', markersize=0.4, label='Exact solution')  plt.plot(x_t, u_test, 'rv', markersize=0.4, label='PINN solution')  plt.legend()  # 显示图例  plt.show()  # 显示图形  # 注意:代码中注释掉的plt.close()和.close()通常不是必要的,除非在循环中多次调用plt.plot或打开文件需要关闭。  
# plt.close()用于关闭当前图形窗口,但在这里调用plt.show()后通常不需要。  

下面是主函数:

# 导入必要的库  
import os  
import tensorflow as tf  
import numpy as np  
import time  
import matplotlib.pyplot as plt  
import scipy.io  # 设置随机数种子以确保结果的可重复性  
np.random.seed(1234)  
tf.set_random_seed(1234)  # 注意:在TensorFlow 2.x中,应使用tf.random.set_seed  def main():  # 定义问题域和分辨率等参数  x_range = [-1.0, 1.0]  # 定义x的范围  N_res = 50  # 残差点数量  N_bx = 2  # 边界点数量  xa, xb = x_range  # 边界值  # 创建数据集对象  data = Dataset(x_range, N_res, N_bx, xa, xb)  # 构建数据  X_res, X_b0, X_b1, Xmin, Xmax = data.build_data()  # 定义神经网络结构  layers = [1] + 5*[40] + [1]  # 神经网络层数和每层的神经元数  # 创建占位符  x_res_train = tf.placeholder(shape=[None, 1], dtype=tf.float32)  x_b0_train = tf.placeholder(shape=[None, 1], dtype=tf.float32)  x_b1_train = tf.placeholder(shape=[None, 1], dtype=tf.float32)  # 创建PINN对象  pinn = DNN(layers, Xmin, Xmax)  W, b = pinn.hyper_initial()  # 初始化权重和偏置  # 定义网络输出和物理方程残差  u_pred = pinn.fnn_BC2(x_res_train, W, b)  # 使用特定边界条件的网络输出  f_pred = pinn.pdenn_BC2(x_res_train, W, b)  # 残差,即物理方程的不满足度  # 定义边界条件输出  u_b0_pred = pinn.fnn(x_b0_train, W, b)  u_b1_pred = pinn.fnn(x_b1_train, W, b)  # 定义损失函数(这里只考虑了残差的平方和)  loss = tf.reduce_mean(tf.square(f_pred))  # 定义优化器  train_adam = tf.train.AdamOptimizer(0.0008).minimize(loss)  train_lbfgs = tf.contrib.opt.ScipyOptimizerInterface(loss,method = "L-BFGS-B",options = {'maxiter': 80000,'ftol': 1.0*np.finfo(float).eps}) # 注意:tf.contrib在TensorFlow 2.x中已被移除  # TensorFlow 1.x 会话管理  sess = tf.Session()  sess.run(tf.global_variables_initializer())  # 准备训练和测试数据字典  train_dict = {x_res_train: X_res, x_b0_train: X_b0, x_b1_train: X_b1}x_t = np.linspace(xa, xb, 101).reshape((-1, 1))test_dict = {x_res_train: x_t}Exact_sln = Exact(xa, xb)  # 真实解的计算对象  u_e = Exact_sln.u_exact(x_t)  # 真实解  # 训练模型  Model = Train(train_dict)  start_time = time.perf_counter()Model.nntrain(sess, u_pred, loss, test_dict, u_e, x_t, train_adam, train_lbfgs)  # 打印训练时间  stop_time = time.perf_counter()print('Duration time is %.3f seconds'%(stop_time - start_time))# 在模型训练结束后,计算并打印误差  calculate_errors(sess, x_res_train, u_pred, x_t, u_e)  #Save the dataN_test = 101datasave = SavePlot(sess, x_range, N_test, xa, xb)datasave.saveplt(u_pred, x_res_train)if __name__ == '__main__':  main()

我是在 Jupyter 文件上运行的,在其他集成开发环境中也可以类似运行。

运行结果:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

效果不错!

下期预告:

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

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

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

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

相关文章

非对称加密算法RSA的OpenSSL代码实现Demo

目录 1 RSA简介 1.1 RSA算法介绍 1.2 RSA算法的速度与安全性 1.3 RSA存储格式 1.3.1 PKCS#1 标准主要用于 RSA密钥&#xff0c;其RSA公钥和RSA私钥PEM格式 1.3.2 PKCS#8 标准定义了一个密钥格式的通用方案&#xff0c;其公钥和私钥PEM格式 2 OpenSSL代码实现 2.1 生…

初学51单片机之指针基础与串口通信应用

开始之前推荐一个电路学习软件&#xff0c;这个软件笔者也刚接触。名字是Circuit有在线版本和不在线版本&#xff0c;这是笔者在B站看视频翻到的。 Paul Falstadhttps://www.falstad.com/这是地址。 离线版本在网站内点这个进去 根据你的系统下载你需要的版本红线的是windows…

第九讲:POU与变量基础

POU(Program Organization Unit)的分类 一、定义及分类 POU即程序组成单元 二、三种POU的作用 1、功能/功能快:看作算法 功能块的POU是比较复杂的指令 三、功能块POU和功能POU的区别 1、理解功能POU(对比) 不添加实例名,就不需要去建立变量,所以就不会占到内存。 因…

算法题目整合4

文章目录 122. 大数减法123. 滑动窗口最大值117. 软件构建124. 小红的数组构造125. 精华帖子126. 连续子数组最大和 122. 大数减法 题目描述 以字符串的形式读入两个数字&#xff0c;编写一个函数计算它们的差&#xff0c;以字符串形式返回。输入描述 输入两个数字&#xff…

物联网专业创新人才培养体系的探索与实践

一、引言 随着物联网&#xff08;IoT&#xff09;技术的迅猛发展&#xff0c;物联网领域的人才需求日益增加。物联网技术作为新一轮信息技术革命的核心&#xff0c;已经渗透到社会生活的各个领域&#xff0c;对推动经济转型升级、提升国家竞争力具有重要意义。因此&#xff0c…

VUE之---slot插槽

什么是插槽 slot 【插槽】&#xff0c; 是 Vue 的内容分发机制&#xff0c; 组件内部的模板引擎使用slot 元素作为承载分发内容的出口。slot 是子组件的一个模板标签元素&#xff0c; 而这一个标签元素是否显示&#xff0c; 以及怎么显示是由父组件决定的。 VUE中slot【插槽】…

自己开发软件实现网站抓取m3u8链接

几天前一个同学说想下载一个网站的视频找不到连接&#xff0c;问我有没有什么办法,网站抓取m3u8链接 网页抓取m3u8链接。当时一听觉得应该简单&#xff0c;于是说我抽空看看。然后就分析目标网页&#xff0c;试图从网页源码里找出连接&#xff0c;有的源代码直接有,但是有的没有…

Java二十三种设计模式-代理模式模式(8/23)

代理模式&#xff1a;为对象访问提供灵活的控制 引言 代理模式&#xff08;Proxy Pattern&#xff09;是一种结构型设计模式&#xff0c;它为其他对象提供一个代替或占位符&#xff0c;以控制对它的访问。 基础知识&#xff0c;java设计模式总体来说设计模式分为三大类&#…

Varjo XR-4系列现已获得达索3DEXPERIENCE平台官方支持

近日&#xff0c;全球领先的工业虚拟和混合现实解决方案提供商Varjo宣布&#xff0c;Varjo XR-4系列现已获得达索3DEXPERIENCE平台的本地支持。这种集成为工程师和设计师带来了先进的虚拟和混合现实功能&#xff0c;他们可以通过沉浸式技术创新并简化他们的3D工作流程。 在达索…

【iOS】Tagged Pointer

目录 前言什么是Tagged Pointer&#xff1f;引入Tagged Pointer技术之前引入Tagged Pointer之后总结 Tagged Pointer原理&#xff08;TagData分析&#xff09;关闭数据混淆MacOS分析NSNumberNSString iOS分析 判断Tagged PointerTagged Pointer应用Tagged Pointer 注意点 Tagge…

Qt绘制指南针(仪表盘绘制封装使用)

指南针是一种用来确定方向的工具。它由一个磁针制成&#xff0c;其一端被磁化&#xff0c;可以自由旋转。当放置在水平面上时&#xff0c;磁针会指向地球的磁北极。通过观察磁针的指向&#xff0c;我们可以确定地理北方的方向。本示例是在Qt中绘制一个指南针&#xff0c;通过继…

Android WebViewClient 的 `shouldOverrideUrlLoading` 方法

简介 在Android开发中&#xff0c;WebView是一个强大的工具&#xff0c;可以在你的应用中显示网页内容。了解 WebViewClient 中的 shouldOverrideUrlLoading 方法是至关重要的&#xff0c;因为这个方法允许你控制 URL 在 WebView 中的处理方式。 在本文中&#xff0c;我们将详…

S71200 - 笔记

1 S71200 0 ProfiNet - 2 PLC编程 01.如何零基础快速上手S7-1200_哔哩哔哩_bilibili 西门子S7-1200PLC编程设计学习视频&#xff0c;从入门开始讲解_哔哩哔哩_bilibili

Linux:进程信号(一.认识信号、信号的产生及深层理解、Term与Core)

上次结束了进程间通信的知识介绍&#xff1a;Linux&#xff1a;进程间通信&#xff08;二.共享内存详细讲解以及小项目使用和相关指令、消息队列、信号量 文章目录 1.认识信号进程看待信号方式 2.信号的产生2.1信号的处理的方式 --- signal()函数2.2kill指令产生信号2.3键盘产生…

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

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

现货白银交易中spring形态的应用

在现货白银市场中交易想取得成功并从市场中获利&#xff0c;掌握一些工具是必不可少的&#xff0c;而今天我们要介绍的现货白银的交易工具就是spring形态。 对于spring这个英文&#xff0c;我们都很熟悉&#xff0c;它有春天的意思&#xff0c;但这里所说的spring形态并不是指春…

ComfyUI进阶:Comfyroll节点 (最终篇)+应用实例

前言&#xff1a; 学习ComfyUI是一场持久战&#xff0c;而Comfyroll 是一款功能强大的自定义节点集合&#xff0c;专为 ComfyUI 用户打造&#xff0c;旨在提供更加丰富和专业的图像生成与编辑工具。借助这些节点&#xff0c;用户可以在静态图像的精细调整和动态动画的复杂构建…

【LabVIEW作业篇 - 5】:水仙花数、数组与for循环的连接

文章目录 水仙花数数组与for循环的连接 水仙花数 水仙花数&#xff0c;是指一个3位数&#xff0c;它的每个位上的数字的3次幂之和等于它本身。如371 3^3 7^3 1^3&#xff0c;则371是一个水仙花数。 思路&#xff1a;水仙花数是一个三位数&#xff0c;通过使用for循环&#xf…

redis的使用场景和持久化方式

redis的使用场景 热点数据的缓存。热点&#xff1a;频繁读取的数据。限时任务的操作&#xff1a;短信验证码。完成session共享的问题完成分布式锁。 redis的持久化方式 什么是持久化&#xff1a;把内存中的数据存储到磁盘的过程&#xff0c;同时也可以把磁盘中的数据加载到内存…

FPGA实现二选一数据选择器

在FPGA开发当中&#xff0c;我们最早开始接触的就是关于二选一选择器的设计。 1、原理 通过一个sel选择位判断输出out为a还是b&#xff0c;这里我们规定&#xff1a; sel0时&#xff0c;outa sel1时&#xff0c;outb 2、工程代码 多路选择器的缩写为MUX&#xff0c;这里我们见…