FFTW基本概念与安装使用
FFTW基本概念与安装使用
- 1 基本概念
- 2 编译安装
- 3 使用实例
- 3.1 单线程
- 3.2 多线程
本文主要介绍FFTW库的基本概念、编译安装和使用方法。
1 基本概念
FFTW (Fastest Fourier Transform in the West)是C语言的一个子程序库,用于计算一维或多维离散傅里叶变换(Discrete Fourier transform, DFT),输入可以是任意长度的实数或复数数组。最新的版本为3.3.10,所以也记为FFTW3。
FFTW的计算流程包括规划(planning)和执行(execution)两个阶段。在规划阶段,规划器(planner)会根据用户输入的复杂问题递归的分解为更简单的子问题,当子问题足够简单时,便调用预定义的代码直接解决。由此形成诸多解决问题的方案(plans),并从其中选择速度最快的一种,方案确定后便可进入执行阶段。在执行阶段,用户按照数据结构输入待变换数组,然后按照方案逐步执行,最后输入变换后的数组。
对于给定傅里叶变换问题,FFTW规划器能够给出解决问题的一系列方案,并从中选择最快的一种。FFTW能够解决多维的傅里叶变换问题,定义二维傅里叶变换的输入数据数组为n0×n1,三维傅里叶变换的输入数据数组为n0×n1×n2。数组中数据的顺序为row-major顺序,即最后一个维度的索引变化最快(n0×n1表示n0个n1点的序列,n1连续变化)。FFTW有4中工作模式:
- 单线程单内存:使用一个线程、且数据存储到一个内存中。
- 多线程共享内存:为提升计算速度,可以使用多线程并行进行一维或多维的傅里叶变换,所有线程使用同一共享内存。
- 多核分布式内存:当变换的矩阵非常大以至于单处理器的内存容量不足时,分布式内存并行处理架构则变得非常实用。在该架构下,每个处理器具备独立的内存,成千上万个处理器构成一个集群。每个处理器对应的内存仅存储待变换数组的一部分数据,从内存中读取相应的数据进行傅里叶变换。因此在进行多维傅里叶变换时,需要在分布式内存之间进行数据交互,数据交互方式使用MPI (Message-Passing Interface)。
- 多处理器多线程:FFTW也支持多处理器和多线程同时使用,例如具备4个支持共享内存的处理器节点,可以在每个节点内使用多线程进行并行计算,在节点间使用MPI进行数据交互。由于计算流程和数据交互更加复杂,需要进行详细的设计。
2 编译安装
从FFTW官网下载FFTW3.3.10,依次执行下述命令对软件进行配置、编译和安装。
- 配置:
./configure --enable-threads
- 编译:
make
- 安装:
make install
- 安装依赖
- Ubuntu:
sudo apt-get install libfftw3-dev libfftw3-doc libfftw3-double3
- CentOS:
yum install fftw-devel
- Ubuntu:
- 卸载:
make distclean
根据第三节说明编写程序,程序命名为fftw.cpp,执行下述编译语句进行编译和运行,-lfftw3表示使用fftw3的库进行编译,-lfftw3_threads表示使用多线程的库。
- 编译
- 单线程编译:
g++ -o fftw fftw.cpp -lfftw3
- 多线程编译:
g++ -o fftw fftw.cpp -lfftw3 -lfftw3_threads -lm
- 单线程编译:
- 运行:
./fftw
3 使用实例
3.1 单线程
- 一维傅里叶变换
#include <complex>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <ctime>
#include <chrono>
#include <unistd.h>
#include "fftw3.h"using namespace std;int main() {const int len = 8; //序列长度fftw_complex *in, *out; //定义输入输出变量fftw_plan plan; //定义方案in = (fftw_complex*) fftw_malloc (sizeof(fftw_complex) * len); //分配输入空间out = (fftw_complex*) fftw_malloc (sizeof(fftw_complex) * len); //分配输出空间// 初始化输入信号for (int i = 0; i < len; i++) {in[i][0] = 35.24 * i; //实部in[i][1] = -27.62 * i; //虚部std::cout << in[i][0] << " " << in[i][1] << std::endl;}// 定义fftw_planplan = fftw_plan_dft_1d(len, in, out, FFTW_FORWARD, FFTW_ESTIMATE);//plan = fftw_plan_dft_1d(len, in, out, FFTW_FORWARD, FFTW_MEASURE);// 执行fftauto start = std::chrono::high_resolution_clock::now();fftw_execute(plan);//usleep(1);auto end = std::chrono::high_resolution_clock::now();auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();std::cout << "程序运行时间: " << duration << " 微秒" << std::endl;// 输出结果ofstream fout("out.txt");int w = 36;for (int i = 0; i < len; i++) {if (out[i][1] < 0) {fout << out[i][0] << out[i][1] << ' ';}else {fout << out[i][0] << '+' << out[i][1] << ' ';}}// 释放内存fftw_cleanup();fftw_free(in);fftw_free(out);return 0;
}
- 二维傅里叶变换
#include <complex>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <ctime>
#include <chrono>
#include <unistd.h>
#include "fftw3.h"using namespace std;#define ROWS 64
#define COLS 64int main() {fftw_complex *in, *out; //定义输入输出变量fftw_plan plan; //定义方案in = (fftw_complex*) fftw_malloc (sizeof(fftw_complex)*ROWS*COLS); //分配输入空间out = (fftw_complex*) fftw_malloc (sizeof(fftw_complex)*ROWS*COLS); //分配输出空间// 初始化输入信号for (int i = 0; i < ROWS; i++) {for (int j = 0; j < COLS; j++) {in[i*COLS+j][0] = 35.24 * i; //实部in[i*COLS+j][1] = -27.62 * j; //虚部std::cout << in[i*COLS+j][0] << " " << in[i*COLS+j][1] << std::endl;}}// 定义fftw_planplan = fftw_plan_dft_2d(ROWS, COLS, in, out, FFTW_FORWARD, FFTW_ESTIMATE);//plan = fftw_plan_dft_1d(len, in, out, FFTW_FORWARD, FFTW_MEASURE);// 执行fftauto start = std::chrono::high_resolution_clock::now();fftw_execute(plan);//usleep(1);auto end = std::chrono::high_resolution_clock::now();auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();std::cout << "程序运行时间: " << duration << " 微秒" << std::endl;// 输出结果ofstream fout("results_cpp");int w = 36;for (int i = 0; i < ROWS; i++) {for (int j = 0; j < COLS; j++) {if (out[i*COLS+j][1] < 0) {fout << out[i*COLS+j][0] << out[i*COLS+j][1] << ' ';}else {fout << out[i*COLS+j][0] << '+' << out[i*COLS+j][1] << ' ';}if (j == COLS-1) {fout << endl;}}}// 释放内存fftw_cleanup();fftw_free(in);fftw_free(out);return 0;
}
- 三维傅里叶变换
#include <complex>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <ctime> //计时
#include <chrono> //计时
#include <unistd.h> //usleep函数
#include <string.h>
#include <stdio.h>
#include "fftw3.h"using namespace std;#define HIGH 64
#define ROWS 64
#define COLS 64int main() {fftw_complex *in, *out; //定义输入输出变量fftw_plan plan; //定义方案int i, j, k;in = (fftw_complex*) fftw_malloc (sizeof(fftw_complex)*HIGH*ROWS*COLS); //分配输入空间out = (fftw_complex*) fftw_malloc (sizeof(fftw_complex)*HIGH*ROWS*COLS); //分配输出空间// 初始化输入信号for (k = 0; k < HIGH; k++) {for (j = 0; j < ROWS; j++) {for (i = 0; i < COLS; i++) {in[k*ROWS*COLS+j*COLS+i][0] = k*215.42 + 35.24*i; //实部in[k*ROWS*COLS+j*COLS+i][1] = k*215.42 - 27.62*j; //虚部//std::cout << in[k*ROWS*COLS+j*COLS+i][0] << " " << in[k*ROWS*COLS+j*COLS+i][1] << std::endl;}}}/*ifstream fin("data");string line; //读取文件的每一行string value; //每一行的数据int cnt;int pos; //分割符位置int len; //字符串长度k = j = cnt = 0;while (getline(fin, line)) {j = cnt / COLS;if (cnt >= COLS * ROWS) {k++;cnt = 0;} else {cnt = cnt + COLS;}len = line.size(); //字符串长度if (len == 0) {continue; //跳过空行}for (i = 0; i < COLS; i++) {len = line.size();pos = line.find(' '); //查找字符在字符串中的位置value = line.substr(0,pos);//std::cout << value << ' ';line = line.substr(pos+1,len); //剩余字符串//std::cout << line << endl;//if (i == COLS-1) {// std::cout << endl;//}in[k*ROWS*COLS+j*COLS+i][0] = stof(value); //实部in[k*ROWS*COLS+j*COLS+i][1] = 0; //虚部//std::cout << in[k*ROWS*COLS+j*COLS+i][0] << " " << in[k*ROWS*COLS+j*COLS+i][1] << std::endl;}}*/// 定义fftw_planplan = fftw_plan_dft_3d(HIGH, ROWS, COLS, in, out, FFTW_FORWARD, FFTW_ESTIMATE);// 执行fftauto start = std::chrono::high_resolution_clock::now();fftw_execute(plan);//usleep(1);auto end = std::chrono::high_resolution_clock::now();auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();std::cout << "程序运行时间: " << duration << " 微秒" << std::endl;// 输出结果ofstream fout("results_cpp");for (k = 0; k < HIGH; k++) {for (j = 0; j < ROWS; j++) {for (i = 0; i < COLS; i++) {if (out[k*ROWS*COLS+j*COLS+i][1] < 0) {fout << out[k*ROWS*COLS+j*COLS+i][0] << out[k*ROWS*COLS+j*COLS+i][1] << ' ';} else {fout << out[k*ROWS*COLS+j*COLS+i][0] << '+' << out[k*ROWS*COLS+j*COLS+i][1] << ' ';}if (i == COLS-1) {fout << endl;}if (j==ROWS-1 && i==COLS-1) {fout << endl;}}}}// 释放内存fftw_cleanup();fftw_free(in);fftw_free(out);return 0;
}
3.2 多线程
- 三维傅里叶变换
#include <complex>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <ctime> //计时
#include <chrono> //计时
#include <unistd.h> //usleep函数
#include <string.h>
#include <stdio.h>
#include "fftw3.h"using namespace std;#define HIGH 64
#define ROWS 64
#define COLS 64int main() {fftw_complex *in, *out; //定义输入输出变量fftw_plan plan; //定义方案int nthreads; //使用的线程数int i, j, k;in = (fftw_complex*) fftw_malloc (sizeof(fftw_complex)*HIGH*ROWS*COLS); //分配输入空间out = (fftw_complex*) fftw_malloc (sizeof(fftw_complex)*HIGH*ROWS*COLS); //分配输出空间nthreads = 12;// 初始化输入信号for (k = 0; k < HIGH; k++) {for (j = 0; j < ROWS; j++) {for (i = 0; i < COLS; i++) {in[k*ROWS*COLS+j*COLS+i][0] = k*215.42 + 35.24*i; //实部in[k*ROWS*COLS+j*COLS+i][1] = k*215.42 - 27.62*j; //虚部//std::cout << in[k*ROWS*COLS+j*COLS+i][0] << " " << in[k*ROWS*COLS+j*COLS+i][1] << std::endl;}}}/*// 从文件输入数据 ifstream fin("data");string line; //读取文件的每一行string value; //每一行的数据int cnt;int pos; //分割符位置int len; //字符串长度k = j = cnt = 0;while (getline(fin, line)) {j = cnt / COLS;if (cnt >= COLS * ROWS) {k++;cnt = 0;} else {cnt = cnt + COLS;}len = line.size(); //字符串长度if (len == 0) {continue; //跳过空行}for (i = 0; i < COLS; i++) {len = line.size();pos = line.find(' '); //查找字符在字符串中的位置value = line.substr(0,pos);//std::cout << value << ' ';line = line.substr(pos+1,len); //剩余字符串//std::cout << line << endl;//if (i == COLS-1) {// std::cout << endl;//}in[k*ROWS*COLS+j*COLS+i][0] = stof(value); //实部in[k*ROWS*COLS+j*COLS+i][1] = 0; //虚部//std::cout << in[k*ROWS*COLS+j*COLS+i][0] << " " << in[k*ROWS*COLS+j*COLS+i][1] << std::endl;}}*/fftw_init_threads();fftw_plan_with_nthreads(nthreads);plan = fftw_plan_dft_3d(HIGH, ROWS, COLS, in, out, FFTW_FORWARD, FFTW_ESTIMATE); // 定义fftw_planauto start = std::chrono::high_resolution_clock::now();fftw_execute(plan); // 执行fft//usleep(1);auto end = std::chrono::high_resolution_clock::now();auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();std::cout << "程序运行时间: " << duration << " 微秒" << std::endl;// 输出结果ofstream fout("results_cpp");for (k = 0; k < HIGH; k++) {for (j = 0; j < ROWS; j++) {for (i = 0; i < COLS; i++) {if (out[k*ROWS*COLS+j*COLS+i][1] < 0) {fout << out[k*ROWS*COLS+j*COLS+i][0] << out[k*ROWS*COLS+j*COLS+i][1] << ' ';} else {fout << out[k*ROWS*COLS+j*COLS+i][0] << '+' << out[k*ROWS*COLS+j*COLS+i][1] << ' ';}if (i == COLS-1) {fout << endl;}if (j==ROWS-1 && i==COLS-1) {fout << endl;}}}}// 释放内存fftw_cleanup();fftw_free(in);fftw_free(out);return 0;
}
相关文章:

FFTW基本概念与安装使用
FFTW基本概念与安装使用 1 基本概念2 编译安装3 使用实例3.1 单线程3.2 多线程 本文主要介绍FFTW库的基本概念、编译安装和使用方法。 1 基本概念 FFTW (Fastest Fourier Transform in the West)是C语言的一个子程序库,用于计算一维或多维离散傅里叶变换(Discrete …...

【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
Hiヽ(゜▽゜ )-欢迎来到蓝染Aizen的CSDN博客~ 🔥 博客主页: 【✨蓝染 の Blog😘】 💖感谢大家点赞👍 收藏⭐ 评论✍ 文章目录 行为型模式1、模板方法模式(1)概述(2&…...

教师如何打造专属私密成绩查询系统?
期末的校园,被一种特殊的氛围所笼罩。老师们如同辛勤的工匠,精心打磨着每一个教学环节。复习阶段,他们在知识的宝库中精挑细选,把一学期的重点内容一一梳理,为学生们打造出系统的复习框架。课堂上,他们激情…...

【1224】C选填(字符串\0占大小,类大小函数调用,const定义常量,逗号表达式取尾,abs返回值
1.设有数组定义: char array[]"China"; 则数组array所占的存储空间为__________ 6 注意要加上\0的位置 数组中考虑‘\0’,sizeof()判断大小也要考虑‘\0’ 2.初始化数组char[] strArray"kuai-shou",strArray的长度为(&am…...

本科阶段最后一次竞赛Vlog——2024年智能车大赛智慧医疗组准备全过程——终篇
本科阶段最后一次竞赛Vlog——2024年智能车大赛智慧医疗组准备全过程——终篇 至此,本系列的所有备赛分享已经结束 首先说说备赛的过程吧,这次比赛,真的是让我学到了太多书本上学不到的东西。一开始,对统筹控制还很模糊&a…...

复合机器人:开启智能制造新时代
在当今科技飞速发展的时代,智能制造已成为制造业转型升级的关键驱动力。而复合机器人作为智能制造领域的一颗璀璨新星,正以其卓越的性能和创新的设计,为各行各业带来前所未有的变革与机遇。 复合机器人,顾名思义,是融…...

装饰者模式
代码详解:【设计模式】Java 设计模式之装饰者模式(Decorator)_java 装饰者模式-CSDN博客 // 抽象构件角色 public interface Component {void operation(); }// 具体构件角色 public class ConcreteComponent implements Component {Override…...

【机器学习】当教育遇上机器学习:打破传统,开启因材施教新时代
我的个人主页 我的领域:人工智能篇,希望能帮助到大家!!!👍点赞 收藏❤ 教育是人类社会发展的基石,然而传统教育模式往往难以满足每个学生的个性化需求。随着机器学习技术的兴起,教…...

【蓝桥杯每日一题】分糖果——DFS
分糖果 蓝桥杯每日一题 2024-12-24 分糖果 DFS 题目描述 两种糖果分别有 9 个和 16 个,要全部分给 7 个小朋友,每个小朋友得到的糖果总数最少为 2 个最多为 5 个,问有多少种不同的分法。糖果必须全部分完。 只要有其中一个小朋友在两种方案中…...

information_schema是什么?
前言 在现代数据驱动的应用开发中,理解和管理数据库结构变得尤为重要。几乎所有的SQL数据库管理系统(DBMS)都提供了一个名为 information_schema 的虚拟数据库。它不仅是一个了解数据库内部结构的强大工具,也是一个实现跨平台兼容…...

案例分析-THC7984设计问题报告
目录 简介 配置信息 结论: 简介 使用的环境 AD芯片:THC7984 VGA信号:通过电脑主机产生1024x768 60HZ信号。 配置信息 AD数字数字产生通过FPGA接收。 AD寄存器配置(第一个数数据,第二个是地址): iic_write_reg 1 0x1e iic_write_reg 02 0x5...

HarmonyOS NEXT 技术实践-基于基础视觉服务的多目标识别
在智能手机、平板和其他智能设备日益智能化的今天,视觉识别技术成为提升用户体验和智能交互的重要手段。HarmonyOS NEXT通过基础视觉服务(HMS Core Vision)提供了一套强大的视觉识别功能,其中多目标识别作为其关键技术之一&#x…...

【python】银行客户流失预测预处理部分,独热编码·标签编码·数据离散化处理·数据筛选·数据分割
数据预处理 通过网盘分享的文件:银行流失预测数据和代码 链接: https://pan.baidu.com/s/1loiB8rMvZArfjJccu4KW6w?pwdpfcs 提取码: pfcs 非数值特征处理 目的:将非数值特征转换为数值型,以便模型能够处理。方法: 地理位置&am…...

使用 docker ps 查不到刚刚创建的容器
问题描述 docker创建mysql容器并实现本地目录挂载,虽然创建成功了,但是查看容器却不存在,删除重新创建还是同样的问题。 原因分析: 因为做本地目录挂载的时候在宿主机中创建了相关文件夹,并且还预先把数据库文件丢…...

vue2+element 前端表格下载
前台下载table表格 可下载fixed columns和普通平铺的表格 exportExcel() {const tableContainer document.querySelector(#table)const fixflg tableContainer ? tableContainer.querySelector(.el-table__fixed) : null// const fixflg document.querySelector(.el-table_…...

MySQL使用LOAD DATA INFILE方式导入文本文件
【图书推荐】《MySQL 9从入门到性能优化(视频教学版)》-CSDN博客 《MySQL 9从入门到性能优化(视频教学版)(数据库技术丛书)》(王英英)【摘要 书评 试读】- 京东图书 (jd.com) MySQL9数据库技术_夏天又到了…...

【从零开始入门unity游戏开发之——unity篇02】unity6基础入门——软件下载安装、Unity Hub配置、安装unity编辑器、许可证管理
文章目录 一、软件下载安装1、Unity官网2、下载Unity Hub 二、修改Unity Hub配置1、设置Unity Hub中文语言2、修改默认存储目录 三、安装unity编辑器1、点击安装编辑器2、版本选择3、关于版本号4、安装模块选择5、等待下载完成自动安装即可6、追加unity和模块 四、许可证管理专…...

SpringBootWeb 篇-深入了解 SpringBoot + Vue 的前后端分离项目部署上线与 Nginx 配置文件结构
🔥博客主页: 【小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录 1.0 云服务器的准备 2.0 Xshell 和 Xftp 软件 2.1 Xshell 介绍 2.2 Xftp 介绍 3.0 在云服务器进行环境配置 3.1 安装 JDK 3.2 安装 MySQL 3.3 安装 Nginx 4.0 SpringB…...

优化程序中的数据:从代数到向量解
前言 在前文笔者简单介绍了把数据迭代抽象为线性代数,并介绍了空间体、维度等概念。 数据复用 数据复用是一种提高程序执行效率与数据局部性的方法,分为自复用与组复用, 自复用:如果多个迭代访问同一个内存位置,那…...

【Web】2024“国城杯”网络安全挑战大赛决赛题解(全)
最近在忙联通的安全准入测试,很少有时间看CTF了,今晚抽点时间回顾下上周线下的题(期末还没开始复习😢) 感觉做渗透测试一半的时间在和甲方掰扯&水垃圾洞,没啥惊喜感,还是CTF有意思 目录 Mountain ez_zhuawa 图…...

基于ceres优化的3d激光雷达开源算法
以下是一些基于CERES优化的开源激光雷达SLAM或相关算法: (1) LOAM (Lidar Odometry And Mapping) 简介: LOAM是一种经典的激光雷达里程计和建图算法,它通过提取特征点(角点和平面点),利用ICP(Iterative Cl…...

【FAQ】HarmonyOS SDK 闭源开放能力 — Vision Kit(2)
1.问题描述: 人脸活体检测返回上一页App由沉浸式变为非沉浸式多了上下安全区域。 解决方案: 检测结束后需要自己去设置沉浸式配置。 2.问题描述: Vision Kit文字识别是本地识别,还是上传至服务器,由服务器来识别文…...

【LeetCode】726、原子的数量
【LeetCode】726、原子的数量 文章目录 一、递归: 嵌套类问题1.1 递归: 嵌套类问题 二、多语言解法 一、递归: 嵌套类问题 1.1 递归: 嵌套类问题 遇到 ( 括号, 则递归计算子问题 遇到大写字母, 或遇到 ( 括号, 则清算历史, 并开始新的记录 记录由两部分组成: 大写字母开头的 …...

VMware虚拟机三种网络工作模式
vmware为我们提供了三种网络工作模式,它们分别是:Bridged(桥接模式)、NAT(网络地址转换模式)、Host-Only(仅主机模式)。 打开vmware虚拟机,我们可以在选项栏的“编辑”下的“虚拟网络编辑器”中看到VMnet0(桥接模式)、VMnet1(仅主机模式)、VMnet8(NAT模式),那…...

14-zookeeper环境搭建
0、环境 java:1.8zookeeper:3.5.6 1、下载 zookeeper下载点击这里。 2、安装 下载完成后解压,放到你想放的目录里。先看一下zookeeper的目录结构,如下图: 进入conf目录,复制zoo_sample.cfg࿰…...

[搜广推]王树森推荐系统笔记——矩阵补充最近邻查找
视频合集链接 矩阵补充(工业界不常用) 模型结构 embedding可以把 用户ID 或者 物品ID 映射成向量输入用户ID 和 物品ID,输出向量的内积(一个实数),内积越大说明用户对这个物品越感兴趣模型中的两个embed…...

Unity3D * 粒子特效 * Particle System
(基于阿发教程做的重点笔记) 粒子 用于模拟一些流动的,没有形状的物质,例如 液体,烟雾,火焰,爆炸,魔法等效果 去除粒子外框 particle system 粒子发生器,有1个主模块和22个子模块࿰…...

【基础篇】1. JasperSoft Studio编辑器与报表属性介绍
编辑器介绍 Jaspersoft Studio有一个多选项卡编辑器,其中包括三个标签:设计,源代码和预览。 Design:报表设计页面,可以图形化拖拉组件设计报表,打开报表文件的主页面Source:源代码页码ÿ…...

数据结构:算法篇:快速排序;直接插入排序
目录 快速排序 直接插入排序 改良版冒泡排序 快速排序 理解: ①从待排序元素中选定一个基准元素; ②以基准元素将数据分为两部分:(可以将:大于基准元素放左,小于基准元素放右) ③对左半部分…...

WebAPI编程(第一天,第二天)
WebAPI编程(第一天,第二天) day01 - Web APIs 1.1. Web API介绍 1.1.1 API的概念1.1.2 Web API的概念1.1.3 API 和 Web API 总结 1.2. DOM 介绍 1.2.1 什么是DOM1.2.2. DOM树 1.3. 获取元素 1.3.1. 根据ID获取1.3.2. 根据标签名获取元素1.3.…...