前提: 本地开发因为拉了新的代码,又不想重新build ,为了节省时间,碰巧有一套测试docker环境,想着能不能本地build 一个jar 包,直接扔上去测试下新加的代码。 于是:
1.Linux 环境下面,把即将要放到pod 里面的jar 上传到环境中。 2.kubectl cp /opt/XXX.jar pod-6f8c86679c-lwpgj:/ -n namespaces -c <容器名称> XXX.jar 对应jar 包,
pod-6f8c86679c-lwpgj 对应 pod 名称
namespaces 对应填入匹配的namespace 上面这个命令执行之后 一直出现 如下错误
error :tar: XXX.jar: Cannot open: Permission denied
tar: Exiting with failure status due to previous errors
command terminated with exit code 2
最终发现 解决方案, 目标位置添加一个目标路径 /tmp/ 将指令修改成如下,问题得到解决!
kubectl cp /opt/XXX.jar pod-6f8c86679c-lwpgj:/tmp/ -n namespaces -c <容器名称>
AJAX请求 后台的方法返回的值为boolean类型
在做小东西的时候遇到了一个问题,因为平时JS写的不多,AJAX写的也少。所以遇到这样的问题也一时找不到问题。
$.ajax({
url: "/XXXX",
type: "GET",
data: {XXXX: XXXX},
success: function (data) {
if (data) {
} else {
}
}
}
我后台的方法是用java写的,返回的值为boolean类型。
但是这个判断是有问题的!!!
data的类型不是boolean类型。。。。然后一直就不按正常的逻辑判断往下走。这个很不开心,我java给你返回的boolean 你怎么就不认呢??
他还就真的不认!!!
这里只可能是data的问题了。。我机智的使用了typeof判断了一下 这个data 。结果他是一个String。。我不知道为什么会是一个String。但是我知道特么的让我昨天晚上没睡好!!!!
然后我就改成了这个样子。。
$.ajax({
url: "/XXXX",
type: "GET",
data: {XXXX: XXXX},
success: function (data) {
if (data==“true”) {
} else {
}
}
}
别人告诉我 这个是json。。。
A0:1189*841 mm,A1:841*594 mm,A2:594*420 mm,A3:420*297 mm,A4:297*210 mm。
1、首先你要懂得绘图,如果不会,这里说的你就不会明白。2、一般是在模型中绘图. 打印选项中点布局或范围就可以打印出标准的A3图纸了。8、至于有关线型、字体等.
A3:297X420,单位毫米,即长420毫米,宽297毫米。........A0:841X1189;A1:594X841; A2:420X594; A3:297X420; A4:210X297
老师要我做张小报.可我不知道A3的纸有多大..希望有人告诉我.
a3纸大小为297mmχ420mm。 a3 规格的纸张按国家纸张开本行业标准 (gb/t 1999 ) 又叫做 "大 8 开 "。国家标准中图纸从小到大一般可分为a5、a4、a3、a2、a1、a.
A3 图纸尺寸外框297*420; 需要装钉边的图纸规格,要装订的这边是25(无论是横幅还是竖幅),其它三个边都是 5。 不需要装钉边的规格是四个边都是 10。 右下角“.
选择文件——打印——图纸尺寸选A3,打印出来确是A4,到底怎么设置打A3 。
进入页面设置----打印设置-----图形尺寸(A3)------用"窗口"选择你要打印的图形-----确定.注:让它保持默认(按图纸空间缩放)好了.
A0:841X1189;A1:594X841;A2:420X594;A3:297X420;A4:210X297以上均为幅面尺寸
国家标准中图纸从小到大一般可分为A5、A4、A3、A2、A1、A0,其中A0最大,一般很少有小于A3的图纸(除非某些特种行业)。 各种图号图纸的长边与短边的比例一.
a0:840*1188mm a1:594*840mm a2:420*594mm a3:297*420mm a4:210*297mm a5:148.5*210mm
用毫米表示.
A3的长是420宽是297 A2的是2个A3和一起长是297+297=594宽420 以上依次类推
1、打开CAD软件。2、策划图框的大概样子,A3的图纸标准幅面尺寸为420*297,图框的画就为390*287。3、开始绘制,先画390*287的矩形。4、画完大图框的矩形后就.
原发布者:百度—百家号 CAD2007怎样画标准A3图框 绘画方法: 1、创建图层在里面设置好颜色随层、线性为实线、线宽0.7mm如图一所示。 2、绘制一个A3大小的矩.
A3跟A2的区别就是尺寸的区别 A3 420*297 A2 594*420 他们之间的长跟宽的比例都是1.41414 你选中A3的图纸用SCALE命令,放大1.41414倍就从A3->A2。
怎么画建筑图纸上的A3图纸? 最好有较为详细的步骤,本人为初学者,不太。
你指的是手绘还是用CAD? 如果用CAD的话,可以直接话啊 按你的比例,直接在. 希望你早日成为CAD高手!补充:其实画A3的图纸就是先画个A3的边框之类的,你下.
1、画一个A3的矩形(即420,297);2、把画框与矩形左下角对齐;3、输入命令SC,敲空格;4、输入R,敲空格;5、指定两点,即点左下角和右上角;6、把图形拉到矩.
A0的是841*1189 A3的是297*420 8张A3纸,我是从建筑施工图纸看问题的。不知道别的跟建筑一样不一样。
单向数据流
数据从父级组件传递给子组件,只能单向绑定。子组件内部不能直接修改从父组件传递过来的数据。
如果要使用父组件传递过来的变量值,需要在组件内的数据项中声明一个变量,把父组件传递过来的变量赋值给内部变量,然后就可以随意修改了。
Demo21.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Hello World</title> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div> <h4>单向数据流</h4> <p>数据从父级组件传递给子组件,只能单向绑定。子组件内部不能直接修改从父组件传递过来的数据。</p> <p>如果要使用父组件传递过来的变量值,需要在组件内的数据项中声明一个变量,把父组件传递过来的变量赋值给内部变量,然后就可以随意修改了。</p> <br> </div> <div id="app"></div> </body> <script> const app = Vue.createApp({ data() { return { counter: 123 } }, template: ` <div>单向数据流</div> <global :counter="counter"/> <br> ` }); app.component('global', { props: ['counter'], data() { return { newCounter: this.counter } }, template: ` <h3>直接操作父组件变量 {{counter}}</h3> <button @click="
### 1.用v-permission代替v-if,即使用自定义指令代替v-if
### 2.路由跳转发起get请求的流程
views/xxx/index.vue
cruds() { return CRUD({ title: "部署", url: "api/deploy", crudMethod: { ...crudDeploy }, }); }, components/Crud/crud.js
created() { for (const k in this.$crud) { if (this.$crud[k].queryOnPresenterCreated) { // 默认查询 this.$crud[k].toQuery() } } }, // 搜索 toQuery() { crud.page.page = 1 crud.refresh() }, // 刷新 refresh() { if (!callVmHook(crud, CRUD.HOOK.beforeRefresh)) { return } return new Promise((resolve, reject) => { crud.loading = true // 请求数据 initData(crud.url, crud.getQueryParams()).then(res => { // console.
Seesion介绍 Session是一个接口(HttpSession)Session就是会话。它是用来维护客户端和服务器之间关联的一种技术每个客户端都会有一个Session会话 每个用户申请都会得到一个不一样的session范围服务器通过session的ID来判断用户的Session范围 Session会话中,我们经常用来保存用户登录后的信息session的默认存活时间为30分,可以通过配置xml文件修改session的存活时间 request请求申请的数据调用结束就自动销毁,点击一次等于一次请求session存活时间长,不适合存储大量数据,能不使用session尽量不使用,否则堆栈容易溢出,一般放在请求范围request内 在客户端完全关闭后,session自动销毁 如何创建和获取Session 创建Session对象
//获取session范围,如果没有则创建一个session范围 HttpSession session = request.getSession(); 设置Session值
//设置session值 session.setAttribute("key1",value1); session.setAttribute("key2",value2); 关于Session本身的信息
// session是否存在 System.out.println("add session is new? " + session.isNew()); // session的ID System.out.println("add session id:" + session.getId()); // session的创建时间 System.out.println("add session createtime:" + new Date(session.getCreationTime()).toLocaleString()); 获取Session信息
//从session域中通过key获取对应value,类型为Object,可能需要根据需求做类型强转 session.getAttribute("key1"); 修改Session默认存活时间 在xml文件中配置session的默认存活时间以下代码放在代码块中根据需求使用 <session-config> <!-- 存活分钟,这里的 1 表示session存活1分钟 --> <session-timeout>1</session-timeout> </session-config>
1、JVM参数配置中:
-Xmx指定jvm的最大堆大小。
-Xms指定jvm的初始堆大小。即最小内存值
-XMn指定jvm中年轻代(New Ceneration)的大小。
XX:SurvivorRatio:指定年轻代中Eden区与Survivor区的大小比值为3,而Survivor区有两个,即将年轻代看做5份,每个Survivor区占一份,Eden区占3份,Survivor区大小=5120/5=1024m,Survivor区总大小为2048m(Survivor区有两个,占两份)
2、byte是8位有符号数
a=127为01111111,如果执行++a,先加1再使用,那么就会变为10000000,第一个为符号位,所以此时为-128
3、java并发技术:
CopyOnWriterArryList是使用CopyOnWriter机制实现的并发容器,能够进行并发的读,而不需要加锁,适用于写少读多的并发场景;
ReadWriterLock即为读写锁,当写操作时,其他线程无法读取或x写入数据,而当读操作时,其他线程无法写入数据,但却可以读取数据,所以适用于读多写少的场景;
ConcurrentHashMap使用锁分段机制,读写都加锁;
使用volatile修饰的变量,只保证多线程操作的可见性,不保证原子性。
4、静态方法不属于任何对象,所以其调用与类是否实例化没有关系。
5、JDK1.5及以上版本支持基本数据类型与包装类的基本转换。
Integer a=10 ;//自动装箱
int b=a;//自动拆箱
JDK1.5及以上版本直接用包装类对象与基本数据类型进行(==)比较时,会自动拆箱;调用a.equals(b)进行比较时会自动装箱。
JDK1.5以下时,不会进行自动装箱或者封箱操作,则不能用基本数据类型和对象进行比较,在调用equals()方法时,传入参数要求是引用参数(对象),则不能传入基本数据类型。
所以当碰到基本数据类型与包装类的装箱和拆箱问题时,需要注意JDK的版本,不同环境的结果会不同
6、private:只能在本类内进行访问;
default:可以被本包的其他类访问,但不能被其他包的类访问;
protected:只能被本包及不同包的子类访问;
public:所有包的所有类都可访问。
前言
之前一直在简书上写文章,然后自己搭建博客,想了一下,其实更多的精力还是应该放在学习上面,博客等就是分享自己的所学,一直认为,我如果能够把文章写的很明白了,自己也就掌握的差不多了,其次,很多东西自己也方便查看,加快开发的速度。
Overview
Retrofit 与 RxJava 完美结合,支持断点下载,上传,支持缓存,自定义绑定生命周期.
github地址
效果图
Download
Step 1. Add the JitPack repository to your build file
Add it in your root build.gradle at the end of repositories:
allprojects {
repositories {
...
maven { url 'https://www.jitpack.io' }
}
}
复制代码
Step 2. Add the dependency
dependencies {
implementation 'com.github.JiangHaiYang01:RxHttp-RxJava:0.0.2'
}
复制代码
Usage
基础使用
配置retrifot
rxHttp = RxHttp.Builder()
.baseUrl("https://www.wanandroid.com")
.isLog(true)
.level(HttpLevel.BODY)
.writeTimeout(10)
.readTimeout(10)
.connectTimeout(10)
.build(this)
复制代码
散点图的相关性与显著性---MATLAB 背景1.相关性与显著性检验2.MATLAB函数corrcoef 背景 得到了两个变量的一组数据,绘制散点图,似乎很有关系,如下:
在直接用matlab拟合出方程之前,可以先检测其相关性与显著性。
1.相关性与显著性检验 相关性:两个变量间的线性相关性,用 r 值衡量,r为正是正相关,r为负是负相关,范围-1~1.
统计假设检验:对随机变量的分布/参数做出一个假设,利用样本数据来检验这个假设;如果只限定犯第一类错误的概率,则是显著性检验(significance test) [1],显著性水平用 p 值衡量。
显著性检验是为了判断假设是否成立,即样本与假设的偏差是因为随机误差还是因为假设不真。
2.MATLAB函数corrcoef [R,P]=corrcoef(A)
矩阵A的每一列是随机变量的一组观测值;
R是相关系数矩阵;
P是p值矩阵;
对上面的散点图数据求得:
R=[1 0.9970; 0.9970 1],(1,2)和(2,1)元 r 值为0.997
P=[1 0; 0 1] , (1,2)和(2,1)元 p值为0 (p<0.05即显著相关)
因为这两个变量呈现出了显著相关性,所以可以进行拟合。
参考
[1] :https://www.cnblogs.com/hdu-zsk/p/6293721.html
了解es6模块化,看这篇就够了 ES ModuleES 的基本特性script标签中使用ES自动采用严格模式 独立的私有作用域ESM通过CORS去请求外部JS模块ESM的script脚本会延迟执行ES 导入和导出exportexport <成员声明变量>export { 变量 }as关键字default关键字 import基础用法导入defualt变量as关键字*关键字import导入的变量的特性接收普通变量和default变量import路径问题动态import ES Module es module 是es6近几年最新出的一个模块化规范。相对于AMD规范,它有了更加严谨的语法标准,使用更加便捷,并且现在大多浏览器都已经支持该特性。
ES 的基本特性 script标签中使用ES 我们只需要给script标签加上一个属性type=module,那么该script就是一个es模块了。而实际上每个js文件也是一个es模块
<script type="module"> // 这就是一个es模块 </script> 自动采用严格模式 对于每个es模块,模块内部会自动采用严格模式,最直观的表现就是,非严格模式下的this指向的是window,严格模式下则this则是undefined
<script> console.log(this) </script> <script type="module"> console.log(this) </script> 结果
独立的私有作用域 普通的script标签都是全局作用域的,而每个es模块都有独立的私有作用域,很好的解决了命名冲突问题
<script type="module"> const a = '111' console.log(a) </script> <script type="module"> const a = '222' console.log(a) </script> 结果
ESM通过CORS去请求外部JS模块 这个的意思是,es模块是通过跨域的方式请求外部js模块,所以请求的该js模块必须是支持跨域的,否则会报错
<script type="module" scr="请求的模块路径必须是支持跨域的"></script> ESM的script脚本会延迟执行 ESM的script脚本会相对与普通的script脚本会延迟执行
<script type="module"> console.log('我是ESM script') </script> <script> console.log('我是普通script') </script> 执行结果
vm和生命周期函数
createApp({})
mount()
根组件vm -- proxy形式的对象
mvvm模式 vm -- viewModel
生命周期函数 -- 在某个特定时刻自动执行的函数
有八个生命周期函数,
beforeCreate( ) :在实例生成之前会自动执行的函数created( ) : 在实例生成之后会自动执行的函数beforeMount( ) : 在模板渲染完成之前执行的函数mounted( ) : 在模板渲染完成之后执行的函数beforeUpdate :当data中的数据变化时, 会立即自动执行的函数updated:当data中的数据发生变化,页面重新渲染完后,会自动执行的函数beforeUnmount( ) :当Vue应用失效时,会自动执行的函数unmounted() : 当Vue应用失效时,且DOM完全销毁之后,会自动执行 但在vue3中,会使用新的函数调用方式
beforeCreate -> 请使用 setup()created -> 请使用 setup()beforeMount -> onBeforeMountmounted -> onMountedbeforeUpdate -> onBeforeUpdateupdated -> onUpdatedbeforeDestroy -> onBeforeUnmountdestroyed -> onUnmountederrorCaptured -> onErrorCaptured Demo6.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Hello World</title> <script src="
Maven中由于他的约定大于配置,我们之后可能遇到我们写的配置文件,无法被导出或者生效的问题,解决方案:
<!-- 在build中配置resources , 来防止我们资源导出失败的问题--> <build> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> </resource> </resources> </build>
通过redis-cli中执行save或者bgsave可以得到RDB文件(文件名由配置文件中dbfilename指定,例如dbfilename "dump.rdb"),这个文件包含Redis实例中全量的数据,那么dump.rdb的文件格式大概是什么样的呢?
RDB文件定义
获取RDB文件
我们首先通过redis-cli中执行save得到dump.rdb文件,然后用WinHex打开这个文件:
dump.rdb.png
说明:导出RDB文件时整个Redis实例中db=0里有个string类型的username,值为afei;db=6里有个string类型的uname,值为root,且设置了失效时间;
剖析RDB文件
根据WinHex达到的dump.rdb文件一个一个字节剖析文件真实的内容,以52这个16进制数为例,其十进制数值为82,通过ASCII码对照表可知,82对应的字符是R,相应的:45->69->E,44->68->D,49->73->I,53->83->S,最终该RDB文件内容如下:REDIS
验证RDB文件定义
前面5个16进制52 45 44 49 53已经被验证为REDIS
30 30 30 36则表示RDB文件版本号
FE表示db选择器编码,00则表示选择编号为0这个db
00这个ASCII码对应的字符为NUT,即
08这个ASCII码对应的字符为BS,即BackSpace退格按键;
75 73 65 72 6E 61 6D 65 04 61 66 65 69 则表示:
说明:04这个ASCII对应的字符是EOT,表示文尾,end of transmission;所以username的值afei是另起一行;
FE表示db选择器编码,06则表示选择编号为6这个db
FC表示设置了毫秒级失效,接下来的8个字节表示失效时间的Unix时间戳;
4F D7 D3 E4 5D 01 00 00 00 表示失效时间Unix时间戳;
05这一个字节表示value的类型:string,hash,list ,set,sorted set;
75 6E 61 6D 65 04 72 6F 6F 74则表示:
FF表示RDB文件结束;
C7 41 31 D7 AA 1F 24 A2这8个字节表示整个RDB文件的rdbsum CRC 64;
前言
昨天项目报错
java.lang.IllegalStateException: Duplicate key 1
代码如下:
Map userId2BatchId = userLevelList.stream().collect(Collectors.toMap(RazUserLevel::getUserId, RazUserLevel::getBatchId);
原因是存在重复key导致
正文
查看toMap文档
toMap
public static Collector> toMap(Function super T,? extends K> keyMapper,
Function super T,? extends U> valueMapper)
1
2
Returns a Collector that accumulates elements into a Map whose keys and values are the result of applying the provided mapping functions to the input elements.
If the mapped keys contains duplicates (according to Object.equals(Object)), an IllegalStateException is thrown when the collection operation is performed.
在Java平台的结构中, Java虚拟机(JVM) 处在核心的位置,是程序与底层操作系统和硬件无关的关键。它的下方是移植接口,移植接口由两部分组成:适配器和Java操作系统, 其中依赖于平台的部分称为适配器;JVM 通过移植接口在具体的平台和操作系统上实现;在JVM 的上方是Java的基本类库和扩展类库以及它们的API, 利用Java API编写的应用程序(application) 和小程序(Java applet) 可以在任何Java平台上运行而无需考虑底层平台, 就是因为有Java虚拟机(JVM)实现了程序与操作系统的分离,从而实现了Java 的平台无关性。
1、java程序是跨平台的,不依赖任何操作系统,只依赖JVM(java虚拟机)而已, 只要操作系统(Windows也得,Linux也得)装有jvm就可以运行了。
java不依赖任何操作系统
jvm依赖操作系统
2、Java程序运行不依赖操作系统,Java 应用编程接口为Java应用提供了一个独立于操作系统的标准接口,可分为基本部分和扩展部分。在硬件或操作系统平台上安装一个Java平台之后,Java应用程序就可运行。现在Java平台已经嵌入了几乎所有的操作系统。这样Java程序可以只编译一次,就可以在各种系统中运行。
3、java语言是通过JVM(java虚拟机)来进行编译和执行的,所以,不管是Windows还是Linux,只要是有相应的虚拟机就可以了,操作系统本身对java没什么影响。
JVM全称(Java Virtual Machine),就是我们很耳熟的Java虚拟机。它能够识别.class后缀的文件,并且能够解析它的指令,最终调用操作系统上的函数,完成我们想要的操作。
已被986人点赞
出现问题:
[root@k97 kube-prometheus]# kubectl top pods -n monitoring Error from server (ServiceUnavailable): the server is currently unable to handle the request (get pods.metrics.k8s.io) 分析问题:
[root@k97 kube-prometheus]# systemctl status kube-apiserver.service -l ● kube-apiserver.service - Kubernetes API Server Loaded: loaded (/etc/systemd/system/kube-apiserver.service; enabled; vendor preset: disabled) Active: active (running) since 三 2021-02-24 13:28:04 CST; 21h ago Docs: https://github.com/GoogleCloudPlatform/kubernetes Main PID: 24783 (kube-apiserver) Tasks: 22 Memory: 742.9M CGroup: /system.slice/kube-apiserver.service └─24783 /opt/k8s/bin/kube-apiserver --advertise-address=172.16.160.97 --default-not-ready-toleration-seconds=360 --default-unreachable-toleration-seconds=360 --feature-gates=DynamicAuditing=true --max-mutating-requests-inflight=2000 --max-requests-inflight=4000 --default-watch-cache-size=200 --delete-collection-workers=2 --encryption-provider-config=/etc/kubernetes/encryption-config.
为确保安全,`kubernetes` 系统各组件需要使用 `x509` 证书对通信进行加密和认证。
当我执行 kubectl exec 命令来登陆到 Pod 里面进行操作。遇到以下问题:
[root@k97 work]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES dnsutils-ds-bd9pz 1/1 Running 0 26s 172.16.176.4 k99 <none> <none> dnsutils-ds-p4d2x 1/1 Running 0 26s 172.16.120.4 k97 <none> <none> dnsutils-ds-pfhzs 1/1 Running 0 26s 172.16.232.4 k98 <none> <none> my-nginx-86575b68dc-8s44j 1/1 Running 0 8m4s 172.16.176.3 k99 <none> <none> my-nginx-86575b68dc-q89h4 1/1 Running 0 8m4s 172.
在学习 kotlin 泛型的时候,经常会遇到 in out 这两个词,一会用in 一会用out,为啥这里要用 out ?为啥哪里用 in ?啥什么用 out 啥时候用in ?对应上面问题以前我是晕乎乎的,不是很明白,于是打算写这篇文章梳理一下,搞清楚怎么回事。
Java 泛型 在学kotlin 泛型之前,先回顾一下Java中的泛型
为了方便说明引入下面几个类
具体代码
public class Animal { } public class Dog extends Animal{ } public class Cat extends Animal{ } public class Corgi extends Dog { } public class Result<T>{ private T data; public Result() { } public Result(T data) { this.data = data; } public void setData(T data) { this.data = data; } public T getData() { return data; } } 1.
/**获取 input 标签 name 属性为 goods_name 的 所有值 *有多个 goods_name 时 可以使用each 循环获取单个值 *也可以通过 $("input[name='goods_name']")[0].value; 获取个体值 */ var goods_name=$("input[name='goods_name']").val(); //获取id为goods_name的值 ,id选择器 var goods_name=$("#goods_name").val(); //类选择器,获取class为goods_name的值 var goods_name=$(".goods_name").val(); //替换css样式 $("#showgoods").css("display","block"); //替换属性 $("#showgoods").attr("display","block"); //显示函数 -- 隐藏函数 $("#showgoods").show(); $("#showgoods").hide(); //文档操作 //向所有段落中追加。 追加内容在标签里 $("p").append("<b>Hello</b>");//<p>I would like to say: <b>Hello</b></p> //向所有段落结束后追加。追加内容在标签外,或者反包围标签 $("p").appendTo("div");//<div><p>I would like to say: </p></div> //ajax //请求参数 var list = {}; // $.ajax({ //请求方式 type : "POST", //请求的媒体类型 //contentType: "application/json;charset=UTF-8", contentType:"JSON", //请求地址 url : "
1、聊一聊
其实每个人在无助的时候都需要一句"Cry On My Shoulder!"
今天跟大家介绍一种波峰波谷的检测方法,不是很难,不过能够凸显数学在编程算法中的重要作用。
2、正文部分
1
波峰波谷用处
对于信号波峰波谷识别在嵌入式领域应该是非常广泛的,因为大部分的信号都处于一种时变的状态,信号在时域上处于一种类似于正弦波的波动状态。
比如计步软件就是通过IMU模块所采集的变化的波形状态来识别波峰波谷,最终估算你所走过步数;
图片来源网络侵删
上图显示了一个典型的x-, y-和z-测量模式,对应于一个跑步者的垂直,向前和侧面加速度。无论如何佩戴计步器,至少有一个轴会有相对较大的周期性加速度变化,因此通过检测其波峰波谷等算法即可对于检测步行或跑步的单位周期至关重要。
图片来源网络侵删
还有在电力系统中的交流电压电流,我们需要通过检测波峰波谷来确定电压电流在交流周期中的最大最小值,从而动态调节系统参数来达到自适应的目的,所以波峰波谷的检测是非常有用的。
2
比较法识别
常规的设计办法为比较法 : 其中x表示当前采样点
波峰:f(x) > f(x−1) 且 f(x) > f(x+1)
波谷:f(x) < f(x−1) 且 f(x) < f(x+1)
然而这样识别对于没有什么噪声,且每个采样点为不同的信号来说还是合适的,但在严苛的环境中还需要构造更多的判断条件来进行一些错误判断的规避,终究还是麻烦了一些,并且容易遗漏。
3
差分识别
在学生阶段我们就学习了导数的概念,如果一个函数一阶导数左右异号,那分别就是波峰或者波谷。而对于数字信号的处理通过采样都会变成离散信号,信号对时间的微分在离散域内即为差分。
在进行波形识别之前数据采集是必不可少的,其中最重要的是采样速率和精度,以便从采样信号中不失真的恢复原连续信号。(香农采样)
采样的过程中由于电子器件的杂讯等,数据难免会引入噪声,为了简化识别算法一般都会进行滤波处理,比如一些平滑处理等,然后才开始波峰波谷识别。
A
识别算法过程
1、获得采样点序列
2、进行差分处理
3、由于不在乎具体的差分幅值,把所有数据归一到-1,0,1
4、差分值为0的点即为相同点,如果使用比较法则峰值检测可能失效,便需要更多的条件,而这里我们直接把相同点0置为前一个非0即可规避该问题。
5、最终Diff再次进行差分,-2/+2即为波峰/波谷。
B
参考代码
1#include <stdio.h> 2#include <stdlib.h> 3#define SAMPLE_MAX 20 4#define PV_MAX 10 5 6float Sample[SAMPLE_MAX]={1,2,3,4,4,4,5,2,1,0,0,5,1,0,0,1,2,3,4,0}; 7float SampleDiff[SAMPLE_MAX]={0}; 8 9typedef struct _tag_FindPV 10{ 11 int Pos_Peak[PV_MAX]; //波峰位置存储 12 int Pos_Valley[PV_MAX]; //波谷位置存储 13 int Pcnt; //所识别的波峰计数 14 int Vcnt; //所识别的波谷计数 15}SFindPV; 16 17SFindPV stFindPV; 18 19/******************************************** 20 * Fuction : initialFindPV 21 * Note : 初始化相关数据 22 *******************************************/ 23void initialFindPV(void) 24{ 25 int Index = 0; 26 27 for(Index = 0; Index < SAMPLE_MAX;Index ++) 28 { 29 SampleDiff[Index] = 0; 30 } 31 32 for(Index = 0; Index < PV_MAX;Index ++) 33 { 34 stFindPV.