-
Simulink_BP神经网络PID控制
2019-01-03 13:27:10使用MATLAB软件中的simulink模块,进行BP神经网络PID控制仿真 -
基于S函数的BP神经网络PID控制器及Simulink仿真_杨艺_虎恩典
2014-06-15 14:50:12BP 网络在人工神经网络中应用最为广泛,文中给出基于 MATLAB 语言的 BP 神经网络 PID 控制器的 S 函数实 现,在此基础上建立 BP 神经网络 PID 控制器的 Simulink 仿真模型,最后给出了该仿真模型应用在非线性对象中... -
BP神经网络的液位PID控制及仿真
2021-01-30 17:59:31针对硫化镍矿选矿浮选工业过程中液位控制进行数学分析,建立 BP预测模型并实施多浮选槽液位控制方法,利用...仿真结果证明了BP神经网络对解决硫化镍矿浮选过程液位PID控制的有效性,具有广泛应用和推广的价值。 -
基于S函数的BP神经网络PID控制器Simulink仿真.pdf
2009-03-28 21:42:47该论文给出了控制器的算法的实现,是用matlab中的S函数写的,而且还给出了仿真图,以及封装图等等,对大家肯定有很大的帮助 -
MATLAB神经网络30个案例分析(高清+源码)包括BP、RBF、SVM、SOM、Hopfield、LVQ、Elman、小波等神经网络....
2019-05-27 16:33:59------- 目录 第1章 P神经网络的数据分类——语音特征信号分类 第2章 BP神经网络的非线性系统建模——非线性函数拟合 第3章 遗传算法优化BP神经网络——非线性函数拟合 第4章 神经网络遗传算法函数极值寻优——非... -
MATLAB神经网络43个案例分析
2018-03-30 22:15:37第1章 BP神经网络的数据分类——语音特征信号分类 第2章 BP神经网络的非线性系统建模——非线性函数拟合 第3章 遗传算法优化BP神经网络——非线性函数拟合 第4章 神经网络遗传算法函数极值寻优——非线性函数极值寻... -
MATLAB 神经网络43个案例分析
2017-10-30 11:52:59第1章 BP神经网络的数据分类——语音特征信号分类 第2章 BP神经网络的非线性系统建模——非线性函数拟合 第3章 遗传算法优化BP神经网络——非线性函数拟合 第4章 神经网络遗传算法函数极值寻优——非线性函数极值寻... -
MATLAB神经网络30个案例分析
2016-04-21 14:52:29, -------, 目录, 第1章 P神经网络的数据分类——语音特征信号分类, 第2章 BP神经网络的非线性系统建模——非线性函数拟合, 第3章 遗传算法优化BP神经网络——非线性函数拟合, 第4章 神经网络遗传算法函数极值寻优... -
matlab神经网络30个案例分析
2011-06-01 20:06:07BP_Adaboost模型即把BP神经网络作为弱分类器,反复训练BP神经网络预测样本输出,通过Adaboost算法得到多个BP神经网络弱分类器组成的强分类器。 第6章 PID神经元网络解耦控制算法——多变量系统控制54 根据PID神经元... -
《MATLAB+神经网络30个案例分析》程序和数据
2017-12-22 09:06:23案例1:BP神经网络的数据分类—语音特征信号分类 案例2 BP神经网络的非线性系统建模-非线性函数拟合 案例3:神经网络遗传算法函数极值寻优-非线性函数极值寻优 案例4:遗传算法优化BP神经网络-非线性函数拟合 案例5... -
神经网络PID设计完整版
2010-08-01 18:46:56对这样一个系统在MATLAB平台上进行仿真研究,,仿真结果表明基于BP神经网络的自整定PID控制具有良好的自适应能力和自学习能力,对大迟延和变对象的系统可取得良好的控制效果。 关键词:主汽温,PID,BP神经网络,... -
MATLAB 神经网络30个案例分析
2011-12-25 04:37:55第2章 bp神经网络的非线性系统建模——非线性函数拟合11 第3章 遗传算法优化bp神经网络——非线性函数拟合21 第4章 神经网络遗传算法函数极值寻优——非线性函数极值寻优36 第5章 基于bp_adaboost的强分类器设计... -
《MATLAB 神经网络43个案例分析》源代码&数据
2018-08-13 15:15:27第1章 BP神经网络的数据分类——语音特征信号分类 第2章 BP神经网络的非线性系统建模——非线性函数拟合 第3章 遗传算法优化BP神经网络——非线性函数拟合 第4章 神经网络遗传算法函数极值寻优——非线性函数极值寻... -
MATLAB 神经网络30个案例分析程序和代码
2018-04-30 13:03:44第2章 BP神经网络的非线性系统建模——非线性函数拟合 第3章 遗传算法优化BP神经网络——非线性函数拟合 第4章 神经网络遗传算法函数极值寻优——非线性函数极值寻优 第5章 基于BP_Adaboost的强分类器设计——公司... -
MATLAB神经网络30个案例分析(全书+源代码)
2018-07-25 12:57:04第2章 BP神经网络的非线性系统建模——非线性函数拟合 第3章 遗传算法优化BP神经网络——非线性函数拟合 第4章 神经网络遗传算法函数极值寻优——非线性函数极值寻优 第5章 基于BP_Adaboost的强分类器设计——公司... -
《MATLAB 神经网络43个案例分析》包含代码和测试数据
2018-04-08 11:29:59第1章 BP神经网络的数据分类——语音特征信号分类 第2章 BP神经网络的非线性系统建模——非线性函数拟合 第3章遗传算法优化BP神经网络——非线性函数拟合 第4章神经网络遗传算法函数极值寻优——非线性函数极值寻优 ... -
MATLAB 神经网络43个案例分析》源代码&数据.
2015-01-18 16:32:33第1章 BP神经网络的数据分类——语音特征信号分类 第2章 BP神经网络的非线性系统建模——非线性函数拟合 第3章 遗传算法优化BP神经网络——非线性函数拟合 第4章 神经网络遗传算法函数极值寻优——非线性函数极值寻... -
基于神经网络的摆动电机的模糊PID控制
2021-01-26 18:27:38分析BP神经模糊PID中,BP神经网络,模糊算法和PID控制如何优化、互补和配合。最后用matlab仿真结果来说明BP前馈神经网络模糊PID控制器具有无超调、稳定性强、很好的抗干扰等优点,并非线性系统具有一定鲁棒性。 -
基于改进RBF模糊神经网络的PID参数自整定
2021-01-12 19:38:13针对常规PID控制器和模糊PID控制器存在控制精度差、不能...通过在MATLAB中进行神经网络训练和PID仿真实验,表明了改进RBF模糊神经网络PID控制器具有收敛速度快、能够自适应、控制精度高等优点,具有一定的可行性。 -
神经网络的43个源程序及数据
2019-03-30 10:36:38第1章 BP神经网络的数据分类——语音特征信号分类 第2章 BP神经网络的非线性系统建模——非线性函数拟合 第3章 遗传算法优化BP神经网络——非线性函数拟合 第4章 神经网络遗传算法函数极值寻优——非线性函数极值寻... -
毕业设计_神经网络控制算法仿真
2011-04-28 20:02:58对这样一个系统在MATLAB平台上进行仿真研究,仿真结果表明基于BP神经网络的自整定PID控制具有良好的自适应能力和自学习能力,对大迟延和变对象的系统可取得良好的控制效果。 关键词:主汽温,PID,BP神经网络,... -
matlab常用代码大全科研神器
2016-11-08 23:16:03第1章 BP神经网络的数据分类——语音特征信号分类 第2章 BP神经网络的非线性系统建模——非线性函数拟合 第3章 遗传算法优化BP神经网络——非线性函数拟合 第4章 神经网络遗传算法函数极值寻优——非线性函数极值寻... -
matlab串口数据出传输
2019-05-12 11:34:38在进行PID参数整定的工作过程中,我需要将电机的转速、扭矩、母线电压、母线电流、相电压、相电流等参数通过串口传递到电脑上用Matlab来进行BP神经网络算法的PID整定计算,再将计算得到的PID参数传给电机的驱动板,...https://blog.csdn.net/DBLLLLLLLL/article/details/82631183
在进行PID参数整定的工作过程中,我需要将电机的转速、扭矩、母线电压、母线电流、相电压、相电流等参数通过串口传递到电脑上用Matlab来进行BP神经网络算法的PID整定计算,再将计算得到的PID参数传给电机的驱动板,来控制电机运行。在整个过程中采用了Matlab来进行串口数据的读写。目前整个流程已经走通,在此将实现过程中遇到的问题,解决方法,以及尚未解决的疑问进行总结。</p>
1.MATLAB串口通信实现
Matlab串口数据接收一般可以通过两种方法来实现,一种是直接调用tmtool工具,找到相应的串口,配置串口参数,生成代码;另一种方法是通过一系列与串口有关的函数来对串口进行操作。
通过tmtool进行串口设计比较简单,如图所示,在Communiate项目栏中可以对串口进行读写操作并输出,这里可以设置数据种类(Data type)为ASCII码,二进制、二进制数据块(这里笔者的理解是类似一个数据帧,拥有帧头、传输数据个数位等)。通过数据格式(Data format)来设置接收数据的格式,例如ASCII码的格式有字符、字符串、带换行符的字符串等;二进制有位数等。还可以设置写入和读取是否按照HEX(16进制)进行表示。
在Configure项目栏中,可以对串口的参数进行配置,如图所示。
BauRate是对串口波特率的设置,只有上下位机采用相同的波特率时串口才能够进行正常通讯。
DataBits : 是数据位,有8位和9位两种,一般选8位。
DataTerminalReady(DTR) : 数据终端就绪,表明机器已经准备好可以接受数据的一个标志位,一般用在RS232的串口场合。
FlowControl : 流控制位,当数据读写速度存在差异时,可以采用流控制,来开启和关闭数据流,有硬件和软件控制两种方式。
**InputBufferSize/OutputBufferSize** : 是输入缓存大小和输出缓存大小,单位是字节。
Parity : 奇偶校验位,这里应该与下位机格式相匹配。
RequestToSend(RTS): 请求结束位,也是在RS232中常用。
StopBits: 结束位,这里应该与下位机格式相匹配。
Terminator: 中断标志,这里是以某个字符作为中断函数入口的标志,检测到这个字符存在后即可进入回调函数。
Timeout: 溢出时间,当开始接收后超过这个时间还没有数据还没有接收完成,即可认为数据接收失败,这个时间可按照实际传输周期来设定,一般越小越好。
ByreOrder: 是数据的传输模式,有大端模式和小端模式两种。小端模式是指数据的高字节保存在内存的高地址中,大端模式是指数据的高字节保存在内存的低地址中。以unsigned int value = 0x12345678为例,该数分为四个字节 12 34 56 78:
小端模式情况下,字节存储顺序是
Buffer[3]=0x12 ------高位
Buffer[2]=0x34
Buffer[1]=0x56
Buffer[0]=0x78 ------低位
大端模式下,字节存储顺序是
Buffer[3]=0x78------高位
Buffer[2]=0x56
Buffer[1]=0x34
Buffer[0]=0x12 ------低位大端模式和小端模式只在传输的一个数据是个多字节数据时,才需要区分。一般来说下位机ARM是按照小端模式来存储的,这一现象我会在另一篇下位机串口通讯时将共用体时举出例子。因为我这里传输的数据每次就是一个字节,因此无所谓大小端。
Session Log项目栏可以将之前的各种操作用函数语言来表示。
采用与串口有关的函数也能实现对串口的操作。作者主要是通过这种方法来实现整个串口的运行。
首先了解几个主要函数:
delete(instrfindall) : 删除所有串口信息,在程序结束后没有删除串口信息,可能会导致串口被占用,下一次程序无法使用串口或者其他软件无法使用串口。因此在不再使用串口的时候,应将串口释放。为了Matlab运行的正确性,也可以将运行中的所有工作变量删除,这里可以采用clera all语句。
obj1=serial(‘com2’): 定义某串口为变量obj1,也就是相当于为串口com2起了一个名字叫obj1,后面对obj1操作就相当于对com2操作。
fclose(obj1)/fopen(obj1): 关闭串口和开启串口,有些参数设定需要先关闭串口,因此在进行串口参数设定前先将串口关闭,设定完成后再打开。
obj1:直接在命令行窗口输入定义好的串口变量,可以看到一个串口obj1的参数列表。
set(obj1, ‘BaudRate’, 115200): 通过set函数可以对obj1进行参数设定,格式是set(串口变量名,‘参数名称’,参数),这里是设定波特率是115200。
set(obj1, ‘InputBufferSize’, 100): 输入缓存大小 100 字节。
set(obj1, ‘OutputBufferSize’, 100): 输出缓存大小 100 字节。
set(obj1, ‘Timeout’, 1.0): 溢出时间 1.0 s。
set(obj1,‘BytesAvailableFcnMode’,‘terminator’): 回调函数中断的模式,有两种,一种是terminator模式,关键词中断,当检测到某一关键字时进行中断。一种是byte模式,当二进制达到某个字节数时中断。
set(obj1,‘terminator’,‘D’): 中断关键字是ASCII的D
set(obj1,‘BytesAvailableFcn’,@my_callback): 回调函数的设定,当发生上述中断时,进入回调函数my_callback,在回调函数里可以对数据进行读写等操作。
(上面串口中断模式还有byte模式,这里给出函数示例: set(obj1,‘BytesAvailableFcnMode’,‘terminator’)
set(obj1,‘byte’,24) )在回调函数my_callback里面,可以进行串口数据的读取和发送等操作,下面先介绍几个串口接收和发送相关的函数:
data=fread(obj1, 24):向串口obj1读取24个数据,因为我这里数据是一个数据一个字节,因此也就相当于24个字节,这里默认情况下是按照一个数据8位,也可以加上数据格式,告诉电脑一个每个数据是什么格式,如data= fread(obj1, 24,‘short’)。
fwrite(obj2, sendbuff, ‘uint8’):向串口obj2发送数据,被发送的数据存储在笔者自定的一个向量sendbuff中,这里会将sendbuff中的所有数据按照unit8的的格式依次发送。
这里我将整个串口设置和回调函数的代码给出:
代码1:主函数
因为项目需要,这里有一个串口接收数据,一个串口发送数据。这里我接收的数据是一个数据帧24个字节,发送的数据是8个字节。在接收的字节中帧头是’D’,所以采用关键字中断模式,中断标志是’D’。%主函数 进行串口设置和开启 delete(instrfindall) clear obj1 clear obj2 clear all global obj1; global obj2; global data; global sendbuff; global data1; global data2; global data3; global data4; global data5; global data6; global n; n=0; data=zeros(24,1) sendbuff=zeros(1,8); sendbuff(7)= hex2dec('0D'); sendbuff(8)= hex2dec('0A'); data1=0; data2=0; data3=0; data4=0; data5=0; data6=0; obj1=serial('com9'); fclose(obj1); set(obj1, 'InputBufferSize', 100); set(obj1, 'OutputBufferSize', 100); set(obj1, 'BaudRate', 112500); set(obj1, 'Timeout', 1.0); set(obj1,'BytesAvailableFcnMode','terminator'); set(obj1,'terminator','D'); set(obj1,'BytesAvailableFcn',@my_callback1); fopen(obj1); obj2=serial('com8'); fclose(obj2); set(obj2, 'InputBufferSize', 24); set(obj2, 'OutputBufferSize', 24); set(obj2, 'BaudRate', 115200); set(obj2, 'Timeout', 1.0); fopen(obj2);
代码2:回调函数
进入回调函数后对数据进行读取和处理,然后发送给下位机
接收数据帧的格式是:
字节1:‘D’,10进制表示是68
字节2:0x05,10进制表示是5,1-2是帧头,然后是数据位
字节3-4:表示电机转速,16位数据
字节5-6:表示负载扭矩,16位数据
字节7-10:表示母线电压,32位数据
字节11-14:表示母线电流,32位数据
字节15-18:表示相电压,32位数据
字节19-22:表示相电流,32位数据
字节23:0X0D
字节24:0X0A发送数据帧的格式:
字节1-2:表示Kp,16位数据
字节3-4:表示Ki,16位数据
字节5-6:表示Kd,16位数据
字节7:0X0D
字节8:0X0Afunction my_callback1(obj1,event) global data; global obj2; global sendbuff; global data1; global data2; global data3; global data4; global data5; global data6; global n; n=n+1; data= fread(obj1, 24) if lenth(data)==24 if data(1) == 68 if data(2) == 5 data1 = (data(3)*256+data(4))/1000; data2 = (data(5)*256+data(6))/1000; data3 = (data(7)*16777216+data(8)*65536+data(9)*256+data(10))/100; data4 = (data(11)*16777216+data(12)*65536+data(13)*256+data(14))/100; data5 = (data(15)*16777216+data(16)*65536+data(17)*256+data(18))/100; data6 = (data(19)*16777216+data(20)*65536+data(21)*256+data(22))/100; end end if data(1) == 5 data1 = (data(2)*256+data(3))/1000; data2 = (data(4)*256+data(5))/1000; data3 = (data(6)*16777216+data(7)*65536+data(8)*256+data(9))/100; data4 = (data(10)*16777216+data(11)*65536+data(12)*256+data(13))/100; data5 = (data(14)*16777216+data(15)*65536+data(16)*256+data(17))/100; data6 = (data(18)*16777216+data(19)*65536+data(20)*256+data(21))/100; end sendbuff(1)=floor((data1+data4)/256); sendbuff(2)=floor((data1+data4)); sendbuff(3)=floor((data2+data5)/256); sendbuff(4)=floor((data2+data5)); sendbuff(5)=floor((data3+data6)/256); sendbuff(6)=floor((data4+data6)); fwrite(obj2, sendbuff, 'uint8'); %my_fwrite(obj2, sendbuff, 'uint8'); end end
2.关于提高串口速度的讨论
在进行PID参数整定时,由于整个PID的调整周期较短,因此希望整个串口读取、处理、发送的时间最好在2ms以内完成。这个速度对于计算机来说其实是不容易实现的,因此如何提高整个回调函数的运算速度成为编写代码的关键。这里我发现了一些提高运行速度的方法:
对于串口读写速度,主要是串口发送函数 fwrite(obj2, sendbuff, ‘uint8’)消耗了太多的时间,运行时这里耗费的时间有20ms+,这对于整个项目时不可接受的,笔者在思考和尝试的时候发现了一个方法可以让这个时间缩小到0.7ms左右。那就是用一个新的my_fwrite.m文件代替原来的内部函数fwrite.m(新的fwrite.m代码如下)。并将上述的代码改为my_fwrite(obj2, sendbuff, ‘uint8’)。
新的文件如下:
function my_fwrite(obj, varargin) %FWRITE Write binary data to instrument. % % FWRITE(OBJ, A) writes the data, A, to the instrument connected to % interface object, OBJ. % % The interface object must be connected to the instrument with the % FOPEN function before any data can be written to the instrument % otherwise an error will be returned. A connected interface object % has a Status property value of open. % % FWRITE(OBJ,A,'PRECISION') writes binary data translating MATLAB % values to the specified precision, PRECISION. The supported % PRECISION strings are defined below. By default the 'uchar' % PRECISION is used. % % MATLAB Description % 'uchar' unsigned character, 8 bits. % 'schar' signed character, 8 bits. % 'int8' integer, 8 bits. % 'int16' integer, 16 bits. % 'int32' integer, 32 bits. % 'uint8' unsigned integer, 8 bits. % 'uint16' unsigned integer, 16 bits. % 'uint32' unsigned integer, 32 bits. % 'single' floating point, 32 bits. % 'float32' floating point, 32 bits. % 'double' floating point, 64 bits. % 'float64' floating point, 64 bits. % 'char' character, 8 bits (signed or unsigned). % 'short' integer, 16 bits. % 'int' integer, 32 bits. % 'long' integer, 32 or 64 bits. % 'ushort' unsigned integer, 16 bits. % 'uint' unsigned integer, 32 bits. % 'ulong' unsigned integer, 32 bits or 64 bits. % 'float' floating point, 32 bits. % % FWRITE(OBJ, A, 'MODE') % FWRITE(OBJ, A, 'PRECISION', 'MODE') writes data asynchronously % to the instrument when MODE is 'async' and writes data synchronously % to the instrument when MODE is 'sync'. By default, the data is % written with the 'sync' MODE, meaning control is returned to % the MATLAB command line after the specified data has been written % to the instrument or a timeout occurs. When the 'async' MODE is % used, control is returned to the MATLAB command line immediately % after executing the FWRITE function. % % The byte order of the instrument can be specified with OBJ's % ByteOrder property. % % OBJ's ValuesSent property will be updated by the number of values % written to the instrument. % % If OBJ's RecordStatus property is configured to on with the RECORD % function, the data written to the instrument will be recorded in % the file specified by OBJ's RecordName property value. % % Example: % s = visa('ni', 'ASRL2::INSTR'); % fopen(s); % fwrite(s, [0 5 5 0 5 5 0]); % fclose(s); % % See also ICINTERFACE/FOPEN, ICINTERFACE/FPRINTF, ICINTERFACE/RECORD, % ICINTERFACE/PROPINFO, INSTRHELP.
% % MP 7-13-99 % Copyright 1999-2012 The MathWorks, Inc. % Error checking. if ~isa(obj, 'icinterface') error(message('instrument:fwrite:invalidOBJInterface')); end if length(obj)>1 error(message('instrument:fwrite:invalidOBJDim')); end % Parse the input. switch nargin case 1 error(message('instrument:fwrite:invalidSyntaxA')); case 2 cmd = varargin{1}; precision = 'uchar'; mode = 0; case 3 % Original assumption: fwrite(obj, cmd, precision); [cmd, precision] = deal(varargin{1:2}); mode = 0; if ~(isa(precision, 'char') || isa(precision, 'double')) error(message('instrument:fwrite:invalidArg')); end if strcmpi(precision, 'sync') % Actual: fwrite(obj, cmd, mode); mode = 0; precision = 'uchar'; elseif strcmpi(precision, 'async') % Actual: fwrite(obj, cmd, mode); mode = 1; precision = 'uchar'; end case 4 % Ex. fprintf(obj, format, cmd, mode); [cmd, precision, mode] = deal(varargin{1:3}); if ~ischar(mode) error(message('instrument:fwrite:invalidMODE')); end if strcmpi(mode, 'sync') mode = 0; elseif strcmpi(mode, 'async') mode = 1; else error(message('instrument:fwrite:invalidMODE')); end otherwise error(message('instrument:fwrite:invalidSyntaxArgv')); end % % % % Error checking. % % % if ~isa(precision, 'char') % % % error(message('instrument:fwrite:invalidPRECISIONstring')); % % % end % % % if ~(isnumeric(cmd) || ischar(cmd)) % % % error(message('instrument:fwrite:invalidA')); % % % end % Convert the data to the requested precision. switch (precision) case {'uchar', 'char'} cmd = uint8(cmd); type = 5; signed = 0; case {'schar'} cmd = int8(cmd); type = 5; signed = 1; case {'int8'} cmd = int8(cmd); type = 0; signed = 1; case {'int16', 'short'} cmd = int16(cmd); type = 1; signed = 1; case {'int32', 'int', 'long'} cmd = int32(cmd); type = 2; signed = 1; case {'uint8'} cmd = uint8(cmd); type = 0; signed = 0; case {'uint16', 'ushort'} cmd = uint16(cmd); type = 1; signed = 0; case {'uint32', 'uint', 'ulong'} cmd = uint32(cmd); type = 2; signed = 0; import java.lang.Long for iLoop = 1:length(cmd) tmp(iLoop) = Long(cmd(iLoop)); %#ok<AGROW> end cmd=tmp; case {'single', 'float32', 'float'} cmd = single(cmd); type = 3; signed = 1; case {'double' ,'float64'} cmd = double(cmd); type = 4; signed = 1; otherwise error(message('instrument:fwrite:invalidPRECISION')); end % i2c does not support async mode if mode == 1 error(message('instrument:fwrite:i2cAyncNotSupported')); end % Call the write java method. try fwrite(igetfield(obj, 'jobject'), cmd, length(cmd), type, mode, signed); catch aException newExc = MException('instrument:fwrite:opfailed', aException.message); throw(newExc); end
除此之外,在进行数据的处理的时候,应尽量对数据进行乘除取整取余等数学运算而不是调用一些强制转换的函数或者移位函数。笔者考虑可能是在寻找和调用matlab系统内部函数花费了较多的时间。
同时,这个运算速度和matlab版本以及电脑的CPU性能有关,同样的程序i5跑起来是2ms,i7跑起来0.8ms。
通过以上方法将原来数十微妙的运行速度降到了运行一次在一微妙以内。所以还是有些效果的。
在进行PID参数整定的工作过程中,我需要将电机的转速、扭矩、母线电压、母线电流、相电压、相电流等参数通过串口传递到电脑上用Matlab来进行BP神经网络算法的PID整定计算,再将计算得到的PID参数传给电机的驱动板,来控制电机运行。在整个过程中采用了Matlab来进行串口数据的读写。目前整个流程已经走通,在此将实现过程中遇到的问题,解决方法,以及尚未解决的疑问进行总结。
相关链接
https://blog.csdn.net/DBLLLLLLLL/article/details/82631183 -
遗传算法 用matlab实现
2010-04-29 17:09:48这是一个基于模拟退火算法的混沌神经网络模型,遗传bp神经网络在pid控制器中的应用,多多指教 -
Matlab串口数据接收发送流程和串口速度提高
2018-09-11 19:28:52在进行PID参数整定的工作过程中,我需要将电机的转速、扭矩、母线电压、母线电流、相电压、相电流等参数通过串口传递到电脑上用Matlab来进行BP神经网络算法的PID整定计算,再将计算得到的PID参数传给电机的驱动板,...在进行PID参数整定的工作过程中,我需要将电机的转速、扭矩、母线电压、母线电流、相电压、相电流等参数通过串口传递到电脑上用Matlab来进行BP神经网络算法的PID整定计算,再将计算得到的PID参数传给电机的驱动板,来控制电机运行。在整个过程中采用了Matlab来进行串口数据的读写。目前整个流程已经走通,在此将实现过程中遇到的问题,解决方法,以及尚未解决的疑问进行总结。
1.MATLAB串口通信实现
Matlab串口数据接收一般可以通过两种方法来实现,一种是直接调用tmtool工具,找到相应的串口,配置串口参数,生成代码;另一种方法是通过一系列与串口有关的函数来对串口进行操作。
通过tmtool进行串口设计比较简单,如图所示,在Communiate项目栏中可以对串口进行读写操作并输出,这里可以设置数据种类(Data type)为ASCII码,二进制、二进制数据块(这里笔者的理解是类似一个数据帧,拥有帧头、传输数据个数位等)。通过数据格式(Data format)来设置接收数据的格式,例如ASCII码的格式有字符、字符串、带换行符的字符串等;二进制有位数等。还可以设置写入和读取是否按照HEX(16进制)进行表示。
在Configure项目栏中,可以对串口的参数进行配置,如图所示。
BauRate是对串口波特率的设置,只有上下位机采用相同的波特率时串口才能够进行正常通讯。
DataBits : 是数据位,有8位和9位两种,一般选8位。
DataTerminalReady(DTR) : 数据终端就绪,表明机器已经准备好可以接受数据的一个标志位,一般用在RS232的串口场合。
FlowControl : 流控制位,当数据读写速度存在差异时,可以采用流控制,来开启和关闭数据流,有硬件和软件控制两种方式。
InputBufferSize/OutputBufferSize : 是输入缓存大小和输出缓存大小,单位是字节。
Parity : 奇偶校验位,这里应该与下位机格式相匹配。
RequestToSend(RTS): 请求结束位,也是在RS232中常用。
StopBits: 结束位,这里应该与下位机格式相匹配。
Terminator: 中断标志,这里是以某个字符作为中断函数入口的标志,检测到这个字符存在后即可进入回调函数。
Timeout: 溢出时间,当开始接收后超过这个时间还没有数据还没有接收完成,即可认为数据接收失败,这个时间可按照实际传输周期来设定,一般越小越好。
ByreOrder: 是数据的传输模式,有大端模式和小端模式两种。小端模式是指数据的高字节保存在内存的高地址中,大端模式是指数据的高字节保存在内存的低地址中。以unsigned int value = 0x12345678为例,该数分为四个字节 12 34 56 78:
小端模式情况下,字节存储顺序是
Buffer[3]=0x12 ------高位
Buffer[2]=0x34
Buffer[1]=0x56
Buffer[0]=0x78 ------低位
大端模式下,字节存储顺序是
Buffer[3]=0x78------高位
Buffer[2]=0x56
Buffer[1]=0x34
Buffer[0]=0x12 ------低位大端模式和小端模式只在传输的一个数据是个多字节数据时,才需要区分。一般来说下位机ARM是按照小端模式来存储的,这一现象我会在另一篇下位机串口通讯时将共用体时举出例子。因为我这里传输的数据每次就是一个字节,因此无所谓大小端。
Session Log项目栏可以将之前的各种操作用函数语言来表示。
采用与串口有关的函数也能实现对串口的操作。作者主要是通过这种方法来实现整个串口的运行。
首先了解几个主要函数:
delete(instrfindall) : 删除所有串口信息,在程序结束后没有删除串口信息,可能会导致串口被占用,下一次程序无法使用串口或者其他软件无法使用串口。因此在不再使用串口的时候,应将串口释放。为了Matlab运行的正确性,也可以将运行中的所有工作变量删除,这里可以采用clera all语句。
obj1=serial(‘com2’): 定义某串口为变量obj1,也就是相当于为串口com2起了一个名字叫obj1,后面对obj1操作就相当于对com2操作。
fclose(obj1)/fopen(obj1): 关闭串口和开启串口,有些参数设定需要先关闭串口,因此在进行串口参数设定前先将串口关闭,设定完成后再打开。
obj1:直接在命令行窗口输入定义好的串口变量,可以看到一个串口obj1的参数列表。
set(obj1, ‘BaudRate’, 115200): 通过set函数可以对obj1进行参数设定,格式是set(串口变量名,‘参数名称’,参数),这里是设定波特率是115200。
set(obj1, ‘InputBufferSize’, 100): 输入缓存大小 100 字节。
set(obj1, ‘OutputBufferSize’, 100): 输出缓存大小 100 字节。
set(obj1, ‘Timeout’, 1.0): 溢出时间 1.0 s。
set(obj1,‘BytesAvailableFcnMode’,‘terminator’): 回调函数中断的模式,有两种,一种是terminator模式,关键词中断,当检测到某一关键字时进行中断。一种是byte模式,当二进制达到某个字节数时中断。
set(obj1,‘terminator’,‘D’): 中断关键字是ASCII的D
set(obj1,‘BytesAvailableFcn’,@my_callback): 回调函数的设定,当发生上述中断时,进入回调函数my_callback,在回调函数里可以对数据进行读写等操作。
(上面串口中断模式还有byte模式,这里给出函数示例: set(obj1,‘BytesAvailableFcnMode’,‘terminator’)
set(obj1,‘byte’,24) )在回调函数my_callback里面,可以进行串口数据的读取和发送等操作,下面先介绍几个串口接收和发送相关的函数:
data=fread(obj1, 24):向串口obj1读取24个数据,因为我这里数据是一个数据一个字节,因此也就相当于24个字节,这里默认情况下是按照一个数据8位,也可以加上数据格式,告诉电脑一个每个数据是什么格式,如data= fread(obj1, 24,‘short’)。
fwrite(obj2, sendbuff, ‘uint8’):向串口obj2发送数据,被发送的数据存储在笔者自定的一个向量sendbuff中,这里会将sendbuff中的所有数据按照unit8的的格式依次发送。
这里我将整个串口设置和回调函数的代码给出:
代码1:主函数
因为项目需要,这里有一个串口接收数据,一个串口发送数据。这里我接收的数据是一个数据帧24个字节,发送的数据是8个字节。在接收的字节中帧头是’D’,所以采用关键字中断模式,中断标志是’D’。%主函数 进行串口设置和开启 delete(instrfindall) clear obj1 clear obj2 clear all global obj1; global obj2; global data; global sendbuff; global data1; global data2; global data3; global data4; global data5; global data6; global n; n=0; data=zeros(24,1) sendbuff=zeros(1,8); sendbuff(7)= hex2dec('0D'); sendbuff(8)= hex2dec('0A'); data1=0; data2=0; data3=0; data4=0; data5=0; data6=0; obj1=serial('com9'); fclose(obj1); set(obj1, 'InputBufferSize', 100); set(obj1, 'OutputBufferSize', 100); set(obj1, 'BaudRate', 112500); set(obj1, 'Timeout', 1.0); set(obj1,'BytesAvailableFcnMode','terminator'); set(obj1,'terminator','D'); set(obj1,'BytesAvailableFcn',@my_callback1); fopen(obj1); obj2=serial('com8'); fclose(obj2); set(obj2, 'InputBufferSize', 24); set(obj2, 'OutputBufferSize', 24); set(obj2, 'BaudRate', 115200); set(obj2, 'Timeout', 1.0); fopen(obj2);
代码2:回调函数
进入回调函数后对数据进行读取和处理,然后发送给下位机
接收数据帧的格式是:
字节1:‘D’,10进制表示是68
字节2:0x05,10进制表示是5,1-2是帧头,然后是数据位
字节3-4:表示电机转速,16位数据
字节5-6:表示负载扭矩,16位数据
字节7-10:表示母线电压,32位数据
字节11-14:表示母线电流,32位数据
字节15-18:表示相电压,32位数据
字节19-22:表示相电流,32位数据
字节23:0X0D
字节24:0X0A发送数据帧的格式:
字节1-2:表示Kp,16位数据
字节3-4:表示Ki,16位数据
字节5-6:表示Kd,16位数据
字节7:0X0D
字节8:0X0Afunction my_callback1(obj1,event) global data; global obj2; global sendbuff; global data1; global data2; global data3; global data4; global data5; global data6; global n; n=n+1; data= fread(obj1, 24) if lenth(data)==24 if data(1) == 68 if data(2) == 5 data1 = (data(3)*256+data(4))/1000; data2 = (data(5)*256+data(6))/1000; data3 = (data(7)*16777216+data(8)*65536+data(9)*256+data(10))/100; data4 = (data(11)*16777216+data(12)*65536+data(13)*256+data(14))/100; data5 = (data(15)*16777216+data(16)*65536+data(17)*256+data(18))/100; data6 = (data(19)*16777216+data(20)*65536+data(21)*256+data(22))/100; end end if data(1) == 5 data1 = (data(2)*256+data(3))/1000; data2 = (data(4)*256+data(5))/1000; data3 = (data(6)*16777216+data(7)*65536+data(8)*256+data(9))/100; data4 = (data(10)*16777216+data(11)*65536+data(12)*256+data(13))/100; data5 = (data(14)*16777216+data(15)*65536+data(16)*256+data(17))/100; data6 = (data(18)*16777216+data(19)*65536+data(20)*256+data(21))/100; end sendbuff(1)=floor((data1+data4)/256); sendbuff(2)=floor((data1+data4)); sendbuff(3)=floor((data2+data5)/256); sendbuff(4)=floor((data2+data5)); sendbuff(5)=floor((data3+data6)/256); sendbuff(6)=floor((data4+data6)); fwrite(obj2, sendbuff, 'uint8'); %my_fwrite(obj2, sendbuff, 'uint8'); end end
2.关于提高串口速度的讨论
在进行PID参数整定时,由于整个PID的调整周期较短,因此希望整个串口读取、处理、发送的时间最好在2ms以内完成。这个速度对于计算机来说其实是不容易实现的,因此如何提高整个回调函数的运算速度成为编写代码的关键。这里我发现了一些提高运行速度的方法:
对于串口读写速度,主要是串口发送函数 fwrite(obj2, sendbuff, ‘uint8’)消耗了太多的时间,运行时这里耗费的时间有20ms+,这对于整个项目时不可接受的,笔者在思考和尝试的时候发现了一个方法可以让这个时间缩小到0.7ms左右。那就是用一个新的my_fwrite.m文件代替原来的内部函数fwrite.m(新的fwrite.m代码如下)。并将上述的代码改为my_fwrite(obj2, sendbuff, ‘uint8’)。
新的文件如下:
function my_fwrite(obj, varargin) %FWRITE Write binary data to instrument. % % FWRITE(OBJ, A) writes the data, A, to the instrument connected to % interface object, OBJ. % % The interface object must be connected to the instrument with the % FOPEN function before any data can be written to the instrument % otherwise an error will be returned. A connected interface object % has a Status property value of open. % % FWRITE(OBJ,A,'PRECISION') writes binary data translating MATLAB % values to the specified precision, PRECISION. The supported % PRECISION strings are defined below. By default the 'uchar' % PRECISION is used. % % MATLAB Description % 'uchar' unsigned character, 8 bits. % 'schar' signed character, 8 bits. % 'int8' integer, 8 bits. % 'int16' integer, 16 bits. % 'int32' integer, 32 bits. % 'uint8' unsigned integer, 8 bits. % 'uint16' unsigned integer, 16 bits. % 'uint32' unsigned integer, 32 bits. % 'single' floating point, 32 bits. % 'float32' floating point, 32 bits. % 'double' floating point, 64 bits. % 'float64' floating point, 64 bits. % 'char' character, 8 bits (signed or unsigned). % 'short' integer, 16 bits. % 'int' integer, 32 bits. % 'long' integer, 32 or 64 bits. % 'ushort' unsigned integer, 16 bits. % 'uint' unsigned integer, 32 bits. % 'ulong' unsigned integer, 32 bits or 64 bits. % 'float' floating point, 32 bits. % % FWRITE(OBJ, A, 'MODE') % FWRITE(OBJ, A, 'PRECISION', 'MODE') writes data asynchronously % to the instrument when MODE is 'async' and writes data synchronously % to the instrument when MODE is 'sync'. By default, the data is % written with the 'sync' MODE, meaning control is returned to % the MATLAB command line after the specified data has been written % to the instrument or a timeout occurs. When the 'async' MODE is % used, control is returned to the MATLAB command line immediately % after executing the FWRITE function. % % The byte order of the instrument can be specified with OBJ's % ByteOrder property. % % OBJ's ValuesSent property will be updated by the number of values % written to the instrument. % % If OBJ's RecordStatus property is configured to on with the RECORD % function, the data written to the instrument will be recorded in % the file specified by OBJ's RecordName property value. % % Example: % s = visa('ni', 'ASRL2::INSTR'); % fopen(s); % fwrite(s, [0 5 5 0 5 5 0]); % fclose(s); % % See also ICINTERFACE/FOPEN, ICINTERFACE/FPRINTF, ICINTERFACE/RECORD, % ICINTERFACE/PROPINFO, INSTRHELP. % % MP 7-13-99 % Copyright 1999-2012 The MathWorks, Inc. % Error checking. if ~isa(obj, 'icinterface') error(message('instrument:fwrite:invalidOBJInterface')); end if length(obj)>1 error(message('instrument:fwrite:invalidOBJDim')); end % Parse the input. switch nargin case 1 error(message('instrument:fwrite:invalidSyntaxA')); case 2 cmd = varargin{1}; precision = 'uchar'; mode = 0; case 3 % Original assumption: fwrite(obj, cmd, precision); [cmd, precision] = deal(varargin{1:2}); mode = 0; if ~(isa(precision, 'char') || isa(precision, 'double')) error(message('instrument:fwrite:invalidArg')); end if strcmpi(precision, 'sync') % Actual: fwrite(obj, cmd, mode); mode = 0; precision = 'uchar'; elseif strcmpi(precision, 'async') % Actual: fwrite(obj, cmd, mode); mode = 1; precision = 'uchar'; end case 4 % Ex. fprintf(obj, format, cmd, mode); [cmd, precision, mode] = deal(varargin{1:3}); if ~ischar(mode) error(message('instrument:fwrite:invalidMODE')); end if strcmpi(mode, 'sync') mode = 0; elseif strcmpi(mode, 'async') mode = 1; else error(message('instrument:fwrite:invalidMODE')); end otherwise error(message('instrument:fwrite:invalidSyntaxArgv')); end % % % % Error checking. % % % if ~isa(precision, 'char') % % % error(message('instrument:fwrite:invalidPRECISIONstring')); % % % end % % % if ~(isnumeric(cmd) || ischar(cmd)) % % % error(message('instrument:fwrite:invalidA')); % % % end % Convert the data to the requested precision. switch (precision) case {'uchar', 'char'} cmd = uint8(cmd); type = 5; signed = 0; case {'schar'} cmd = int8(cmd); type = 5; signed = 1; case {'int8'} cmd = int8(cmd); type = 0; signed = 1; case {'int16', 'short'} cmd = int16(cmd); type = 1; signed = 1; case {'int32', 'int', 'long'} cmd = int32(cmd); type = 2; signed = 1; case {'uint8'} cmd = uint8(cmd); type = 0; signed = 0; case {'uint16', 'ushort'} cmd = uint16(cmd); type = 1; signed = 0; case {'uint32', 'uint', 'ulong'} cmd = uint32(cmd); type = 2; signed = 0; import java.lang.Long for iLoop = 1:length(cmd) tmp(iLoop) = Long(cmd(iLoop)); %#ok<AGROW> end cmd=tmp; case {'single', 'float32', 'float'} cmd = single(cmd); type = 3; signed = 1; case {'double' ,'float64'} cmd = double(cmd); type = 4; signed = 1; otherwise error(message('instrument:fwrite:invalidPRECISION')); end % i2c does not support async mode if mode == 1 error(message('instrument:fwrite:i2cAyncNotSupported')); end % Call the write java method. try fwrite(igetfield(obj, 'jobject'), cmd, length(cmd), type, mode, signed); catch aException newExc = MException('instrument:fwrite:opfailed', aException.message); throw(newExc); end
除此之外,在进行数据的处理的时候,应尽量对数据进行乘除取整取余等数学运算而不是调用一些强制转换的函数或者移位函数。笔者考虑可能是在寻找和调用matlab系统内部函数花费了较多的时间。
同时,这个运算速度和matlab版本以及电脑的CPU性能有关,同样的程序i5跑起来是2ms,i7跑起来0.8ms。
通过以上方法将原来数十微妙的运行速度降到了运行一次在一微妙以内。所以还是有些效果的。
-
智能控制及其MATLAB实现2005李国勇编著.part3.rar
2008-07-11 12:36:351.1.5 神经网络的学习 1.1.6 神经网络的分类 1.2 典型神经网络的模型 1.2.1 MP模型 1.2.2 感知机神经网络 1.2.3 自适应线性神经网络 1.2.4 BP神经网络 1.2.5 径向基神经网络 ... -
[MATLAB智能算法30个案例分析].史峰
2014-08-14 11:51:33应用最广的有导师学习神经网络(BP神经网络及RBF神经网络)的原理及其在回归拟合中的应用。 26 有导师学习神经网络的分类——鸢尾花种类识别(郁磊) 有导师学习神经网络以其良好的学习能力广泛应用于各个领域中,其...