SMART BATCH PLO 是设计院的设计师的福音 非常方便导图 ,可以自动识别图框,批量打印,把真正的时间花在设计上面 ,不是导图上面
给大家介绍一下使用方法:
1你的时间就是你的价值
星空CAD批量打印软件 Smart Batchplot专注于提升CAD出图效率。使用SBP,可以为设计师每个项目节约10.2小时;可以让图文店每天多打印1860张A2图纸。SBP朵用模智能算法为用户准确匹配到最合适纸张,免去用户指定纸张的步骤,并且可以多种比例一次批量打印,这是其他同类软件做不到,或者正在模仿SBP。
2自动匹配合适纸张
出过CAD图纸的用户都知道,当一张图中,有A0、A1、A2、A3以及各种加长图纸时,打印的工作量成倍增加。多种规格图纸,即使用一般的批量打印软件,也需要分多次打印,每次打印都要手动指定正确的纸张,最后打印出来,图纸不是缺失就是重复,还有可能纸张规格错误。利用SBP,可以根据图框的尺寸,就能通过先进的模糊匹配算法匹配到最合适的纸张,从而实现一次批量打印完成,而且不出现任何问题。
3多种比例混合打印
工程图纸是有比例的,虽然大部分图纸的比例可能是1:100或者1:500,但也经常有特殊图纸需要用到其他比例,比如1:25、1:50、1:150、1:200、1:1000等比例。当多种比例的图纸混合在一起需要打印时,其他批量打印机是做不到一次批量打印的,CAD自身更加做不到,分批次打印要手动指定纸张和比例值。利用SBP,可以快速生成图纸比例属性,然后轻松识别图纸的比例属性,真正实现一次批量打印多种比例的DWG文件。
4一键生成图纸目录
图纸目录对于设计师来说绝对是个烦人的内容,因为目录要根据图纸去经常修改,所以很容易出错。对于小项目,一个专业可能就20多张图纸,这样的图纸目录好维护,但是也需要经常仔细核对;对于大项目,一个专业图纸可能100多张以上,这个时候目录维护就是大麻烦,做好的目录,需要中间插张图,那就要浪费半天时间修改目录。利用SBP,可以通过 -xcel更新图签属性,也可以根据图签信息一键生成图纸目录。
5多个文件批量打印
一个项目一般不可能就一个CAD图形文件,而是由多个文件组成。网上能找到多个CAD文件一起打印的软件,但仅仅是每个文件按照其设定好的打印布局打印一张图纸,基本没有任何作用。如果项目文件很多,手动打开图纸一张一张去打印,那将是出图人的噩梦。利用SBP,设置好这几个文件共同的图框识别条件,然后添加需要打印的CAD文件印可一次批量打印。
6强大的文件命名系统
现在有越来越多的地方实行电子审图,所以对打印文件命名有严格要求。除普遍要求文件名要包含专业和图纸名称外,有时要求文件名称要包含图号、日期、图幅、比例等内容。通过传统的打印方式,你必须每个文件
进行重命名,而且很多时候你需要开打PDF
才能确定文件名称,这是非常繁琐且极易出
错的工作。SBP含有一套非常强大的文件命
名系统,可以通过特殊标签和属性标签对打
印文件进行动态命名,足以满足变态要求。
前言 MediaPlayer是Android音视频子系统中重要的一个子模块库,其功能丰富,且与Audio库联系紧密,是Android系统音视频子系统学习的第一站。源码解读需要具备相关Java、JNI、C++、Binder等知识,较为复杂难懂,简单记录追踪流程。
java层 【frameworks/base/media/java/android/media/MediaPlayer.java】
**setDataSource()**在MediaPlayer.java中用户可直接调用的方法有四个:
public void setDataSource(String path)public void setDataSource(FileDescriptor fd)public void setDataSource(FileDescriptor fd, long offset, long length)public void setDataSource(MediaDataSource dataSource) 下面就第一个setDataSource(String path)进行具体分析,其字符串可以是本地文件路径也可以是网络url。
public void setDataSource(String path) //传参1,本地文件地址或网络地址 throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { setDataSource(path, null, null); //调用1-1 重载函数 } 可以看到,上面的代码调用了内部函数setDataSource(String path, Map<String, String> headers, List cookies)。
@UnsupportedAppUsage //被调用1-1 private void setDataSource(String path, Map<String, String> headers, List<HttpCookie> cookies) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { //声明并初始化键值对数组 String[] keys = null; String[] values = null; //赋值 if (headers !
问题报错: glance在上传镜像文件时产生:HTTPInternalServerError (HTTP 500)的错误。
分析原因&&问题解决: glance服务在进行上传镜像文件前,需要控制数据库,并同步数据库。同时为了进行镜像服务,需要编辑配置文件。
一. 配置数据库
创建数据库 mysql -u root -popenstack create database glance; 创建glance用户 grant all privileges on glance.* to 'glance'@'localhost' identified by 'openstack'; grant all privileges on glance.* to 'glance'@'%' identified by 'openstack'; 二、配置镜像服务
编辑/etc/glance/glance-registry.conf 配置文件,在[DEFAULT]下加入以下内容: rabbit_host=localhost rabbit_port=5672 rabbit_use_ssl=false rabbit_userid=guest rabbit_password=guest rabbit_virtual_host=/ rabbit_notification_exchange=glance rabbit_notification_topic=notifications rabbit_durable_queues=false` 重新启动glance-registry 和 glance-api 服务 sudo restart glance-registry sudo restart glance-api 同步数据库,并不允许glance 服务控制数据库版本 sudo glance-manage db_sync sudo glance-manage db_version_control 0 如果在执行过程中,出现以下错误,则编辑 /etc/mysql/my.
文章目录 1. 升级gcc:2. gcc切换:3.重新source一下环境变量4.查看gcc版本:5. 重新编译redis6. 修改配置文件7. 创建systemctl的文件(使用systemctl进行管理)8. 创建软连接(方便在任何地方执行redis-cli) centos7默认安装的是gcc是4.8.5,redis6.0只支持5.3以上版本 1. 升级gcc: yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
2. gcc切换: 临时切换:scl enable devtoolset-9 bash
永久切换:echo "source /opt/rh/devtoolset-9/enable" >> /etc/profile
3.重新source一下环境变量 source /etc/profile
4.查看gcc版本: gcc -v
5. 重新编译redis 进入redis目录,执行make install
make install PREFIX=/usr/local/redis
6. 修改配置文件 cp redis.conf /usr/local/redis/bin/
模式改为后台启动
daemonize yes
7. 创建systemctl的文件(使用systemctl进行管理) vim /etc/systemd/system/redis.service
[Unit] Description=redis-server After=network.target [Service] Type=forking ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis/bin/redis.conf PrivateTmp=true [Install] WantedBy=multi-user.target 8. 创建软连接(方便在任何地方执行redis-cli) ln -s /usr/local/redis/bin/redis-cli /usr/bin/redis-cli
1、聊一聊
今天跟大家分享的是迈克在本公众号的第三首歌曲,在bug菌心里迈克的歌早就不仅仅只是一首歌曲了,更是件值得一直品味的艺术品。
本文开启数字电源的第一篇原创文章,数字电源核心理论-伏秒和安秒平衡!
2、主题前言
在公众号简介中bug菌跟大家谈到过要分享数字电源方面的知识,一些玩电力电子的小伙伴也是因此关注了本公众号,所以也非常感谢这些小伙伴的信任,所以今天这篇文章也是想看一下有多少玩电源的小伙伴。
bug菌一直觉得数字电源是滤波、控制算法等最能彰显着魅力的一个载体,如果要完成一套稳定且高性能的变换器设计,你不仅需要具备良好的电路等硬件知识,还需要对系统建模、控制等等都要了如指掌。
比如下面buck变换器示意图,通过使用控制芯片AD采集电流电压,经过一系列滤波控制输出合适的占空比控制开关管来给负载供能。
一般有经验的工程师基本上上手直接调PID,最终性能也能满足一般的应用需求,但是如果需要更快的电压、电流的上升时间,更小的超调,更好的带载能力等高性能,那就不是一个PID能搞定的事情,往往需要通过仿真建模设计更加优秀的控制器来满足需求,如果谈到控制学那又是另外一片天了。
很多人觉得电源很成熟了,没什么可玩的了 ! 如果你有这样的想法至少bug菌会觉得你对电源了解得不够深。 随着电源数字化的发展,高性能、高效率的智能化电源给电源软件工程师带来更多挑战,比如能源的互联、电池的能量管理、全屋能源的智能管理分配等等都是一个非常综合性的控制系统,再与物联网一集合,那就需要你有更加全面的软件知识了。
3、伏秒和安秒平衡
在目前的数字电源中其调制方法主要分为脉冲宽度调制(PWM)和脉冲频率(PFM),当然还有一些其他的调试方法以及混合调制,基本上大同小异吧,bug菌这里就以大家熟悉的PWM调制进行平衡理论的讲解。
玩数字电源其实主要就是控制电流和电压,要实现控制势必就需要被控量是可控且稳定的,系统稳定性为控制理论内容,这里就暂时不展开,那么伏妙平衡与安妙平衡就为系统稳态提供了理论依据,同时也是为电力变换中两大储能元件"电容"与“电感”量身定制的。
1
伏秒平衡
字面上理解为电压与时间形成平衡,该平衡理论也叫做电感伏妙平衡理论,大概在高中的时候我们就学习过电感的特性方程,即变化的电流产生电压。
对于PWM型变换器其开关周期重复且固定,所以伏妙平衡也会选择在一个开关周期内分析,稳态势必有首尾电流相等:
这样我们通过对电感特性方程两边积分即可得到如下表达式:
从而得到结论,要维持电感电流稳定,只需要电感两端电压在一个开关周期内积分为0即可,然后进一步变换为如下表达式:
这样就得到了伏秒平衡表达式,即一个开关周期内电压平均值为0。
2
安秒平衡
对于安秒平衡也叫电容电荷平衡原理,它主要应用在对电容的稳态分析上,同样我们看看电容的特性方程:
同样当电容处于稳态过程中,在一个开关周期内其起始时刻电容电压值应该等于结束时刻电容电压值。
对电容特性两边电压方程求积分,从而获得如下表达式:
然后经过进一步变换:
可以得到安秒平衡表达式,即一个开关周期内其电流的平均值为0即可。
4、仿真解读
如下是两张Buck电路的matlab仿真示波器截图,bug菌将通过两个图来进一步分析这两大理论:
图形解释:
图1中浅蓝色为buck输出电压,黄色为电感电流,黄色中的红色线为负载电流。
图2中红色为缩放的电感电压值,浅蓝色为PWM波形,紫色为电容电流,绿色为电容电压,黄色为电感电流。
图1中输出电压和电感电压最终都处于稳态,图2为图1稳态下的波形数据。
分析波形:
重点在图二,图中黄色电感电流处于稳态,那么根据伏妙平衡原理,其一个开关周期内电感两端电压平均值为0,当电感两端电压为负,电流反向上升;电感两端电压为正,电流反向下降,从而维持平衡。
那么基于这样的原理,我们就可以通过控制占空比来控制电感的电流,最终达到控制输出电流的目的。
同理通过图二,我们看到绿色电容电压已经维持直线稳定,那么根据安秒平衡其通过电容的电流必然在开关周期内的平均值为0,我们通过紫色曲线可以确认这一点。
5、两大理论的感性认识
对于安秒平衡大家应该比较好理解,电流的积分便得到了电荷,可以看成积累或者丢失电荷,最终会形成电压差,而如果要维持电压稳定,就需要电荷守恒。
而对于伏妙平衡很多人不是很理解,电压对时间的积分是什么?确实比较抽象,其实伏妙平衡主要应用在电感等磁性元件上,我们可以通过电磁理论来分析理解:
一谈到电磁不得不拿出大佬的神器,法拉第电磁感应定律:
理想电感(不考虑内阻的的情况下)的端电压(电势差)的来源就是电感的感应电动势,电动势等于N*磁通量的变化也就是磁链的变化,同样也是L*电感电流的变化,要维持电感电路开关周期内电流稳定,就只需要磁链平衡即可。
那么电流上升,磁链上升,电流下降,磁链下降,这样形成了磁链平衡。
5、结束语
今天的数字电源内容就讲到这里了,大家在以后建立变换器稳态模型基本上都会要用到这两大理论,同时欢迎大家留言,如果大家感兴趣可以分享点赞。
好了,这里是公众号:“最后一个bug”,一个为大家打造的技术知识提升基地。
推荐好文 点击蓝色字体即可跳转
☞【开源】bug菌把"动态数字显示"开源了!
☞【嵌入式】bug粉碎机之volatile的那些坑
☞【MCU】用stm32的UID给固件加密(重点在加密)
☞【C进阶】拿着"sizeof这些用法和坑"去吹牛吧!
☞ 【进阶】同事用#include"xxx.c"把我给惊呆了!!
由于想设置orderNo1无法修改,加入了disabled="disabled",结果后端就收不到值了,只要去了disabled标签就可以了!
<input type="text" class="form-control" id="orderNo1" name="orderNo1" value="" disabled="disabled">
今天安装Linux环境下 安装R服务的时候遇到了 这么一个问题。
网上查看了一下大多数都是让重装一下:
安装curl wget http://curl.haxx.se/download/curl-7.50.1.tar.gz 1. tar zxvf curl-7.50.1.tar.gz 2. cd curl-7.50.1 3. ./configure --prefix=/opt/curl-7.50.1 4. make && make install 但是重试了好多遍仍然没有用,后来仔细看了一下日志,原来是跟Anaconda里面的curl版本冲突了,conda 是领悟一个同事安装的。
查看curl版本
curl --version
查看当前的curl安装目录。
which curl
看看是不是 系统默认的哪个版本。
装完anaconda后每次打开terminal都是自动激活anaconda里的base environment的,很多设置都是跟着这个base environment来的。所以,conda deactivate一下就行了!这时候再去执行which curl就会发现,它指向系统中的版本了,再去编译就不再报错了。对了,这里在catkin_make前要记得删一下之前生成的CMakeLists.txt文件和build、devel文件夹,让它重新编译,否则还会有报错信息。
如果不想每次都执行conda deactivate的话,就执行下面这句:
conda config --set auto_activate_base false
取消base environment的自动激活就好啦!
文档对象模型dom
The DOM or Document Object Model is the representation of objects and hierarchy in a document which is generally an HTML or XML document. DOM is the skeleton of a document where changes over DOM generally change the document visually.
DOM或Document Object Model是文档(通常是HTML或XML文档)中对象和层次结构的表示。 DOM是文档的骨架,在DOM上进行更改通常会在视觉上更改文档。
什么是DOM(文档对象模型)? (What Is DOM (Document Object Model)?) DOM provides a structured and hierarchical presentation about the document. DOM is mostly used for Web pages where they contain a lot of different elements related to each other.
在java代码中操作redis Java访问redisDemo.jspDemoServletbookList.jsp Java访问redis string(字符串)
hash(哈希)
list(列表)
set(集合)
zset(sorted set:有序集合)
zadd/zrevrange
注1:不需要记得API的方法,只需要查redis命令
1 添加依赖
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> Demo.jsp package com.liuchunming.redis; import redis.clients.jedis.Jedis; import sun.applet.Main; import java.util.Map; /** * @authorliuchunming * @site www.liuchunming.com * @company xxx公司 * @create 2020-10-08 10:14 * * * 讲解Java代码操作redis * string 、hash 、list * * * 1、加载驱动 * 2、建立连接(url、uname、pwd) * 3、preparestatement * 4、执行sql * 5、处理结果 * 6、关闭资源 * * * redis连接步骤 * 1、建立连接、连接后授权 * 2、使用redis */ public class Demo1 { public static void main(String[] args) { Jedis jedis = new Jedis("
import numpy as np #ndarray 的条件选取 array = np.arange(100).reshape(10,10) logicalData0 = np.logical_and(array[:,1]>5,array[:,1]<100) logicalData1 = np.logical_and(array[:,2]>5,array[:,2]<100) logicalData = np.logical_and(logicalData0,logicalData1) print(logicalData) #直接报错 #ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() print(array[:,1]>5 and array[:,1]<100 and array[:,2]>5 and array[:,2]<100) #如果采用and ,结果不对 #即使是and ,也不能直接使用and,需要对list中每个元素进行and操作 data = (array[:,1]>5).tolist() and (array[:,1]<100).tolist() and (array[:,2]>5).tolist() and (array[:,2]<100).tolist() print(data)
有时候要连接服务器就敲几行代码的情况下,不愿意去安装SSH终端工具的情况
通常我都是用 Windows10自带的CMD里面的 SSH 但今天莫名其妙不能用了,出现 WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
查了一遍,原来是密钥文件出现问题了。
解决方法也很粗暴直接到.ssh文件夹 删掉known_hosts 文件就可以了
del C:\Users\Administrator\.ssh\known_hosts 删除之后重新登陆就OK了
顺便补上 其它操作系统的方法
OS X 系统和Linux系统下 known_hosts 文件路径略有不同:
OS X 下解决办法:
cd Users/yourname/.ssh/ vi known_hosts 在 known_hosts 文件中找到目标主机ip那一行 dd 删除该行再重新连接即可。
Linux 下解决办法:
cd root/.ssh/ vi known_hosts
最近虚拟机有问题了,但是要交实验,怎么办,一时半会也搞不出来啊,所以用了在线的linux编辑器,下面是几款比较好的linux编辑器
1.JS/UIX - Terminal
直接进入,点击 open terminal。就可以开始把玩了!它提供非常简单的终端环境,并没有自带 gcc 等编译套件,适合用于练习基本命令和 shell 脚本。
2.cb.vu
使用的是 FreeBSD,整体也是非常流畅,不过同样不支持代码编译运行。
但是我在点进去时跳出这个页面,不敢轻易尝试
3.copy.sh
这个感觉还不错,就是要加载一会
4.实验楼
这个是蓝桥杯里面的一个学习虚拟机的,跟在本机安装的没什么差别
5.ShellCheck
如同它的名字,这是一个用来检查你的脚本是否存在问题的工具。
概要 在使用Android SDK 版本超过29编译的时候,Android Studio会提示Environment.getExternalStorageDirectory()过时了,要用Context#getExternalFilesDir代替,Android Q以后Environment.getExternalStorageDirectory()返回的路径可能无法直接访问,所以改成了Context#getExternalFilesDir
所以Environment.getExternalStorageDirectory()可以改成:
getExternalFilesDir(null); 得到的路径如下:
/storage/emulated/0/Android/data/yourPackageName/files
这个目录会在应用被卸载的时候删除,而且访问这个目录不需要动态申请STORAGE权限。
如果这个目录不存在,系统会自动帮你创建,看下源码:
getExternalFilesDir的参数可以传以下几种:
String?: The type of files directory to return. May be null for the root of the files directory or one of the following constants for a subdirectory: android.os.Environment#DIRECTORY_MUSIC, android.os.Environment#DIRECTORY_PODCASTS, android.os.Environment#DIRECTORY_RINGTONES, android.os.Environment#DIRECTORY_ALARMS, android.os.Environment#DIRECTORY_NOTIFICATIONS, android.os.Environment#DIRECTORY_PICTURES, or android.os.Environment#DIRECTORY_MOVIES. This value may be null. 例如我们传一个
getExternalFilesDir(Environment.DIRECTORY_PICTURES); 得到的路径如下:
/storage/emulated/0/Android/data/yourPackageName/files/Pictures
什么是严格模式 JavaScript 除了提供正常模式外,还提供了严格模式(strict mode)。ES5 的严格模式是采用具有限制性 JavaScript 变体的一种方式,即在严格的条件下运行 JS 代码。
严格模式在 IE10 以上版本的浏览器中才会被支持,旧版本浏览器中会被忽略。
严格模式对正常的 JavaScript 语义做了一些更改:
消除了 Javascript 语法的一些不合理、不严谨之处,减少了一些怪异行为。消除代码运行的一些不安全之处,保证代码运行的安全。提高编译器效率,增加运行速度。禁用了在ECMAScript 的未来版本中可能会定义的一些语法,为未来新版本的 Javascript 做好铺垫。比如一些保留字如:class, enum, export, extends, import, super 不能做变量名。 开启严格模式 严格模式可以应用到整个脚本或个别函数中。因此在使用时,我们可以将严格模式分为为脚本开启严格模式和为函数开启严格模式两种情况。
1. 为脚本开启严格模式
为整个脚本文件开启严格模式,需要在所有语句之前放一个特定语句“use strict”;(或‘use strict’;)。
<script> "use strict"; console.log("这是严格模式。"); </script> 因为"use strict"加了引号,所以老版本的浏览器会把它当作一行普通字符串而忽略。
有的 script 基本是严格模式,有的 script 脚本是正常模式,这样不利于文件合并,所以可以将整个脚本文件放在一个立即执行的匿名函数之中。这样独立创建一个作用域而不影响其他 script 脚本文件。
<script> (function (){ "use strict"; var num = 10; function fn() {} })(); </script> 2. 为函数开启严格模式
要给某个函数开启严格模式,需要把“use strict”; (或 ‘use strict’; ) 声明放在函数体所有语句之前。
由来 组件之间的通信可以通过props和$emit的方式进行通信,但是如果组件之间的关系非常复杂的话,通过以上的方式会很麻烦,并且程序会非常脆弱,没有建中性可言。
在vue2.2.0 中新增provide和inject属性,可以方便的帮助我们进行组件间的传值。
使用的方式很简单:
父组件通过provide提供数据,其他组价可以使用inject注入数据。
注意 不推荐直接用于应用程序代码中。一般使用的场景是自定义组件库的时候,底层组件之间需要通信的时候使用。
provide 和 inject 主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。
特点 这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。
格式 provide 选项应该是一个对象或返回一个对象的函数。该对象包含可注入其子孙的属性。
inject 选项应该是:
一个字符串数组或 一个对象,对象的 key 是本地的绑定名(自定义的一个名字),value 是:
在provide传过来的值(字符串或 Symbol),或
一个对象,该对象的:
from 属性是provide传过来的 (字符串或 Symbol)
default 属性是降级情况下使用的 value 示例: 父组件
<template> <div> <h1>HelloWorld</h1> <One></One> </div> </template> <script> import One from "./One"; export default { components: { One }, // provide: { // for: "这是父组件的provide" // } provide() { return { for: "这是父组件的provide" }; } }; </script> 子组件1:
1.django从2.0开始ForeignKey中的on_delete参数是必须的。
on_delete=None, # 删除关联表中的数据时,当前表与其关联的field的行为
on_delete=models.CASCADE, # 删除关联数据,与之关联也删除
on_delete=models.DO_NOTHING, # 删除关联数据,什么也不做
on_delete=models.PROTECT, # 删除关联数据,引发错误ProtectedError
# models.ForeignKey(‘关联表’, on_delete=models.SET_NULL, blank=True, null=True)
on_delete=models.SET_NULL, # 删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空,一对一同理)
# models.ForeignKey(‘关联表’, on_delete=models.SET_DEFAULT, default=‘默认值’)
on_delete=models.SET_DEFAULT, # 删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值,一对一同理)
on_delete=models.SET, # 删除关联数据,
a. 与之关联的值设置为指定值,设置:models.SET(值)
b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)
解决方案:
将foreignkey的on_delete属性设置为models.CASCADE,例如
topic = models.ForeignKey(Topic)改为topic = models.ForeignKey(Topic,on_delete=models.CASCADE)
用Python解决女朋友看电影没字幕的需求 文章目录 用Python解决女朋友看电影没字幕的需求一、故事情节二、开发前的准备工作三、开发过程详细介绍(一)接口规范说明(二)项目开发1、界面部分的实现2、处理音视频功能开发3、发送数据翻译功能的开发 四、效果展示五、总结 一、故事情节 是这样子的,女朋友晚上突然翻到了自己喜欢看的一个电影,但是没有字幕,这让她很苦恼。
我急中生智,紧急的解决了我女朋友的需求。
想到了使用Python做一个可以识别语音,然后翻译出来文字的软件。
如下图就是本片文章所要完成的效果,哈哈,是不是还不错,很棒的样子。
如果有兴趣可以给我点个赞,之后带来更多好玩、有趣的demo和实现的教程。
《甄嬛传》第一集的某一小段:
其实,是这样子的:
最近剧荒,偶然翻出了曾经下载的电视剧回味一番,经典就是经典,不论是剧情还是台词,都那么有魅力,咦?等等,台词,台词……作为一个IT从业者,我忽然灵光一现——现在语音识别技术这么发达,能否有什么办法能帮我保存下一些精彩桥段的台词呢?或许我也可以是个野生字幕君:p ,似乎也可以在此基础上顺手再翻译一下个别难懂的台词!
略加思索,我大概有了个想法——做个视频中提取音频的程序,而后去请求一个开放的语音识别API来帮我把语音转为文字。鉴于之前调用有道智云的愉快经验,我决定再次拿来为我所用,很快做出了这个demo(请忽略这丑丑的界面布局,能用就行……)。
欢迎关注我,一块来履行我之前的承诺,连更一个月之内,把几篇写完。
序号预计完成时间开发dome名字以及功能&发布文章内容是否已写完文章链接19月3文本翻译,单文本翻译,批量翻译demo。已完成CSDN:点我直达 微信公众号:点我直达29月11OCR-demo,完成批量上传识别;在一个demo中可选择不同类型的OCR识别《包含手写体/印刷体/身份证/表格/整题/名片),然后调用平台能力,具体实现步骤等。已完成CSDN:点我直达
微信公众号:310月27语音识别demo,demo中上传—段视频,并截取视频中短语音识别-demo的一段音频进行短语音识别CSDN:点我直达
微信公众号:49月17智能语音评测-demoCSDN:
微信公众号:59月24作文批改-demoCSDN:
微信公众号:69月30语音合成-demoCSDN:
微信公众号:710月15单题拍搜-demoCSDN:
微信公众号:810月20图片翻译-demoCSDN:
微信公众号: 二、开发前的准备工作 首先,是需要在有道智云的个人页面上创建实例、创建应用、绑定应用和实例,获取调用接口用到的应用的id和密钥。具体个人注册的过程和应用创建过程详见文章不到100行代码搞定Python做OCR识别身份证,文字等各种字体
三、开发过程详细介绍 下面介绍具体的代码开发过程。
(一)接口规范说明 首先分析有道智云的API输入输出规范。根据文档来看,调用接口格式如下:
有道语音识别API HTTPS地址:
https://openapi.youdao.com/asrapi 接口调用参数:
字段名类型含义必填备注qtext要翻译的音频文件的Base64编码字符串True必须是Base64编码langTypetext源语言True支持语言appKeytext应用 IDTrue可在 应用管理 查看salttextUUIDTrueUUIDcurtimetext时间戳(秒)true秒数signtext签名,通过md5(应用ID+q+salt+curTime+密钥)生成True应用ID+q+salt+curTime+密钥的MD5值signTypetext签名版本Truev2formattext语音文件的格式,wavtruewavratetext采样率, 推荐 16000 采用率true16000channeltext声道数, 仅支持单声道,请填写固定值1true1typetext上传类型, 仅支持base64上传,请填写固定值1true1 其中q为base64编码的待识别音频文件,“上传的文件时长不能超过120s,文件大小不能超过10M”,这点需要注意一下。
API的返回内容较为简单:
字段含义errorCode识别结果错误码,一定存在。 详细信息参加 错误代码列表result识别结果,识别成功一定存在 (二)项目开发 这个项目使用python3开发,包括maindow.py,videoprocess.py,srbynetease.py三个文件。
界面部分,使用python自带的tkinter库,提供视频文件选择、时间输入框和确认按钮;
videoprocess.py:来实现在视频的指定时间区间提取音频和处理API返回信息的功能;
srbynetease.py:将处理好的音频发送到短语音识别API并返回结果。
1、界面部分的实现 界面部分代码如下,比较简单。
root=tk.Tk() root.title("netease youdao sr test") frm = tk.Frame(root) frm.grid(padx='50', pady='50') btn_get_file = tk.Button(frm, text='选择待识别视频', command=get_file) btn_get_file.
背景:
自定向下的语法分析方法,LL(1)是一种非常直观的方法,它的分析过程是按照句子的定义来进行的,也就是说从开始符出发对要分析的串进行推导,如果推导成功就证明这个被分析的串是一个合法的句子,否则的话就有语法错误,但是在推导过程中,对文法进行了一些限定,保证推导过程是唯一的 。总体上说,LL(1)就是在选择规则的时候加入了约束条件,考虑到输入流中的第一个符号,以及推导过程中的非终极符的规则选择,只有当头符属于当前Vn为左部的某条规则的Predict 集的时候,才使用该规则进行推导,否则即错。对规则的限定就是说规则要唯一,所以P集交集为空。构造语法分析器的方法也很简单,分成输入流、分析栈、LL(1)分析表、驱动程序四个部分,构造表的目的是提高分析器的效率,驱动程序中的动作无非4个——替换、查找、成功、失败。这样就把结构用程序描述出来了,得到语法分析器。 递归下降法是另一种自顶向下的语法分析方法
一、递归下降法的基本原理 先不考虑左递归的问题,在定义语法分析程序的时候,每一个非终极符都定义成一个过程或者函数:
每棵子树都是以根节点的非终极符推导出来的短语可以考虑每个非终极符构造一个函数,去匹配子树的叶节点
从树中即可看出,加入每一个非终极符都定义成一个过程或者是函数,选择一个规则的时候就让它和规则的右边进行匹配,遇到终极符就可能直接匹配上了,遇到非终极符还是要调用该非终极符所对应的过程或者是函数 对文法的要求: 实际上这里就是一个条件:交集为空,因为含有直接左递归的文法一定不满足第二个条件,间接左递归也不行。
二、语法分析程序的构造 程序中有一个全局变量token,用来存储输入流的第一个语法符号,分析的时候需要一个一个往里读,token保存当前字符串的第一个字符;遇到非终极符的时候有一个匹配的动作即Match(a),如果满足Match后面的函数的内容可以读取下一个语法符号了。
非终极符的过程或者函数的写法: 子程序构造方法: 同一个非终极符推导出来的规则写在一个函数中,每个规则的Predict集作为if条件判断中的布尔表达式的一部分(这里也体现了第二条规则的满足,即没有交集);对于终极符,直接执行Match部分如果当前的X属于空集,则当前执行的语句是空语句 主程序构造方法: 执行ReadToken();把字符串读入执行开始符对应的子程序进行终止判断(就是#部分的判断) 整体的问题解决方法 相关例题: 函数部分:
E(){ if token ∈ {i,(} then{ T(); E'(); } } E'(){ if token ∈ {+} then{ match(+); T(); E'(); } if token ∈ {#,)} then skip; } T(){ if token ∈ {i,(} then { F(); T'(); } } T'(){ if token ∈ {*} then { match(*); F(); T'(); } if token ∈ {+,#,)} then skip; } F(){ if token ∈ {(} then{ match('('); E(); match(')'); } if token ∈ {i} then match(i); } main(){ ReadToken(); E(); if(token=='#') return true; else return false; } 相应语法🌲分析部分:
jdk 1.8
1、导入maven依赖 <!-- websocket服务端依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <!-- websocket客户端依赖 --> <dependency> <groupId>org.java-websocket</groupId> <artifactId>Java-WebSocket</artifactId> <version>1.3.5</version> </dependency> 2、config配置类 @Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } } 3、消息体类 @Data public class WebsocketMessage { private String id; // 接收消息的用户id private String toType; // 消息类型 private String fromUserId; // 消息发送的用户id private String message; // 消息体 } 4、websocket服务端 @Slf4j @Component @ServerEndpoint("/websocket/{id}") public class WebSocketServer { private Session session; private String id; private static ConcurrentHashMap<String, WebSocketServer> sessionPools = new ConcurrentHashMap<>(); @OnOpen public void OnOpen(Session session, @PathParam("
1、聊一聊
演员这首歌大家应该再熟悉不过了,其中印象最为深刻的歌词是:"简单点,说话的方式简单点......",说话真的是一门技术,同时也是门艺术!
今天跟大家带来的知识不算难,现在非常多MCU都有全球唯一标识码这个东西,可能大家都了解过,不过具体怎么用并没有实际设计过!下面重点对其加密方面的应用跟大家理一理。
2、stm32的标识码UID
对于目前大部分MCU都会存在一个唯一标识码供用户使用,同样stm32也是一样,通过查找对应的数据手册便可以得到该唯一标识码的具体信息。
这里以stm32F103为例,其他型号的stm32性能也可能不存在该唯一标识,具体需要根据对应的数据手册进行查阅,如果存在可能基地址稍有不同。如下图所示:
分析一下:
1 ) stm32的标识码放在了唯一设备ID寄存器里面,一共96个bit也就是12个字节且只能读取。
2 ) 通过手册上的说明可以大致了解到该唯一标识码的应用场景。
3)一般的量产产品都会有一个设备的条码,那么这个唯一的标识码便可以作为条码的一部分来供查找。
4 ) 在通信协议中该唯一标识码可以作为一种标识序列号来进行设备的加载和区分。
5 ) 当然最后就是把其作为一个安全密钥,然后与软件加密算法结合起来以降低固件被恶意复制的风险。
2、读取UID
对于该唯一标识ID,bug菌这里谈两点注意的:
1、唯一标识ID只是stm32里面一种ID,其实一款芯片内部还有很多其他ID,比如设备ID和其他内部组件的ID等;
2、UID一共是96位具有唯一性,而截取中间的几位不一定具有唯一性。
3、对于UID的读取非常简单,上面的手册截图也说明了,可以通过字节、半字和字来进行读取,也就是说可以用8位、16位、32位来读取。
参考Demo:
1uint32_t Unique[3] = {0}; 2uint8_t unique[12] = {0}; 3 4 int main(void) 5 { 6 uint8_t i; 7 8 Unique[0] = *(uint32_t*)(0x1FFFF7E8); 9 Unique[1] = *(uint32_t*)(0x1FFFF7E8 + 4); 10 Unique[2] = *(uint32_t*)(0x1FFFF7E8 + 8); 11 12 printf("以uint32_t读:\r\n");//插入换行 13 printf("ID 0-31 :%x\r\n",Unique[0]);//插入换行 14 printf("ID 32-63 :%x\r\n"