软件设计师笔记(一)

一、软件能力成熟度模型CMM (1)初始级(initial)。工作无序,项目进行过程中常放弃当初的计划。管理无章法,缺乏健全的管理制度。开发项目成效不稳定,项目成功主要依靠项目负责人的经验和能力,他一旦离去,工作秩序面目全非。 (2)可重复级(Repeatable)。管理制度化,建立了基本的管理制度和规程,管理工作有章可循。 初步实现标准化,开发工作比较好地按标准实施。 变更依法进行,做到基线化,稳定可跟踪,新项目的计划和管理基于过去的实践经验,具有复现以前成功项目的环境和条件。 (3)已定义级(Defined)。开发过程,包括技术工作和管理工作,均已实现标准化、文档化。建立了完善的培训制度和专家评审制度,全部技术活动和管理活动均可控制,对项目进行中的过程、岗位和职责均有共同的理解 。 (4)已管理级(Managed)。产品和过程已建立了定量的质量目标。开发活动中的生产率和质量是可量度的。已建立过程数据库。已实现项目产品和过程的控制。可预测过程和产品质量趋势,如预测偏差,及时纠正。 (5)优化级(Optimizing)。可通过采用新技术、新方法,集中精力改进过程。具备防缺陷、识别薄弱环节以及改进的手段。可取得过程有效性的统计数据,并可据此进行分析,从而得出最佳方法。 能力成熟度模型集成CMMI CL0(未完成的):过程域未执行或未得到CL1中定义的所有目标 CL1(已执行的):其共性目标是过程将可标识的输入工作产品转换成可标识的输出工作产品,以实现支持过程域的特别目标 CL2(已管理的):其共性目标是已管理的过程的制度化。根据组织级政策规定过程的运作将使用哪个过程,项目遵循已文档化的计划和过程描述,所有正在工作的人都有权使用足够的资源,所有工作任务和工作产品都将被监控、控制、和审评 CL3(已定义级的):其共性目标集中于已定义的过程的制度化。过程是按照组织的裁剪指南从组织的标准过程中裁剪得到的,还必须收集过程资产和过程的度量,并且用于将来对过程的改进 CL4(定量管理的):其共性目标集中于可定量管理的过程的制度化,使用测量和质量保证来控制和改进过程域,建立和使用关于质量和过程执行的质量目标作为管理准则 CL5(优化的):使用量化(统计学)手段改变和优化过程域,以满足客户的改变和持续改进计划中的过程域的功效 二、排序算法复杂度 三、冗余附加技术 冗余附加技术是指为实现结构、信息和时间冗余技术所需的资源和技术,包括程序、指令、数据、存放和调动它们的空间和通道等。 在屏蔽硬件错误的容错技术中,冗余附加技术包括:关键程序和数据的冗余及调用;检测、表决、切换、重构和复算的实现。 在屏蔽软件错误的容错技术中,冗余附加技术包括:冗余备份程序的存储及调用;实现错误检查和错误恢复的程序;实现容错软件所需的固化程序。 四、主定理 主定理(Master Theorem) - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/113406812 五、公钥算法 既然是加密,那肯定是不希望别人知道我的消息,所以只有我才能解密,所以可得出公钥负责加密,私钥负责解密;同理,既然是签名,那肯定是不希望有人冒充我发消息,只有我才能发布这个签名,所以可得出私钥负责签名,公钥负责验证。 六、常用端口号 协议/服务名称 端口号 简介 ftp 20、21 File Transfer Protocol 文件传输协议,21用于连接,20用于传输 ssh 22 Secure Shell 安全外壳协议,专为远程登录会话和其他网络服务提供安全性的协议 http 80 Hyper Text Transfer Protocol 超文本传输协议,用于网页浏览 DNS 53 Domain Name System 域名系统,域名解析 https 443 Hypertext Transfer Protocol Secure 超文本传输安全协议,用于安全浏览网页 www代理服务 8080 Apache Tomcat web server,进行网页浏览

java动态代理:jdk动态代理和cglib动态代理

文章目录 1 动态代理1.1 jdk动态代理(基于接口的动态代理)1.2 cglib动态代理(基于类的动态代理) 2 代码实现2.1 jdk动态代理2.2 cglib动态代理 1 动态代理 Java中的动态代理机制是一种实现AOP(面向切面编程)技术的重要手段,它可以在不修改源代码的情况下进行增强操作。在Java中,有两种动态代理方式:一种是JDK动态代理,另一种是CGLIB动态代理。 1.1 jdk动态代理(基于接口的动态代理) Java基于接口的动态代理是一种在运行时动态生成代理类的技术。它是通过反射机制在运行时生成代理对象,对被代理对象的方法进行拦截处理,实现增强功能,而不需要像静态代理一样手动编写代理类。 Java基于接口的动态代理需要实现两个接口:InvocationHandler和Proxy。InvocationHandler接口中定义了一个invoke方法,该方法接收一个代理对象、被代理对象的方法和参数,并返回代理对象对被代理对象的方法进行增强后的返回值。Proxy类中则提供了一个静态方法newProxyInstance,用于创建代理对象。 使用Java基于接口的动态代理,需要按照以下步骤: 定义一个接口,该接口中定义需要被代理的方法。实现InvocationHandler接口,重写invoke方法,对需要被代理的方法进行增强处理。使用Proxy类的newProxyInstance方法,创建代理对象。 Java基于接口的动态代理可以实现一些横切关注点,比如记录方法调用时长、打印日志、权限校验等,使得我们的代码更加灵活和易于维护。 1.2 cglib动态代理(基于类的动态代理) Java CGLIB 动态代理是一种在运行时生成代理对象的技术,它可以在不修改原始类型(类)的基础上,为该类型创建一个代理子类,该代理子类可以拦截原始类中的方法调用。相较于Java JDK动态代理,它可以代理没有实现接口的类。 CGLIB 是 Code Generation Library(代码生成库)的简称,是一个强大的高性能的代码生成库,CGLIB 可以在运行期间扩展 Java 类和实现 Java 接口。它提供了很多实用的功能,例如方法拦截、字段拦截、方法调用前后拦截等等。 2 代码实现 下面以一个计算器为例,通过动态代理拦截计算器方法的执行,在方法执行前后打印日志。 src\main\java\myproxy ├──cglib_proxy │ ├──CglibTest.java │ └──MyLoggerInterceptor.java ├──jdk_proxy │ ├──JDKProxyTest.java │ └──MyLoggerProxy.java ├──Calculator.java └──CalculatorImpl.java public interface Calculator { public int add(int a, int b); public int sub(int a, int b); } public class CalculatorImpl implements Calculator { @Override public int add(int a, int b) { System.

【特征选择】基于二进制粒子群算法的特征选择方法(GRNN广义回归神经网络分类)【Matlab代码#32】

文章目录 【可更换其他算法,`获取资源`请见文章第6节:资源获取】1. 特征选择问题2. 二进制粒子群算法3. 广义回归神经网络(GRNN)分类4. 部分代码展示5. 仿真结果展示6. 资源获取 【可更换其他算法,获取资源请见文章第6节:资源获取】 1. 特征选择问题 特征选择是指从原始数据中选择最具有代表性和有用性的特征,以用于建模和预测任务。它是机器学习和数据挖掘中的重要步骤,可以提高模型的性能和解释能力,并降低计算成本和过拟合的风险。 特征选择的方法可以分为三大类:过滤方法(Filter methods)、包装方法(Wrapper methods)和嵌入方法(Embedded methods)。 过滤方法是根据某种准则或评估指标对特征进行评估和排序,然后选择排名靠前的特征。常用的过滤方法包括相关系数、信息增益、方差选择等。这些方法独立于具体的学习算法,计算效率高,但不能考虑特征子集之间的相互关系。 包装方法是利用机器学习算法对不同的特征子集进行评估,以确定最佳的特征子集。这类方法通常以模型性能为评价指标,例如递归特征消除(Recursive Feature Elimination, RFE)和遗传算法等。包装方法的计算代价较高,但能够考虑特征之间的相互关系。本文采用的就是包装方法。 嵌入方法是指在学习算法中直接嵌入特征选择过程,通过学习过程自动选择最佳的特征。常见的嵌入方法包括L1正则化(L1 Regularization)和决策树的剪枝等。 选择适合的特征选择方法需要考虑数据的特点、问题的要求以及计算资源的限制。常用的特征选择工具包括scikit-learn(Python)、Weka(Java)和caret(R)等,它们提供了多种特征选择方法的实现。 需要注意的是,特征选择是一个迭代的过程,需要根据实际情况不断尝试和调整。在特征选择之前,应该对数据进行预处理、探索性数据分析和特征工程等步骤,以保证特征选择的效果和模型的可靠性。 2. 二进制粒子群算法 二进制粒子群算法(Binary Particle Swarm Optimization,BPSO)是一种基于群体智能的优化算法,用于解决二进制编码的优化问题。它是粒子群算法(Particle Swarm Optimization,PSO)的一种变体,适用于离散型优化问题。 在二进制粒子群算法中,每个粒子表示一个解向量,而解向量中的每个维度都是二进制值,通常用0和1表示。粒子群算法通过模拟鸟群中鸟的觅食行为,来搜索最优解。每个粒子根据自身历史最优解和群体最优解的信息,更新自己的位置和速度,并通过适应度函数评估自身的解的质量。 3. 广义回归神经网络(GRNN)分类 图1 广义回归神经网络结构图 GRNN数据分类过程如下: 输入训练数据集,包括特征向量和对应的类别标签。对每个训练样本,计算其与测试样本之间的距离。常用的距离度量方法包括欧氏距离、曼哈顿距离等。基于距离计算每个训练样本的权重,通常使用高斯核函数来计算权重。高斯核函数将距离转换为权重,越近的样本权重越高,越远的样本权重越低。对每个类别的样本,根据其权重进行加权平均。权重越高的样本对应的类别影响越大。将测试样本划分到具有最高加权平均值的类别中。 4. 部分代码展示 %% GRNN 广义回归神经网络 classification all_select=ones(1,dim); [predictResult,accuracy,objval]=GRNN(all_select,trainData ,testData,trainlabel,testlabel,labels,dim); %% PSO optimisation for feature selection SearchAgents_no=30; % Number of search agents Max_iteration=30; % Maximum numbef of iterations % 二进制粒子群算法 [Target_score,Target_pos,PSO_cg_curve]=BPSO(SearchAgents_no,Max_iteration,dim,trainData,testData,trainlabel,testlabel,labels); % final evaluation for PSO tuned selected features [predictedLables_PSO,accuracy_PSO,~]=GRNN(Target_pos,trainData,testData,trainlabel,testlabel,labels,dim); %% % plot for Predicted classes figure(1) plot(testlabel,'ko','markersize', 8) hold on plot(predictResult,'b*','markersize', 8) xlabel('测试集样本'); ylabel('类别标签'); legend('实际测试集分类','全部特征下GRNN预测分类'); title("

毫米波雷达点云 DBSCAN聚类算法

毫米雷达点云 DBSCAN聚类算法 聚类的目的聚类算法分类原型聚类层次聚类密度聚类 DBSCAN聚类算法原理相关定义算法流程以及伪代码DBSCAN算法优缺点DBSCAN参数选择聚类衡量指标 DBSCAN算法仿真DBSCAN代码DBSCAN算法对毫米波雷达点云数据进行聚类 聚类的目的 聚类的目的是将一组数据点划分为具有相似特征或属性的组或簇。通过聚类分析,我们可以识别出数据中的内在模式、结构和关联关系,从而获得对数据的更深入理解。 具体来说,聚类的目的可以分为以下三部分: 发现数据的内在结构: 聚类可以将数据分成簇,这些簇可能表示数据的不同模式、集群或分布。通过将相似的数据点放在同一簇中,我们可以揭示数据的内在结构和组织方式。 数据预处理 通过将数据分成不同的簇,可以减少数据的复杂性和噪声,提取关键特征,并简化后续的数据分析任务。(比如形状特征) 异常点剔除 聚类算法可以帮助我们识别和排除异常点或噪声数据。这些异常点可能是数据中的异常值、离群点或错误数据,对于准确的分析和建模是有害的。 聚类算法分类 现有的聚类算法可以大致分为三种,分别是 原型聚类(Prototype-based clustering)-层次聚类 (Hierarchical clustering)密度聚类 (Density-based clustering) 原型聚类 该类算法的主要思想为根据给定的划分集合个数 K,将所有数据对象分配到K个集合中,每个集合中各个数据对象到本身集合中心点相似度最高相对于其他集合中心对象。 该算法主要通过迭代的方式得到最优的聚类中心点和各个聚类集合,主要适用于球状簇的发现。 常用的划分聚类算法 K-means、 CLARANs、 CLARA、PAM 等。 在数据挖掘领域被广泛应用,但是这些算法都要求在聚类之前就确定输出的簇的数量。对于汽车雷达来说,也就是要求在聚类之前就确定目标的数量,这显然是无法做到的,因为汽车雷达无法确定当前的目标数量是多少。 层次聚类 层次聚类尝试在不同层次对数据集进行划分,从而形成树形的聚类结构。层次聚类可以采用“自下而上”的聚类策略,也可以采用“自上而下”的聚类策略。AGNES 方 法 (AGglomerative NESting)是一种常用的“自下而上”的层次聚类算法。然而这种算法面临和原型聚类相同的问 题,也需要在聚类之前确定输出的簇的数量,因此也无法直接应用到汽车雷达上,因此就只剩下了密度聚类。 密度聚类 密度聚类(Density-based clustering)没有其它两种聚类的限制,不需要事先确定簇的数量。密度聚类假设簇的 结构能通过目标点分布的紧密程度来确定。在密度聚类中,簇被认为是数据空间中目标点密集的区域,在簇之间出 现的低密度的目标点被认为是噪声. 这些簇可以有任意的形状,并且簇内的目标点也可以任意分布,这一点和汽车 雷达上的检测目标特性十分接近。汽车雷达对应同一个目标的检测点之间距离接近,并且这些点的密度分布是一定 的(这个密度分布和物体的反射特性相关)。因为具备以上这些特性,密度聚类更加适合于汽车雷达的应用,DBSCAN 算法(Density-Based Spatial Clustering of Applications with Noise)是一种常用的密度聚类算法。 DBSCAN聚类算法原理 相关定义 DBSCAN是一种基于密度的聚类算法,这类密度聚类算法一般假定类别可以通过样本分布的紧密程度决定。同一类别的样本,他们之间的紧密相连的,也就是说,在该类别任意样本周围不远处一定有同类别的样本存在。 DBSCAN是基于一组邻域来描述样本集的紧密程度的,参数(ϵ, MinPts)用来描述邻域的样本分布紧密程度。其中,ϵ描述了某一样本的邻域距离阈值,MinPts描述了某一样本的距离为ϵ的邻域中样本个数的阈值。 给出算法中用到的定义: ● ϵ领域:对于 x j ∈ D x_j \in D xj​∈D,其ϵ-邻域包含样本集D中与xj的距离不大于ϵ的子样本集,即 N ϵ ( x j ) = { x i ∈ D ∣ d i s t a n c e ( x i , x j ) ≤ ϵ } N_{\epsilon}(x_j) = \{x_i \in D | distance(x_i,x_j) \leq \epsilon\} Nϵ​(xj​)={xi​∈D∣distance(xi​,xj​)≤ϵ},这个子样本集的个数记为 ∣ N ϵ ( x j ) ∣ |N_{\epsilon}(x_j)| ∣Nϵ​(xj​)∣。

【2023年电工杯数学建模竞赛】选题分析+A题B题完整思路+代码分享

2023年电工杯B题(附带ChatGpt思路)思路已更新,请点击一下链接 【2023年电工杯数学建模竞赛B题人工智能对大学生学习影响的评价】完整思路分析+完整代码+(附带ChatGpt思路) 1.竞赛介绍 2.本次大赛选题分析 首先大家要清楚获奖只和比例有关,和具体题目关系不大,不会出现选难题就比简单题获奖率高很多的情况出现,这是一个选拔性质的比赛是按照比例来的 2.1 2023年电工杯A题选题解析 这道题一眼看上去就很复杂,很多大一大二的学生还没学完微分方程就让求稳态解了,所以还是不建议新手直接上手这道题。这道题适合相关研究方向的专业人士以及想挑战难题的同学。 这道题设计的专业知识包括热力学,热传导方程,凝聚态物理,电荷计算,功率调节和优化,整体专业性很强。建议选择这道题的同学也别想着做出所有问,能解决两三问,然后专注于完成论文差不多就能获奖了。总之难题的话大家都难,最后还是按照比例,还是看谁在有限时间内做的更好。 2.2 2023年电工杯B题选题解析 这道题相对容易,适合新手上手。但是想做好并且获奖还是需要下功夫的。简单的题选的人肯定多,怎么做出彩是必须要考虑的事情。 这道题涉及数据处理,数据可视化分析,评价指标体系建立,综合评价模型建立以及最后的分析报告。综合评价方法尽量不要使用层次分析法这种主观赋权法,考虑客观权重法,比如主成分综合评价,变异系数法等等。 博主这次先做B题稍后会分享B题解题思路和完整代码,可以先关注 3.选题思路 其实很多带专业背景的题目,最后通过抽象成数学模型就是上述三类问题。比如图像类问题,很多时候要么抽象成优化模型来求解,要么就是机器学习模型来训练识别。那我就从三类题型来说明一些基本的模型: 优化类:优化类问题基本没有可以直接套的模型,很多问题都需要自己来写出优化目标和约束条件。或者参考相关文献来设计模型。并且如果模型设计的复杂了,还需要自己设计优化求解算法。。。总之,优化问题是很难得。基本的优化模型包括:线性规划,整数规划,01背包,非线性规划(建模赛题基本都是非线性的。。。哈哈哈),最小二乘优化。基本求解算法包括:牛顿迭代,拟牛顿,梯度下降,共轭梯度下降,各种智能寻优算法等等。总而言之,优化就是难啊难,而且优化建模题基本上都有答案范围,模型建的不好,解的不好都over。。。 评价类:评价类问题,一般都有可以套用的方法,比如主观一些的:层次分析法,模糊评价法。客观计算权重的(需要数据):熵权法,TOPSIS综合评价法,主成分权重法。对于评价类问题最好还是用客观计算权重的方法。 数据类:上面两类问题可以说是建模竞赛以往的常规类型,数据类问题是最近几年随着人工智能,数据挖掘技术的热潮带起来的。。。可以说,数据类问题在以后的建模比赛中只会越来越多,而且数据量也会越来越大。 建议新手规避优化题,因为你很难做好,做出彩 3.获奖经验分享 数学建模百分百获奖经验分享 4.代码分享 站内链接,谢谢审核 2023年电工杯B题完整代码+结果

docker安装redis

1.查询redis的docker镜像 docker search redis 2,下载所需镜像 docker pull redis 默认是下载最新镜像,如果对版本有要求: docker pull redis: <版本号>,例如我下载的是6.2.4版本: docker pull redis:6.2.4 3,创建挂载路径: mkdir -p /data/redis/conf 创建redis的配置文件挂载路径 mkdir -p /data/redis/data 创建redis数据挂载路径 4,以配置文件启动redis,配置redis配置文件 配置文件最好跟自己的redis版本对应,不然在启动的时候可能会报各种参数不存在等问题,配置文件可以去下载: https://redis.io/docs/management/config/ 如果跟我的版本相差不大,可以用我的这个配置文件参数: #bind 192.168.1.100 10.0.0.1 #bind 127.0.0.1 ::1 #bind 127.0.0.1 protected-mode no port 6379 tcp-backlog 511 #设置的密码 requirepass 123456 timeout 0 tcp-keepalive 300 daemonize no supervised no pidfile /var/run/redis_6379.pid loglevel notice logfile "" databases 30 always-show-logo yes save 900 1 save 300 10 save 60 10000 stop-writes-on-bgsave-error yes rdbcompression yes rdbchecksum yes dbfilename dump.

当下的程序员该如何面对复杂的就业坏境

已经2023年了,我们都知道现在开发趋向于年轻化,大部分都是90后、95后,毕竟,软件开发不像硬件开发一样,年限越高,相对来说越吃香。 31岁,前端工程师,工作经历8年,7年左右都在外包公司,1年左右在创业公司。 经常能在网上听到一些某某公司清退一些35岁以上人员,特意百度查了一下30岁程序猿的出路,发现知乎上有这么一个话题,“30岁以上的程序员该何去何从?” 100多w的阅读量,说明越来越多的程序猿都在关注这个话题。 我总结了几点: 1.了解最新的新技术 技术的更新是很快的,例如,以前那时候,几乎后台的面试要求都是springmvc,前端面试就是css+html+js, 后端现在要求springboot+springcloud,而前端也变成需要懂小程序、h4、vue等等。 2.深入底层源码学习 技术更新换代是很快,但是,每一个技术,都是借鉴某个技术的思想,或者在某个技术上衍生出来的,例如springboot是方便, 但是,这些技术给我们带来便利的同时,如果不对他底层有所了解,遇到问题,你也会很被动,应该知其然而知其所以然。 3.保持一颗谦虚的心,须知人外有人 可以去参加一些技术大会,也可以进一些技术群,社长,在写博客过程中,就认识了不少技术大佬,记得诚、扬帆向海、第三女神程忆难 4.形成适合自己的学习方法 技术是学不完的,我们在学习的过程中,应该形成一套自己的学习方法。我们的学习方法,就是看某个技术点的视频, 针对某个技术点,再具体去看一些博客,看看大家都是如何理解的,以便自己更好的理解融会贯通。过一段时间,再回把这部分知识点, 总结起来,通过写博客的方式,分享出来。因为,不时会有一些大佬给你评论,提出自己的一些观点,这样形成一个技术的交流,对技术会有提升。 5.想好以后的方向 需要注意几个时间节点,刚刚出学校的时候,有能力尽量去大厂,当然前提是保证自己能生存下来。实际上, 也遇到一些,自己找事都有点困难的人,还挑三拣四,瞧不起去外包,不想去外包这种公司,或者小一点的公司。 个人建议: 一般大约毕业,正常应该是22岁左右,大家都是成年人,也有自己的思想,出了校门,就不要找父母了,自己自食其力,有工作先做着, 在工作之余,提升自我。先保证自己在社会上能生存,再谈一些其他的。 3-4年的时候,这个时候的我们,应该好好考虑一下,以后个人的一个职业发展方向了,是向技术方法发展,还是管理方向发展。 6.知识付费 在我们技术有一点阶段后,就可以实现知识付费,开通付费专刊,还有人录制视频教程。 7良好的体魄 好的体魄,你才能更好的学习,这是一些的前提,所以有时间还是得好好锻炼, 实际上,程序猿这个职业,就决定了我们,可能避免不了加班,但是,我们应该适量,把握好度,看一看网上那些关于程序猿的新闻,所以,我们应该有所警惕,保证身体,有时间就锻炼一下。 总结: 各行各样都会淘汰一些能力差的,不仅仅是IT这个行业,所以,不要被程序猿是吃青春饭等等这类话题所吓倒,也不要觉得,找到一份工作,就享受安逸的生活, 你在安逸的同时,别人正在奋力的向前跑,这样与别人的差距也就会越来越遥远,加油,希望,我们每一个人,成为更好的自己。

spring boot 权限管理的几种方式

Spring Boot 提供了多种权限管理方式,以下是几种常见的方法,以及相应的示例: 基于角色的访问控制(Role-Based Access Control,RBAC) 在基于角色的访问控制中,权限分配给角色,然后将角色分配给用户。这种方法简化了权限管理,因为您只需要管理角色和用户之间的关系。 示例:使用 Spring Security 实现 RBAC 1.1. 添加 Spring Security 依赖项到 pom.xml: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> 1.2. 创建一个 SecurityConfig 类,继承 WebSecurityConfigurerAdapter,并配置角色和权限: @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/admin/**").hasRole("ADMIN") .antMatchers("/user/**").hasAnyRole("ADMIN", "USER") .antMatchers("/").permitAll() .and().formLogin(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("admin").password(passwordEncoder().encode("admin123")).roles("ADMIN") .and() .withUser("user").password(passwordEncoder().encode("user123")).roles("USER"); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } 基于属性的访问控制(Attribute-Based Access Control,ABAC) 在基于属性的访问控制中,权限是基于用户、资源和环境属性的。这种方法提供了更细粒度的权限控制,但可能更难管理。

matlab 让数组每个元素重复出现

直接使用repelem或者利用函数repmat和 reshape 1.repelem 重复数组元素副本 u = repelem(v,n),返回一个重复 v 中元素的向量,其中 v 是一个标量或向量。 B = repelem(A,r1,...,rN),将 A 中的每个元素依 r1,...,rN 进行重复,返回一个数组。 举例: a=[1 2 3]; u = repelem(a,2); >> u u = 1 1 2 2 3 3 2. repmat 矩阵的复制排列 B=repmat(A,n):返回B是一个n*n块大小的矩阵,每一块矩阵都是A B=repmat(A,m,n):返回值是由m*n个块组成的大矩阵,每一个块都是矩阵A。 B=repmat(A,[m,n,p,…]):返回值B是一个多维数组形式的块,每一个块都是矩阵A reshape 将矩阵重排: reshape(M, m, n)将矩阵M重排成m * n 举例: a = [1 2 3 ]; repeat = 2; % 要重复几次就写几 tmp = repmat(a, repeat, 1); b=reshape(tmp, 1, length(a)*repeat); b >> b b = 1 1 2 2 3 3 matlab如何让数组每个元素重复出现?_百度知道 (baidu.

全面SOA化的电子电气架构是什么样?

交流群 | 进“传感器群/滑板底盘群/汽车基础软件群/域控制器群”请扫描文末二维码,添加九章小助手,务必备注交流群名称 + 真实姓名 + 公司 + 职位(不备注无法通过好友验证) 作者 | 张萌宇 在汽车产业向智能化转型的过程中,汽车的开发模式、消费者对车的认知,以及汽车销售的商业模式都在发生着颠覆性的改变。传统的电子电气架构已经越来越无法适应现如今消费者对汽车智能化的要求。 工程师在传统电子电气架构上开发新功能时,耗时长且迭代难,此外,工程师在开发时还需要考虑种种限制条件并且要针对不同车型做定制化开发。 △传统电子电气架构的痛点 为避免上述问题,越来越多的车企倾向于选择区域接入+中央计算的SOA架构。华为在这次上海车展前夕发布的iDVP智能数字底座,便是这样一套满足区域接入+中央计算标准的SOA架构。 1. 华为iDVP智能汽车数字底座的结构与预期功能 △整车层次示意图 在底盘等机械硬件之上,华为将整车分为几个层次,从下往上依次为硬件平台、软件平台、应用生态以及车云,如上图所示。 iDVP包含硬件平台和软件平台两部分,其中,硬件平台是指计算与通信架构基础硬件平台,软件平台又分为操作系统、基础管理框架以及SOA软件框架。为方便用户在iDVP上开发软件,华为还开发了配套的工具链,如下图所示: △iDVP结构示意图 1.1 计算与通信架构硬件平台 计算和通信架构平台负责设计车辆的计算和通信方式,目前主要包括星型组网和以太环网,如下图所示: △ 通信架构示意图 VDC代表智能车控域控制器,MDC代表智能驾驶域控制器,CDC代表智能座舱域控制器。域控制器可以通过VIU连接到传感器和执行器。 在星型组网中,VDC通过以太网和分布于车身的VIU相连,从而控制车身上的传感器和执行器,MDC和CDC通过连接VDC来控制传感器和执行器。 在以太环网中,各个域控制器和VIU均通过以太网有直接的连接,并且VIU可以组成一个环状网络,某一段网络断掉时还有备份路线,通信的可靠性和安全性更能得到保障。 1.2 操作系统 操作系统包括VOS和AOS。 VOS:智能车控操作系统,可以支持存量应用平滑地从CP向AP迁移,并且可以在多核部署的同时保证应用对多核无感知,还支持数字孪生和整车OTA。 AOS:智能驾驶操作系统,支持车规级安全,具备丰富的AI原生开发库,可以提高模型化仿真、验证、智能驾驶开发的效率。 1.3 SOA软件框架 SOA软件框架包括了设备抽象层和原子服务层,方便用户在iDVP上开发软件。 根据4月16日华为智能汽车解决方案发布会上的信息,华为的SOA架构涵盖了车身域、动力域、底盘域、智能驾驶域,以及热管理域,相关的应用均可以在SOA架构下实现。 1.3.1 设备抽象层 据华为方面的设计理念,设备抽象层对传感器、执行器、Legacy ECU 等硬件资源进行抽象,通过API向上为服务提供设备访问接口,屏蔽设备功能实现差异(硬件差异&厂家差异),减少定制化与重复劳动。工程师在开发相关功能时,不用考虑硬件设备的电气参数差异,直接调用相应接口即可。 例如,当工程师需要调用电机时,只需要输入“转动方向”,“转速”的参数,然后调用电机的接口就可以实现对电机的控制,而无需了解及考虑电机的控制电气信号差异性。 根据4月16日华为智能汽车解决方案发布会上的信息,目前,华为已经开发了符合中汽协SDV标准的300+个设备抽象API。设备抽象服务涵盖了车身域、热管理域、动力域、底盘域等,而可以提供抽象服务的设备包括了电机、按钮开关、继电器、车灯、温度传感器等各类执行器和传感器。 △SDV设备抽象API 1.3.2 原子服务 原子服务将硬件设备的基础动作封装成API,从而给上层应用提供最基本的操作单元。如此一来,硬件设备和软件端口就可以实现解耦。例如,调整车窗的车窗开度,打开车窗,关闭车窗,停止开启或关闭车窗,在原子服务里都会根据基础操作封装成一个个接口。 根据4月16日华为智能汽车解决方案发布会上的信息,目前,华为已经开发了符合中汽协SDV标准的400+个原子服务API,服务涵盖了车身控制、交互域、运动控制、能量管理、智能驾驶域等各个方面,包括了车门服务、雾灯服务、通风服务、座舱温控等各类服务,方便工程师在开发软件时调用。 △SDV原子服务 1.4 基础管理框架 基础管理框架主要负责分布式通信、整车OTA、功能安全、诊断等基本功能。 1.5 工具链 工具链可以提供车辆软件开发过程中的工具,匹配软件开发工作流程。 按照工作流程,工具链产品可分为:整车级架构设计工具——包括iDVP API服务定义库、iDVP SWC工程库、iDVP网络拓扑库等,主要用于整车级的服务化设计;然后是模型化开发工具——包括iDVP底软配置工具包、iDVP行为模型库等,主要用于模型化开发与配置;最后是数字底座仿真器——包括时序分析工具等,主要用于整车级的服务化验证。 △iDVP工具链 2. iDVP的优势 在4月16日的华为智能汽车解决方案发布会上,iDVP被称为是软件定义汽车的“黑土地”,在软件定义汽车时代,iDVP可以大幅提升软件开发的效率,平衡用户体验的基础一致性和个性化。那么,iDVP有哪些优势呢? 2.1 区域接入+中央控制架构,提升架构灵活性 iDVP采用区域接入+中央控制的架构。在这样的架构下,整车ECU可以减少20~30个,节省约50w的功耗。 △iDVP典型架构

【SpringBoot】1、SpringBoot整合JWT实现Token验证

这里写目录标题 1.单点登录1.1 单系统登录1.1.1 单系统登录流程(使用Session实现单系统登录) 1.2 多系统(单点)登录1.2.1 单点登录实现方案1.2.1.1 Session跨域1.2.1.2 Spring Session共享 1.3 Token机制1.3.1 传统身份认证1.3.2 基于Token的身份认证 1.4 JWT机制1.4.1 JWT数据结构1.4.1.1 header1.4.1.2 payload1.4.1.3 signature 1.4.2 JWT执行流程1.4.3 JWT代码案例 1.单点登录 单点登录(Single Sign On), 简称为SSO, 是目前比较流行的企业业务整合的解决方案之一. SSO的定义:在多个应用系统中, 用户只需要登录一次就可以访问所有相互信任的应用系统, 企业间需要相互授信 1.1 单系统登录 众所皆知, HTTP是无状态的协议, 这意味着服务器无法确认用户的信息。 于是乎,W3C就提出了:给每一个用户都发一个通行证,无论谁访问的时候都需要携带通行证,这样服务器就可以从通行证上确认用户的信息。通行证就是Cookie。 如果说Cookie是检查用户身上的”通行证“来确认用户的身份,那么Session就是通过检查服务器上的”客户明细表“来确认用户的身份的。Session相当于在服务器中建立了一份“客户明细表”。 1.1.1 单系统登录流程(使用Session实现单系统登录) 一、登录 用户登录成功后, 通过request获取Session(本质是根据Cookie中携带的JSESSIONID寻找Session) 如果没有携带JSESSIONID或者JSESSIONID找不到Session, 说明用户未登录, 此时将用户信息保存到Session对象中(默认会以Cookie方式向客户端返回JSESSIONID, 但此JSESSIONID是会话级别的)如果Session能找到, 说明当前用户已经登录 二、记住我(关闭掉浏览器后,重新打开浏览器还能保持登录状态) 因为默认返回的JSESSIONID是会话级别的, 我们可以手动为Cookie中添加JSESSIONID信息,设置Cookie的过期时间, 此时不管你的浏览器是否关闭,Cookie中都会携带JSESSION信息 //登录成功后,手动添加cookie,保存JSESSIONID信息 Cookie cookie = new Cookie("JSESSIONID", session.getId()); //300年后过期(永久有效) cookie.setMaxAge(60 * 60 * 24 * 30 * 12 * 300); //设置cookie 和 session生命周期同步.

win11配置Linux子系统,并打造Linux开发环境

概述 对于程序员来说接触linux系统是必不可少的,即使我们在本地开发调试的时候是在window进行,但是实际上部署运行大概率是会在Linux机器,所以在Liunx环境下学习或者进行开发调试是必要的。本文主要是教新手如何在自己window系统电脑上如何多配置一个Linux子系统,并打造Linux开发环境 1.安装&运行Ubuntu 1.wsl安装Ubuntu # 打开PowerShell 执行命令 wsl --update (系统自动为你的电脑下载一个适配linux环境) # 安装Ubuntu wsl --install Ubuntu # 查看是否安装成功 wsl --status 2.运行Ubuntu PowerShell命令 # 打开PowerShell执行命令 wsl 其实Ubuntu系统和我们的window系统是公用的一个系统 /mnt是共享目录,/mnt目录下是电脑的c盘,这种方式进入会进到我们当前的目录 运行Ubuntu.exe 按照图上操作,会进入Ubuntu系统用户的家目录 2.更新Ubuntu镜像源 先备份下原有镜像源文件 更新文件内容 我使用的是阿里的镜像源,在阿里云搜索Ubuntu找到对应的镜像源,复制粘贴就行了 更新apt sudo apt-get update # 使用 apt-get 下载c语言环境 sudo apt-get install gcc 安装的linux子系统自带python环境,应该都是python3,也可以自己下载其他的版本输入命令就可以进入python环境 python3 其他的环境依赖工具也是类似的方法 sudo apt-get install g++ (下载c++的依赖)sudo apt-get install gdb (调试工具) 在window机器上搭建Linux环境并且简单打造linux开发环境就做好了

Oracle表信息查询

SELECT * FROM USER_TABLES 查看当前用户下的表 SELECT * FROM DBA_TABLES 查看数据库中所有的表 SELECT CREATED,LAST_DDL_TIME from user_objects where object_name=upper('表名') SELECT CREATED, LAST_DDL_TIME FROM USER_OBJECTS WHERE OBJECT_NAME = 'PDCA_NEW_REPAIR'; 其中CREATED 为创建时间 ,LAST_DDL_TIME为最后修改时间 持续更新。。。

CAN总线要点总结(CAN2.0A/B)

前言 工作也有几年了,在项目中也接触过几次CAN总线,但总是止步于会用即可,对于很多细节上的东西有时还是稀里糊涂的状态,这几天正好有点时间,因此整理了这篇文章来对自己的CAN总线知识体系查漏补缺。 发展历史 1986年发布CAN1.0。1991年博世发布CAN2.0规范,分为CAN2.0A(11位标识符)和CAN2.0B(11+18=29位标识符)。1993年ISO组织发布ISO11898规范: ISO11898-1 涵盖数据链路层。ISO 11898-2 涵盖高速CAN的CAN物理层(经典CAN速度1Mbps,CAN FD 5Mbps)。ISO 11898-3 涵盖低速、容错CAN的物理层(速度125kbps)。后续推出ISO 11898-4 -5 和-6标准。 2012年博世发布CAN FD 1.0(速度2Mbps,使用加强版CAN PHY的CAN FD-SiC可以做到5-8Mbps)。2018年发布第三代CAN数据链路层协议CAN XL,速度提升至10Mbps,兼容CAN FD。 电气特性 总线与总线上各个节点使用双绞线连接,两端各自端接120Ω,1/2W电阻。 差分通信,总线执行逻辑线与机制(为后续冲突仲裁服务),显性电平为0,隐性电平为1。在物理层上目前主流有两种标准。 理论通信速率VS最大长度(以经典CAN为例,所有节点应该使用同一速率)。 速度长度1Mbps40m500kbps100m250kbps200m125kbps500m10kbps6km 总线拓扑 Tips: 如果手头没有收发器,但是又想对CAN应用进行简单验证,可以考虑如下方法,此方法适用于CAN2.0A/B,后续实际采集的波形,都是按这种方法采集的: CAN协议报文 1、数据帧 数据帧在物理层的实际样子,这里以CAN2.0A为例子(这里可以发现每当出现连续的5个相同bit,则需要填充一个相反的bit作为stuff bit,此规则不适用于CRC段和其后的段): CAN2.0A数据帧和CAN FD数据帧对比: 这里有个地方我觉得是有问题的,IFS CAN2.0A/B数据帧构成说明: CAN2.0A为标准帧,CAN2.0B为拓展帧,两者主要差异在于仲裁段不同。上图灰色部分固定为显性(0),白色部分固定为隐性(1),蓝色部分的电平状态根据数据而定,ACK位的图示表示TXD输出隐形,同时RXD接收显性输入。 以下表格说明标准帧的各部分组成: 隶属段缩写长度说明帧起始SOF(Start of Frame)1固定为显性(0)仲裁段ID(Identifier)11基本ID,越小优先级越高,禁止高7位都为隐性,即禁止ID=1111111XXXX仲裁段RTR1远程传输请求位,在数据帧中固定为显性(0),同ID数据帧优先于远程帧控制段IDE1拓展帧标记,在标准帧中固定为显性(0)控制段r01保留位,固定为显性(0)控制段DLC4数据段长度,CAN2.0A/B中允许长度为0~8数据段Data0~64数据长度由DLC指定,支持0~8字节CRC段CRC15CRC校验值CRC段CRC界定符1用于分隔CRC和ACK段,固定输出1位隐性(1)ACK段ACK Slot1发送节点输出隐性(1),同时接收接收节点发送的显性(0)ACK段ACK界定符1同CRC界定符,分隔ACK段与后续段,固定输出隐性(1)帧结束EOF7固定输出7位隐性(1)可以看到,由于RTR位的存在,相同ID的数据帧和遥控帧(远程帧)同时发送时,总是数据帧赢得仲裁 CAN2.0B拓展数据帧只是仲裁段和控制段有差异,这里说明拓展数据帧的仲裁段和控制段: 隶属段缩写长度说明仲裁段ID(Identifier)11基本ID,越小优先级越高,禁止高7位都为隐性,即禁止ID=1111111XXXX仲裁段SRR1Substitute Remote Request,固定为隐性(1)仲裁段IDE1拓展帧标记,在拓展帧中固定为隐性(1)仲裁段拓展ID18扩展ID仲裁段RTR1远程传输请求位,在数据帧中固定为显性(0),同ID数据帧优先于远程帧控制段r11保留位,固定为显性(0)控制段r01保留位,固定为显性(0)控制段DLC4数据段长度,CAN2.0A/B中允许长度为0~8可以看到,由于SRR位的存在,基本ID(11位ID)相同的标准数据帧与拓展数据帧仲裁时,总是标准数据帧赢得仲裁。 2、遥控帧(远程帧) 遥控帧与数据帧并无大的差异,与数据帧相比,遥控帧将RTR位置为隐性(1),同时不包含数据段。在遥控帧中,DLC表示请求传输的数据长度。 3、错误帧 错误帧用于在节点检测到错误时通知其他节点,十分简易的帧结构,由6位错误标志(根据节点当前所处的错误状态来确定错误标志的电平),8位错误界定符组成。 一个值得关注的小问题: 为什么会有错误标志重叠部? 不同节点发现错误的时机可能不同,这会导致节点开始发送错误标志的开始时间不同。最坏的情况是某个节点收到其他节点发送的6位错误标志位才反应过来出现了错误,此时它才开始发送自己的错误标志位。因此错误标志位重叠部最长可以为12位。 4、过载帧 过载帧和错误帧有着几乎一模一样的帧结构! 这里就会有一个问题,要怎么区分过载帧和错误帧呢? 一般来说,错误帧会在一帧数据的收发过程中发出,比如发送时发现数据帧没有收到ACK回复,或者接收时发现报文的CRC不对,此时错误帧会被发出以终止这条数据帧的继续发送,发送节点会在下次总线空闲时重新尝试发送此条报文。而过载帧一般会在总线空闲时由接收节点发出,这会拉低总线以阻止其他发送节点继续发送数据帧到总线上,给接收节点留出喘息的时间来处理上一帧。 5、帧间隔 每条数据帧与遥控帧发送前需要等待至少3个位的隐性帧将自己与前面的任何帧(数据帧、遥控帧、错误帧、过载帧) 分隔开来。过载帧和错误帧发送前不需要等待帧间隔!。 我们在图上还看到了延迟传送部分,当一个处于被动错误状态下的节点要发送数据帧或遥控帧时,它不但要等待3位的帧间隔,还需要额外再等待8位的延迟传送。“被动错误状态”这个概念见后面的错误处理相关章节。 CAN协议收发流程 发送过程 设置ID、DLC、数据帧等。任何节点在总线空闲时都可以发送数据,这时启动发送帧。除了正在发送数据的节点,其他节点处于监听状态。多个节点同时发送将启动仲裁,ID值小的优先发送,仲裁失败的进入监听状态。最终在完成仲裁后,同一时间,只会有一个节点发送数据。数据发送完成后,发送的节点释放总线(通过发送一个隐性的1),开始监听接收节点返回的ACK。成功接收ACK(一个显性的0)后,继续发送帧数据中的结束段,之后发送节点发送下一帧或进入接收状态。如果第7步没有收到ACK,将放弃后续发送并进入CAN错误处理流程**(错误处理?发送节点在内的所有节点都会监测是否出现错误,监测到错误的一个或多个节点会将总线保持在逻辑0至少6个总线周期,此时所有节点注意到此错误并采取措施,发送失败的消息将会被重新发送)**。发送节点维护发送错误计数器TEC,当错误数到达0xFF时,节点将会从网络中断开(进入bus-off状态)。 接收过程 除了处于发送状态和总线关闭状态(bus-off)的节点,所有节点都处于接收状态。如果收到有效的CAN消息,监听节点将进行应答。如果接收节点设置了过滤器,将根据过滤设置过滤掉不需要的消息(不影响应答,也就是控制器应答后自己把报文丢掉了,没有通知应用层)。过滤后收到的数据存入FIFO,用户根据DLC值处理数据大小。推荐用CAN中断或DMA方式,及时处理数据。 发送报文时的仲裁问题 所有CAN单元都可以在总线空闲时(最后一个ACK后出现连续11个隐性电平)发出消息。先发送报文的CAN单元可获得发送权(通过发送一个显性的起始位使得总线退出空闲状态)。如果两个CAN单元同时发出起始位,则通过线与机制对仲裁段进行仲裁,ID标识符更小的优先发送,输掉仲裁的CAN单元停止发送并等待下一次总线空闲时重发。仲裁的本质,是对发送到总线的信号进行回读,如果发送的是隐性位但读回的是显性位,则输掉仲裁并退出发送。由于显性位对应为“0”,因此越小的ID(开头0越多)在仲裁时具有越高的优先级。 CAN错误处理 错误类型 帧错误检测 检测到错误的节点将发送错误帧来发出错误通知,收到错误通知的节点也开始发送错误帧。检测到错误的发送节点放弃发送当前帧,并根据错误类型增加内部的发送错误计数器TEC;检测到错误的接收节点放弃当前帧接收,并根据错误类型增加内部的接收错误计数器REC。当TEC到达0xFF时,发送节点进入bus-off状态,从总线上断开;如果不是,则尝试在下一次总线空闲时重发当前帧。之后每次传输成功或接收成功一帧,对应的TEC和REC减1(有一个例外,当REC大于127时,REC会在接收成功时直接设置为127)。 节点错误状态 TEC和REC的计数值决定了CAN节点处于什么错误状态,如下图:

JVM性能调优监控工具进行介绍(jconsole,jmap,jstack)

java -Xmx1000m -Xss100m -jar yourjarfile.jar 是一种 Java 命令行参数的设置方式,用于在命令行运行 Java 应用程序时设置 Java 虚拟机的堆大小和栈大小等参数。 具体来说,-Xmx1000m 参数是设置 Java 虚拟机的最大堆大小,这里将最大堆大小设置为 1000MB,即 1GB。设置较大的堆大小可以让 Java 应用程序拥有更多的内存空间用于分配对象和缓存数据等,但也要注意程序运行时占用的内存不要超过系统物理内存,否则会导致系统缓慢或崩溃。JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4。 -Xss100m 参数是设置 Java 虚拟机线程栈大小,这里将线程栈大小设置为 100MB。线程栈是应用程序用于存储方法调用和本地变量的内存区域,设置较大的线程栈可以允许程序调用更深的递归方法或者同时启动更多的线程,但也要注意占用的内存不要超过系统物理内存或默认值(通常为 512KB 或 1MB),否则也会导致应用程序崩溃或运行缓慢。 默认情况下不会指定栈内存大小,因此将使用默认值. Java 栈内存大小在不同的 JVM 和操作系统下可能有所不同,但通常默认大小为 1MB~10MB,具体取决于对应的 JVM 和操作系统。 综上所述,这条命令意思是启动一个 Java 应用程序,设置虚拟机的最大堆内存为 1GB,设置线程栈大小为 100MB,并指定要运行的 JAR 文件。 jconsole远程tomcat进程 修改tomcat/bin/catalina.sh文件,粘贴如下到catalina.sh 文件 JAVA_OPTS="-Djava.rmi.server.hostname=192.168.53.53 -Dcom.sun.management.jmxremote.port=11000 -Dcom.sun.management.jmxremote.rmi.port=11000 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false" 打开jconsole连接tomcat进程,无需输入 用户名/口令 jconsole远程jboss进程(用户名/口令 可以不用填写),查看 内存,线程, 类 在%JBOSS_HOME%\bin\run.sh文件中将 JAVA_OPTS="$JAVA_OPTS -Dprogram.name=$PROGNAME "修改为: JAVA_OPTS="$JAVA_OPTS -Dprogram.name=$PROGNAME -Dcom.sun.management.jmxremote.port=15080 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false" jstack -h 查看帮助 jstack是jdk自带的线程跟踪工具,用于打印指定 java进程(如jboss中run.

Flutter 笔记 | Flutter 基础组件

Text Text 用于显示简单样式文本,它包含一些控制文本显示样式的一些属性,一个简单的例子如下: Text("Hello world", textAlign: TextAlign.left, ); Text("Hello world! I'm Jack. "*4, maxLines: 1, overflow: TextOverflow.ellipsis, ); Text("Hello world", textScaleFactor: 1.5, ); 下面是Text的常用属性: 属性功能textAlign文本对齐方式(center居中,left左对齐,right右对齐,justfy两端对齐)textDirection文本方向(ltr从左至右,rtl从右至左)overflow文字超出屏幕之后的处理方式(clip裁剪,fade渐隐,ellipsis省略号)textScaleFactor字体显示大小的缩放因子maxLines文字显示最大行数style字体的样式设置 注意, textAlign 对齐的参考系是Text widget 本身。如果 Text 文本内容宽度不足一行,Text 的宽度和文本内容长度相等,那么这时指定对齐方式是没有意义的,只有 Text 宽度大于文本内容长度时指定此属性才有意义。下面我们指定一个较长的字符串: Text("Hello world "*6, //字符串重复六次 textAlign: TextAlign.center, ); 运行效果: ​ 字符串内容超过一行,Text 宽度等于屏幕宽度,第二行文本便会居中显示。 TextStyle TextStyle用于指定文本显示的样式如颜色、字体、粗细、背景等。下面是TextStyle的常用属性: 属性功能decoration文字装饰线(none没有线,lineThrough删除线,overline上划线, underline 下划线)decorationColor文字装饰线颜色decorationStyle文字装饰线风格([dashed,dotted]虚线,double两根线,solid一根实线,wavy波浪线)wordSpacing单词间隙(如果是负值,会让单词变得更紧凑letterSpacing字母间隙(如果是负值,会让字母变得更紧凑)fontFamily指定字体fontStyle文字样式(italic斜体,normal正常体)fontSize文字大小color文字颜色fontWeight字体粗细(bold粗体,normal正常体)height指定行高,但它不是绝对值只是一个因子,具体的行高等于fontSize*height 简单示例: Text("Hello world", style: TextStyle( color: Colors.blue, fontSize: 18.0, height: 1.2, fontFamily: "Courier", background: Paint()..color=Colors.yellow, decoration:TextDecoration.underline, decorationStyle: TextDecorationStyle.dashed ), ); 效果:

chatgpt赋能python:Python去除空格和换行的实用技巧

Python 去除空格和换行的实用技巧 在使用 Python 进行文本处理的过程中,经常会遇到需要去除空格和换行符的情况。可能你需要去掉用户输入数据中的多余空格,也可能你需要从一个文本文件中抽取出数据并且规范化格式。本文提供了多种去除空格和换行的方法,旨在为大家提供一些实用的技巧和方法,帮助大家更好地应对各种文本处理需求。 什么是空格和换行符? 在学习去除空格和换行的技巧之前,我们先来了解一下什么是空格和换行符。空格是指在文本中插入的一个或多个空格字符(空格字符是指 ASCII 码表上的空格符),可以用来作为单词或句子之间的分隔符。而换行符则是指在文本中插入的特殊符号,可以在文本中分段或分行。 Python如何去除空格? Python 提供了多种方法来去除字符串中的空格。下面列举了一些常用的方法: 1. strip() 方法 strip() 方法可以去除字符串首尾的空格: s = " hello world " s = s.strip() print(s) # 输出:hello world 2. split() 方法 split() 方法可以将字符串按照分隔符分割成一个列表,然后通过 join() 方法将列表中的元素合并为一个字符串,从而去除字符串中间的空格: s = "hello world" s = "".join(s.split()) print(s) # 输出:helloworld 3. replace() 方法 replace() 方法可以将指定字符串或字符替换为另一个字符串或字符。利用这个方法,我们可以将空格替换为空: s = "hello world" s = s.replace(" ", "") print(s) # 输出:helloworld Python如何去除换行符? 除了空格之外,Python 也提供了多种方法来去除字符串中的换行符: 1. replace() 方法 通过将换行符替换为空串的方法可以去除换行符:

谷歌新版本跨域错误深度剖析与解决:request client is not a secure context and the resource is in more-private address

快速解决: ====================================================== 最近在测试http服务时,谷歌浏览器报了以下错误 “The request client is not a secure context and the resource is in more-private address space ‘local’”. 从报错信息来看,“不安全的请求方请求了更私有的本地资源” 对于该错误,其实已经在几个月前就已经遇到过,当时对于此的解决方式是修改谷歌浏览器的设置以关闭该检查。 如今,这个错误又一次出现,并且当初修改设置的方式已经不再可行,所以需要寻找其他方法。 这篇博文将分析该错误的原因与相关解决方案。 原因: 谷歌浏览器的更新 Chrome安全更新: 从 Chrome 94 开始阻止来自不安全公共网站的私有网络请求。 在 Chrome 98 中。 ●Chrome会在私有网络子资源请求之前发送预检请求。 ● 预检失败只在DevTools中显示警告,不影响私人网络请求。 ● Chrome收集兼容性数据,并向受影响最大的网站伸出援手。 ● Google 预计这将与现有网站广泛兼容。 最早在Chrome 101中全面部署 可以看到,从94版本开始,谷歌针对不安全网站访问私有网络进行了更新,阻止这种访问更私有资源的请求。同时,在进行私有网络资源请求前,还会先发送OPTIONS预检请求。 那么谷歌浏览器的这个更新,是基于什么呢?PNA(Private Network Access) 规范。对于不满足PNA的请求,谷歌浏览器会提示跨域错误 专用网络访问 这里发一下专用网络访问草案的网址: https://wicg.github.io/private-network-access/#intro 读了文档,大致了解到:PNA是对“公网”访问“私网”进行限制,以提高安全性,防止一些攻击。 文档中对于混合内容、Websocket等各个形式下的措施都有说明。 每个 IP 地址都属于一个 IP 地址空间,该空间可以是一个 三个不同的值: 本地:包含本地 仅限主机。换句话说,每个地址的目标都不同 装置。 私有:包含 仅在当前网络中有意义的地址。在其他 单词,其目标因网络位置而异的地址。 公共:包含所有 其他地址。换句话说,目标相同的地址 IP 网络上的全球所有设备。 为方便起见,我们还定义了以下术语: 本地地址是 IP 地址空间为本地的

Vue3挂载全局属性和方法

mian.js文件 创建app实例后,开始在实例上挂载全局变量/方法 app.config.globalProperties.属性名(方法名) = 值 在组件中,读取全局变量(方法) 通过打印getCurrentInstance(),我们可以发现结果数据中的ctx的值和proxy的值是一样的,所以在获取全局变量的时候可能会 通过ctx去实现,需注意的是 -- ctx打包后在生产环境下是获取不到的,为了保证项目的正常运行,正常应该使用 proxy。 也就是说:{ctx}=getCurrentInstance()和{proxy}=getCurrentInstance()的结果是一样的,但是正确应该使用后者。 参考文章:关于Vue3里面的getCurrentInstance:可以获取挂载在全局的属性和获取上下文_口袋の的天空的博客-CSDN博客

MATLAB 之 绘制三维图形的基本函数、三维曲面和其他三维图形

文章目录 一、绘制三维曲线的基本函数二、三维曲面1. 平面网格坐标矩阵的生成2. 绘制三维曲面的函数3. 标准三维曲面 三、其他三维图形1. 三维条形图2. 三维饼图3. 三维实心图4. 三维散点图5. 三维杆图6. 三维箭头图 三维图形具有更强的数据表现能力,为此 MATLAB 提供了丰富的函数来绘制三维图形。绘制三维图形与绘制二维图形的方法十分类似,很多都是在二维绘图的基础上扩展而来。 一、绘制三维曲线的基本函数 基本的三维图形函数为 plot3,它是将二维绘图函数 plot 的有关功能扩展到三维空间,用来绘制三维曲线。plot3 函数与 plot 函数用法十分相似,其调用格式如下: plot3(x1,y1,z1,选项1,x2,y2,z2,选项2,…,xn,yn,zn,选项n) 其中,每一组 x 、 y 、 z x、y、z x、y、z 组成一组曲线的坐标参数,选项的定义和 plot 函数相同(线型、颜色和标记符号等参数,详见 MATLAB 之 二维图形绘制的基本函数和辅助操作)。当 x 、 y 、 z x、y、z x、y、z 是同长度的向量时,则 x 、 y 、 z x、y、z x、y、z 对应元素构成一条三维曲线。当 x 、 y 、 z x、y、z x、y、z 是同型矩阵时,则以 x 、 y 、 z x、y、z x、y、z 对应列元素绘制三维曲线,曲线条数等于矩阵列数。例如,我们绘制空间曲线: { x 2 + y 2 + z 2 = 64 y + z = 0 \left\{\begin{matrix}x^{2}+y^{2}+z^{2}=64 \\y+z=0 \end{matrix}\right.

Keithley吉时利2450源表技术参数

Keithley SMU 2450源表,吉时利2450:Keithley 的触摸屏图形源测量单元仪器可带来直观的测试平台体验,满足电源和测量需求。应用:离散设备、组件、FET、二管、电阻、电池、电源管理 IC、太阳能电池、LED、纳米材料、有机材料等。 Keithley吉时利2450 SMU源表仪器提供四象限精密电压和电流源/负载,外加触摸屏用户界面上的测量。 这些仪器可同时提供 10 fA - 10 A 脉冲电流和/或 100nV - 200V 电压、1000W 脉冲和 100W 直流总功率的源和测量。 使测量登上全新高度:SMU 仪器可捕获更详细的设备行为,并在扩展范围内检定设备,因此您能更好地了解设备,提高其质量,改善其性能。 KEITHLEY吉时利2450数字源表的特点: ● 5英寸、高分辨率容性触摸屏图形用户界面 ● 0.012%基本测量准确度和6位半分辨率 ● 增强灵敏度20mV和10nA源/测量范围 ● 源和阱(4象限)操作 ● 4种“个性”模式用于快速设置和测量 ● 上下文相关的前面板帮助 ● 前面板输入香蕉头插座;后面板输入三同轴连接 ● 2450型增强SCPI和TSP®脚本编程模式 ● 2400型SCPI兼容编程模式 ● 前面板USB内存端口用于数据/编程/配置I/O 技术参数: 源电压范围:20mV 至 200V 输出功率:20W 源电流范围:10nA 至 1A 电阻测量范围:2ohm 至 200Mohm 外部宽度:255mm 外部深度:425mm 外部长度/高度:106mm 工作温度最小值:0°C 工作温度最高值:50°C

windowsAPI调用,实现鼠标自动点击

#include "windows.h" //鼠标点击函数,传入屏幕坐标 void doPressAct(int x, int y, int type_id) { SetCursorPos(x, y); if (type_id == 1) {//鼠标单击一下左键 mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTDOWN, x, y, 0, 0); mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTUP, x, y, 0, 0); } else if (type_id == 2) {//鼠标双击左键 mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTDOWN, x, y, 0, 0); mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTUP, x, y, 0, 0); mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTDOWN, x, y, 0, 0); mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTUP, x, y, 0, 0); } }

QT编程常见崩溃问题总结

一 主程序事件循环函数崩溃 : a.exec()处崩溃 该处崩溃一般调试的时候显示的堆栈信息停止的位置都是QT的dll库。我们的代码中只给出了a.exec()崩溃。 原因一: 子线程中更改界面上控件。在Qt事件循环中一般只有主线程可以用来改变某一个显示控件的状态。子线程想要改变界面时可以给主程序发信号。 原因二: 在事件循环中,有部分控件访问的地址越界 例如: QPixmap q_pixmap; //my_frame.data 是一块连续的内存空间,存放自定义图像数据。该类型创建的QImage数据为浅拷贝 QImage q_image(static_cast<uchar*>(my_frame.data), width, height, QImage::Format_Grayscale8); //pix_image 内部数据指针指向my_frame.data 所在地址。pix_image 只要不对图片进行更改就不会进行真正的深拷贝复制。 pix_image = pix_image.fromImage(img_image, Qt::ImageConversionFlag::NoFormatConversion); QLabel label; label.setPixmap(pix_image); 当自定义的分配的那一块图像缓冲区被释放时,QT程序因为label上的图片数据指针被释放,指向了无效数据空间。该控件可能有权限访问也可能没有,就会造成随机崩溃。提现在代码上就是主程序事件循环上崩溃。

CMakelist使用说明

默认路径 CMAKE_CURRENT_LIST_FILE :输出调用这个变量的CMakeLists.txt 的完整路径 CMAKE_MODULE_PATH :定义自己的cmake 模块所在的路径 EXECUTABLE_OUTPUT_PATH :重新定义最终结果的存放目录 LIBRARY_OUTPUT_PATH :重新定义最终结果的存放目录 CMAKE_INCLUDE_CURRENT_DIR :自动添加CMAKE_CURRENT_BINARY_DIR 和CMAKE_CURRENT_SOURCE_DIR 到当前处理的CMakeLists.txt PRIVATE: 将链接只用于当前目标,相当于.c包含,对外的.h不包含 INTERFACE: 将链接只用于依赖于当前目标的文件,当前目标不使用; 相当于.c不使用,对外的.h使用 PUBLIC:相当于PRIVATE + INTERFACE;所有对象都可以使用链接;相当于.c使用,对外的.h也使用 关键字 Option 在CMakeList中添加编译选项。 option(TRANSLATION_ENABLED "TRANSLATION_ENABLED " OFF) if(TRANSLATION_ENABLED){ message("Auto generate translation file ") } add_executable 添加可执行文件 add_executable(${APP_NAME} ${APP_SRC} ) aux_source_directory 把当前路径下src目录下的所有源文件路径放到变量hello_src中(不会递归包含子目录,仅包含指定的dir目录) aux_source_directory(./src ${hello_src}) $ENV{NAME} cmake 调用环境变量: MESSAGE(STATUS “HOME dir: $ENV{HOME}”) 设置环境变量的方式是:SET(ENV{ 变量名} 值) file (GLOB) 查找文件夹目录下的所有符合类型的文件,放入ALL_SOURCES 对象中 file (GLOB ALL_SOURCES "./Src/*.cpp" "./Src/UI/*.cpp" "./Src/Tools/*.cpp") find_package() set(QT_PATH D:/Qt/5.12.11/msvc2017_64) SET(CMAKE_PREFIX_PATH ${QT_PATH}/lib/cmake) #将cmake文件夹包含进项目优先查找路径中,之后find_package才能找到

msvcr110.dll丢失的解决方法,多种方法助你解决msvcr110.dll丢失

当您在尝试打开某个程序或游戏时,可能会看到一个错误消息,提示您的计算机缺少msvcr110.dll文件。这是因为该文件是Microsoft Visual C++ Redistributable库的一部分,缺少它可能会导致应用程序无法正常运行。在本文中,我们将详细介绍msvcr110.dll丢失的解决方法。 一.什么是msvcr110.dll MSVCR110.dll是Microsoft Visual C++ 2012 Redistributable的一部分。它是一个动态链接库文件,包含了许多用于C++编程的函数和类。如果您的计算机上没有安装Visual C++ Redistributable,或者该文件已被删除或损坏,那么您将会看到“msvcr110.dll丢失”错误消息。 二.修复msvcr110.dll丢失问题的方法 以下是修复msvcr110.dll丢失问题的几种方法: 方法1:重新安装Microsoft Visual C++ Redistributable 首先,您可以尝试重新安装Microsoft Visual C++ Redistributable。前往Microsoft官方网站下载并安装适用于您的操作系统的最新版本即可。安装完成后,重新启动计算机,并尝试打开应用程序或游戏,看看是否仍然出现msvcr110.dll丢失的错误消息。 方法2:从另一个计算机复制msvcr110.dll文件 如果重新安装Microsoft Visual C++ Redistributable没有解决问题,您可以尝试从另一个计算机复制msvcr110.dll文件。首先,找到另一个计算机上的该文件,并将其复制到U盘或其他可移动存储设备上。然后,在您的计算机上找到缺少该文件的应用程序或游戏的安装目录,并将该文件复制到该目录下即可。 方法3:使用dll修复工具修复msvcr110.dll 如果以上两种方法都无法解决问题,那么您可以尝试使用dll修复工具来修复msvcr110.dll丢失问题。这些工具可以自动扫描您的计算机,并查找丢失或损坏的dll文件。它们还可以下载并安装缺失的dll文件,并在必要时修复注册表项。直接在百度上搜索电脑修复精灵,进入官方站点下载一个dll修复工具,利用这个dll修复软件直接进行一键修复就可以了。 使用dll修复工具的优势 与手动复制dll文件相比,使用dll修复工具有以下优势: 1. 自动修复:dll修复工具可以自动扫描和修复丢失或损坏的dll文件,省去了手动查找和复制文件的麻烦。 2. 安全可靠:大多数dll修复工具都是由专业的软件公司开发的,具有良好的声誉和高质量的服务。使用它们修复dll问题通常是安全可靠的。 3. 便捷快速:使用dll修复工具可以快速解决dll问题,节省时间和精力。 在本文中,我们介绍了三种修复msvcr110.dll丢失问题的方法,包括重新安装Microsoft Visual C++ Redistributable、从另一个计算机复制msvcr110.dll文件以及使用dll修复工具。其中,使用dll修复工具是最方便、快速和安全的方法。以上就是关于msvcr110.dll丢失的解决方法的一些相关分享,希望本文能帮助到大家。

C++:静态变量

一、类或结构体外部静态变量 静态变量的初始化和空间释放:全局静态变量是在软件刚运行时就初始化,局部静态变量是在软件运行到那一块代码时才初始化。无论全局还是局部静态变量都是在程序运行结束后释放空间。静态变量的空间是放在静态存储区的,初始化一个含有静态变量的类实例时,该实例的大小是不包含静态变量的空间的;sizeof(ClassName),使用类名查看大小也是不包含静态变量的 1.1 外部静态变量 static int s_StVariable = 0; class StaticClass { public: int m_Varible; }; 变量s_StVariable 为定义在类外部的静态变量。 在类的外部声明为静态变量时,只有编译器在编译该翻译单元的时候才会识别到。链接器在链接其他翻译单元时,对其他的翻译单元而言,s_StVariable 这个静态变量是不可见的。 这样也就是我们常说的,静态变量只有在自己定义的.cpp文件中才会有效的原因。类中时有public,private之类的访问权限控制。我们如果把一个.cpp(翻译单元)看成是一个类的话,外部的static声明就是相当于定义这个变量或者函数为private。 1.2 全局变量 如果我们声明变量s_StVariable 时候不加static修饰,即 int s_StVariable = 0; class StaticClass { public: int m_Varible; }; 那么s_StVariable 就是一个全局的变量,全局是指在链接器连接的时候任何翻译单元都可以访问这个变量,即这个变量对于其他的翻译单元来说是Public的。一般我们不建议这样使用,全局变量很容易出现冲突。 1.3 extern外部变量 和类外的static变量相似的,还有另外一个关键字extern; extern int e_Varible; class StaticClass { public: int m_Varible; }; static关键字声明的变量是告诉编译器,这个变量是该翻译单元(.cpp)私有的,链接器查找时只有定义该变量的翻译单元可以使用,其他的翻译单元不可见该变量。 extern声明的变量是告诉链接器去其他的翻译单元中查找这个变量,即我在另一个cpp文件中定义一个全局变量int e_Varible 。在本文件内用extern做一个声明,我就可以使用另一个文件的全局变量。如果不加extern则会出现重定义冲突。加上extern后的变量相当于函数的函数声明。 1.4 头文件中的静态变量 一般情况下我们可能会选择在一个公共的.h头文件中定义一堆的全局静态变量,用于其他的cpp文件中,做配置信息。在其他的cpp文件将这个.h包含进去的时候,其实就是相当于在自己的cpp中定义了一个静态变量,多个cpp就是每一个文件中都有一个私有的静态变量。 当然.h中定义静态变量一般我们都会声明为const,不能修改,防止不同的cpp修改后变量值不同步。 二、类或结构体内部静态变量 2.1 静态成员变量 class StaticClass { public: static int m_Varible; static void Print() { std::cout << m_Varible; } int m_x, m_y; }; int StaticClass::m_Varible = 0; 成员变量m_Varible为我们定义在类内部的静态变量。类内部的静态变量作用就是让该类的所有实例对象有一个共用的数据变量,实现所有实例对象之间的公用数据同步。

QString格式化问题

整形 补齐固定长度 QString file_name = QString("%1").arg(22, 4, 10, QLatin1Char('0')); /* 参数说明: 22:输入的整形数据 4:放在%1位置上最小的为数 10,:进制单位 QLatin1Char('0'):补的0 */ 浮点数 保留固定小数位数 double num2 = 123.456789; QString str2 = QString::number(num2, 'f', 2); qDebug() << "str2:" << str2 << endl; 保留固定位数和长度 double num2 = 123.456789; QString str2 = QString("%1").arg(QString::number(num2, 'f', 2), -10, ' '); qDebug() << "str2:" << str2 << endl; 非数字字符串 补齐固定长度 QString file_name = QString("%1.bmp").arg(QString("ceshi"), -10 , ' '); qDebug() << file_name; //输出:ceshi .

Element ui el-upload 组件上传文件之后 file-list绑定的数据源依旧是空数组

el-upload 组件确实不支持自动更新 file-list,需要手动在上传成功和删除的回调中处理文件列表同步。 无奈只能手动实现,设置 on-success 和 on-remove 的回调处理。 <el-upload :action="uploadUrl" accept="image/jpeg,image/png" multiple :limit="5" :data="uploadConfig" :on-remove="(file, fileList) => { return handleRemoveByLogo1(file, fileList, 1); }" :before-remove="beforeRemove1" :before-upload="beforeUploadByLogo" :on-exceed="handleExceed" :on-preview="handlePreview1" :on-success="(res, file, files) => { return handleSuccessLogo1(res, file, files, 1); }" :file-list="imgJson[1].fileList" list-type="picture-card"> <img src="./img/camera.png" /> <span>拍照确认</span> </el-upload> 注意: el-upload手动修改file-list之后无法一次上传多张照片会报 Uncaught TypeError: Cannot set property 'status' of null

Qt编译mysql驱动

一、确保安装Qt时选择了source,即源码。 二、找到Qt安装目录下mysql驱动工程,以安装在E盘为例,工程路径为: E:\Qt\Qt5.14.1\5.14.1\Src\qtbase\src\plugins\sqldrivers\mysql 三、打开工程,修改mysql.pro文件,修改后如下: TARGET = qsqlmysql HEADERS += $$PWD/qsql_mysql_p.h SOURCES += $$PWD/qsql_mysql.cpp $$PWD/main.cpp #第一步,注释这里 #QMAKE_USE += mysql OTHER_FILES += mysql.json PLUGIN_CLASS_NAME = QMYSQLDriverPlugin include(../qsqldriverbase.pri) #第二步,添加.h依赖文件,找到自己安装的mysql对应路径 INCLUDEPATH+="E:\mysql\mysql-5.7.30-winx64 (1)\mysql-5.7.30-winx64\include" #第三步,添加依赖的.lib文件 LIBS+="E:\mysql\mysql-5.7.30-winx64 (1)\mysql-5.7.30-winx64\lib\libmysql.lib" #第四步生成你所需要的dll存放目录 DESTDIR=../mysql/lib 四、编译生成需要的文件,在工程同级目录下的lib文件夹中。 五、将编译生成的文件放到对应目录,选择自己对应的编译器版本。 E:\Qt\Qt5.14.1\5.14.1\mingw73_64\plugins\sqldrivers 六、在mysql安装路径找到mysql的libmysql.dll和libmysql.lib拷贝到相应的编译套件的bin目录下 7、至此就可以在Qt中使用QMYSQL驱动了。

HDLBits学习(三)*

Gates100 Vector100r 题目:给了一个长度是100的向量,请把它翻转输出一下 code: module top_module( input [99:0] in, output [99:0] out ); genvar i; generate for(i=0;i<99;i++)begin:a2 always @(*)begin out[i]=in[99-i]; end end endgenerate endmodule 用always for always@(*)begin for (int i=0;i<=99;i=i+1)begin out[i]=in[99-i]; end end Popcount255 题目:​ 设计电路来计算输入矢量中 ’1‘ 的个数,题目要求建立一个255bit输入的矢量来判断输入中 ’1‘ 的个数。 code: integer i; always @(*)begin out=8'd0; //要初始化0,不然仿真有问题 for(i=0;i<255;i++)begin if(in[i]==1'b1)begin //在generate for循环中,变量不能当做条件 out=out+1'b1; end else begin out=out; end end end 另一种思路: 有多少个1就是把所有的1相加: assign out = in[0]+in[1]+...+in[254]; Adder100i 题目:通过实例化100个全加器来实现一个100bit的二进制加法器。该加法器有两个100bit的输入和cin,输出为sum与cout。为了鼓励大家使用实例化来完成电路设计,我们同时需要输出每个全加器的cout。 故cout[99]标志着全加器的最终进位。 code:

js 解决浮点精度

在 JavaScript 中,由于浮点数的精度有限,可能会出现精度丢失等问题,以下是几种解决方法: 将小数转换为整数进行计算。 例如,将小数 0.1 转换为整数 1e15,相加后再除以 1e15,可以减小精度丢失的影响。 let a = 0.1; let b = 0.2; let c = 0.3; let sum = (a * 1e15 + b * 1e15 + c * 1e15) / 1e15; console.log(sum); // 输出 0.6 使用 toFixed 方法保留小数位数。 toFixed 方法可以将一个数字保留指定的小数位数,并返回一个字符串。 let a = 0.1; let b = 0.2; let c = 0.3; let sum = (a + b + c).toFixed(1); console.log(sum); // 输出 0.

vant中输入框右侧加icon或单位或label下面加一行提示语

van-field变为双标记可以在右侧加icon图标或单位或label下面加一行提示语 (1)输入框右侧加icon图标 <van-form> <van-field v-model="detailInfo.coverableCities" type="text" label="覆盖城市" required placeholder="请选择可覆盖城市(可多选)" :rules="rules.coverableCities" @focus="coverableCitiesObj.coverableCitiesShow = true"> </van-field> <van-icon name="arrow" color="#999" size="1.2rem" /> </van-form> 效果: (2)输入框在右侧加单位 <van-form> <van-field v-model="detailInfo.zwCount" type="number" label="车位展位数量" required placeholder="请输入车位展位数量"> </van-field> <span class="unit">个</span> </van-form> 效果: (3)label下面加一行提示语 <van-form> <van-field v-model="detailInfo.lesson" type="text" label="合作车辆品牌" label-class="lesson" required placeholder="请输入合作车辆品牌"> </van-field> <span class="label-lesson"> (擅长车辆价格范围,若曾有包店,经销商供应商或主机厂供应商服务经验请填写) </span> </van-form> 效果: css部分: .van-form { position: relative; } .van-form .van-cell { padding: 0; flex-direction: column; margin-top: 1.5rem; } .van-form .van-cell::after { border-bottom: none; } .

JS中操作数组的方法(全)

目录 1.Array.of() 2.Array.prototype.pop() 3.Array.prototype.push() 4.Array.prototype.reduce() 5.Array.prototype.reduceRight() 6.Array.prototype.reverse() 7.Array.prototype.shift() 8.Array.prototype.slice() 9.Array.prototype.some() 10.Array.prototype.sort() 11.Array.prototype.splice() 12.Array.prototype.toLocaleString() 13.Array.prototype.toReversed() 14.Array.prototype.toSorted() 15. Array.prototype.toSpliced() 16. Array.prototype.toString() 17.Array.prototype.unshift() 18.Array.prototype.at() 19.Array.prototype.concat() 20.Array.prototype.copyWithin() 21.Array.prototype.entries() 22.Array.prototype.every() 23.Array.prototype.fill() 24.Array.prototype.filter() 25.Array.prototype.find() 26.Array.prototype.findIndex() 27.Array.prototype.findLast() 28.Array.prototype.findLastIndex() 29.Array.prototype.flat() 30.Array.prototype.flatMap() 31.Array.prototype.forEach() 32.Array.from() 33.Array.prototype.indexOf() 34.Array.isArray() 35.Array.prototype.join() 36.Array.prototype.keys() 37.Array.prototype.map() 1.Array.of() Array.of() 静态方法通过可变数量的参数创建一个新的 Array 实例,而不考虑参数的数量或类型。 console.log(Array.of('foo', 2, 'bar', true)); // Expected output: Array ["foo", 2, "bar", true] console.log(Array.of()); // Expected output: Array [] 2.Array.prototype.pop() pop() 方法从数组中删除最后一个元素,并返回该元素的值。此方法会更改数组的长度。 const plants = ['broccoli', 'cauliflower', 'cabbage', 'kale', 'tomato']; console.

计算机网络考试周极限复习--1

第一章 时延 因特网协议栈和OSI参考模型 应用层:报文 HTTP(提供了Web文档的请求和传送),SMP(提供了电子邮件报文的传送), FTP(它提供两个端系统之间的文件传送) 运输层:报文段 因特网的运输层在应用程序端点之间传送应用报文 TCP UDP 网络层:数据报 网际协议:IP 该协议定义了在数据报中的各个字段以及端系统和路由器如何作用于这些字段 所有具有网络层的因特网组件必须运行IP 链路层:帧 第二章 应用层 应用层协议 定义了运行在不同端系统上的应用程序进程如何互相传递报文 Web 与 HTTP Web的应用层协议是超文本传输协议 RTT 往返时间 SMTP协议 SMTP是因特网电子邮件中主要的应用层协议,使用TCP可靠数据传输服务,从发送方额邮件服务器向接收方的邮件服务器发送邮件 DNS:因特网的目录服务 P2P文件分发 运输层 网络层提供了主机之间的逻辑通信,运输层为运行在不同主机上的进程之间提供了逻辑通信 多路复用和多路解复用 多路分解:将运输层的报文段中的数据交付给正确的套接字的工作 多路复用:在源主机从不同的套接字中收集数据块,并未每个数据块封装上首部信息从而生成报文段,然后将报文段传递到网络层,所有这些工作叫做多路复用

Linux系统安装Apache

本篇内容是练习安装apache服务,如果误删和本人没有任何连带责任。 yum安装和源码(tar包)安装,方式的不同 1,yum安装是将yum源中的rpm包下载到本地,安装这个rpm包。这个rpm包是别人编译安装好的二进制包。 2,源码安装,下载是源码包,要进行编译和安装,编译过程,可以进行参数设定。 一、检查是否以及安装Apache服务 rpm -qa | grep -i httpd 找到进行删除 yum remove httpd* -y 二、安装apache ①使用yum源来安装apache以及其依赖包 yum install httpd -y 然后启动 6.8版本使用: resvice httpd start 7.9版本使用:systemctl start httpd 配置站点文件在 vi /var/www/html/index.html ②使用wget从官网下载 2.1首先安装编译工具 yum install gcc gcc-c++ -y 2.2 然后再下载apache安装包以及其依赖包 wget -O /usr/local/src/httpd-2.4.57.tar.bz2 https://downloads.apache.org/httpd/httpd-2.4.57.tar.bz2 wget -O /usr/local/src/apr-1.7.4.tar.bz2 https://downloads.apache.org/apr/apr-1.7.4.tar.bz2 wget -O /usr/local/src/apr-util-1.6.3.tar.bz2 https://downloads.apache.org/apr/apr-util-1.6.3.tar.bz2 wget -O /usr/local/src//pcre2-10.42.tar.bz2 https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.42/pcre2-10.42.tar.bz2 这个网址是国外的,所以下载会有些慢。嫌慢的人可以考虑这个腾讯的网址 wget -O /usr/local/src/httpd-2.4.57.tar.bz2 https://mirrors.cloud.tencent.com/apache/httpd/httpd-2.4.57.tar.bz2 2.3解压 将我们下载好的安装包解压 tar -jxvf httpd-2.4.57.tar.bz2 tar -jxvf apr-1.

利用qsort排序

一、简单排序10个元素的一维数组 #define _CRT_SECURE_NO_WARNINGS #pragma warning(disable:6031) #include<stdio.h> #include<stdlib.h> void print_arr(int arr[], int sz) { int i = 0; for (i = 0; i < sz; i++) { printf("%d ", arr[i]); } printf("\n"); } int com_int(const void* e1, const void* e2) { return *(int*)e1 - *(int*)e2; } int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9,0 }; qsort(arr, 10, 4, com_int); print_arr(arr, 10); } 如果你想降序的话,那为社么不用这个呐 int com_int(const void* e1, const void* e2)

用户自定义控件依赖属性Command的绑定

自定义用户控件增加Command依赖属性并绑定 自定义控件 IconButton.cs中增加依赖属性 public ICommand Command { get => (ICommand)GetValue(CommandProperty); set => SetValue(CommandProperty, value); } public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(IconButton), new PropertyMetadata(null)); <UserControl x:Class="EasyCode.Controls.IconButton" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="me" > <Button Command="{Binding Command,ElementName=me}">Click Me!</Button> </UserControl> 在父窗口中设置如下绑定: <my:GreatUserControl Command="{Binding SomeCommand}" />

编码踩坑——Redis Pipeline中调用Lua脚本报错JedisMoveDataException的问题 / Lua脚本常遇到的问题

本篇记录使用Redis Pipeline时,调用redis.clients.jedis.PipelineBase#eval时,报错JedisMoveDataException的问题;通过查看源码发现问题的原因,通过jedis在Github的issue了解了解决方案;涉及知识:Redis slot、Redis Pipeline、Redis Lua; 问题背景 有一段涉及用户通知疲劳度控制相关的代码,由于要保证执行逻辑的原子性,用到了Lua脚本:先判断rateLimiterKey是否exist存在,若存在则返回0-不通过,否则对该key赋值并设置ttl(setex),返回1-通过;如下: local key = KEYS[1] local duration = tonumber(ARGV[1]) local exists = tonumber(redis.call('exists', key)) --exists=1,则表示存在,返回0; if exists == 1 then return 0 end --否则设置key及ttl,返回1; redis.call('setex', key, duration, "") return 1 在对批量用户做上述校验时,想到是否可用Redis Pipeline来优化,从而减小网络传输开销;关于Redis Pipeline的知识可查阅我之前的文章《编码技巧——Redis Pipeline》; 通过查看JedisClusterPipeLine对象的方法,发现Jedis确实提供了pipeline下的eval方法,如下: 于是,立即试了下,代码如下: try { pipeline = jedisCluster.pipelined(); for (String receiverId : receiverIds) { final String rateLimitKey = buildRecieverRateLimiterKey(msgType, receiverId, topic); pipeline.eval(LuaScript.setexFlag(), Lists.newArrayList(rateLimitKey), Lists.newArrayList(String.valueOf(ttl))); } // pipeline执行并获取结果 final List<Object> allVal = pipeline.

光敏晶体管(ALS-PT19-315C/L177/TR8) 光照度和电压,电流关系分析.

背景 当我们使用光敏晶体管进行,测算光照度时,大多使用ADC电路测到电压. 那么怎么根据这个电压计算出对应具体的光照度呢? 下面将以 ALS-PT19-315C/L177/TR8 型号的 光敏晶体管为例,来进行分析介绍,并给出 如何根据最大光照度范围 选定合适的电阻和电容. 1,直接看数据手册给出的 光照度和输出电压的关系 图1 由上图 我们可以得到下面的一个关系. 最大输出电压负载电阻最大可测算光照度最大电流4.6V1K30750LUX(和我们在图上推算的29900 是大概一致的)4.6mA4.6V7.5K4100LUX0.613mA4.6V75K410LUX0.061mA 继续,根据 7.5K 和75K 的 对应的 最大光照度和电阻值的关系, 我们可以得出他们之间应该是线性的. 即4100 是 410 的10倍. 75 是 7.5的10倍. 由此, 可以得到 上表的所有值. [1K电阻时计算得出 30750LUX (和我们在图上推算的29900 是大概一致的)] 由上面这个表所得出的线性关系.当我们 想要测算的最大光照度值为 1000lux 和 2000lux时, 应选的电阻为 1000lux -> 30.7K 2000lux-> 15.3K 2继续根据数据手册 得到合适的电容值 而滤波电容, 根据数据手册中建议的关系. 那么选择常用的 100nf 就可以了. 3,根据 ADC 得到的电压值, 计算出 光照度. 假设 电阻选定为30.7K 最大光照度为 1000LUX, 最大电压值为4.6V. 经ADC测到的输出电压为 2.3V, 那么光照度 如下

异步编程简介- promise

异步编程简介- promise 异步编程历史 前端异步编程经历callback、promise、generate、async/await几个阶段。 目前在简单场景使用回调,步骤比较多的场景使用promise和async/await,generate昙花一现,由于其api不易理解并且不易于使用而很少使用。 Promise 简介 promise目的:异步编程解决回调地狱,让程序开发者编写的异步代码具有更好的可读性。 promise规范规定了一种异步编程解决方案的API。规范规定了promise对象的状态和then方法。 promise是这种异步编程的解决方案的具体实现。 状态特性用来让使用promise的用户可以及时通知promise任务执行结果。 then特性让使用promise的用户可以控制执行完一个任务后执行下一个任务。 (使用回调进行异步编程的话,都是用户手动控制的,使用promise的话,只需要告诉promise:“我要执行什么任务”、“我执行的任务结束了”、“然后我要做什么”) promise语法 promise对象 new Promise对象时候传入函数,函数立即执行,函数接收resolve、reject参数,调用resolve或reject时候会改变promise状态。状态改变后不会再变化。 promise状态 pending fullfilled rejected 未调用resolve或者reject时候处于pending状态,调用resolve后处于fullfilled状态,调用reject后处于rejected状态。如果在pending状态时候,执行任务抛出错误,则变成reject状态。 状态变化后,会执行通过then注册的回调。执行顺序和调用then方法的顺序相同。 调用then方法时候,如果状态是pending则注册回调,等到状态改变时候执行,如果状态已经改变则执行相应的回调。 const p = new Promise((resolve, reject) => { resolve('test'); }); p.then( data => console.log(1, 'resolve', data), data => console.log(1, 'reject', data) ); p.then( data => console.log(2, 'resolve', data), data => console.log(2, 'reject', data) ); // 执行结果 1 "resolve" "test" 2 "resolve" "test" const p = new Promise((resolve, reject) => { throw new Error('test-error'); // 由于抛出错误,promise状态已经改变为rejected,再调用resolve将不会改变promise状态 resolve('test'); }); p.

vuepress简单使用

vuepress简单使用 1.基础配置 找个文件夹npm init,生成一个package.json npm init 加载vuepress npm install -D vuepress 在 package.json 中添加一些 scripts 这一步骤是可选的,但我们推荐你完成它。在下文中,我们会默认这些 scripts 已经被添加。 { "scripts": { "docs:dev": "vuepress dev docs", "docs:build": "vuepress build docs" } } 然后就可以运行下试试看,就会发现网站启动了.一般是http://localhost:8080 2.添加md文件 VuePress 遵循 “约定优于配置” 的原则,推荐的目录结构如下: . ├── docs │ ├── .vuepress (可选的) │ │ ├── components (可选的) │ │ ├── theme (可选的) │ │ │ └── Layout.vue │ │ ├── public (可选的) │ │ ├── styles (可选的) │ │ │ ├── index.

Netlogo学习笔记

第一行:国际惯例咕咕咕。 第二行:人工势场这个概念好神奇(虽然我觉得就是强行捏了一个高大上的词 第三行:希望全天下的软件都能把要用的东西集成成库,然后只需要无脑点点就可以了(我本人:又懒又馋还不爱劳动(武林外传十娘皱眉苦瓜脸.jpg 第四行:所有代码注释:不知道netlogo该怎么写注释就按python来了【upd:我知道了用“;;”来注释但是懒得改了】 第五行:netlogo的语法就是所有的东西都得空格隔开,3*9也得写成3 * 9 第六行:我要开始自行编辑了 一、安装+初步认识 这本书真好使,简单明了容易上手:《Netlogo多主体建模入门》 话不多说官网走起:netlogo下载链接 (实验室15kb的网速支持我摸鱼)(老师你看这可不怪我是网不行)(我超会找借口der) 1.1 生命游戏 具体规则:略(好多不想打上,反正就是小方格中的黑白色块在周8个邻居的相互作用下变黑变白的过程) 步骤:新建项目:文件->模型库->life(左图);setup-random:初始化(中图);go-forever:最终结果(右图) 结果:最终会形成小方格中黑白色块的死亡or存活图 1.2 鸟群模型 具体规则:略(模拟鸟群靠近or远离其他鸟,且保持飞行方向的过程) 步骤:新建项目:文件->模型库->bioligy(左图);setup+go(右图) 结果:最终可以看到鸟群成群一起往某个方向飞并且鸟群没有发生碰撞 1.3 财富分布模型 具体规则:略(更麻烦了,分谷物和人的分布,人:采集谷物+消耗谷物+代谢不同+可能饿死+新出生,谷物:生长) 步骤:文件->模型库->ScocialSicence.Economics.Sugarscape(左图);set-go(右图) 结果:class plot+class histogram:展示穷人、中产、富人的数量对比(可以看出二八定律);Lorenz curve(洛伦兹曲线):反映财富分配不均衡现象(红线越弯曲不均衡程度越高);Gini-Index(基尼系数):国际通用衡量财富不均衡的指标,数值越大越不均衡(一般0.3/0.4左右) 二、正式上手 此部分中都有各自的规则(但是由于我懒,我就不写了 2.1 小球宇宙 本模型:随机出现,单步移动 学习:对语法集合等有个初步认识 添加按钮并对按钮命名,右键黑色世界后编辑可对模拟世界的属性进行修改,在代码模块中编写代码对按钮进行设置 #对setup按钮进行设置 to setup clear-all #每次运行清空屏幕 set-default-shape turtles "circle" #设置形状为圆形 create-turtles 50[ setxy random-xcor random-ycor #50个小球且setxy随机横纵坐标 ] end #对go按钮进行设置 to go ask turtles[ #ask相当于循环,对turtles这个集合进行下面操作的循环 forward 1 #每点一次小球前进一个位置 ] end 效果图(左:setup,右:go): 2.2 生命游戏 本模型:被邻居影响而改变

SpringBoot中使用枚举类、switch、常量类(声明并初始化map)实现类策略者模式,接口返回常量数据

场景 SpringBoot中策略模式+工厂模式业务实例(接口传参-枚举类查询策略映射关系-执行不同策略)规避大量if-else: SpringBoot中策略模式+工厂模式业务实例(接口传参-枚举类查询策略映射关系-执行不同策略)规避大量if-else_霸道流氓气质的博客-CSDN博客 SpringBoot+@Validate+全局异常拦截实现自定义规则参数校验(校验get请求参数不能为空且在指定枚举类型中): SpringBoot+@Validate+全局异常拦截实现自定义规则参数校验(校验get请求参数不能为空且在指定枚举类型中)_霸道流氓气质的博客-CSDN博客 Java中使用枚举类和switch实现映射存储的类似策略模式实现定制化流程: Java中使用枚举类和switch实现映射存储的类似策略模式实现定制化流程_霸道流氓气质的博客-CSDN博客 在上面几篇文章的基础上,实现提供一个接口根据请求参数不同返回对应固定的常量值。 比如接口请求需要提供请求码,根据请求码查询对应的策略,并返回常量类中声明和初始化的字符串常量和Map常量。 注: 博客: https://blog.csdn.net/badao_liumang_qizhi 实现 1、新建枚举类存储请求码与不同对象的策略关系 package com.badao.demo.enums; import com.badao.demo.constant.Constants; import org.springframework.lang.Nullable; import java.util.HashMap; import java.util.Map; public enum MineMessageEnum { ZLW("zlw", "0001","badao1",Constants.SIFANGJISIGNAL,null), JJT("jjt", "0002","badao2", Constants.SIFANGJISIGNAL,null), CCL("ccl", "0005","badao3",Constants.KEERMASIGNAL,Constants.KEERMATURNOUT); private final String apiCode; private final String mineCode; private final String mineName; private final String signalRule; private final String turnoutRule; private static final Map<String, MineMessageEnum> mappings = new HashMap<>(); static { for (MineMessageEnum messageEnum : values()) { mappings.

【微信小程序】支付及退款流程详解

目录 一. 支付 1. 前端请求支付 2. 后端请求微信服务器 3.后端接受微信服务器返回数据 4. 前端发起支付 5.后端接受微信服务器回调 二.退款 一. 用户发起退款请求 二. 商户发起退款请求 三. 退款完成 一. 支付 支付主要分为几个步骤: 前端携带支付需要的数据(商品id,购买数量等)发起支付请求 后端在接收到支付请求后,处理支付数据,然后携带处理后的数据请求 微信服务器 的 支付统一下单接口 后端接收到上一步请求微信服务器的返回数据,再次处理,然后返回前端让前端可以开始支付。 前端进行支付动作 前端支付完成后,微信服务器会向后端发送支付通知(也就是微信要告诉你客户已经付过钱了),后端根据这个通知确定支付完成,然后就去做支付完成后的相应动作,比如修改订单状态,添加交易日志啊等等。 从这几个步骤可以看出,后端主要的作用就是将支付需要的数据传给微信服务器,再根据微信服务器的响应确定支付是否完成。 这个流程还是蛮容易理解的。形象的说,前端就是个顾客,后端就是店家,微信服务器的统一下单接口就像收银员。顾客跟店家说,我是谁谁谁,现在我要付多少多少钱给你买什么什么。店家就跟收银员说,那个谁谁谁要付多少钱,你准备收钱吧。收银员收到钱后,就去告诉店家,我已经收到钱了,你给他东西吧。 下面就详细的说明一下各个步骤的具体实现。 1. 前端请求支付 前端请求支付,就是简单的携带支付需要的数据,例如用户标识,支付金额,支付订单 ID 等等跟 **你的业务逻辑有关** 或者跟 **下一步请求微信服务器支付统一下单接口需要的数据有关** 的相关数据,使用微信小程序的 wx.request( ) 去请求后端的支付接口。 2. 后端请求微信服务器 后端接收到前端发送的支付请求后,可以进行一下相关验证,例如判断一下用户有没有问题,支付金额对不对等等。 在验证没什么问题,可以向微信服务器申请支付之后,后端需要使用 微信规定的数据格式 去请求微信的支付统一下单接口。 微信规定的请求数据: 这需要较多代码实现。因为需要的数据个数较多,而且还需要加密并以 XML 格式发送。 首先,有以下数据是使用小程序支付必须提供给微信服务器的参数。 小程序 appid。写小程序的大概没有不知道这个的。。。 用户标识 openid。也就是用户的小程序标识,在我上篇博客中说明了如何获取。 商户号 mch_id 。申请开通微信支付商户认证成功后微信发给你的邮件里有 商户订单号 out_trade_no 。商户为这次支付生成的订单号 总金额 total_fee 。订单总金额,很重要的一点是单位是分,要特别注意。 微信服务器回调通知接口地址 notify_url。微信确认钱已经到账后,会往这个地址多次发送消息,告诉你顾客已经付完钱了,你需要返回消息给微信表示你已经收到了通知。。这个地址不能有端口号,同时要能直接接受POST方法请求。

Docker中安装MySQL 5.7的教程

Docker中安装MySQL 5.7的教程 搜索MySQL 5.7的镜像 docker search mysql:5.7 下载MySQL 5.7的镜像 docker pull mysql:5.7 运行MySQL 5.7的容器: docker run -p 3306:3306 --name mysql57 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7 其中,-p参数指定端口映射,–name参数指定容器名称,-e参数指定环境变量,-d参数指定后台运行。 至此,MySQL 5.7的安装和启动已经完成。可以开始使用MySQL 5.7了,然后打开Navicat连接一下看看吧。 进入MySQL 5.7的容器: docker exec -it mysql57 bash 在容器中运行MySQL 5.7: mysql -uroot -p123456

搭建 Python 开发环境

前言 所谓 “工欲善其事,必先利其器”。在学习 Python 之前需要先搭建 Python 开发环境,由于 Python 是跨平台的,所以可以在多个操作系统上进行编程,并且编写好的程序可以在不同系统上运行。常用的的操作系统为 Windows、Linux、Mac OS。 Windows上推荐使用 Windows 7 及以上版本,另外 Python 3.5 及以上版本不能在 Windows XP 系统上使用; Linux 系统推荐使用 Ubuntu 版本; Mac OS X 10.3(Panther)开始已经包含 Python; 安装 Python 要进行 Python 开发,需要先安装 Python 解释器。因为 Python 是解释型编程语言,所以需要一个解释器,这样才能运行我们编写的代码。 以 Windows 系统为例,选择下载64位离线安装包; 可以在命令行输入 “python” 查看是否安装完成; Python 自带的开发工具 IDLE 在安装 Python 后,会自动安装一个 IDLE。它是一个 Python Shell(可以在打开的 IDLE 窗口的标题栏上看到),也就是一个通过输入文本与程序交互的途径,程序开发人员可以利用 Python Shell 与 Python 交互。初学者建议一开始可以使用 IDLE 来编写代码。 整理了一些 IDLE 中常用的快捷键,方便新人快速上手 第三方开发工具 除了 Python 自带的 IDLE 之外,还有很多能够进行 Python 编程的开发工具。\

车载与体征/手势检测 毫米波雷达信号处理流程

说明 本篇博文旨在搭建一个车载毫米波雷达、体征检测(呼吸心跳检测)、手势识别信号处理的框架,介绍其流程,并尽可能多地给出一些流程中的细节处理(内容确实几乎都是文字内容..),本篇博文不涉及各部分算法的具体原理与实现。本篇博文内容其实很简单,也会基于博主本人的积累以及读者的反馈不断更新内容,我们一起维护,我会定期完善。 Blog: 20221012博文第一次撰写 文章架构 目录 说明 文章架构 一、毫米波雷达信号处理概述 二、车载毫米波雷达的信号处理 三、体征检测与手势识别的雷达信号处理 四、总结 五、参考资料 一、毫米波雷达信号处理概述 应用于体征检测的雷达信号类型有很多,调频连续波(FMCW,chirp)是其中的一种,但现阶段应用于车载的基本就只有chirp的信号形式,后续对信号处理流程的说明都基于chirp的信号形式。 FMCW雷达的信号处理流程并不复杂,车载的:到从ADC数据到点云,体征检测的:从ADC数据到时间-相位的波形图,信号的处理流程和方法其实比较固定。各车载毫米波雷达厂家的信号处理方法也大同小异,正是基于此,加特兰在其芯片中甚至直接将得到点云之前信号处理过程硬化了,软件开发者只需要给硬件接口配置合适的参数即可,处理流程的硬化可以极大程度地提高处理速度、降低开发难度。 但是现阶段对雷达的信号处理已经不仅是限于对目标的定位和跟踪,越来越高的比如识别、分类乃至成像等要求都希望雷达可以实现,于是包括机器学习等方法开始被用到了雷达的信号处理中。此外,针对车载雷达的应用场景,各类ADAS报警功能的实现;针对体征检测的场景,病人的诊断报告以及一些应用场景下的报警功能的实现,连同这些更后端的功能实现都需要集中到雷达中做。 综合来看,雷达的信号处理流程虽然不复杂且比较固化,但是涉及的(可供研究和优化的)细节还是有很多的,此外,包括跟踪、分类、实际应用场景下的功能实现等也丰富了信号处理的内容,给信号处理工程师带来了更多的挑战,理清楚信号处理的流程,搭建一整个的知识框架是十分有必要的,这也是本篇博文想要做的事情。 博主本人现阶段对基于机器学习的方法做分类和识别,以及后端的应用功能的实现并不熟悉,相关原理和更细节的说明我会在往后进行补充。此外本人现阶段接触体征检测/手势识别还极少,有不当之处欢迎指正。 二、车载毫米波雷达的信号处理 车载和体征检测/手势识别雷达的射频前端基本一致:包括chirp的收发(当然车载的以及体征检测的对chirp的包括周期、带宽、斜率等的设置是不一样的)、混频、滤波、增益控制,直到ADC采集到原始的数据,现阶段的混频有两种方案:单路或IQ两路,这两种方案也都可以应用于车载以及体征检测,IQ两路可以减小对ADC采样率的要求,且距离维FFT后不需要丢掉多余的数据(单路在距离FFT后需要丢掉后面一半的数据),当然其成本会高很多,关于射频前端以及这两种混频方案的区别与优劣可以参考之前的博文:毫米波雷达的硬件架构与射频前端_墨@#≯的博客-CSDN博客。 车载毫米波雷达的大体的信号处理框架大体如下: 车载毫米波雷达信号处理流程 对前述各个流程的细节说明: 对于雷达的单帧数据,ADC采集完成后,对应到各个通道的数据是一个N*M大小的数据矩阵,其中N为单个chirp下的采样点数,N也被称为快时间维,M为单帧下对应到该通道的chirp数,M也被称为慢时间维。假设一共有K个通道,则对应ADC数据(radar cube)大小为N*M*K。 对这K个N*M大小的矩阵做2D-FFT就完成了二维压缩,随后为了增加SNR,在做CFAR检测前有一个对K个二维压缩后的矩阵进行累加的过程,累加的方法有很多,常用的是非相干累加:把K个二维压缩后的矩阵取绝对值并累加,得到一个累加后的幅值矩阵【值得注意的是,可能是如果直接FFT后累加会超过32bit能装载值的上限?所以Ti在累加之前取了log2,关于整个数据处理过程中一些中间值的大小是否会超过限定bit数下的上限,是我们在产品研发的数据处理时需要考虑的,比如加特兰在其做FFT的过程中会对每一级的中间值进行右移的操作以减小值的大小。】;另外的一种累加方法是相干累加:给不同的通道加不同的权值再累加(类似波束成形,这些权值共同构成一个导向矢量),这种相干累加可以通过设置的权值使雷达视场内其中一些方向的能量增加,从而增加这些区域的目标检测准确度,一般是会设置不同的权值,并对这些权值下得到的累加后的幅值矩阵分别做CFAR处理,再对这些CFAR的结果取并集。 累加完成后就是对累加得到的幅值矩阵做CFAR处理,CFAR算法有很多,比如CA-CFAR、OS-CFAR、GO/SO-CFAR等,做CFAR操作时,一种比较有意思的操作是分区CFAR,所谓的分区CFAR是指针对不同的距离区域使用不同的CFAR算法或者同一种CFAR使用不同的保护单元、参考单元以及阈值,分区CFAR的依据是:处在雷达不同距离门下的目标其能量一般不一样,为了减少虚警和漏警的情况发生,比如可以考虑在近处的位置将阈值设置得大一些,当然有基于距离的分区CFAR也就有基于速度的分区CFAR,一些更细节的东西可以参考加特兰芯片的Baseband User-guide 加特兰微电子 - Alps (calterah.com),里头有比较详细的说明。 CFAR完成后此时我们便可以基于被检测到的点在该二维矩阵中的横纵坐标索引得到该点对应的距离和速度的信息,但此时该速度信息还不能说是可信的,如果目标的速度超过了我们设计参数时的最大无模糊速度值: 式中,为该矩阵(该通道接收)前后两个chirp(两列)之间的时间间隔,事实上当发射通道增加时,该最大无模糊测速范围是很容易达到甚至超过的:举例来说,我们假设有3个发射天线按照TDM-MIMO的模式发射,相邻两天线发射的chirp间隔为40us(该值对于车载毫米波雷达来说不是很大),则这里的 = 120us,于是对应的最大无模糊测速范围约为8m/s,该值无疑是不够的,我们还是能检测到速度大于最大无模糊测速范围的目标,只是此值“藏在”了无模糊测速范围内,于是此时我们就需要进行速度解模糊,速度解模糊目的就是将目标的真实速度求出来,速度解模糊的方法很多,一般需要发射端帮忙,相关的具体的内容我会在后续的博文中作为一个专题给出(不只是速度模糊还有角度模糊等)。 做完速度解模糊后,我们得到的目标的真实速度,此时我们还需要知道目标的角度才能准确对目标进行定位,但是在测角之前,针对TDM-MIMO的发射模式我们还需要做相位补偿(这里的相位补偿也只需要针对TDM这种各天线不在同一时刻发射的情况,其它的发射情况并不需要,详情可以参考我之前的博文:车载毫米波雷达MIMO阵列的天线发射问题_墨@#≯的博客-CSDN博客),相位补偿是针对当目标在运动以及天线是以时分的方式发射时的场景,这种情况下前后发射天线对应的通道会有因目标运动导致的相位差产生,该相位差值会影响测角,所以我们需要将该相位差补偿掉,且这一补偿的前提是测速的准确性!补偿的方法是以第一个发射天线为基准,对后续的发射天线对应各接收通道减去速度引起的相位差值: 2*pi*(V*P*Tc/λ),式中P = 1,2,…S,对应后续各个发射天线(假设一共有S+1个发射天线)。 CFAR检测的每个结果,我们其实并不知道在这个距离和速度门下藏有多少个目标,在完成相位补偿后就可以进行测角(DOA估计)操作了,该部分的测角操作后得到多少个目标,才是该距离和速度门下有多少个目标。值得注意的是,对于非4D毫米波雷达的实际应用场景(特别是针对动目标),同距离和速度门下的目标数量其实很少(基本只有一个?),特别是我们可以把距离和速度分辨率做得很高,这进一步减少了同一个距离和速度门下存在多个目标的可能性;但是对于4D毫米波雷达,雷达的角分辨率很高,我们需要测静止目标,且要求得到更多的点云信息,此时我们需要尽可能多且全地从该距离和速度门中拿到较多的目标点云信息。测角是车载雷达一个比较棘手但很重要的步骤,关于目标的DOA估计可以参看我后续会写的一篇关于车载毫米波雷达DOA估计的博文。 完成测角的操作后,我们此时便得到了目标作为一个点的所有信息:包括其距离、速度、角度(可以包括其水平和俯仰角),还可以得到该点的SNR等信息,这些信息便可以帮助我们进行后续的聚类操作,适用于车载毫米波雷达的常用聚类方法为DBSCAN,聚类的目的在于将单个可能得到的诸多点汇集成一点以方便后续的跟踪等数据处理的操作。 随后我们再基于聚类得到的点云做跟踪处理,车载毫米波雷达实际应用时是随着车一同运动的,雷达自身也有速度,而我们之前计算得到的是雷达与目标之间的相对的径向速度,此时我们需要从CAN中获取车速以及车的转向角等信息将目标转成以大地为参考系的速度(关于车速转换及其与车辆方向的关系等这些细节我会在后续出一期专题以研究该问题),来辅助这里的跟踪操作,目标跟踪主要有两部分内容:数据关联算法+滤波算法,数据关联可以使用比如最近邻算法等,滤波则有扩展卡尔曼滤波(EKF)等,这部分的算法细节不再本博文的讨论范围,博主本人对这些接触也比较少,后续随着积累的加深可以出一期相关的博文。 如果ADAS功能交给车内的域控去实现,此时对于雷达来说便完成了它的任务,但是现阶段ADAS功能更多的还是在雷达内部实现,ADAS功能比如包括ACC、AEB、BSD、LCA等,相关的介绍以及行业标准我会近期出一期博文做详细点的介绍,雷达需要基于点云信息使用算法对满足条件的情况发出预警信息。 补充说明1: 对于传统的车载毫米波雷达,其实还有一个细节:静态杂波滤除,该部分的处理一般放在2D-FFT之前,该方法一般是针对1D-FFT后的数据,每个数据减去同一个距离门下的速度维度的均值以达到去除静止目标的目的。因为传统的车载毫米波雷达由于不具备测高、识别能力,毫米波雷达无法判断检测到的物体在高空还是在地面(汽车是否能通过),也无法判断该物体是否能轧过(例如地面的易拉罐、窨井盖)。如果都判定为障碍物,则汽车会频繁减速刹车,严重影响驾驶体验。因此行业内采用“静态杂波滤除”,将所有静止物体信号过滤掉。但这种做法存在较大隐患,这也是Tesla前期几起事故的原因之一:摄像头没有识别出倾倒的白色货车车厢,毫米波雷达识别到,但是结果在决策中置信度太低,导致车辆没有触发自动紧急自动功能。 补充说明2: 前面提到有4D雷达,以及在雷达内部实现包括目标识别和分类的功能(或者说不限于雷达内部,而是基于4D雷达采集的数据实现目标识别和分类),该话题是现阶段车载毫米波雷达领域十分热门的话题,虽然在产品上暂时还没有实现,但是得益于4D毫米波雷达极高的角分辨率,针对4D雷达所采集的数据使用各种方法(特别是机器学习)做目标识别和分类相关的文章近些年可谓层出不穷。 基于4D毫米波雷达的目标识别和分类,信息来源可以是4D雷达致密的点云(至少相较于传统的毫米波雷达,当然4D毫米波雷达其点云的密度相较激光雷达还是差很多的),此时的点云应该是聚类前的点云。此外,从ADC数据直到点云数据这中间的数据处理其本质是一个信息筛选的过程,我们在获取我们想要的信息的同时其实也丢掉了很多可能有用的信息,这些信息可能我们人没法去使用,但是喂给深度学习算法是另外一回事了,所以很多的目标识别和分类方法是基于比如距离-多普勒图、距离-角度图去实现的,相关的内容博主本人现阶段也只是简单的了解,更多的我会随着个人积累和理解的加深在后续出相关的专题博文做更详细的介绍。 (最近又了解到,不只是4D毫米波雷达,包括角雷达和前向雷达其实OEM都希望雷达能给出目标对应的分类信息。) 补充说明3: 前面给出的车载毫米波雷达的信号处理流程可以说是完备的,但是实际实践起来不同的厂家(包括上游芯片厂家给的demo,以及毫米波雷达厂家其产品中的实践)可能会有一些差异,比如读者可以参考Ti相关的SDK中给的code和说明。但是总体而言大同小异,且读者在理清楚了前述框架的前提下再去看任何厂家的雷达信号处理对其流程的理解应该不再有困难。 三、体征检测与手势识别的雷达信号处理 这部分的内容博主现阶段也算是早期接触,想着一并做个总结,于是一起放在了这里。包括车载雷达、体征检测、手势识别,对应的雷达硬件架构可以说一样的,可以参考我之前写的博文:毫米波雷达的硬件架构与射频前端_墨@#≯的博客-CSDN博客,后两者对实时性也有要求但整体上没有车载那么高,此外后两者没有测速的要求,所以从雷达的发射与处理的角度来说后两者的要求会更低一些,另外,后两者其实可以归为消费电子产品,从包括法规在内的要求上也没有车规级的车载雷达的要求高。体征检测主要包括呼吸和心跳检测,体征检测与手势识别信号处理的方式不太一样,后文将分别介绍。 关于呼吸和心跳检测: 总体上来说:对采集的adc信号进行距离维度的fft后,找到目标的对应距离门,并提取该距离门的相位值,对多帧都进行该操作(中间还涉及到相位的解模糊等操作),随后对得到的该时间-相位信息基于下述正常的频率范围做带通滤波,分别得到呼吸和心跳下的时域信息,随后对其做傅里叶变换得到目标的呼吸和心跳频率信息。 From front From back 生命体征 频率 幅度 幅度 呼吸频率(成人) 0.1—0.5Hz 1---12mm 0.1---0.5mm