精华内容
下载资源
问答
  • gaussian kernel的参数(linear 和poly就没有这个),如下图.gamma越大,σ越小,使得高斯分布又高又瘦,造成模型只能作用于支持向量附近,可能导致过拟合;反之,gamma越小,σ越大,高斯分布会过于平滑,在训练集...

    前言

    • 有复现需要的时候建议全部指定random_state
    • 不收敛的时候指定一下max_iter

    logistics regression

    model = LogisticRegression(C=my_c, max_iter=500, random_state=0)
    

    重要参数:

    • C

    默认L2正则化,默认优化器的情况下,基本只有个C可以调。

    svm

    在这里插入图片描述
    在这里插入图片描述

    重要参数:

    • C:惩罚系数的相反数(如上图),C越大越容易过拟合,C越小越容易欠拟合
    • kernel: linear,poly , rbf, 其中rbf就是高斯
    • degree: 仅适用于poly,poly的最高次数
    • gamma:仅适用于rbf。gaussian kernel的参数(linear 和poly就没有这个),如下图.gamma越大,σ越小,使得高斯分布又高又瘦,造成模型只能作用于支持向量附近,可能导致过拟合;反之,gamma越小,σ越大,高斯分布会过于平滑,在训练集上分类效果不佳,可能导致欠拟合。

    gamma

    knn

    参考链接:https://www.cnblogs.com/listenfwind/p/10685192.html

    重要参数:

    • k: knn的k,选几个最近的邻居。太小容易过拟合,太大有问题。
      weights(权重): 三个选项:'distance" 表示距离近的邻居权重大;'uniform’表示远近都一样;自定义函数

    展开全文
  • XGBoost调步骤常见问题

    千次阅读 2021-11-30 10:22:12
    XGBoost xgboost中的基学习器除了可以是CART(gbtree)也可以是线性分类器(gblinear) xgboost在目标函数中显示的加上了正则化项,基学习为CART时,正则化项与树的叶子节点的数量T和叶子节点的值有关。 正则项里...

    XGBoost

    xgboost中的基学习器除了可以是CART(gbtree)也可以是线性分类器(gblinear)

    • xgboost在目标函数中显示的加上了正则化项,基学习为CART时,正则化项与树的叶子节点的数量T和叶子节点的值有关。
      正则项里包含了树的叶子节点个数、每个叶子节点上输出的score的L2模的平方和。
      从Bias-variance tradeoff角度来讲,正则项降低了模型的variance,使学习出来的模型更加简单,防止过拟合,这也是xgboost优于传统GBDT的一个特性。
      在这里插入图片描述

    • GB中使用Loss Function对f(x)的一阶导数计算出伪残差用于学习生成fm(x),xgboost不仅使用到了一阶导数,还使用二阶导数。
      第t次的loss:
      在这里插入图片描述
      对上式做二阶泰勒展开:g为一阶导数,h为二阶导数
      在这里插入图片描述

    • 上面提到CART回归树中寻找最佳分割点的衡量标准是最小化均方差,XGBoost的并行是在特征粒度上的,XGBoost预先对特征的值进行排序,然后保存为block结构
      xgboost寻找分割点的标准是最大化,lamda,gama与正则化项相关在这里插入图片描述
      xgboost算法的步骤和GB基本相同,都是首先初始化为一个常数,gb是根据一阶导数ri,xgboost是根据一阶导数gi和二阶导数hi,迭代生成基学习器,相加更新学习器。

    • xgboost考虑了训练数据为稀疏值的情况,可以为缺失值或者指定的值指定分支的默认方向,这能大大提升算法的效率

    • 列抽样。xgboost借鉴了随机森林的做法,支持列抽样,不仅能降低过拟合,还能减少计算,这也是xgboost异于传统gbdt的一个特性。

      XGBoost参数设置

      通用参数

      这些参数用来控制XGBoost的宏观功能。

    • booster[默认gbtree]

      选择每次迭代的模型,有两种选择:
      gbtree:基于树的模型
      gbliner:线性模型

    • silent[默认0]

      当这个参数值为1时,静默模式开启,不会输出任何信息。
      一般这个参数就保持默认的0,因为这样能帮我们更好地理解模型。

    • nthread[默认值为最大可能的线程数]

      这个参数用来进行多线程控制,应当输入系统的核数。
      如果你希望使用CPU全部的核,那就不要输入这个参数,算法会自动检测它。

    booster参数

    • max_depth[默认6]

      和GBM中的参数相同,这个值为树的最大深度。
      这个值也是用来避免过拟合的。max_depth越大,模型会学到更具体更局部的样本。
      需要使用CV函数来进行调优。
      典型值:3-10

    • eta[默认0.3]

      和GBM中的 learning rate 参数类似。
      通过减少每一步的权重,可以提高模型的鲁棒性。
      典型值为0.01-0.2

    • base_score [ 默认0.5 ]
      所有实例的初始化预测分数,全局偏置;
      为了足够的迭代次数,改变这个值将不会有太大的影响。

    • min_child_weight[默认1]
      决定最小叶子节点样本权重和。
      和GBM的 min_child_leaf 参数类似,但不完全一样。XGBoost的这个参数是最小样本权重的和,而GBM参数是最小样本总数。
      这个参数用于避免过拟合。当它的值较大时,可以避免模型学习到局部的特殊样本。
      但是如果这个值过高,会导致欠拟合。这个参数需要使用CV来调整。

    • max_leaf_nodes

      树上最大的节点或叶子的数量。
      可以替代max_depth的作用。因为如果生成的是二叉树,一个深度为n的树最多生成 n 2 n^2 n2个叶子。
      如果定义了这个参数,GBM会忽略max_depth参数。

    • gamma[默认0]

      在节点分裂时,只有分裂后损失函数的值下降了,才会分裂这个节点。Gamma指定了节点分裂所需的最小损失函数下降值。
      这个参数的值越大,算法越保守。这个参数的值和损失函数息息相关,所以是需要调整的。

    • max_delta_step[默认0]

      这参数限制每棵树权重改变的最大步长。如果这个参数的值为0,那就意味着没有约束。如果它被赋予了某个正值,那么它会让这个算法更加保守。
      通常,这个参数不需要设置。但是当各类别的样本十分不平衡时,它对逻辑回归是很有帮助的。
      这个参数一般用不到,但是你可以挖掘出来它更多的用处。

    • subsample[默认1]

      和GBM中的subsample参数一模一样。这个参数控制对于每棵树,随机采样的比例。
      减小这个参数的值,算法会更加保守,避免过拟合。但是,如果这个值设置得过小,它可能会导致欠拟合。
      典型值:0.5-1

    • colsample_bytree[默认1]

      和GBM里面的max_features参数类似。用来控制每棵随机采样的列数的占比(每一列是一个特征)。
      典型值:0.5-1

    • colsample_bylevel[默认1]

      用来控制树的每一级的每一次分裂,对列数的采样的占比。
      我个人一般不太用这个参数,因为subsample参数和colsample_bytree参数可以起到相同的作用。但是如果感兴趣,可以挖掘这个参数更多的用处。

    • lambda[默认1]

      权重的L2正则化项。(和Ridge regression类似)。
      这个参数是用来控制XGBoost的正则化部分的。虽然大部分数据科学家很少用到这个参数,但是这个参数在减少过拟合上还是可以挖掘出更多用处的。

    • alpha[默认1]

      权重的L1正则化项。(和Lasso regression类似)。
      可以应用在很高维度的情况下,使得算法的速度更快。

    • scale_pos_weight[默认1]

      在各类别样本十分不平衡时,把这个参数设定为一个正值,可以使算法更快收敛

    学习目标参数

    这个参数用来控制理想的优化目标和每一步结果的度量方法

    • objective [ default=reg:linear ]

      定义学习任务及相应的学习目标,可选的目标函数如下:

      • “reg:linear” —— 线性回归。
      • “reg:logistic”—— 逻辑回归。
      • “binary:logistic”—— 二分类的逻辑回归问题,输出为概率。
      • “binary:logitraw”—— 二分类的逻辑回归问题,输出的结果为wTx。
      • “count:poisson”—— 计数问题的poisson回归,输出结果为poisson分布。在poisson回归中,max_delta_step的缺省值为0.7。(used to safeguard optimization)
      • “multi:softmax” –让XGBoost采用softmax目标函数处理多分类问题,同时需要设置参数num_class(类别个数)
      • “multi:softprob” –和softmax一样,但是输出的是ndata * nclass的向量,可以将该向量reshape成ndata行nclass列的矩阵。没行数据表示样本所属于每个类别的概率。
      • “rank:pairwise” –set XGBoost to do ranking task by minimizing the pairwise loss
    • eval_metric [ default according to objective ]
      对于回归问题,默认值是rmse,对于分类问题,默认值是error。

      • rmse 均方根误差
      • mae 平均绝对误差
      • logloss 负对数似然函数值
      • error 二分类错误率(阈值为0.5)
      • merror 多分类错误率
      • mlogloss 多分类logloss损失函数
      • auc 曲线下面积
    • seed [ default=0 ]
      随机数的种子。缺省值为0

    
    from sklearn.model_selection import train_test_split
    
    train_x, test_x, train_y, test_y = train_test_split(feature_matrix, labels, random_state=0)
    
    import xgboost as xgb
    dtrain=xgb.DMatrix(train_x,label=train_y)
    dtest=xgb.DMatrix(test_x)
    
    params={    'booster': 'gbtree',            
        'objective': 'multi:softmax',  # 多分类的问题
        'num_class': 10,               # 类别数,与 multisoftmax 并用
        'gamma': 0.1,                  # 用于控制是否后剪枝的参数,越大越保守,一般0.1、0.2这样子。
        'max_depth': 12,               # 构建树的深度,越大越容易过拟合
        'lambda': 2,                   # 控制模型复杂度的权重值的L2正则化项参数,参数越大,模型越不容易过拟合。
        'subsample': 0.7,              # 随机采样训练样本
        'colsample_bytree': 0.7,       # 生成树时进行的列采样
        'min_child_weight': 3,
        'silent': 1,                   # 设置成1则没有运行信息输出,最好是设置为0.
        'eta': 0.1,                  # 如同学习率
        'seed': 1000,
        'nthread': 10                 # cpu 线程数,默认值为最大可能的线程数
    }
    
    watchlist = [(dtrain,'train')]
    
    bst=xgb.train(params,dtrain,num_boost_round=100,evals=watchlist)
    
    y_pred=bst.predict(dtest)
    
    y_pred_binary = (ypred >= 0.5)*1
    
    from sklearn import metrics
    print 'AUC: %.4f' % metrics.roc_auc_score(test_y,y_pred)
    print 'ACC: %.4f' % metrics.accuracy_score(test_y,y_pred_binary)
    print 'Recall: %.4f' % metrics.recall_score(test_y,y_pred_binary)
    print 'F1-score: %.4f' %metrics.f1_score(test_y,y_pred_binary)
    print 'Precesion: %.4f' %metrics.precision_score(test_y,y_pred_binary)
    metrics.confusion_matrix(test_y,y_pred_binary)
    
    

    参数调优的一般方法

    我们会使用和GBM中相似的方法。需要进行如下步骤:

    • 选择较高的学习速率(learning rate)。一般情况下,学习速率的值为0.1。但是,对于不同的问题,理想的学习速率有时候会在0.05到0.3之间波动。选择对应于此学习速率的理想决策树数量。XGBoost有一个很有用的函数“cv”,这个函数可以在每一次迭代中使用交叉验证,并返回理想的决策树数量。
    • 对于给定的学习速率和决策树数量,进行决策树特定参数调优(max_depth, min_child_weight, gamma, subsample, colsample_bytree)。在确定一棵树的过程中,我们可以选择不同的参数。
    • xgboost的正则化参数的调优。(lambda, alpha)。这些参数可以降低模型的复杂度,从而提高模型的表现。
    • 降低学习速率,确定理想参数。
    import xgboost as xgb
    
    data_train = xgb.DMatrix('agaricus_train.txt')
    data_test = xgb.DMatrix('agaricus_test.txt')
    print (data_train)
    print (type(data_train))
    
    # 设置参数
    param = {'max_depth': 3, 'eta': 1, 'silent': 1, 'objective': 'binary:logistic'} 
    
    # 可以显示每一颗树添加后的误差
    watchlist = [(data_test, 'eval'), (data_train, 'train')]
    n_round = 50
    bst = xgb.train(param, data_train, num_boost_round=n_round, evals=watchlist, obj=log_reg, feval=error_rate)
    
    # 计算错误率
    y_hat = bst.predict(data_test)
    y = data_test.get_label()
    print(y_hat)
    print(y)
    
    

    XGBoost常见问题

    xgboost 什么场景不适用

    数据量很大以及特征比较多时太耗内存,太慢了,比如寻找最优特征分裂点时需要遍历所有特征去计算(虽然做了预排序和并行处理) ,但它还是很慢和很耗内存,需要读取所有数据到内存中才好做特征分裂。

    GDBT 和Xgboost 的区别?

    好的地方: 二阶泰勒展开,节点分数惩罚正则,增益计算不同,gbdt 是gini,xgb 是优化推导公式

    • 传统的GBDT以CART作为基分类器,XGboost 还支持线性分类器,这时候xgboost 相当于带L1 和L2 正则化项的逻辑斯蒂回归(分类问题) 或者线性回归。

    • 传统的GBDT在优化时只用到了一阶导数信息,xgboost 则对代价函数进行了二阶泰勒展开,同时用到了一阶和二阶导数,xgboost 还支持自定义代价函数,只要函数可一阶和二阶求导。

    • Xgboost 在代价函数中加入了正则项,用于控制模型的复杂度,正则项里包含了 树的叶子节点个数,每个叶子节点上输出的score 的L2 模的平方和。从Bias -variance tradeoff 角度来讲,正则项降低了模型的variance,使学习出来的模型更加简单,防止过拟合,这也就是xgboost 优于传统CBDT的一个特性。

    • Shrinkage ,相当于学习速率(xgboost 中的eta) .Xgboost 在进行完一次迭代后,会将叶子节点上权重·乘上该系数,主要是为了削弱每棵树的影响,让后面有更大的学习空间,实际应用中,一般把eta 设置的小一点,然后迭代次数设置的大一点。

    • 列抽样,: xgboost 借鉴了随机森林的做法,支持列抽样,不仅能降低过拟合,还能减少计算,这也是xgboost 异于传统gdbt 的一个特性。

    • 缺失值的处理,对特征的值有缺失的样本,xgboost 可以自动学习出它分裂的方向。

    • xgboost 支持并行,不是在trees 粒度的并行,而是在特征粒度上的,决策树的学习最耗时的一个步骤就是对特征的值进行排序(因为要确定最佳分割点) ,xgboost 在训练之前,预先对数据进行了排序,然后保存了block 结构,后面的迭代中重复使用了这个结构,大大减少了计算量。在进行节点分裂时,需要计算每个特征的增益,最终选增益最大的那个特征去做分裂,那么各个特征的增益计算可以开多线程进行。

    • 可并行的近似直方图算法,树节点在进行分裂时,我们需要计算每个特征的每个分割点对应的增益,即用贪心法枚举所有节能的分割点,当数据无法一次载入内存或者在分布式情况下,贪心算法效率就会变得很低,所以xgboost 还提出了一种可并行的近似直方图算法,用于高效的生成候选的分割点。

    XGBoost 和lgb 的区别

    是对GBDT 方法的不同实现,针对同一目标,做了不同的优化处理。

    它们在基础逻辑上并没有啥不同,限定max_tree或者max_iterations,之后算法从0 棵树开始跑,每一轮根据上一轮的残差增加一颗决策树,在每一次增加决策树的时候选择当前最优结构,而在生成当前决策树的过程中,采用了不同的优化方案。

    • XGBoost 使用基于预排序的决策树算法,每遍历一个特征需要计算一次特征增益,时间复杂度为Q(datafeature).

    lgb 使用基于直方图的决策树算法,直方图的优化算法只需要计算k 次,时间复杂度为O(kfeature)

    • XGBoost 按照层生长的决策树生成,LGb采用带有深度限制的叶子节点算法,在分裂次数相同的情况下,leaf-wise 可以降低更多的误差,得到更好的精度,leaf-wise 的缺点在于会产生较深的决策树,产生过拟合。

    • 支持类别特征,不需要进行独热编码处理。

    • 优化了特征并行和数据并行算法,除此之外还添加了投票并行方案。

    • 采用基于梯度的单边采用来保持数据分布,减少模型因数据分布发生变化而造成的模型精度下降。

    • 特征捆绑转化为图着色问题,减少特征数量。

    XGBoost分裂终止条件

    • 当引入的分裂带来的增益小于一个阀值的时候,我们可以剪掉这个分裂,所以并不是每一次分裂loss function整体都会增加的,有点预剪枝的意思(其实我这里有点疑问的,一般后剪枝效果比预剪枝要好点吧,只不过复杂麻烦些,这里大神请指教,为啥这里使用的是预剪枝的思想,当然Xgboost支持后剪枝),阈值参数为γγ 正则项里叶子节点数T的系数(大神请确认下);

    • 当树达到最大深度时则停止建立决策树,设置一个超参数max_depth,这个好理解吧,树太深很容易出现的情况学习局部样本,过拟合;

    • 当样本权重和小于设定阈值时则停止建树,这个解释一下,涉及到一个超参数-最小的样本权重和min_child_weight,和GBM的 min_child_leaf 参数类似,但不完全一样,大意就是一个叶子节点样本太少了,也终止同样是过拟合;

    展开全文
  • 第1章:人参行业的概念界定发展环境剖析1.1 人参行业概念界定 1.1.1 人参的概念价值 (1)人参定义 (2)人参功能 1.1.2 人参的分类 1.1.3 人参所属的国民经济分类 1.1.4 本报告的数据来源统计口径说明 ...


    【撰写单位】:鸿晟信合研究院    

    第1章:人参行业的概念界定及发展环境剖析1.1 人参行业概念界定

    1.1.1 人参的概念及价值

    (1)人参定义

    (2)人参功能

    1.1.2 人参的分类

    1.1.3 人参所属的国民经济分类

    1.1.4 本报告的数据来源及统计口径说明

    1.2 人参行业市场环境分析

    1.2.1 政策环境分析

    (1)行业监管体制及主管部门

    (2)行业相关标准

    (3)行业政策法规

    (4)行业政策规划

    (5)政策环境对行业的影响分析

    1.2.2 经济环境分析

    (1)宏观经济环境发展现状及展望

    (2)消费情况变化

    (3)宏观经济对行业的影响分析

    1.2.3 社会环境分析

    (1)中国人口规模及结构

    (2)国民养生、意识提升

    (3)中国城市化与需求

    (4)传统礼仪与礼品消费

    (5)社会环境对行业发展的影响分析

    1.2.4 技术环境分析

    (1)中国人参种植技术及与韩国的对比

    (2)中国人参加工技术及与韩国的对比

    (3)中国人参相关专利的申请及公开情况

    (4)技术环境对行业的影响分析

    1.2.5 行业市场环境综述

    第2章:全球人参行业市场发展现状分析2.1 全球人参行业市场供给及需求现状

    2.1.1 全球人参行业种植类型及产量分析

    2.1.2 全球人参贸易发展情况

    2.1.3 全球人参行业市场规模

    2.2 全球人参行业市场竞争格局分析

    2.2.1 全球人参行业产地区域格局分析

    2.2.2 全球人参行业进出口交易国别格局

    2.3 国际典型地区人参行业市场分析

    2.3.1 韩国人参行业市场发展分析

    (1)韩国人参种类及市场特征

    (2)韩国人参产量及出口情况

    (3)韩国人参行业需求量及进口情况

    (4)韩国人参行业市场需求规模

    2.3.2 美国人参行业市场发展分析

    (1)美国人参种类及市场特征

    (2)美国人参行业产量及出口情况

    (3)美国人参行业需求量及进口情况

    2.3.3 加拿大人参行业市场发展分析

    (1)加拿大人参种类及市场特征

    (2)加拿大人参行业产量及出口情况

    (3)加拿大人参行业需求量及进口情况

    2.4 国际典型人参加工企业案例简析

    2.4.1 韩国人参公社

    2.4.2 美国许氏人参企业

    2.5 全球人参行业市场发展趋势分析

    2.5.1 全球人参行业市场供给前景分析

    2.5.2 全球人参行业市场需求前景分析

    2.5.3 全球人参产品发展趋势分析

    第3章:中国人参行业市场发展现状分析3.1 中国人参行业发展历程及行业市场特征

    3.1.1 中国人参行业发展历程

    3.1.2 中国人参行业发展特点

    3.2 中国人参行业市场供给及需求现状分析

    3.2.1 中国人参行业参与者类型

    (1)传统参类制品企业

    (2)医药企业

    (3)品企业

    3.2.2 中国人参市场供给研究

    (1)产品产量

    (2)产品产值

    3.2.3 中国人参市场需求研究

    (1)市场需求特征

    (2)人参的销量

    (3)行业销售收入

    3.2.4 中国人参行业进出口统计

    (1)中国人参进出口概况

    (2)中国人参行业进口统计

    (3)中国人参行业出口统计

    3.2.5 中国人参行业供需平衡现状

    3.2.6 中国人参价格水平分析

    (1)人参市场价格影响因素

    (2)人参市场价格走势分析

    3.3 中国人参行业经济效益及经营状况分析

    3.3.1 人参上市企业经营情况分析

    3.3.2 人参上市企业获利水平

    3.4 中国人参行业发展痛点分析

    第4章:中国人参行业竞争状态及市场格局分析4.1 人参行业波特五力模型分析

    4.1.1 现有竞争者之间的竞争

    4.1.2 关键要素的供应商议价能力分析

    4.1.3 消费者议价能力分析

    4.1.4 行业潜在进入者分析

    4.1.5 替代品风险分析

    4.1.6 竞争情况总结

    4.2 中国人参与韩国人参的优劣势对比

    4.2.1 中国人参对比韩国人参优势分析

    (1)中韩人参同出一源

    (2)人参加工方式与营养价值含量相似

    (3)消费市场高度重合

    4.2.2 中国人参对比韩国人参劣势分析

    (1)种植技术对比

    (2)加工技术对比

    (3)产品品牌包装对比

    (4)管理机制对比

    (5)管理标准及认证严格程度对比

    (6)产业挖掘深度对比

    (7)政策对比

    4.3 中国人参细分产品市场结构

    4.4 中国人参区域市场发展格局

    4.4.1 中国人参区域市场供应格局

    4.4.2 中国人参区域市场消费格局

    4.5 中国人参企业/品牌竞争格局

    4.6 中国人参市场集中度分析

    4.6.1 区域集中度分析

    4.6.2 品牌集中度

    4.7 中国人参行业投融资、兼并及重组分析

    4.7.1 行业投融资状况

    4.7.2 行业并购重组分析

    第5章:中国人参行业产业链全景解析5.1 人参行业产业链全景预览

    5.1.1 人参行业产业链全景预览

    5.1.2 人参行业成本结构分析

    5.2 人参行业上游种植市场发展状况

    5.2.1 中国人参种植市场发展现状

    5.2.2 中国人参种植区域供给规模

    5.2.3 中国人参种植面积

    5.2.4 中国人参种植市场发展趋势

    (1)广泛收集种质资源,选育优良品种

    (2)攻克人参连作障碍保障人参种植业可持续发展

    (3)大力发展非林种植人参模式

    5.3 人参行业中游加工市场发展状况

    5.3.1 人参加工市场发展现状

    5.3.2 人参加工涉及的设备类型

    (1)人参清洗机械设备

    (2)人参烘干机械设备

    (3)人参分选机械设备

    (4)人参包装机械设备

    (5)人参加工通用机械设备

    5.3.3 人参加工相关设备的市场供给

    5.3.4 人参加工企业发展格局

    5.3.5 人参加工市场发展趋势

    第6章:中国人参中游细分产品市场需求潜力6.1 中国人参中游细分产品需求特征对比

    6.2 中国人参日用品市场需求潜力

    6.2.1 人参日用品的概念界定及分类

    (1)人参日用品的定义及特征

    (2)人参日用品的分类

    6.2.2 人参日用品需求规模

    6.2.3 人参日用品市场竞争分析

    6.2.4 人参日用品市场前景分析

    6.3 中国人参品市场需求潜力

    6.3.1 人参品的概念界定及分类

    (1)人参品的定义及特征

    (2)人参品的分类

    6.3.2 人参品需求规模

    6.3.3 人参品市场竞争分析

    6.3.4 人参品市场前景分析

    第7章:中国人参下游销售渠道及重点区域市场发展解析7.1 中国人参行业下游销售渠道分布及发展现状

    7.1.1 线下渠道发展现状及竞争格局

    7.1.2 线上渠道发展现状及竞争格局

    7.2 中国人参行业重点区域市场发展状况解析

    7.2.1 吉林省

    (1)行业区域发展环境

    (2)行业区域市场供给及出口

    (3)行业区域市场竞争

    (4)行业区域发展问题

    (5)行业区域发展前景分析

    7.2.2 辽宁省

    (1)行业区域发展环境

    (2)行业区域市场供给及出口

    (3)行业区域市场竞争

    (4)行业区域发展问题

    (5)行业区域发展前景分析

    7.2.3 黑龙江省

    (1)行业区域发展环境

    (2)行业区域市场供给及出口

    (3)行业区域市场竞争

    (4)行业区域发展问题

    (5)行业区域发展前景分析

    第8章:中国人参行业供应链代表性企业案例研究8.1 中国人参行业供应链企业代表发展对比

    8.2 中国人参供应链代表性企业案例分析

    8.2.1 参仙源参业股份有限公司

    (1)企业发展历程及基本信息

    (2)企业经营状况介绍

    (3)企业业务结构及销售网络

    (4)企业人参业务布局

    (5)企业发展人参业务的优劣势分析

    8.2.2 通化盛吉信生物科技股份有限公司

    (1)企业发展历程及基本信息

    (2)企业经营状况介绍

    (3)企业业务结构及销售网络

    (4)企业人参业务布局

    (5)企业发展人参业务的优劣势分析

    8.2.3 吉林加一健康产业股份有限公司

    (1)企业发展历程及基本信息

    (2)企业经营状况介绍

    (3)企业业务结构及销售网络

    (4)企业人参业务布局

    (5)企业发展人参业务的优劣势分析

    8.2.4 长白山皇封参业股份有限公司

    (1)企业发展历程及基本信息

    (2)企业经营状况介绍

    (3)企业业务结构及销售网络

    (4)企业人参业务布局

    (5)企业发展人参业务的优劣势分析

    8.2.5 浙江兰溪锦荣生物科技股份有限公司

    (1)企业发展历程及基本信息

    (2)企业经营状况介绍

    (3)企业业务结构及销售网络

    (4)企业人参业务布局

    (5)企业发展人参业务的优劣势分析

    8.2.6 中国医药健康产业股份有限公司

    (1)企业发展历程及基本信息

    (2)企业经营状况介绍

    (3)企业业务结构及销售网络

    (4)企业人参业务布局

    (5)企业发展人参业务的优劣势分析

    8.2.7 吉林紫鑫药业股份有限公司

    (1)企业发展历程及基本信息

    (2)企业经营状况介绍

    (3)企业业务结构及销售网络

    (4)企业人参业务布局

    (5)企业发展人参业务的优劣势分析

    8.2.8 通化百泉参业集团股份有限公司

    (1)企业发展历程及基本信息

    (2)企业经营状况介绍

    (3)企业业务结构及销售网络

    (4)企业人参业务布局

    (5)企业发展人参业务的优劣势分析

    8.2.9 吉林省长白山人参有限公司

    (1)企业发展历程及基本信息

    (2)企业经营状况介绍

    (3)企业业务结构及销售网络

    (4)企业人参业务布局

    (5)企业发展人参业务的优劣势分析

    8.2.10 吉林省长白山三生健康管理有限公司

    (1)企业发展历程及基本信息

    (2)企业经营状况介绍

    (3)企业业务结构及销售网络

    (4)企业人参业务布局

    (5)企业发展人参业务的优劣势分析

    第9章:中国人参行业趋势前景预测及投资机会分析9.1 人参行业发展前景预测

    9.1.1 行业市场容量预测

    (1)产量预测

    (2)需求预测

    9.1.2 行业发展趋势预测

    (1)出口趋势预测

    (2)产品发展趋势预测

    (3)价格趋势预测

    (4)产量趋势预测

    9.2 人参行业投资特性分析

    9.2.1 行业进入壁垒分析

    (1)原产地壁垒

    (2)资源壁垒

    (3)品牌壁垒

    (4)规模化经营壁垒

    (5)技术壁垒

    9.2.2 行业投资风险预警

    (1)人参行业经营风险及控制策略

    (2)人参行业食品安全风险及控制策略

    (3)人参市场竞争风险及控制策略

    (4)人参行业技术风险及控制策略

    9.3 人参行业投资价值与投资机会

    9.3.1 行业投资价值分析

    9.3.2 行业投资机会分析

    (1)产业链投资机会分析

    (2)重点区域投资机会分析

    (3)细分市场投资机会分析

    (4)产业空白点投资机会

    9.4 人参行业品牌及竞争策略与可持续发展建议

    9.4.1 行业品牌策略分析

    (1)企业品牌的重要性

    (2)人参企业品牌的现状分析

    (3)我国人参企业的品牌战略

    (4)人参品牌战略管理的策略

    9.4.2 人参市场竞争策略分析

    (1)成本领先战略

    (2)差异化战略

    (3)集中化战略

    9.4.3 行业可持续发展建议

    (1)扩大品牌效应

    (2)规范标准建立

    (3)研发技术提升

    图表目录
    图表1:人参功能分析

    图表2:人参品种的分类

    图表3:人参行业所属的国民经济分类

    图表4:本报告主要数据来源

    图表5:人参行业监管部门

    图表6:国家层面发布的人参行业现行标准

    图表7:截至2021年我国人参行业相关政策法规

    图表8:截至2021年人参行业相关规划

    图表9:2008-2021年中国GDP增长走势图(单位:亿元,%)

    图表10:2021年主要经济指标增长预测(单位:%)

    图表11:疫情对中国经济影响(2021年GDP增速)的三种可能性(单位:%)

    图表12:2008-2021年中国城镇居民家庭和农村居民家庭人均可支配收入变动图(单位:元,%)

    图表13:2012-2021年中国居民人均可支配收入及增长速度(单位:元,%)

    图表14:2013-2021年中国居民人均消费支出(单位:元)

    图表15:2013-2021年中国居民消费结构情况(单位:元)

    图表16:2011-2021年中国大陆人口数量情况(单位:亿人)

    图表17:2021年年末中国大陆人口数及其构成(单位:万人,%)

    图表18:城市化与医疗行业的关系

    图表19:2000-2021年我国人参行业技术专利申请情况(单位:项)

    图表20:2001-2021年我国人参行业技术专利公开情况(单位:项)

    图表21:截至2021年5月初我国人参行业技术专利申请人排行(前二十位)(单位:项,%)

    图表22:截至2021年5月初中国人参行业技术专利分布领域(前二十位)(单位:项,%)

    图表23:市场环境对人参行业发展的影响评述

    图表24:2010-2021年全球人参行业进出口量走势(单位:吨)

    图表25:2010-2021年全球人参行业进出口金额走势(单位:亿美元)

    图表26:2017-2021年全球人参行业市场规模变化(单位:亿美元)

    图表27:全球人参产量区域格局(单位:%)

    图表28:2021年全球人参行业进口金额国别及地区结构(单位:万美元)

    图表29:2021年全球人参行业出口金额国别及地区结构(单位:万美元)

    图表30:韩国人参产量按细分品种结构(单位:%)

    图表31:2010-2021年韩国人参产量走势(单位:吨)

    图表32:2010-2021年韩国人参行业出口量及出口金额走势(单位:吨,万美元)

    图表33:2010-2021年韩国人参行业进口量及进口金额走势(单位:吨,万美元)

    图表34:2010-2021年美国人参行业出口量及出口金额走势(单位:吨,万美元)

    图表35:2010-2021年美国人参行业进口量及进口金额走势(单位:吨,万美元)

    图表36:2010-2021年加拿大人参行业出口量及出口金额走势(单位:吨,万美元)

    图表37:2010-2021年加拿大人参行业进口金额走势(单位:万美元)

    图表38:韩国人参公社组织架构图

    图表39:2020-2025年全球人参行业市场供给规模预测(单位:万吨)

    图表40:2020-2025年全球人参行业市场需求规模预测(单位:亿美元)

    图表41:我国人参行业发展历程分析

    图表42:人参行业特点分析

    图表43:中国人参行业参与者类型

    图表44:我国国内人参市场传统参类制品企业

    图表45:我国国内人参市场主要医药企业

    图表46:我国国内人参市场品企业

    图表47:2012-2021年中国人参产量变化(单位:吨,%)

    图表48:2015-2025年中国吉林省人参产值情况分析(单位:亿元)

    图表49:人参消费群体分析

    图表50:我国人参购买用途分析(单位:%)

    图表51:我国人参购买渠道分析(单位:%)

    图表52:购买人参时考虑价格分析(单位:%)

    图表53:购买人参时考虑因素分析(单位:%)

    图表54:2017-2021年我国人参表观消费量情况分析(单位:吨)

    图表55:2014-2021年我国人参产业市场规模情况分析(单位:亿元)

    图表56:2018-2021年Q1中国人参行业进出口状况表(单位:万美元,吨)

    图表57:2017-2021年中国人参行业进口情况分析(单位:吨,万美元)

    图表58:2021年中国人参行业进口国别情况分析(单位:吨,万美元)

    图表59:2021年中国人参行业进口贸易方式情况分析(单位:吨,万美元,%)

    图表60:2021年中国人参行业进口企业注册地情况分析(单位:吨,万美元)

    图表61:2017-2021年中国人参行业进口价格水平分析(单位:万美元/吨)

    图表62:2014-2021年中国人参行业出口情况分析(单位:吨,万美元)

    图表63:2021年中国人参行业出口国别及地区TOP10情况分析(按出口数量)(单位:吨)

    图表64:2021年中国人参行业出口国别及地区TOP10情况分析(按出口金额)(单位:万美元)

    图表65:2021年中国人参行业出口贸易方式情况分析(单位:吨,万美元,%)

    图表66:2021年中国人参行业出口企业注册地情况分析(单位:吨,万美元)

    图表67:2017-2021年中国人参行业出口价格水平分析(单位:万美元/吨)

    图表68:人参市场价格的影响因素

    图表69:2019-2021年我国人参市场价格走势(单位:元/斤)

    图表70:人参行业代表性上市公司

    图表71:2015-2021年人参行业四家上市企业营收增长趋势图(单位:亿元)

    图表72:2015-2021年人参行业四家上市企业毛利率趋势图(单位:%)

    图表73:中国人参行业发展痛点分析

    图表74:人参行业现有企业的竞争分析表

    图表75:人参行业对上游议价能力分析表

    图表76:人参行业对下游议价能力分析表

    图表77:人参行业潜在进入者威胁分析表

    图表78:中国人参行业五力竞争综合分析

    图表79:我国国内人参企业产品特征

    图表80:我国人参区域市场消费情况

    图表81:截至2021年4月我国人参市场影响力前十的品牌

    图表82:我国人参产量分布情况(单位:%)

    图表83:2015年以来我国人参行业投资事件汇总

    图表84:2015年以来我国人参行业并购事件汇总

    图表85:人参行业产业链示意图

    图表86:我国人参种植行业存在问题分析

    图表87:我国人参产区情况

    图表88:2016-2021年我国人参种植面积(单位:公顷)

    图表89:我国人参产品甘匡

    图表90:我国人参加工主要工艺流程

    图表91:我国人参清洗机械设备介绍

    图表92:滚筒式人参清洗机示例

    图表93:我国人参烘干主要方法介绍

    图表94:远红外负压烘干机示例

    图表95:我国人参分选机械设备介绍

    图表96:我国人参分选机示例

    图表97:截至2021年5月10日我国人参加工相关设备产品信息(单位:条)

    图表98:中国人参中游细分产品需求概述

    图表99:人参日用品及相关产品分析

    图表100:2016-2021年益盛药业人参化妆品销售收入情况分析(单位:万元,%)

    图表101:我国人参日用品主要企业分析

    图表102:类人参产品分析

    图表103:类人参食品分析

    图表104:2016-2021年益盛药业人参品销售收入情况分析(单位:万元,%)

    图表105:我国人参品主要企业分析

    图表106:中国人参行业线下渠道分析

    图表107:洋参类品线下各销售渠道分布(单位:%)

    图表108:中国人参行业主要线上渠道布局分析

    图表109:吉林省人参产业政策汇总

    图表110:吉林省人参产业分布图

    图表111:2012-2021年吉林省人参播种面积情况(单位:公顷)

    图表112:2012-2021年吉林省人参产量及变化情况(单位:吨,%)

    图表113:2017-2021年Q1吉林省人参行业出口情况分析(单位:吨,万美元)

    图表114:吉林省人参产业市场竞争分析

    图表115:吉林省人参产业发展问题

    图表116:辽宁省人参产业政策汇总

    图表117:2012-2021年辽宁省人参产量及变化情况(单位:吨,%)

    图表118:2017-2021年Q1辽宁省人参行业出口情况分析(单位:吨,万美元)

    图表119:辽宁省人参产业市场竞争分析

    图表120:辽宁省人参产业发展问题
     

    展开全文
  • 电机控制

    千次阅读 2021-11-10 23:56:26
    电机调一、电机相关0、废话1、电机种类2、电机控制方式二、电机控制器1、PID控制器2、PID 各环节作用3、PID 种类三、电机调1、Tmotor 调1.1 控制框图1.2 PID 程序1.3 Tmotor 控制的完整程序1.4 PID 调试技巧2...

    一、电机相关

    电机作为一种能将电能转化为机械能的装置,其在制造、医疗、运动控制等等许多地方都起着重要的作用。想学习了解机器人的小伙伴,从电机了解起走也是一条不错(坎坷)的道路。

    0、废话

       其实电机对于我来说是接触的比较多了的,记得小时候玩四驱车,就特意将“马达”拆开来看过想搞懂原理,也单独将电机拿出来制作了一些小的diy,后来到了高中在学到了电磁学,算是了解了基础的原理了(在不停的刷题后),再后来到大学就是真正的使用了。第一次使用应该是在大一买的单片机,配了一个电机,有程序可以进行调速,但当时由于一些原因,没有再去使用。又到了大三,学习了电机拖动,对电机的认识又深了一点,也做了一些关于电机的实验。但是,令我难以忘记的是研究生开始调试电机的时候,真的是…一言难尽,之前也参考过许多大佬的博客,所以想把自己的这段难忘的经历做个总结,也给有需要的朋友一个参考。

    1、电机种类

    • 电源种类分为:直流电机和交流电机。我们常见常用的电机大多是直流电机,相比前者,交流电机不需要换向器和电刷转换电流方向,与直流电机相比它的结构更简单,功率更大,在工业领域被广泛应用
      在这里插入图片描述

    • 根据有无电刷分为:有刷电机和无刷电机。有刷电机结构简单、开发久技术成熟、响应速度快,起动扭矩大、运行平稳,起制动效果好、控制精度高、使用成本低,维修方便;而无刷电机由于无电刷,具有低干扰、噪音低、运转顺畅、寿命长、低维护成本等优点。于是我接触的以无刷电机为主。
      在这里插入图片描述

    • 根据有无反馈分为:步进电机和伺服电机。前者没有反馈信号,位置精度不够高,且转速远远小于后者。在需要精确的控制,伺服电机更加常用。

    2、电机控制方式

    • 力矩控制:指定电机提供设置大小的力矩。(但是由于力矩传感器太贵了,这里的力矩的大小通常是通过电流换算的,其恒电流情况下,转矩=转矩常数*电流)
    • 速度控制:指定电机达到设置的速度转动。
    • 位置控制:指定电机转动到设置的位置。

    由于位置是速度的积分,所以三种控制方式的控制框图是有要求的,下面是一种常见的控制结构图,当然,如果只针对某一两种控制模式,其控制方案将比这个更加简易。
    在这里插入图片描述

    二、电机控制器

        为了方便用户的使用,市面上许多电机都是针对上面的控制方式进行了封装的,也就是我们常听说的——控制器。控制器的控制方案有许多,针对不同的控制环也有不同的控制方案,例如:对于电流环,有FOC矢量控制,速度、位置环有PID。当然,也有其他的控制算法,但这里我们就使用常用的就行了。现在我们也可以开始谈谈标题了。

    1、PID控制器

        PID 是一种传统且经典的控制算法,在工程中应用非常广泛,相比其他高大上甚至只存在于 paper 上的算法, PID 是非常接地气的。
        PID ,即:Proportional(比例)、Integral(积分)、Differential(微分)的缩写。顾名思义,PID 控制算法是结合比例、积分和微分的融合怪,其规律可以描述为:
    u ( t ) = K p ( e ( t ) + 1 T t ∫ 0 t e ( t ) d t + T d d e ( t ) d t u(t)=K_p(e(t)+\frac{1}{T_t}\int_0^t e(t)dt+T_d\frac{de(t)}{dt} u(t)=Kp(e(t)+Tt10te(t)dt+Tddtde(t)
        其中 K p K_p Kp 是比例增益, T t T_t Tt 是积分时间常数, T d T_d Td 是微分时间常数, u ( t ) u(t) u(t) 是输入信号, e ( t ) e(t) e(t) 是误差。
    在这里插入图片描述

        三个环节在控制中也分别起着不同的控制作用。

    2、PID 各环节作用

    • 比例环节 P:比例环节与稳态误差相关,比例环节越大,上升速度越快,且稳态误差越小,但无论怎样多大都会存在误差,不能消除误差,而且过大还会导致震荡,反而不稳定
      在这里插入图片描述

    • 积分环节 I:积分环节则可以消除误差,合适的积分环节可以很快的消除误差,但是设置较大会产生超调,并且过大也会导致震荡,从而不稳定
      在这里插入图片描述

    • 微分环节 D:微分环节具有预测作用,可以预测信号的变化方向,从而可以减小超调,提高响应速度,但过大会导致系统不稳定
      在这里插入图片描述

    matlab PID 的参考代码如下(上面的图是在下面代码基础上修改了一点,但是核心没有变):

    %%  说明
    % 被控系统: 1/(0.1s+1)
    % 控制器:    PID
    %%
    clc,clear
    ts=0.001;  %采样时间=0.001s
    sys=tf(1,[0.1,1]);            %建立被控对象传递函数
    dsys=c2d(sys,ts,'z')         % 离散化
    [num,den]=tfdata(dsys,'v');   % 得到差分方程系数  y(k) = -den[2]*y(k-1) + num[2]*u(k-1)
    e_last=0;      %前一时刻的偏差      
    E_integ=0;     %累积偏差
    u_last=0.0;    %前一时刻的控制量
    y_last=0;      %前一时刻的输出
    % PID参数
    kp=1;    
    ki=0;
    kd=0;
    u=zeros(1,10000);    %设置仿真长度
    time=zeros(1,10000); %时刻点(设定10000个)
    for k=1:1:10000
        time(k)=k*ts;    %时间
        r(k)=100;        %期望值
        y(k)=-1*den(2)*y_last + num(2)*u_last;    %系统响应输出序列
        e(k)=r(k)-y(k);                           %误差信号
        u(k)=kp*e(k)+ki*E_integ+kd*(e(k)-e_last); %系统PID控制器输出序列
        E_integ=E_integ+e(k);    %误差的累加和
        u_last=u(k);    	     %前一个的控制器输出值
        y_last=y(k);    	     %前一个的系统响应输出值
        e_last=e(k);		     %前一个误差信号的值
    end
    p1=plot(time,r,'-.');xlim([0,1]);hold on; %指令信号的曲线(即期望输入)
    p2=plot(time,y,'--');xlim([0,1]);         %不含积分分离的PID曲线
    hold on;
    

    3、PID 种类

        上面的 PID公示 是针对连续情况下的,而在生活中,我们常常使用的是离散型的变量,比如时间,于是我们需要将 PID 的公式进行离散化,根据离散化的方法不同,PID 控制的公式就有两种,即位置式 PID 和增量式 PID,

    • 位置式 PID
      u ( n ) = K p ∗ e ( n ) + K i ∗ ∑ e ( n ) + K d ∗ [ e ( n ) − e ( n − 1 ) ] / T u(n)=K_p*e(n)+K_i*\sum e(n)+K_d*[e(n)-e(n-1)]/T u(n)=Kpe(n)+Kie(n)+Kd[e(n)e(n1)]/T
      从公式结构上看,位置式存在积分环节,误差会进行累加,当积分项饱和时,误差仍然会进行累加,当误差反向变化时,系统还需要一定时间从饱和区退出,所以常常需要积分限幅和输出限幅,实际使用位置式 pid 时一般常常使用 PD 进行控制。
    • 增量式 PID
      Δ u ( n ) = K p ∗ [ e ( n ) − e ( n − 1 ) ] + K i ∗ e ( n ) + K d ∗ [ e ( n ) − 2 ∗ e ( n − 1 ) + e ( n − 2 ) ] / T \Delta u(n)=K_p*[e(n)-e(n-1)]+K_i* e(n)+K_d*[e(n)-2*e(n-1)+e(n-2)]/T Δu(n)=Kp[e(n)e(n1)]+Kie(n)+Kd[e(n)2e(n1)+e(n2)]/T
      增量式不包含积分环节,控制增量只与前后三次测量值有关,对外界的抗扰性比位置式更好。
    • 两者关系
      可以看到前者计算得到的是输入量,而后者算得的是输入增量,许多同学可能已经猜到了后者就是前者差分得到的
      想更加具体的了解两者关系,可以看这位博主的: 传送门.

    三、电机调参

        常见的调参方式是比较快乐的,直接在生产商写好的驱动下进行参数的设置以及测试,找到合适的参数,更有的还有调参软件,遍历参数寻找合适的参数,从而省去人工调试的复杂环节。
        但这里想要分享的调参方法要多一点步骤,但是大体方向是不变的,这里以 Tmotor 的 AK10-9 与 大疆的 M2006 两款无刷直流电机为例子进行介绍。

    1、Tmotor 调参

        Tmotor 的电机本来是有调参软件的,但是最开始的时候由于资料不完善,加上他的控制环不符合我们的应用要求,所以我们需要进行简单的修改。

    1.1 控制框图

    Tmotor 的运动控制框图如下,可以看到他的电流环采用 FOC 矢量控制,我们不能修改,另外两个环,速度环和位置环,只有比例环节,不能达到无误差的目标,所以我们需要在他的电流环上进行编写封装。
    在这里插入图片描述
    我们需要的控制环应该如下:
    在这里插入图片描述
    下面我们先编写控制程序。

    1.2 PID 程序

    之前探讨过离散 PID 有位置式 PID 算法和增量式 PID 算法,下面是根据其公式编写的 PID 程序,在使用之前需要稍稍修改一下参数。
    位置式 PID

    ********************位置式 PID**************************
    ***        输入参数:电机电流速度位置等反馈值fed        ***
    ********************************************************
    typedef struct PID
    {
    	float target;    //目标参考值
    	float  deadband; //定义电机死区
    	float err_now;   //定义当前误差
    	float err_last;  //定义上一时刻误差
    	float kp;        //比例环节系数
    	float ki;        //积分环节系数
    	float kd;        //微分环节系数,这里已将时间常数包含进去
    	float Pout;      //比例环节输出
    	float Iout;      //积分环节输出
    	float Dout;      //微分环节输出
    	float IntegLimt; //设置积分限幅
    	float output;    //输出量
    	float OutputLimt;//输出限幅
    }PID_PARM;
    
    //初始化PID参数的函数
    void PID_parm_Init(PID_PARM *PID_parm,float target,float kp,float ki,float kd,float IntegLimt,float OutputLimt)
    {
    	PID_parm->target = target; 
    	PID_parm->err_now = 0;
    	PID_parm->err_last = 0;
    	PID_parm->kp = kp; 
    	PID_parm->ki = ki; 
    	PID_parm->kd = kd; 
    	PID_parm->Pout = 0;
    	PID_parm->Iout = 0;
        PID_parm->Dout = 0;
    	PID_parm->IntegLimt = IntegLimt;
    	PID_parm->output = 0; 
    	PID_parm->OutputLimt = OutputLimt;
    }
    
    //计算PID的函数
    float PID_cal(PID_PARM *pid_parm,float feedback)
    {
    	pid_parm->err_now = pid_parm->target - feedback;
    	pid_parm->Pout = pid_parm->kp*pid_parm->err_now;
    	pid_parm->Iout += pid_parm->ki*pid_parm->err_now;
    	pid_parm->Dout = pid_parm->kd*(pid_parm->err_now-pid_parm->err_last);
    	//积分限幅
    	if(pid_parm->Iout > pid_parm->IntegLimt)  pid_parm->Iout = pid_parm->IntegLimt;
    	else if(pid_parm->Iout < -pid_parm->IntegLimt)  pid_parm->Iout = -pid_parm->IntegLimt;
    	//输出限幅
    	pid_parm->output = pid_parm->Pout + pid_parm->Iout + pid_parm->Dout;
    	if(pid_parm->output > pid_parm->OutputLimt)  pid_parm->output = pid_parm->OutputLimt;
    	else if(pid_parm->output < -pid_parm->OutputLimt)  pid_parm->output = -pid_parm->OutputLimt;
    	//数据更新
    	pid_parm->err_last = pid_parm->err_now;
    	return  pid_parm->output;
    }
    
    float u;                  
    PID_PARM pid_parm;
    PID_parm_Init(&pid_parm,10,1,0.1,,0.5,50,100);  //这里的参数随机给的,具体参数需要调节
    u = PID_cal(&pid_parm,fed);                     //计算出来的下一次输入
    

    增量式 PID

    ********************增量式 PID**************************
    ***        输入参数:电机电流速度位置等反馈值fed        ***
    ********************************************************
    typedef struct PID
    {
    	float target;      //目标参考值
    	float  deadband; //定义电机死区
    	float err_now;     //定义当前误差
    	float err_last;    //定义上一时刻误差
    	float err_llast;    //定义上上时刻误差
    	float kp;          //比例环节系数
    	float ki;          //积分环节系数
    	float kd;          //微分环节系数,这里已将时间常数包含进去
    	float Pout;        //比例环节输出
    	float Iout;        //积分环节输出
    	float Dout;        //微分环节输出
    	float output;      //输出增量
    	float output_last; //上一次输出的增量
    	float OutputLimt;  //输出限幅
    }PID_PARM;
    
    //初始化PID参数的函数
    void PID_parm_Init(PID_PARM *PID_parm,float target,float kp,float ki,float kd,float OutputLimt)
    {
    	PID_parm->target = target; 
    	PID_parm->err_now = 0;
    	PID_parm->err_last = 0;
    	PID_parm->err_llast = 0;
    	PID_parm->kp = kp; 
    	PID_parm->ki = ki; 
    	PID_parm->kd = kd; 
    	PID_parm->Pout = 0;
    	fPID_parm->Iout = 0;
    	PID_parm->Dout = 0;
    	PID_parm->output = 0; 
    	PID_parm->output_last = 0; 
    	PID_parm->OutputLimt = OutputLimt;
    }
    
    //计算PID的函数
    float PID_cal(PID_PARM *pid_parm,float feedback)
    {
    	pid_parm->err_now = pid_parm->target - feedback;
    	pid_parm->Pout = pid_parm->kp*(pid_parm->err_now - pid_parm->err_last);
    	pid_parm->Iout = pid_parm->ki*pid_parm->err_now;
    	pid_parm->Dout = pid_parm->kd*(pid_parm->err_now - 2*pid_parm->err_last + pid_parm->err_llast);
    	//输出限幅
    	pid_parm->output += pid_parm->Pout + pid_parm->Iout + pid_parm->Dout;
    	if(pid_parm->output > pid_parm->OutputLimt)  pid_parm->output = pid_parm->OutputLimt;
    	else if(pid_parm->output < -pid_parm->OutputLimt)  pid_parm->output = -pid_parm->OutputLimt;
    	//数据更新
    	pid_parm->err_llast = pid_parm->err_last;
    	pid_parm->err_last = pid_parm->err_now;
    	pid_parm->output_last = pid_parm->output;
    	return  pid_parm->output;
    }
    
    float u;                  
    PID_PARM pid_parm;
    PID_parm_Init(&pid_parm,10,1,0.1,,0.5,100);  //这里的参数随机给的,具体参数需要调节
    u = PID_cal(&pid_parm,fed);                  //计算出来的下一次输入
    

    1.3 Tmotor 控制的完整程序

    这里采用的 stm32 进行控制的,工程文件全部在下面:

    • 头文件们

    key.h

    #ifndef __KEY_H
    #define __KEY_H	 
    #include "sys.h"  	 
    
    /*下面的方式是通过直接操作库函数方式读取IO*/
    #define KEY0 		GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4) //PE4
    #define KEY1 		GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)	//PE3 
    #define KEY2 		GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2) //PE2
    #define WK_UP 	GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)	//PA0
    
    #define KEY0_PRES 	1
    #define KEY1_PRES	2
    #define KEY2_PRES	3
    #define WKUP_PRES   4
    
    void KEY_Init(void);	//IO初始化
    u8 KEY_Scan(u8);  		//按键扫描函数	
    
    #endif
    

    can.h

    #ifndef __CAN_H
    #define __CAN_H	 
    #include "sys.h"	    	 					    
    	
    void CAN1_Init(void);//CAN1初始化
     
    u8 CAN1_Send_Msg(u8* msg);						//发送数据 
    u8 CAN1_Receive_Msg(u8 *buf);
    
    #endif
    

    pid.h

    #ifndef __PID_H
    #define __PID_H	 
    #include "sys.h"	
    #include "stdlib.h"
    
    typedef struct PID
    {
    	float target;      //目标参考值
    	float deadband;    //定义电机死区
    	float err_now;     //定义当前误差
    	float err_last;    //定义上一时刻误差
    	float err_llast;   //定义上上时刻误差
    	float kp;          //比例环节系数
    	float ki;          //积分环节系数
    	float kd;          //微分环节系数,这里已将时间常数包含进去
    	float Pout;        //比例环节输出
    	float Iout;        //积分环节输出
    	float Dout;        //微分环节输出
    	float IntegLimt;   //设置积分限幅
    	float output;      //输出量
    	float output_last; //上一次输出的增量
    	float OutputLimt;  //输出限幅
    }PID_PARM;
    
    void  PID_parm_Init(PID_PARM *PID_parm,float target,float deadband,float kp,float ki,float kd,float IntegLimt,float OutputLimt);
    float Pos_PID_cal(PID_PARM *pid_parm,float feedback);
    float Inc_PID_cal(PID_PARM *pid_parm,float feedback);
    void PID_init(PID_PARM *Spd_PID,PID_PARM *Pos_PID);
    
    #endif
    

    motor.h

    #ifndef __MOTOR_H
    #define __MOTOR_H	 
    #include "sys.h"	    	 
    #include "pid.h"
    
    #define pi 3.1415926
    #define P_MAX   12.5
    #define P_MIN  -12.5
    #define V_MAX  46.57
    #define V_MIN  -46.57
    #define KP_MAX  500
    #define KP_MIN  0
    #define KD_MAX  5
    #define KD_MIN  0
    #define T_MAX  54
    #define T_MIN  -54
    
    extern u8 Tmotor_Mod_Buf[3][8];
    
    typedef enum
    {
    	Tmotor_Open = 0xfc,
    	Tmotor_Close = 0xfd,
    	Tmotor_SetZero = 0xfe,
    }Tmotor_Mod;
    
    typedef struct{
    	u8 id;                  	// id
    	int16_t	 	speed_rps;    	// rad/s
    	int16_t  	real_torque; 	  // 反馈力矩
    
    	uint16_t 	angle;			    // 绝对角度
    }Tmotor_measure_t;
    
    extern Tmotor_measure_t  TmotorData;    // 保存Tmotor电机的状态
    
    int float_to_uint(float x, float x_min, float x_max, int bits);
    float uint_to_float(int x_int, float x_min, float x_max, int bits);
    float limitf(float val, float min_val, float max_val);
    
    void Tmotor_mod(u8 mod);
    void get_Tmotor_measure(Tmotor_measure_t *ptr, CanRxMsg *Rxmsg);
    u8 set_Tmotor_torque(float torque);
    
    void Tmotor_Speed_Control(PID_PARM *PID_spd,float target);
    void Tmotor_Position_Control(PID_PARM *PID_spd,PID_PARM *PID_pos,float target);
    
    #endif
    
    • 源文件们

    key.c

    #include "key.h"
    #include "delay.h" 
    
    void KEY_Init(void)
    {
    	 GPIO_InitTypeDef  GPIO_InitStructure;
    	 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOE, ENABLE);//使能GPIOE时钟
    	
    	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4; //KEY0 KEY1 KEY2对应引脚
    	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通输入模式
    	 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100M
    	 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
    	 GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE2,3,4
    	
    	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//WK_UP对应引脚PA0
    	 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN ;//下拉
    	 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA0
    } 
    //按键处理函数
    //返回按键值
    //mode:0,不支持连续按;1,支持连续按;
    //0,没有任何按键按下
    //1,KEY0按下
    //2,KEY1按下
    //3,KEY2按下 
    //4,WKUP按下 WK_UP
    //注意此函数有响应优先级,KEY0>KEY1>KEY2>WK_UP!!
    u8 KEY_Scan(u8 mode)
    {	 
    	static u8 key_up=1;//按键按松开标志
    	if(mode)key_up=1;  //支持连按		  
    	if(key_up&&(KEY0==0||KEY1==0||KEY2==0||WK_UP==1))
    	{
    		delay_ms(10);//去抖动 
    		key_up=0;
    		if(KEY0==0)return 1;
    		else if(KEY1==0)return 2;
    		else if(KEY2==0)return 3;
    		else if(WK_UP==1)return 4;
    	}else if(KEY0==1&&KEY1==1&&KEY2==1&&WK_UP==0)key_up=1; 	    
     	return 0;// 无按键按下
    }
    

    can.c

    #include "can.h"
    #include "motor.h"
    
    Tmotor_measure_t  TmotorData;
    
    void CAN1_Init()
    {
    	u8 tsjw = CAN_SJW_1tq;
    	u8 tbs2 = CAN_BS2_4tq;
    	u8 tbs1 = CAN_BS1_2tq;
    	u16 brp = 6;
    	u8 mode = CAN_Mode_Normal;     // 提前配置好波特率  这里是1000k
    	
      	GPIO_InitTypeDef GPIO_InitStructure; 
    	CAN_InitTypeDef        CAN_InitStructure;
      	CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    
       	NVIC_InitTypeDef  NVIC_InitStructure;
    
        //使能相关时钟
    	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能PORTA时钟	                   											 
    
      	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟	
    	
        //初始化GPIO
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11| GPIO_Pin_12;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
        GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化PA11,PA12
    	
    	  //引脚复用映射配置
    	GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_CAN1); //GPIOA11复用为CAN1
    	GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_CAN1); //GPIOA12复用为CAN1
    	  
      	//CAN单元设置
       	CAN_InitStructure.CAN_TTCM=DISABLE;	//非时间触发通信模式   
      	CAN_InitStructure.CAN_ABOM=ENABLE;	//软件自动离线管理	  
      	CAN_InitStructure.CAN_AWUM=DISABLE;//睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
      	CAN_InitStructure.CAN_NART=ENABLE;	//禁止报文自动传送 
      	CAN_InitStructure.CAN_RFLM=DISABLE;	//报文不锁定,新的覆盖旧的  
      	CAN_InitStructure.CAN_TXFP=DISABLE;	//优先级由报文标识符决定 
      	CAN_InitStructure.CAN_Mode= mode;	 //模式设置 
      	CAN_InitStructure.CAN_SJW=tsjw;	//重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq~CAN_SJW_4tq
      	CAN_InitStructure.CAN_BS1=tbs1; //Tbs1范围CAN_BS1_1tq ~CAN_BS1_16tq
      	CAN_InitStructure.CAN_BS2=tbs2;//Tbs2范围CAN_BS2_1tq ~	CAN_BS2_8tq
      	CAN_InitStructure.CAN_Prescaler=brp;  //分频系数(Fdiv)为brp+1	
      	CAN_Init(CAN1, &CAN_InitStructure);   // 初始化CAN1 
        
    		//配置过滤器
     	CAN_FilterInitStructure.CAN_FilterNumber=0;	  //过滤器0
      	CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; 
      	CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位 
      	CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;32位ID
      	CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
      	CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32位MASK
      	CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
       	CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
      	CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0
      	CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化
    		
    	  CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);//FIFO0消息挂号中断允许.		    
      
      	NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
      	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;     // 主优先级为1
      	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;            // 次优先级为2
      	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      	NVIC_Init(&NVIC_InitStructure);
    
    }   
    
    void CAN1_RX0_IRQHandler(void)
    {
      	CanRxMsg RxMessage;
        CAN_Receive(CAN1, 0, &RxMessage);
    	if(RxMessage.StdId == 0x00)
    			get_Tmotor_measure(&TmotorData, &RxMessage);	
    }
    
    u8 CAN1_Send_Msg(u8* msg)
    {	
    		u8 mbox;
    		u16 i=0;
    		CanTxMsg TxMessage;
    		TxMessage.StdId=0x01;	 
    		TxMessage.ExtId=0x00;	 
    		TxMessage.IDE=0;		  
    		TxMessage.RTR=0;		  
    		TxMessage.DLC=8;		
    		for(i=0;i<8;i++)
    			TxMessage.Data[i]=msg[i];				 	
    		mbox= CAN_Transmit(CAN1, &TxMessage);  
    		i=0;
    		while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++;
    		if(i>=0XFFF)return 1;
    		return 0;		
    }
    
    u8 CAN1_Receive_Msg(u8 *buf)
    {		   		   
    		u8 i;
    		CanRxMsg RxMessage;
    		if( CAN_MessagePending(CAN1,CAN_FIFO0)==0)return 0;		//没有接收到数据,直接退出 
    		CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);//读取数据	
    		for(i=0;i<RxMessage.DLC;i++)
    			buf[i]=RxMessage.Data[i]; 
    		return RxMessage.DLC;	
    }
    

    pid.c

    #include "pid.h"
    
    //初始化PID参数的函数
    void PID_parm_Init(PID_PARM *PID_parm,float target,float deadband,float kp,float ki,float kd,float IntegLimt,float OutputLimt)
    {
    	PID_parm->target = target; 
    	PID_parm->deadband = deadband;
    	PID_parm->err_now = 0;
    	PID_parm->err_last = 0;
    	PID_parm->err_last = 0;
    	PID_parm->kp = kp; 
    	PID_parm->ki = ki; 
    	PID_parm->kd = kd; 
    	PID_parm->Pout = 0;
    	PID_parm->Iout = 0;
    	PID_parm->Dout = 0;
    	PID_parm->IntegLimt = IntegLimt;
    	PID_parm->output = 0; 
    	PID_parm->output_last = 0;
    	PID_parm->OutputLimt = OutputLimt;
    }
    
    //计算位置PID的函数
    float Pos_PID_cal(PID_PARM *pid_parm,float feedback)
    {
    	pid_parm->err_now = pid_parm->target - feedback;
    	pid_parm->Pout = pid_parm->kp*pid_parm->err_now;
    	pid_parm->Iout += pid_parm->ki*pid_parm->err_now;
    	pid_parm->Dout = pid_parm->kd*(pid_parm->err_now-pid_parm->err_last);
    	//积分限幅
    	if(pid_parm->Iout > pid_parm->IntegLimt)  pid_parm->Iout = pid_parm->IntegLimt;
    	else if(pid_parm->Iout < -pid_parm->IntegLimt)  pid_parm->Iout = -pid_parm->IntegLimt;
    	//输出限幅
    	pid_parm->output = pid_parm->Pout + pid_parm->Iout + pid_parm->Dout;
    	if(pid_parm->output > pid_parm->OutputLimt)  pid_parm->output = pid_parm->OutputLimt;
    	else if(pid_parm->output < -pid_parm->OutputLimt)  pid_parm->output = -pid_parm->OutputLimt;
    	//数据更新
    	pid_parm->err_last = pid_parm->err_now;
    	return  pid_parm->output;
    }
    
    //计算增量PID的函数
    float Inc_PID_cal(PID_PARM *pid_parm,float feedback)
    {
    	pid_parm->err_now = pid_parm->target - feedback;
    	pid_parm->Pout = pid_parm->kp*(pid_parm->err_now - pid_parm->err_last);
    	pid_parm->Iout = pid_parm->ki*pid_parm->err_now;
    	pid_parm->Dout = pid_parm->kd*(pid_parm->err_now - 2*pid_parm->err_last + pid_parm->err_llast);
    	//输出限幅
    	pid_parm->output += pid_parm->Pout + pid_parm->Iout + pid_parm->Dout;
    	if(pid_parm->output > pid_parm->OutputLimt)  pid_parm->output = pid_parm->OutputLimt;
    	else if(pid_parm->output < -pid_parm->OutputLimt)  pid_parm->output = -pid_parm->OutputLimt;
    	//数据更新
    	pid_parm->err_llast = pid_parm->err_last;
    	pid_parm->err_last = pid_parm->err_now;
    	pid_parm->output_last = pid_parm->output;
    	return  pid_parm->output;
    }
    
    //初始化PID参数
    void PID_init(PID_PARM *Spd_PID,PID_PARM *Pos_PID)
    {
    		PID_parm_Init(Pos_PID,0,0.1,0.6,0,2,180,200);      
    		PID_parm_Init(Spd_PID,0,0.01,0.2,0.001,0,0.5,54);  
    }
    

    motor.c

    #include "delay.h"
    #include "motor.h"
    #include "usart.h"
    #include "can.h"
    #include "pid.h"
    
    u8 Tmotor_Mod_Buf[3][8] =
    {  //电机模式指令
    	{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc},
    	{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd},
    	{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe}
    };
    
    //数值转换函数/
    /*                                            /
    float_to_uint: 浮点转整型                     /
    uint_to_float: 整形变浮点                     /
    limitf:        限幅函数                       /
    */                                            /
    ///
    int float_to_uint(float x, float x_min, float x_max, int bits)
    {
        float span = x_max - x_min;
        float offset = x_min;
        return (int) ( (x - offset) * ( (float) ((1<<bits) - 1)) / span);
    }
    
    
    float uint_to_float(int x_int, float x_min, float x_max, int bits)
    {
        float span = x_max - x_min;
        float offset = x_min;
        return ((float) x_int) * span / ((float) ((1<<bits) - 1)) + offset;
    }
    
    
    float limitf(float val, float min_val, float max_val)
    {
    		float val_real = 0.0f;
    		if (val < min_val){
    				val_real = min_val;
    				return val_real;
    		}
    		else if (val > max_val){
    				val_real = max_val;
    			  return val_real;
    		}
    		else{
    				val_real = val;
    			  return val_real;
    		}
    }
    
    /Tmotor电机指令
    /*                                                        /
    Tmotor_mod:           设置电机模式(开、关、设置零点)    /
    get_Tmotor_measure:   获取电机的反馈数据(16进制的)        /
    set_Tmotor_torque:    设置电机力矩                        /
    */                                                        /
    ///
    void Tmotor_mod(u8 mod)
    {
    	switch(mod)
    	{
    		case Tmotor_Open:
    			CAN1_Send_Msg(Tmotor_Mod_Buf[0]);
    		break;
    		
    		case Tmotor_Close:
    			set_Tmotor_torque(0.0f);
    			delay_ms(10);
    			CAN1_Send_Msg(Tmotor_Mod_Buf[1]);
    		break;
    		
    		case Tmotor_SetZero:
    			CAN1_Send_Msg(Tmotor_Mod_Buf[2]);
    		break;
    		default:
    			break;
    	}
    }
    
    
    void get_Tmotor_measure(Tmotor_measure_t *ptr, CanRxMsg *Rxmsg)
    { 
    		ptr->id = Rxmsg->Data[0];                                              //电机id
    		ptr->angle = (uint16_t)(Rxmsg->Data[1]<<8 | Rxmsg->Data[2]);           //电机位置
    		ptr->speed_rps  = (uint16_t)(Rxmsg->Data[3]<<4 | Rxmsg->Data[4]>>4);   //电机速度
    		ptr->real_torque = ((Rxmsg->Data[4]&0x0f)<<8 | Rxmsg->Data[5]);        //电机力矩
    }
    
    
    u8 set_Tmotor_torque(float torque)
    {	
    		int p_int,v_int,kp_int,kd_int,t_int;
    		u8 mbox;
    		u16 i=0;
    		CanTxMsg TxMessage;	
    		// 由于采用力矩模式,不使用位置和速度模式
    		kp_int = float_to_uint(0,KP_MIN,KP_MAX,12);
    		kd_int = float_to_uint(0,KD_MIN,KD_MAX,12);
    		p_int = float_to_uint(0,P_MIN,P_MAX,16);
    		v_int = float_to_uint(0,V_MIN,V_MAX,12);
    		// 真正需要设置的是力矩
    		t_int = float_to_uint(torque,T_MIN,T_MAX,12);
    		
    		TxMessage.StdId=0x01;	 // 标准标识符为1
    		TxMessage.ExtId=0x12;	    // 设置扩展标示符(29位)这里不需要设置
    		TxMessage.IDE=0;		  // 使用扩展标识符
    		TxMessage.RTR=0;		  // 消息类型为数据帧,一帧8位
    		TxMessage.DLC=0x08;							 // 发送两帧信息
    
    		TxMessage.Data[0] = p_int>>8;       //位置高8位
    		TxMessage.Data[1] = p_int&0xFF;     //位置低8位
    		TxMessage.Data[2] = v_int>>4;       //速度高8位
    		TxMessage.Data[3] = ((v_int&0xF)<<4)|(kp_int>>8);  //速度低4位  KP高4位
    		TxMessage.Data[4] = kp_int&0xFF;    //KP低8位
    		TxMessage.Data[5] = kd_int>>4;		//KD高8位
    		TxMessage.Data[6] = ((kd_int&0xF)<<4)|(t_int>>8);  //KP低4位  扭矩高4位
    		TxMessage.Data[7] = t_int&0xFF;		//扭矩低8位
    		mbox= CAN_Transmit(CAN1, &TxMessage);   
    		i=0;
    		while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++;	//等待发送结束
    		if(i>=0XFFF)return 1;
    		return 0;		
    }
    
    /Tmotor电机控制模式
    /*                                                        /
    Tmotor_Speed_Control:   	速度控制                        /
    Tmotor_Postion_Control:   位置控制                        /
    */                                                        /
    ///
    
    void Tmotor_Speed_Control(PID_PARM *PID_spd,float target)
    {
    		// 需要先初始化pid参数
    		// 速度环采用单环即可
    		//  spd单位rpm  所以将反馈的数据 *60/(2*pi)
    		float set_torque;
    		PID_spd->target = target;
    		set_torque = Inc_PID_cal(PID_spd,uint_to_float(TmotorData.speed_rps,V_MIN,V_MAX,12) * 60/(2*pi));
    		printf("v:%f\n",uint_to_float(TmotorData.speed_rps,V_MIN,V_MAX,12)* 60/(2*pi));
    		set_Tmotor_torque(set_torque);
    		
    }
    
    void Tmotor_Position_Control(PID_PARM *PID_spd,PID_PARM *PID_pos,float target)
    {
    		//位置控制模式需要设置双环
    		//采用速度内环和位置外环
    		//电机反馈的角度单位是rad,需要转换为°,所以*180.f/pi
    		float set_torque;
    		float set_spd;
    		PID_pos->target = target;
    		set_spd = Pos_PID_cal(PID_pos,uint_to_float(TmotorData.angle,P_MIN,P_MAX,16) * 180.f/pi);
    		printf("p:%f\n",uint_to_float(TmotorData.angle,P_MIN,P_MAX,16) * 180.f/pi);
    		PID_spd->target = set_spd;
    		set_torque = Inc_PID_cal(PID_spd,uint_to_float(TmotorData.speed_rps,V_MIN,V_MAX,12)*30.f/pi);
    		set_Tmotor_torque(set_torque);
    }
    

    main.c

    #include "sys.h"
    #include "delay.h"
    #include "usart.h"
    #include "led.h"
    #include "can.h"
    #include "key.h"
    #include "pid.h"
    #include "motor.h"
    
    int main(void)
    { 	
    		u8 key;
    		u8 key_flag = 0;
    		u8 open_flag = 0;
    		float spd_target = 60;
    		float pos_target = 0;
    		PID_PARM PID_pos;
    		PID_PARM PID_spd;
    		//初始化相关基础模块
    		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
    		CAN1_Init();  // 设置CAN波特率为1000k
    		delay_init(168);  //初始化延时函数
    		LED_Init();				//初始化LED端口
    		KEY_Init();
    		uart_init(115200);
    		
    		//初始化pid参数
    		PID_init(&PID_spd,&PID_pos);
    		//Tmotor_mod(Tmotor_Open);
    		LED0 = 0;
    		//按键控制电机模式
    		while(1)
    		{
    			key = KEY_Scan(0);	
    			//printf("%d",key);
    			if(key)		
    			{				
    					switch(key)
    					{				 
    						case WKUP_PRES:	
    							Tmotor_mod(Tmotor_Close);
    							open_flag = 0;
    							break;
    						case KEY0_PRES:	
    							key_flag = 1;
    							pos_target += 10;
    							spd_target += 10;
    							break;
    						case KEY1_PRES:	 
    							Tmotor_mod(Tmotor_Open);
    							open_flag = 1;
    							break;
    						case KEY2_PRES:	
    							key_flag = 0;
    							break;
    					}
    			}else delay_ms(10);
    			//当需要执行时			
    			if(open_flag & key_flag)
    			{
    					Tmotor_Speed_Control(&PID_spd,spd_target);
    					//Tmotor_Position_Control(&PID_spd,&PID_pos,pos_target);
    					LED0 = ~LED0;
    					delay_ms(10);
    			}
    			//delay_ms(100);
    		}
    		return 0;
    }   
    

    1.4 PID 调试技巧

        PID 的调试是比较复杂的一个活,所以一般来说都会有调参软件的,当当当当~
        这里当然没有了。。。
        所以我们就只有采用手动试!
        还有一点,我们现在考虑的是位置速度双闭环的系统,针对这个系统我们来进行调试。
        在试之前,我们还需要了解的是,位置式 PID 是输出的位置量(不一定就是位置),常用在位置环(双环时),增量式 PID 是输出的增量,存在稳态误差,常用在内环。同时考虑到位置是速度积分量,所以需要将速度环放在内部,位置环放在外部,先调内环,再调外环,调试的时候,可以先固定微分和积分环节为零,不断的从小到大增大比例环节,在增大到电机抖动就说明不行了,得降低,下降到稳态误差比较小且电机不抖得情况下,尝试增加积分,一点点加,加到电机转动不抖动且稳态误差几乎消除时即可,一般情况下此时稳态误差还会存在,且会伴随着电机在目标值附近来回徘徊,或者出现电机出现超调,即输出值先一下子大于目标值后然后降低到目标值附近(徘徊),这时就需要添加微分环节了,可以消除这个超调哦。调试好内环后,按照同样得方式调试外环参数,最终获得一个比较满意得参数即可。

    2、M2006(M3508)调参

        做过RoboMaster比赛的同学应该接触的比较多,M2006与M3508是大疆出产的两款直流无刷减速电机,由于体积重量和所能提供的力矩大小各有特色各有不同的作用,之前因为项目原因简单的玩了一下。两款电机配备有各自的电机调速器(控制器),我们需要在其基础上对其进行控制。

    2.1 M2006(M3508)控制框图

        该电机只有底层的电流环,速度环和位置环均不存在,但其实和 Tmotor 电机的控制类似,我们同样可以在其上编写位置环和速度环控制。
    在这里插入图片描述
        添加了速度环和位置环的控制框图如下,和上面的其实并没有区别。
    在这里插入图片描述

    2.2 M2006与M3508 完整的控制程序

        具体的控制程序并没有太大区别,不同的只有给定电流的指令。
        具体文件参考 Tmotor 文件进行修改。

    2.3 调试技巧

        大疆的电机和 Tmotor 控制指令的执行是有区别的,Tmotor 的电机给了电流指令后,它会保存这个指令一直执行,所以只需要给定一次就好了;而 DJI 的它是以矩形波的形式让给定电流维持一小段时间,所以需要不断的给定电流指令。具体的调试技巧和上面大同小异,除了参数的问题,还需要注意指令发送的频率,一般来说100HZ左右都是可以达到比较满意的工况的。

    四、存在的问题

        在上面的电机控制中,运行程序的朋友们会发现电机依然存在问题,其中最明显的就是启动时的抖动问题,这个问题也是可以解决的,比如变 PID 控制或者对启动电流进行限制,实现软启动,也可以对电流上升的速度或加速度进行一个限制,如果有机会的话将会在后面将解决后的方案与大家分享。

    展开全文
  • 随机森林调 - python

    2021-03-04 11:33:48
    文章目录1、一般的模型调原则2、随机森林的随机性体现在哪几个方面?2.1 数据集的随机选取2.2 待选特征的随机选取3、为什么使用随机森林?4、随机森林的构建过程5、随机森林优缺点总结5.1 优点5.2 缺点6、特征重要...
  • 深度学习如何调

    2020-12-19 12:14:12
    原标题:深度学习如何调?对于深度学习本人也是半路出家. 现在的工作内容主要就是使用CNN做CV任务. 干调这种活也有两年时间了. 我的回答可能更多的还是侧重工业应用, 技术上只限制在CNN这块.先说下我的观点, 调...
  • 深度学习调参及训练技巧(转)作者:婉儿飞飞链接:https://www.jianshu.com/p/0b116c43eb16来源:简书简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。1. 调训练技巧对深度学习来说是非常...
  • 方法的概念好处 方法的声明即调用 数组 1.循环的嵌套 ​ 在循环里又进行循环,任意循环都可以相互嵌套 ​ 【说明】实际开发中,循环嵌套不超过三层 ​ 使用场景1:打印图形 ​ 二重循环: ​ 外层循环控制:...
  • 在支持向量机(以下简称SVM)的核函数中,高斯核(以下简称RBF)是最常用的,从理论上讲, ...如果线性核不好,我们就需要使用RBF,在享受RBF对非线性数据的良好分类效果前,我们需要对主要的超参数进行选取。本文我们...
  • 本次任务选择lightgbm进行建模调。 1.关于lightgbm LightGBM 由微软提出,主要用于解决 GDBT 在海量数据中遇到的问题,以便其可以更好更快地用于工业实践中。LightGBMGDBT都是boosting的方法,即基模型的训练是...
  • 作者: @Captain Jack 北京理工大学,个人blog主页『运筹OR帷幄』责任编辑: @文雨之(东北大学系统工程博士生)本篇文章是由以上作者在知乎的优秀回答(原文链接: 深度学习调有哪些技巧?),通过『运筹OR帷幄』责任...
  • 相机内参和外的解释

    千次阅读 2021-03-26 18:41:36
    2-110468692&spm=3001.4430 相机内参和外的解释 谁的锅 2020-12-02 09:56:57 553 收藏 1 分类专栏: 相机 文章标签: 其他 版权 相机内参分为内参矩阵和畸变参数矩阵 1、下面给出了内参矩阵,需要注意的是,真实的...
  • 特点 1、减少代码冗余,提高代码复用性,增强程序维护性与可扩展性 2、方法定义,不调用不执行 3、方法定义在最外层作用域中,并且不能在方法中定义方法 使用 方法需要调用才会执行。所以我们需要调用,在 main ...
  • 循环神经网络 为了说明最后一个例子,一个经典的分类器(上图的左边)接收前面的字母;这个字母会被传入隐藏层(用蓝色表示),网络会推导出一个输出。一个循环的神经网络在结构上是不同的。每个单元(用红色表示)不仅连接...
  • sklearn中SVM调说明

    2021-01-12 05:18:15
    写在前面之前只停留在理论上,没有实际沉下心去调,实际去做了后,发现调是个大工程(玄学)。于是这篇来总结一下sklearn中svm的参数说明以及调经验。方便以后查询和回忆。常用核函数1.linear核函数:K(xi,xj)=...
  • 深度学习调trick 调技巧
  • 深度学习调技巧

    2020-12-19 12:14:11
    深度学习调技巧训练技巧对深度学习来说是非常重要的,作为一门实验性质很强的科学,同样的网络结构使用不同的训练方法训练,结果可能会有很大的差异。1.参数初始化下面几种方式,随便选一个,结果基本都差不多。...
  • 几乎所有机器学习领域都可以看到集成学习的身影,现实中集成学习也有很大作用: 市场营销模拟的建模 统计客户来源,保留和流失 预测疾病的风险和病患者的易感性 在现在的算法竞赛中,随机森林、梯度提升树(GBDT),...
  • 作用:用来初始化类,对象。比如我们连接数据库的时候 需要打开连接,可以使用代码块进行数据库的连接操作。 分类:静态代码块和非静态代码块 静态代码块: 》内部可以有输出语句 》随着类的加载而执行,...
  • XGBoost调指南

    千次阅读 2020-12-23 14:22:35
    典型值有: rmse 均方根误差 mae 平均绝对误差 logloss 负对数似然函数值 error 二分类错误率(阈值为0.5) merror 多分类错误率 mlogloss 多分类logloss损失函数 auc 曲线下面积 seed [default=0] 随机数的种子 设置...
  • 但是他同样也是目前学习的算法中用途最广泛,最流行的明星算法。他可以用来分类,用来回归,用来进行检测异常。 1.什么是硬间隔SVM? 在二维空间中划分正反例的就是一条直线,在多维空间中我们可以想象有一个超平面...
  • XGBoost从原理到调

    2021-01-14 23:09:52
    承接上文挂枝儿:再从GBDT到XGBoost!​zhuanlan.zhihu.com理解了原理,那么接下来就要开始学习怎么调了,之前做模型的时候用xgboost比较简单粗暴跟着教程一顿乱fit,但...对了,虽然这篇文章是写调的,但我个...
  • 秘籍:BN层详解

    万次阅读 2021-04-12 21:10:44
    这些参数的选择对训练结果至关重要,以至于我们很多时间都浪费在这些的调上。那么使用BN之后,你可以不需要那么刻意的慢慢调整参数。 2)神经网络一旦训练起来,那么参数就要发生更新,除了输入层的数据外(因为...
  • xgboost调

    2021-03-17 10:48:54
    logistic" --逻辑回归 "binary:logistic" --二分类的逻辑回归,返回预测的概率(不是类别) eval_metric "rmse": 均方误差 "mae": 绝对平均误差 "auc": ROC曲线下方的面积 for ranking evaluation. eta : 默认是0.3,...
  • win10+anaconda+pychram+yolov5调、训练经验慢慢更新

    千次阅读 热门讨论 2021-04-05 00:43:36
    YAML 文件uc_data.yaml — cfg: 模型文件Custom_yolov5s.yaml,需要自己至少修改类别数量类别种类 — weights: 对于本项目不使用预训练权重,如果需要预训练权重,可以访问此地址 — cache-images: 将预处理后的...
  • JAVA中方法的分类及调用目的作为JAVA的初学者,借此次整理,复习JAVA中与方法相关的知识。JAVA中方法的分类构造方法构造方法:类或者抽象类中(接口没有),与类名同名,无返回值,不能用static修饰。格式:权限修饰符...
  • 【数据挖掘】心跳信号分类预测 之 建模调 —— 学习笔记(四)
  • 我们来进行全连接,全连接层的作用就是将我们提取到的特征映射到几个类别上,就是分类器的作用,然后我们来看一下参数怎么来的: self.fc1 = nn.Linear(32*5*5,120) self.fc2 = nn.Linear(120,84) self.fc3 = nn....
  • xgboost2 以及使用XGB.CV来进行调

    千次阅读 2021-05-27 11:33:36
    plt.show() #根据上图可以看到:最佳的n_estimators,因为后面都是平缓的了 #现在模型处于过拟合,一种是把训练集红色线往上,一种是让测试集黑线下降 #那么从现有图来看,两条线越接近,就是我们调的目标 #接下来...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 51,013
精华内容 20,405
关键字:

参的分类及作用