【异步电机系列】电机参数离线辨识(含源码实现)
【一、闲话
很久没有认真更新自己的博客了!正好这段时间在学习异步电机控制,所以把过程中的一些东西写下来,当是回顾也是备忘。本来想是把整个过程的问题和收获都记录下来的(包括硬件设计、mcu控制、算法等),但感觉要好费精力,所以这个异步电机系列就随缘更新吧!自己也是才接触电机控制,有不正确的地方还请多多指教!
文章中出现的一些名字和概念不理解的话建议可以查查资料哦,博主不可能把所有概念都讲的哦。
二、概述
我理解的异步电机控制分为开环控制和闭环控制(传统意义上也可以分为标量和矢量),开环一般为v/f控制,较简单,闭环又分为有无传感器。做闭环的话磁链观测器就很重要了,常分为电压型磁链观测器和电流型磁链观测器,而磁链观测器又跟电机参数息息相关,比如定子电阻对电压型磁链观测器的磁链幅值影响很大,所以我们就要对电机参数进行辨识,就引入今天的主题啦!当然你有现成的电机参数就不用辨识了。参数辨识分为在线辨识和离线辨识,今天的主题是离线辨识。
三、原理
整个工程实现都是参考的一篇硕士论文,最后会把论文贴出来,论文写的很清楚,接下来的原理都是论文上的内容哦。
论文地址:https://download.csdn.net/download/qq_35141454/87771052
3.1 定子电阻辨识
原理就是单相直流试验,给电机某一相通一直流,利用电感通直流阻交流的特点,就可以得到电机的等效电路图,求得定子电阻。如下图,

利用电流闭环先让电流稳定,然后在采集多个电流点,要考虑Mos管导通压降和死区时间的影响,最后通过最小二乘法计算定子电阻,工程实际应用流程如下,

3.2 转子电阻及漏感辨识
原理为单相交流实验,其等效电路图与计算原理如下,


3.3 互感辨识
原理是空载试验,这时同步转速基本等于转子转速,电机转子回路相当于开路了。具体原理如下,

四、工程代码
大家应该最关心的是这个了吧,因为理论跟实践是两个东西,有同学肯定感同身受。认真看了代码可能会有疑惑,有些api找不到实现,比如获取三相电流电压,或者某些标志位,又或者一些平台相关的控制代码。这里博主想讲的是这个是一个具体实现思路,目的在于实现,不是要每个细节都体现出来,平台不一样一些东西就不一样(代码是gd32平台),理解了话就很容易了。(为什么会这么说,因为本人在看代码缺少一些具体实现的时候也会很苦恼,哈哈)
实现的c文件如下,
/** Copyright (c) 2006-2021, RT-Thread Development Team** SPDX-License-Identifier: Apache-2.0** @brief: 异步电机参数辨识* Change Logs:* Date Author Notes* 2023-04-20 liujian the first version*/#include "param_iden.h"
#include "bus_current.h"
#include
#include
#include #if 1
// sqrt(3)
#define SQRT3 (1.732051f)
// sqrt(3)/3
#define SQRT3_DIV3 (0.577350f)
// 定子电阻辨识电流环kp
#define RS_KP (1.0f)
// 定子电阻辨识电流环ki
#define RS_TI (0.1f)// Udc值
#define UDC_VALUE (72)// 定子电阻辨识
rs_param_t m_rs_param = {0};// sin0~90度的表
static int16_t g_sin0_90_table[] = {\0x0000,0x00C9,0x0192,0x025B,0x0324,0x03ED,0x04B6,0x057F,\0x0648,0x0711,0x07D9,0x08A2,0x096A,0x0A33,0x0AFB,0x0BC4,\0x0C8C,0x0D54,0x0E1C,0x0EE3,0x0FAB,0x1072,0x113A,0x1201,\0x12C8,0x138F,0x1455,0x151C,0x15E2,0x16A8,0x176E,0x1833,\0x18F9,0x19BE,0x1A82,0x1B47,0x1C0B,0x1CCF,0x1D93,0x1E57,\0x1F1A,0x1FDD,0x209F,0x2161,0x2223,0x22E5,0x23A6,0x2467,\0x2528,0x25E8,0x26A8,0x2767,0x2826,0x28E5,0x29A3,0x2A61,\0x2B1F,0x2BDC,0x2C99,0x2D55,0x2E11,0x2ECC,0x2F87,0x3041,\0x30FB,0x31B5,0x326E,0x3326,0x33DF,0x3496,0x354D,0x3604,\0x36BA,0x376F,0x3824,0x38D9,0x398C,0x3A40,0x3AF2,0x3BA5,\0x3C56,0x3D07,0x3DB8,0x3E68,0x3F17,0x3FC5,0x4073,0x4121,\0x41CE,0x427A,0x4325,0x43D0,0x447A,0x4524,0x45CD,0x4675,\0x471C,0x47C3,0x4869,0x490F,0x49B4,0x4A58,0x4AFB,0x4B9D,\0x4C3F,0x4CE0,0x4D81,0x4E20,0x4EBF,0x4F5D,0x4FFB,0x5097,\0x5133,0x51CE,0x5268,0x5302,0x539B,0x5432,0x54C9,0x5560,\0x55F5,0x568A,0x571D,0x57B0,0x5842,0x58D3,0x5964,0x59F3,\0x5A82,0x5B0F,0x5B9C,0x5C28,0x5CB3,0x5D3E,0x5DC7,0x5E4F,\0x5ED7,0x5F5D,0x5FE3,0x6068,0x60EB,0x616E,0x61F0,0x6271,\0x62F1,0x6370,0x63EE,0x646C,0x64E8,0x6563,0x65DD,0x6656,\0x66CF,0x6746,0x67BC,0x6832,0x68A6,0x6919,0x698B,0x69FD,\0x6A6D,0x6ADC,0x6B4A,0x6BB7,0x6C23,0x6C8E,0x6CF8,0x6D61,\0x6DC9,0x6E30,0x6E96,0x6EFB,0x6F5E,0x6FC1,0x7022,0x7083,\0x70E2,0x7140,0x719D,0x71F9,0x7254,0x72AE,0x7307,0x735E,\0x73B5,0x740A,0x745F,0x74B2,0x7504,0x7555,0x75A5,0x75F3,\0x7641,0x768D,0x76D8,0x7722,0x776B,0x77B3,0x77FA,0x783F,\0x7884,0x78C7,0x7909,0x794A,0x7989,0x79C8,0x7A05,0x7A41,\0x7A7C,0x7AB6,0x7AEE,0x7B26,0x7B5C,0x7B91,0x7BC5,0x7BF8,\0x7C29,0x7C59,0x7C88,0x7CB6,0x7CE3,0x7D0E,0x7D39,0x7D62,\0x7D89,0x7DB0,0x7DD5,0x7DFA,0x7E1D,0x7E3E,0x7E5F,0x7E7E,\0x7E9C,0x7EB9,0x7ED5,0x7EEF,0x7F09,0x7F21,0x7F37,0x7F4D,\0x7F61,0x7F74,0x7F86,0x7F97,0x7FA6,0x7FB4,0x7FC1,0x7FCD,\0x7FD8,0x7FE1,0x7FE9,0x7FF0,0x7FF5,0x7FF9,0x7FFD,0x7FFE };/*** @brief 等幅值clarke变换* @param motor* @return*/
void ea_clarke(ea_clarke_t *model)
{model->outa = model->ina;model->outb = SQRT3_DIV3 * (model->inb*2 + model->ina);
}/*** @brief pi控制器* @param motor* @return*/
void pi_controller(m_pid_t *model)
{float tmp = 0;float ek = model->target - model->current;model->ek_sum = model->ek_sum_last + ek;tmp = model->ki * model->ek_sum;// 限制积分饱和if ((tmp - model->max) > 0.00001f)tmp = model->max;else if((tmp - model->min) < 0.00001f)tmp = model->min;model->output = tmp + ek * model->kp;// 限制输出if ((model->output - model->max) > 0.00001f)model->output = model->max;else if((model->output - model->min) < 0.00001f)model->output = model->min;model->ek_sum_last = model->ek_sum;
}/*** @brief svpwm输出通道比较值* @param motor*/
uint16_t ccr1 = 0;
uint16_t ccr2 = 0;
uint16_t ccr3 = 0;
static void motor_svpwm(mrpark_t *target)
{// 两个矢量作用时间int32_t Tx = 0;int32_t Ty = 0;// 存放临时比例因子float s1 = 0.0f;float s2 = 0.0f;// ABC三相作用时间int32_t pha_time = 0;int32_t phb_time = 0;int32_t phc_time = 0;// 用于计算扇区uint8_t A = 0;uint8_t B = 0;uint8_t C = 0;// 计算u1 u2 u3用于判断扇区和统计int32_t U1 = target->u_beta;int32_t U2 = (SQRT3 * target->u_alpha - target->u_beta)/2.0f;int32_t U3 = (-SQRT3 * target->u_alpha - target->u_beta)/2.0f;A = U1 > 0? 1:0;B = U2 > 0? 1:0;C = U3 > 0? 1:0;// 计算扇区uint8_t N = 4*C + 2*B + A;// 将udc等放大32767倍float k = SQRT3 * PWM_PERIOD / (UDC_VALUE*32767);// 根据扇区各标量计算作用时间switch (N){case 3: // 扇区1Tx = k * U2;// T4Ty = k * U1;// T6break;case 1: // 扇区2Tx = -k*U2;// T2Ty = -k*U3;// T6break;case 5: // 扇区3Tx = k*U1;// T2Ty = k*U3;// T3break;case 4:Tx = -k*U1;// T1Ty = -k*U2;// T3break;case 6: // 扇区5Tx = k*U3;// T1Ty = k*U2;// T5break;case 2: // 扇区6Tx = -k*U3;// T4Ty = -k*U1;// T5break;}// 作用时间大于TS则比例化if ((Tx + Ty) > PWM_PERIOD){s1 = Tx*1.0/(Tx+Ty);s2 = Ty*1.0/(Tx+Ty);Tx = s1 * PWM_PERIOD;Ty = s2 * PWM_PERIOD;}// 计算ABC三相作用switch( N ){case 3: // 扇区1phc_time = (PWM_PERIOD - Tx - Ty )/2;phb_time = phc_time+Ty;pha_time = phb_time+Tx;break;case 1:// 扇区2phc_time = (PWM_PERIOD - Tx - Ty )/2;pha_time = (phc_time+Ty);phb_time = (pha_time+Tx);break;case 5:// 扇区3pha_time = (PWM_PERIOD - Tx - Ty )/2;phc_time = pha_time+Ty;phb_time = phc_time+Tx;break;case 4:// 扇区4pha_time = (PWM_PERIOD - Tx - Ty )/2;phb_time = pha_time+Ty;phc_time = phb_time+Tx;break;case 6:// 扇区5phb_time = (PWM_PERIOD - Tx - Ty )/2;pha_time = phb_time+Ty;phc_time = pha_time+Tx;break;case 2:// 扇区6phb_time = (PWM_PERIOD - Tx - Ty )/2;phc_time = phb_time+Ty;pha_time = phc_time+Tx;break;default:phb_time = 0;phc_time = 0;pha_time = 0;break;}// 除以2的原因是PWM为中央对齐模式ccr1 = pha_time/2;ccr2 = phb_time/2;ccr3 = phc_time/2;// 设置pwm比较值timer_channel_output_pulse_value_config(TIMER7, TIMER_CH_0, ccr1);timer_channel_output_pulse_value_config(TIMER7, TIMER_CH_1, ccr2);timer_channel_output_pulse_value_config(TIMER7, TIMER_CH_2, ccr3);
}/*** @brief 中值滤波* @param motor* @return*/
static float median_filter(float *data, uint16_t len, uint8_t flag)
{int i;float min, max;float sum = 0.0f;float median = 0.0f;if (NULL == data)return 0;min = data[0];max = data[0];for (i=0; i 0.000001f) // 找到最大值{max = data[i];}else if (data[i] - min < 0.000001f) // 找到最小值{min = data[i];}}if (!flag)median = (sum - min - max)/(len-2); // 去掉最大和最小求平均值elsemedian = sum / len; // 直接求平均值// rt_kprintf("min=%f, max=%f, median=%f\n", min, max, median);return median;
}/*** @brief 最小二乘法* y =ax+b a=x* @param motor* @return*/
static float least_square(float *data, uint16_t len)
{}/*** @brief 定子参数辨识* @param motor* @return*/
/* 目标电流个数 */
#define TARGET_CURRENT_CNT (15)
/* clarke变换 */
ea_clarke_t clarke;
/* 缓存vbus */
float vbus_tmp = 0.0f;
/* 目标电流 */
static float g_current_target_table[TARGET_CURRENT_CNT] = {1.0,1.2,1.4,1.6,1.8,2.0,2.2,2.4,2.6,2.8,3.0,3.2,3.4,3.6,3.8};
void current_loop(void)
{mrpark_t park;// 获取三相电流get_abc_current((float *)&clarke);// 获取母线电压vbus_tmp = get_vm_bus_voltage();// 等幅值clarke变换ea_clarke(&clarke);// pi调节m_rs_param.pid.current = -clarke.outa;pi_controller(&m_rs_param.pid);park.u_alpha = m_rs_param.pid.output*32767;park.u_beta = 0;// svpwm输出motor_svpwm(&park);
}/*** @brief 定子参数辨识* 为adc采集周期调用* step1:等待目标电流稳定* step2:计算单个目标电流均值* step3:最小二乘法计算定子电阻* @param None* @return 0*/
int iden_stator_resistance(void)
{uint32_t i;float vbus = 0.0f;float tmp[TARGET_CURRENT_CNT] = {0};// 电流闭环调节current_loop();switch (m_rs_param.state) {case RS_LEVEL_STANDBY: // 等待目标电流稳定下来m_rs_param.cnt++;if (m_rs_param.cnt > PWM_HZ/10) // 100ms后开始计算{m_rs_param.cnt = 0;// m_rs_param.mcnt = 0;m_rs_param.state = RS_LEVEL_CALC1;}break;case RS_LEVEL_CALC1: // 采样100个电压电流点,进行数字滤波m_rs_param.isam1[m_rs_param.cnt] = -clarke.ina;// 减去死区时间 deltaT/(2Ts)*udc的压降 减去Mos管导通压降vbus = vbus_tmp * ((ccr1*2 - ccr2 - ccr3)/3.0/(PWM_PERIOD/2))- (PWM_HZ*0.17/2000000*vbus_tmp); // 死区时间0.17us- 0.0093*(-clarke.ina); // 导通电阻0.0093m_rs_param.usam1[m_rs_param.cnt] = vbus;m_rs_param.cnt++;if (m_rs_param.cnt >= RS_SAMP_CNT){// 中值滤波m_rs_param.isam2[m_rs_param.mcnt] = median_filter(m_rs_param.isam1, RS_SAMP_CNT, 0);m_rs_param.usam2[m_rs_param.mcnt] = median_filter(m_rs_param.usam1, RS_SAMP_CNT, 0);m_rs_param.mcnt++;// 目标电流集合采集计算完毕if (m_rs_param.mcnt >= TARGET_CURRENT_CNT){m_rs_param.mcnt = 0;m_rs_param.state = RS_LEVEL_CALC2;}else // 计算下一个目标电流{m_rs_param.pid.target = m_rs_param.itable[m_rs_param.mcnt];m_rs_param.state = RS_LEVEL_STANDBY;m_rs_param.cnt = 0;}}break;case RS_LEVEL_CALC2:// 中值滤波m_rs_param.xmedian = median_filter(m_rs_param.isam2, TARGET_CURRENT_CNT, 1); // 计算x平均m_rs_param.ymedian = median_filter(m_rs_param.usam2, TARGET_CURRENT_CNT, 1);// 计算y平均for (i=0; i= TARGET_CURRENT_CNT){rt_kprintf("clac: %f %f %f %f %f %f\n", m_rs_param.x2median, m_rs_param.xymedian,m_rs_param.xmedian, m_rs_param.ymedian, m_rs_param.bres,m_rs_param.rs_res);break;}rt_thread_mdelay(10);}
#endifreturn 0;
}
//MSH_CMD_EXPORT(rs_start, rs start);rr_param_t g_rr_param = {0};/*** @brief 获取当前角度下的sin cos* @param motor*/void get_sin_cos(theta_t *dtc)
{uint8_t sector = 0;uint16_t index = 0;index = (dtc->theta) >> 6; //< 0~65535等比例缩小64倍,范围0~1024//根据扇区计算sin和cos值sector = (index & 0x300) >> 8; //0:0~255 1:256~511 2:512~767 3:767~1023switch(sector){case 0:// 0~90度dtc->sin = (g_sin0_90_table[(uint8_t)(index)]);dtc->cos = (g_sin0_90_table[(uint8_t)(0xFFu - (uint8_t)(index))]);break;case 1:// 90~180度dtc->sin = (g_sin0_90_table[(uint8_t)(0xFFu - (uint8_t)(index))]);dtc->cos = (-g_sin0_90_table[(uint8_t)(index)]);break;case 2:// 180~270度dtc->sin = ( -g_sin0_90_table[(uint8_t)(index)]);dtc->cos = (-g_sin0_90_table[(uint8_t)(0xFFu - (uint8_t)(index))]);break;case 3:// 270~360度dtc->sin = (-g_sin0_90_table[(uint8_t)(0xFFu - (uint8_t)(index))]);dtc->cos = (g_sin0_90_table[(uint8_t)(index)]);break;}
}static complex result = {0};
/*** @brief 离散傅里叶变换* @param*/
void dft_calc(float *input, int k, uint16_t num)
{int n = 0;complex sum;complex point;//[RR_SAM_CNT];sum.real = 0;sum.imag = 0;uint16_t N = num;for(n=0; n= RR_SAM_CNT){g_rr_param.rr_start_flag = 0;g_rr_param.rr_start_flag1 = 0;g_rr_param.cnt = 0;timer_channel_output_pulse_value_config(TIMER7, TIMER_CH_0, 0);timer_channel_output_pulse_value_config(TIMER7, TIMER_CH_1, 0);timer_channel_output_pulse_value_config(TIMER7, TIMER_CH_2, 0);// 电流傅里叶变换 (2/N)*(求和x(n)cos(2*pi*n*k/N)-j求和x(n)sin(2*pi*n*k/N))dft_calc(g_rr_param.isam, 1, RR_SAM_CNT); //k=1,求的是基波频率的傅里叶变换g_rr_param.i_dft.real = result.real*2/RR_SAM_CNT;g_rr_param.i_dft.imag = result.imag*2/RR_SAM_CNT;// 求电流基波分量幅值g_rr_param.i_amp = sqrt(g_rr_param.i_dft.real*g_rr_param.i_dft.real+ g_rr_param.i_dft.imag*g_rr_param.i_dft.imag);// 电压傅里叶变换dft_calc(g_rr_param.usam, 1, RR_SAM_CNT); //k=1,求的是基波频率的傅里叶变换g_rr_param.u_dft.real = result.real*2/RR_SAM_CNT;g_rr_param.u_dft.imag = result.imag*2/RR_SAM_CNT;// 求电压基波分量幅值g_rr_param.u_amp = sqrt(g_rr_param.u_dft.real*g_rr_param.u_dft.real+ g_rr_param.u_dft.imag*g_rr_param.u_dft.imag);// 求功率因数角cos值( Ua*Ia + Ub*Ib)/u_amp*i_ampg_rr_param.acos = ((g_rr_param.i_dft.real*g_rr_param.u_dft.real)+(g_rr_param.i_dft.imag*g_rr_param.u_dft.imag))/(g_rr_param.u_amp * g_rr_param.i_amp);// 求功率因数角sin值( Ub*Ia - Ua*Ib)/u_amp*i_ampg_rr_param.asin = ((g_rr_param.u_dft.imag*g_rr_param.i_dft.real)- (g_rr_param.u_dft.real*g_rr_param.i_dft.imag))/(g_rr_param.u_amp * g_rr_param.i_amp);// 求得转子电阻 Rr=(Vab/Ia)cos*(2/3)-Rsg_rr_param.rr = (g_rr_param.u_amp/g_rr_param.i_amp)*g_rr_param.acos*2/3.0;// 求得转子漏感和定子漏感 lls=llr=(Vab/Ia)sin/3/2*pi*fg_rr_param.lls = (g_rr_param.u_amp/g_rr_param.i_amp)*g_rr_param.asin/3.0/(2*M_PI*BASE_VOL_FREQ);g_rr_param.llr = g_rr_param.lls;}
}/*** @brief 转子电阻和漏感参数辨识* pwm更新中断调用* @param None* @return 0*/
int irr_pwm_intr_handler(void)
{mrpark_t park;// 每个pwm周期转了多少转float cycle_freq = ((float)(BASE_VOL_FREQ)/(float)PWM_HZ);g_rr_param.theta += round(cycle_freq * 65535); // 放大65535倍,每次加freq_ * 65535get_sin_cos((theta_t *)&g_rr_param);park.u_alpha = BASE_VAL_AMP * g_rr_param.cos;park.u_beta = 0;// svpwm输出motor_svpwm(&park);
}//int rr_start(int argc, char **argv)
int rr_start(void)
{int cnt = 0;memset(&g_rr_param, 0, sizeof(rr_param_t));// 关闭三相桥timer_channel_output_pulse_value_config(TIMER7, TIMER_CH_0, 0);timer_channel_output_pulse_value_config(TIMER7, TIMER_CH_1, 0);timer_channel_output_pulse_value_config(TIMER7, TIMER_CH_2, 0);// 等待电流稳定后计算偏置电流rt_thread_mdelay(20);// 计算偏置电流calc_phase_offset();// 开启pwmg_rr_param.rr_start_flag = 1;// 等待输出稳定rt_thread_mdelay(200);// 开启adc采集g_rr_param.rr_start_flag1 = 1;// 等待数据结果rt_thread_mdelay(2000);
#if 1// g_rr_param.rr = g_rr_param.rr - m_rs_param.rs_res;rt_kprintf("Rr=%f llr=%f lls=%f\n", g_rr_param.rr, g_rr_param.llr, g_rr_param.llr);
#elsewhile (1){rt_kprintf("%d %f %f %d %d\n", cnt, g_rr_param.isam[cnt], g_rr_param.usam[cnt], ccr1, ccr2);cnt++;if (cnt >= RR_SAM_CNT){rt_kprintf("total:%f %f %f %f %f %f %f\n", g_rr_param.i_dft.real, g_rr_param.i_dft.imag, g_rr_param.i_amp, g_rr_param.u_dft.real,g_rr_param.u_dft.imag,g_rr_param.u_amp,g_rr_param.acos);rt_kprintf("Rr=%f llr=%f\n", g_rr_param.rr, g_rr_param.llr);break;}rt_thread_mdelay(10);}
#endif
}
//MSH_CMD_EXPORT(rr_start, rr start);lm_param_t g_lm_param = {0};/*** @brief 互感参数辨识* pwm更新中断调用* @param None* @return 0*/
int ilm_pwm_intr_handler(void)
{mrpark_t park;// 每个pwm周期转了多少转float cycle_freq = ((float)(ILM_BASE_VOL_FREQ)/(float)PWM_HZ);g_lm_param.theta += round(cycle_freq * 65535); // 放大65535倍,每次加freq_ * 65535get_sin_cos((theta_t *)&g_lm_param);park.u_alpha = ILM_BASE_VAL_AMP * g_lm_param.cos;park.u_beta = ILM_BASE_VAL_AMP * g_lm_param.sin;// svpwm输出motor_svpwm(&park);
}/*** @brief 互感参数辨识* adc中断调用* @param None* @return 0*/
int ilm_current_intr_handler(void)
{float i_tmp[3] = {0};float vbus_tmp = 0.0f;static float last_i = 0.0f;float cur = 0.0f;// 获取三相电流get_abc_current(i_tmp);// 获取母线电压vbus_tmp = get_vm_bus_voltage();// 低通滤波 这样会导致相位后移// cur = ((i_tmp[0] / 10000.0 + 0.0003 * last_i) / (0.0004));// last_i = cur;g_lm_param.isam[g_lm_param.cnt] = -i_tmp[0];//cur;g_lm_param.usam[g_lm_param.cnt] = vbus_tmp * ((ccr1*2 - ccr2 - ccr3)/3.0/(PWM_PERIOD/2)); //Va - 死区电压-Mos管压降// - (PWM_FREQUENCY*0.17/2000000*vbus_tmp)// - 0.0093*(i_tmp[0]);;g_lm_param.cnt++;// 采集一周期数据完成if (g_lm_param.cnt >= LM_SAM_CNT){g_lm_param.lm_start_flag = 0;g_lm_param.lm_start_flag1 = 0;g_lm_param.cnt = 0;timer_channel_output_pulse_value_config(TIMER7, TIMER_CH_0, 0);timer_channel_output_pulse_value_config(TIMER7, TIMER_CH_1, 0);timer_channel_output_pulse_value_config(TIMER7, TIMER_CH_2, 0);// 电流傅里叶变换 (2/N)*(求和x(n)cos(2*pi*n*k/N)-j求和x(n)sin(2*pi*n*k/N))dft_calc(g_lm_param.isam, 1, LM_SAM_CNT); //k=1,求的是基波频率的傅里叶变换g_lm_param.i_dft.real = result.real*2.0/LM_SAM_CNT;g_lm_param.i_dft.imag = result.imag*2.0/LM_SAM_CNT;// 求电流基波分量幅值g_lm_param.i_amp = sqrt(g_lm_param.i_dft.real*g_lm_param.i_dft.real+ g_lm_param.i_dft.imag*g_lm_param.i_dft.imag);// 电压傅里叶变换dft_calc(g_lm_param.usam, 1, LM_SAM_CNT); //k=1,求的是基波频率的傅里叶变换g_lm_param.u_dft.real = result.real*2.0/LM_SAM_CNT;g_lm_param.u_dft.imag = result.imag*2.0/LM_SAM_CNT;// 求电压基波分量幅值g_lm_param.u_amp = sqrt(g_lm_param.u_dft.real*g_lm_param.u_dft.real+ g_lm_param.u_dft.imag*g_lm_param.u_dft.imag);// 求功率因数角cos值( Ua*Ia + Ub*Ib)/u_amp*i_amp
// g_lm_param.acos = ((g_lm_param.i_dft.real*g_lm_param.u_dft.real)
// +(g_lm_param.i_dft.imag*g_lm_param.u_dft.imag))
// /(g_lm_param.u_amp * g_lm_param.i_amp);// 求功率因数角sin值( Ub*Ia - Ua*Ib)/u_amp*i_ampg_lm_param.asin = ((g_lm_param.u_dft.imag*g_lm_param.i_dft.real)- (g_lm_param.u_dft.real*g_lm_param.i_dft.imag))/(g_lm_param.u_amp * g_lm_param.i_amp);// 求得转子漏感和定子漏感 lls=llr=(Vab/Ia)sin/3/2*pi*fg_lm_param.lm = (g_lm_param.u_amp/g_lm_param.i_amp)*g_lm_param.asin/(2*M_PI*ILM_BASE_VOL_FREQ);}
}//int lm_start(int argc, char **argv)
int lm_start(void)
{int cnt = 0;memset(&g_lm_param, 0, sizeof(lm_param_t));// 关闭三相桥timer_channel_output_pulse_value_config(TIMER7, TIMER_CH_0, 0);timer_channel_output_pulse_value_config(TIMER7, TIMER_CH_1, 0);timer_channel_output_pulse_value_config(TIMER7, TIMER_CH_2, 0);// 等待电流稳定后计算偏置电流rt_thread_mdelay(20);// 计算偏置电流calc_phase_offset();// 开启pwmg_lm_param.lm_start_flag = 1;// 等待输出稳定rt_thread_mdelay(3000);// 开启adc采集g_lm_param.lm_start_flag1 = 1;// 等待数据结果rt_thread_mdelay(2000);
#if 1rt_kprintf("Lm=%f\n", g_lm_param.lm);
#elsewhile (1){rt_kprintf("%d %f %f %d %d\n", cnt, g_lm_param.isam[cnt], g_lm_param.usam[cnt], ccr1, ccr2);cnt++;if (cnt >= LM_SAM_CNT){rt_kprintf("total:%f %f %f %f %f %f %f\n", g_lm_param.i_dft.real, g_lm_param.i_dft.imag, g_lm_param.i_amp, g_lm_param.u_dft.real,g_lm_param.u_dft.imag,g_lm_param.u_amp,g_lm_param.asin);rt_kprintf("Lm=%f\n", g_lm_param.lm);break;}rt_thread_mdelay(10);}
#endif
}
//MSH_CMD_EXPORT(lm_start, lm start);
#if 1motor_iden_param_t param = {0};motor_iden_param_t *get_motor_iden_param(void)
{return ¶m;
}int start_iden(int argc, char **argv)
{int i;int cnt = 0;float rs_sum = 0.0f;float rr_sum = 0.0f;float llr_sum = 0.0f;float lls_sum = 0.0f;float lm_sum = 0.0f;if (argc < 2){rt_kprintf("argc <2!\n");return -1;}cnt = atoi(argv[1]);for (i=0; i
头文件如下,
/** Copyright (c) 2006-2021, RT-Thread Development Team** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date Author Notes* 2023-04-20 lj the first version*/
#ifndef APPLICATIONS_THREE_PHASE_MOTOR_PARAM_IDEN_H_
#define APPLICATIONS_THREE_PHASE_MOTOR_PARAM_IDEN_H_#include // 设置pwm频率
#define PWM_HZ (10000)
// 频率
#define CALC_FREQ PWM_HZ
// pwm周期 时钟/频率
#define PWM_PERIOD (uint16_t)(200000000/PWM_HZ)
// 基波电压频率100hz
#define BASE_VOL_FREQ (200)
// 基波电压幅值
#define BASE_VAL_AMP (2.0f)// 基波电压频率200hz
#define ILM_BASE_VOL_FREQ (200)
// 基波电压幅值
#define ILM_BASE_VAL_AMP (7.5f)// RS采样次数
#define RS_SAMP_CNT (100)
// 单相交流采样点数 PWM_HZ/BASE_VOL_FREQ
#define RR_SAM_CNT (PWM_HZ/BASE_VOL_FREQ) //(100)
// 空载试验采样点数 PWM_HZ/ILM_BASE_VOL_FREQ
#define LM_SAM_CNT (PWM_HZ/ILM_BASE_VOL_FREQ)//(100)typedef enum {RS_LEVEL_NONE,RS_LEVEL_STANDBY, // 电流稳定RS_LEVEL_CALC1, // 计算第一次电流RS_LEVEL_CALC2, // 计算第二次电流
}rs_state_t;/*** @brief pwm通道比较值*/
typedef struct{uint16_t ccr1; //pwm通道1比较值uint16_t ccr2; //pwm通道2比较值uint16_t ccr3; //pwm通道3比较值
}ccr_t;typedef struct {uint16_t theta;float sin;float cos;
}theta_t;/*** @brief 反park变化计算得到的alpha_beta*/
typedef struct {int32_t u_alpha;int32_t u_beta;
}mrpark_t;typedef struct {float ina;float inb;float inc;float outa;float outb;
}ea_clarke_t;/*** @brief pid控制*/
typedef struct {float current; // 输入,当前float target; // 输入,目标float output; // 输出,d轴分量目标电流float kp; // 比例float ki; // 积分float min; // 最小值float max; // 最大值float ek_sum; // 误差积分float ek_sum_last; // 误差积分
}m_pid_t;typedef struct {float i1_target;float i2_target;m_pid_t pid;float *itable;float isam1[RS_SAMP_CNT];float usam1[RS_SAMP_CNT];float isam2[RS_SAMP_CNT];float usam2[RS_SAMP_CNT];float xmedian;float ymedian;float x2median;float xymedian;// float imedian[10];// float umedian[10];uint8_t rs_start_flag;uint8_t state;uint16_t cnt; // 记数节拍uint16_t mcnt; // calc2记数节拍float rs_res; //定子电阻float bres; //定子电阻
}rs_param_t;//复数结构体,用于实现傅里叶运算
typedef struct
{double real,imag;
}complex;typedef struct {uint16_t theta;float sin;float cos;float isam[RR_SAM_CNT];float usam[RR_SAM_CNT];complex i_dft;complex u_dft;float i_amp; // 电流幅值float u_amp; // 电流幅值float acos; // 功率因数角cos值float asin; // 功率因数角sin值float lls;float llr;float rr;uint16_t cnt; //记数节拍uint8_t rr_start_flag;uint8_t rr_start_flag1;
}rr_param_t;typedef struct {uint16_t theta;float sin;float cos;float isam[LM_SAM_CNT];float usam[LM_SAM_CNT];complex i_dft;complex u_dft;float i_amp; // 电流幅值float u_amp; // 电流幅值float acos; // 功率因数角cos值float asin; // 功率因数角sin值float lm;uint16_t cnt; //记数节拍uint8_t lm_start_flag;uint8_t lm_start_flag1;
}lm_param_t;typedef struct {float calc_rs;float calc_rr;float calc_ls;float calc_lr;float calc_lm;float calc_sigma;
}motor_iden_param_t;extern rs_param_t m_rs_param;
extern rr_param_t g_rr_param;
extern lm_param_t g_lm_param;
motor_iden_param_t *get_motor_iden_param(void);#endif /* APPLICATIONS_THREE_PHASE_MOTOR_PARAM_IDEN_H_ */
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
