我们经常使用电机效率map图来直观地显示电机在不同转速和扭矩下的效率。
我们可以以此为参考对电机的结构进行微调,我需要它在低转速时有更高效率,或者说我需要在高转矩时有更好的性能等等。
同时,分析同一路谱数据在不同电机的map图中的平均效率,可以对比不同电机供应商的产品性能。
路谱数据为CAN分析仪采集的,某一时段的电机转矩、转速数据,路谱数据是随时间、工况、车型等不断变化的值。
电机效率map的原始数据来源于对电机在特定转速、转矩下效率的实验测试,属于和某机型绑定的恒定数据。
但此处注意,不同公司的台架平台下,可能会测出不同的map数据,所以要对不同电机进行性能比较,需要尽量在同样台架下获取数据。同时,需要知道获取的是电机效率还是系统效率。
当电机转速和转矩在同一方向时,表现的是驱动效率,当电机转速和转矩在相反方向时,表现的是发电效率。
以转速为横轴,以转矩为纵轴,那第一象限就是前进的驱动效率,第三象限就是反向的驱动效率,第四象限是前进的发电效率,第二象限是反向的发电效率。
理论上来说,电机第一象限和第三象限的map图谱是完全一样的,二四象限的图谱是完全一样的。但是为什么需要算四个象限呢,那是考虑到在一段路谱数据中,自然有正向转,有反向转,一起计算可以提高准确率。
主文件
close all;
clear;
clc;
%%
global tolerance coefficient M2V_MCU_DMSpd M2V_MCU_DMTrq TX_mcuMotorSpeed TX_mcuOutTorque title_name
% M2V_MCU_DMSpd M2V_MCU_DMTrq为行走电机路谱;
% TX_mcuMotorSpeed TX_mcuOutTorque为泵用电机路谱;
load DATA_5T M2V_MCU_DMSpd M2V_MCU_DMTrq TX_mcuMotorSpeed TX_mcuOutTorque
tolerance = 3; % map表格各个档位的速度有可能会在正负1或正负3间切换。
coefficient = 100; % 效率值的系数,如果第三列效率是百分数,例如0.87,就乘以100,如果是87,那就乘以1。
title_name = 'xxx电机在xxx控制器厂商平台下的系统效率或电机效率的map图'; %标题请自己根据需要修改。
xlim_val = 3500; % 生成图的横坐标范围,行走电机为3500,泵用电机为3000
ylim_val = 2500; % 生成图的纵坐标范围, 行走电机为2500,泵用电机为1000
flag = 1; % 行走电机,flag为1,泵用电机,flag为0;
filename = '行走电机效率map.xlsx'; % 将表格放入本程序的同一个文件夹下,并在此填入表格名。
sheet1_name = '驱动效率'; % sheet1,有三列,转速,转矩,效率,第一行是列变量名称,第二行开始是数据。
sheet2_name = '发电效率'; % sheet2,同上。
value_eff = [30 50:5:80 81:2:90 91:1:94 95 95.7 96]; % MAP图显示的效率标签量。
speed_gears1 = [300, 600, 900, 1150, 1200, 1500, 1800, 2100, 2400, 2700, 3000, 3300, 3500]; % 驱动效率map的转速的档位值,从sheet1中提取。
speed_gears2 = [300, 600, 1200, 1500, 1800, 2100, 2400, 2700, 3000, 3300, 3500]; % 发电效率map的转速的档位值,从sheet2中提取。
% Data_Pre是xlsx的处理函数,生成包含三列数据的驱动效率map Motor_STE和包含三列数据的驱动效率map
% Generate_STE,以及两者的外特性曲线散点值。外特性曲线即为map在每个档位速度下的最大转矩值,在外特性曲线外的map图自动置为NAN,即在图中不显示。
[Motor_STE, Generate_STE, Motor_external, Gener_external] = Data_Pre(filename, sheet1_name, sheet2_name, speed_gears1, speed_gears2);
Motor_external(:,2) = Motor_external(:,2) + 70; % 可以给外特性曲线略微增加一些值,因为绘制外特性曲线的散点不一定囊括了所有的工作范围,实际电机的工作范围可能会远远超过,因此可以增加一些范围来使路谱所有数据被囊括其中。
% GtoM_TMcal为主功能函数,用来生成map图和路谱效率计算。
[EFF_Total_AVERAGE, EFF_MOT_AVERAGE, EFF_GEN_AVERAGE, STE_Road] = TMcal(Motor_STE, Generate_STE, Motor_external, Gener_external, xlim_val,ylim_val ,value_eff, flag);
function [Motor_STE, Generate_STE, Motor_external, Gener_external] = Data_Pre(filename, sheet1_name, sheet2_name, speed_gears1, speed_gears2)
global tolerance coefficient
% 读取表格,并将表格sheet生成变量opts
opts1 = detectImportOptions(filename, 'Sheet', sheet1_name);
opts2 = detectImportOptions(filename, 'Sheet', sheet2_name);
% 将sheet的每一列设定一变量名,防止表格抬头名称乱定义。
opts1.VariableNames = {'Var1','Var2','Var3'};
opts2.VariableNames = {'Var1','Var2','Var3'};
% 设置三列数据,数据格式为双精度。
opts1 = setvartype(opts1, {'Var1','Var2','Var3'}, 'double');
opts2 = setvartype(opts2, {'Var1','Var2','Var3'}, 'double');
Motor_data = readtable(filename, opts1);
Generate_data = readtable(filename, opts2);
Motor_data.Var3 = round(Motor_data.Var3 * coefficient, 3);
% 将抬头(第一行)去掉
Motor_STE = Motor_data{2:end, 1:3};
% Motor_data是驱动效率map(sheet1), Generate_data是发电效率map(sheet2).
Generate_data.Var3 = round(Generate_data.Var3 * 100, 3);
Generate_STE = Generate_data{2:end, 1:3};
% Generate_STE(:,2) = -Generate_STE(:,2); %
% 需要注意原发电效率map表格的转矩是否为负,若不为负,需要取相反数。
% 处理外特性曲线数据,is_max为1,那就找出同转速档位的最大转矩值,is_max为0,那就找出最小值。
is_max = 1;
Motor_external = external_character_cal(speed_gears1, tolerance, Motor_STE, is_max);
is_max = 0;
Gener_external = external_character_cal(speed_gears2, tolerance, Generate_STE, is_max);
% 如果需要,可以将修改后的数据写回Excel文件,尽量不要,一旦改了,就难改回来了。
% writetable(data, 'modified_table.xlsx');
end
function result = external_character_cal(speed_gears, tolerance, Motor_data, is_max)
speed = Motor_data(:, 1);
torque = Motor_data(:, 2);
result = zeros(length(speed_gears), 2);
for i = 1:length(speed_gears)
% 找出当前档位的转速范围内的转矩
idx = speed >= (speed_gears(i) - tolerance) & speed <= (speed_gears(i) + tolerance);
torque_in_range = torque(idx);
speed_in_range = speed(idx);
% 找出最大转矩及其对应的转速
if is_max == 1
[max_torque, max_idx] = max(torque_in_range);
else
[max_torque, max_idx] = min(torque_in_range);
end
max_speed = speed_in_range(max_idx);
% 存储结果,外特性曲线经过的 [各转速档位,各转速档位对应的最大转矩]
result(i, :) = [max_speed, max_torque];
end
end
功能函数
% 第一列是转速,第二列是转矩,第三列是效率
function [EFF_Total_AVERAGE, EFF_MOT_AVERAGE, EFF_GEN_AVERAGE, STE_Road] = TMcal(Motor_5T, Generate_5T, Motor_outside, generate_outside, xlim_val, ylim_val, value_eff, flag)
global M2V_MCU_DMSpd M2V_MCU_DMTrq TX_mcuMotorSpeed TX_mcuOutTorque title_name
%% 电机电动效率曲面数据加载
speed_eff_m = Motor_5T(:,1);
torque_eff_m = Motor_5T(:,2);
efficency_eff_m = Motor_5T(:,3);
% 电机电动效率曲面插值
row = 400;
col = row;
[SPEED_M,TORQUE_M] = meshgrid(0:xlim_val/(row-1):xlim_val,0:max(max(torque_eff_m))/(col-1):max(max(torque_eff_m)));
EFFICENCY_M = griddata(speed_eff_m,torque_eff_m,efficency_eff_m,SPEED_M,TORQUE_M);
EFFICENCY1_M = griddata(speed_eff_m,torque_eff_m,efficency_eff_m,SPEED_M,TORQUE_M,'V4');
jm = find(isnan(EFFICENCY_M));
EFFICENCY_M(jm) = EFFICENCY1_M(jm);
% 电机电动外特性曲线插值
speed_ex_m = Motor_outside(:,1);
torque_ex_m = Motor_outside(:,2);
speed_q_m = [0:xlim_val/(row-1):xlim_val];
torque_q_m = interp1(speed_ex_m,torque_ex_m,speed_q_m,'linear','extrap');
% 电机电动效率曲面沿外特性曲线剪切
TRQ_RE_M = repmat(torque_q_m,col,1);
im = find(TORQUE_M > TRQ_RE_M); %确定超出边界的格点下标
EFFICENCY_M(im) = NaN; %强制为非数
%% 电机发电效率曲面数据加载
speed_eff_g = Generate_5T(:,1);
torque_eff_g = Generate_5T(:,2);
efficency_eff_g = Generate_5T(:,3);
torque_eff_minus_g = torque_eff_g; %这里的转矩数据列本身就为负。
% 电机发电效率曲面插值
row = 400;
col = row;
[SPEED_G,TORQUE_G] = meshgrid(0:xlim_val/(row-1):xlim_val,0:min(min(torque_eff_minus_g))/(col-1):min(min(torque_eff_minus_g)));
EFFICENCY_G = griddata(speed_eff_g,torque_eff_minus_g,efficency_eff_g,SPEED_G,TORQUE_G);
EFFICENCY1_G = griddata(speed_eff_g,torque_eff_minus_g,efficency_eff_g,SPEED_G,TORQUE_G,'V4');
jg = find(isnan(EFFICENCY_G));
EFFICENCY_G(jg) = EFFICENCY1_G(jg);
%% 电机发电外特性曲线
speed_ex_g = generate_outside(:,1)';
torque_ex_g = generate_outside(:,2)';
torque_ex_minus_g = torque_ex_g;
% 电机发电外特性曲线插值
speed_q_g = [0:xlim_val/(row-1):xlim_val]; %#ok<NBRAK>
torque_q_g = interp1(speed_ex_g,torque_ex_minus_g,speed_q_g,'cubic','extrap');
% 电机发电效率曲面沿外特性曲线剪切
TRQ_RE_G = repmat(torque_q_g,col,1);
ig = find(TORQUE_G < TRQ_RE_G); %确定超出边界的格点下标
EFFICENCY_G(ig) = NaN; %强制为非数
%% 绘图
figure(1);
% 电机电动效率
colormap(jet); % 色阶
[c,h] = contourf(SPEED_M,TORQUE_M,EFFICENCY_M,value_eff);
ylim([-ylim_val, ylim_val]);
if flag == 1
xlim([-xlim_val,xlim_val]);
else
xlim([0,xlim_val]);
end
hold on
h = clabel(c,h,'labelspacing',160);
set(h,'BackgroundColor',[1 1 6],...
'EdgeColor',[7 7 7],...
'Linewidth',1,...
'Color','r');
hold on
% plot(speed_q_m,torque_q_m,'b','linewidth',2.5);
% hold on
% 电机后退效率
if flag == 1 % 如果是泵用电机,那不需要第三象限
colormap(jet); % 色阶
[c,h] = contourf(-SPEED_M,-TORQUE_M,EFFICENCY_M,value_eff);
hold on
h = clabel(c,h,'labelspacing',160);
set(h,'BackgroundColor',[1 1 6],...
'EdgeColor',[7 7 7],...
'Linewidth',1,...
'Color','r');
% hold on
% plot(-speed_q_m,-torque_q_m,'b','linewidth',2.5);
% hold on
end
%
% % 电机发电效率
[c,h] = contourf(SPEED_G,TORQUE_G,EFFICENCY_G,value_eff);
hold on
h = clabel(c,h,'labelspacing',160);
set(h,'BackgroundColor',[1 1 6],...
'EdgeColor',[7 7 7],...
'Linewidth',1,...
'Color','r');
% hold on
% plot(speed_q_g,torque_q_g,'b','linewidth',2.5);
% hold on
% 电机发电后退效率
if flag ==1 % 如果是泵用电机,那不需要第二象限
[c,h] = contourf(-SPEED_G,-TORQUE_G,EFFICENCY_G,value_eff);
hold on
caxis([25 100]); % 设置颜色条的范围,比如0到100
h = clabel(c,h,'labelspacing',160);
set(h,'BackgroundColor',[1 1 6],...
'EdgeColor',[7 7 7],...
'Linewidth',1,...
'Color','r');
% hold on
% plot(-speed_q_g,-torque_q_g,'b','linewidth',2.5);
% hold on
end
% 加载实测数据
if flag == 1
TmTor0 = M2V_MCU_DMTrq(:,end);
TmSpd0 = M2V_MCU_DMSpd(:,end);
index1 = [1,3]; % 行走电机map图为4个象限。
index2 = [2,4];
else
TmTor0 = TX_mcuOutTorque(:,end);
TmSpd0 = TX_mcuMotorSpeed(:,end);
index1 = [1]; % 泵用电机map图为一、四象限。
index2 = [4];
end
TmSpd = TmSpd0;
TmTor = TmTor0;
scatter(TmSpd,TmTor,20,'o', 'MarkerEdgeColor','k','MarkerFaceColor','y');
hold on
t1 = xlabel('speed [rpm]');
t2 = ylabel('Torque [Nm]');
set([t1,t2],'FontSize',14);
legend('Mot Efficiency Map','Mot WOT','Gen Efficiency Map','Gen WOT','location','southeast')
title(title_name,'FontSize',14 )
grid on;
hold on;
%% 计算平均效率
Ans_out1 = 0; Ans_input1 = 0;
STE_Road = [];
for index = index1
[TmSpd_index, TmTor_index] = Eff_data_pre(TmTor, TmSpd, index);
if index == 1
[Sum_Power_out, Sum_Power_input, CB_EFF_GEN] = Power_IO_cal(SPEED_M, TORQUE_M,EFFICENCY_M,TmSpd_index,TmTor_index);
elseif index == 3
[Sum_Power_out, Sum_Power_input, CB_EFF_GEN] = Power_IO_cal(-SPEED_M, -TORQUE_M,EFFICENCY_M,TmSpd_index,TmTor_index);
end
STE_Road = [STE_Road; [TmSpd_index, TmTor_index, CB_EFF_GEN]];
Ans_out1 = Ans_out1 + Sum_Power_out;
Ans_input1 = Ans_input1 + Sum_Power_input;
end
EFF_MOT_AVERAGE = Ans_out1 / Ans_input1;
Ans_out2 = 0; Ans_input2 = 0;
for index = index2
[TmSpd_index, TmTor_index] = Eff_data_pre(TmTor, TmSpd, index);
if index == 2
[Sum_Power_out, Sum_Power_input, CB_EFF_GEN] = Power_IO_cal(-SPEED_G, -TORQUE_G,EFFICENCY_G,TmSpd_index,TmTor_index);
elseif index == 4
[Sum_Power_out, Sum_Power_input, CB_EFF_GEN] = Power_IO_cal(SPEED_G, TORQUE_G,EFFICENCY_G,TmSpd_index,TmTor_index);
end
STE_Road = [STE_Road; [TmSpd_index, TmTor_index, CB_EFF_GEN]];
Ans_out2 = Ans_out2 + Sum_Power_out;
Ans_input2 = Ans_input2 + Sum_Power_input;
end
EFF_GEN_AVERAGE = Ans_out2 / Ans_input2;
%%
EFF_Total_AVERAGE = (Ans_out1 + Ans_out2) / (Ans_input1 + Ans_input2);
ax = gca;
xlen = ax.XLim;
ylen = ax.YLim;
% 计算右上角的位置
%%
xpos = xlen(2) - 0.03 * (xlen(2) - xlen(1)); % 在x轴方向留出一些空间
ypos = ylen(2) - 0.02 * (ylen(2) - ylen(1)); % 在y轴方向留出一些空间
text(xpos, ypos, ['电驱效率:',num2str(EFF_MOT_AVERAGE),'%'], 'HorizontalAlignment', 'right', 'VerticalAlignment', 'top');
xpos = xlen(2) - 0.03 * (xlen(2) - xlen(1)); % 在x轴方向留出一些空间
ypos = ylen(2) - 0.06 * (ylen(2) - ylen(1)); % 在y轴方向留出一些空间
text(xpos, ypos, ['发电效率:',num2str(EFF_GEN_AVERAGE),'%'], 'HorizontalAlignment', 'right', 'VerticalAlignment', 'top');
xpos = xlen(2) - 0.03 * (xlen(2) - xlen(1)); % 在x轴方向留出一些空间
ypos = ylen(2) - 0.10 * (ylen(2) - ylen(1)); % 在y轴方向留出一些空间
text(xpos, ypos, ['总效率:',num2str(EFF_Total_AVERAGE),'%'], 'HorizontalAlignment', 'right', 'VerticalAlignment', 'top');
set(gcf, 'Position',[100 100 1000 600]);
filename = [title_name , '.jpg'];
saveas(gcf, filename);
end
% 计算输入总功率和输出总功率
function [Sum_Power_out, Sum_Power_input, CB_EFF_GEN] = Power_IO_cal(SPEED, TORQUE,EFFICENCY, TmSpd, TmTor)
CB_EFF_GEN = griddata(SPEED, TORQUE, EFFICENCY, TmSpd, TmTor,'nearest'); % 根据实测数据查表得出效率值
PowerGen_Output = TmSpd.*TmTor./9550;
PowerGen_Input = PowerGen_Output./CB_EFF_GEN;
Sum_Power_out = sum(PowerGen_Output(~isnan(PowerGen_Output)));
Sum_Power_input = sum(PowerGen_Input(~isnan(PowerGen_Input)));
end
function [TmSpd_Mot2, TmTor_Mot2] = Eff_data_pre(TmTor, TmSpd, flag)
% 第一象限
TmTor_Mot1 = TmTor;
TmSpd_Mot1 = TmSpd;
switch flag
case 1
INDEX_TRQNEG = find(TmTor <= 0);
TmTor_Mot1(INDEX_TRQNEG) = [];
TmSpd_Mot1(INDEX_TRQNEG) = [];
INDEX_SPDZERO = find(TmSpd_Mot1 <= 0);
case 2
INDEX_TRQNEG = find(TmTor <= 0);
TmTor_Mot1(INDEX_TRQNEG) = [];
TmSpd_Mot1(INDEX_TRQNEG) = [];
INDEX_SPDZERO = find(TmSpd_Mot1 >= 0);
case 3
INDEX_TRQNEG = find(TmTor >= 0);
TmTor_Mot1(INDEX_TRQNEG) = [];
TmSpd_Mot1(INDEX_TRQNEG) = [];
INDEX_SPDZERO = find(TmSpd_Mot1 >= 0);
otherwise
INDEX_TRQNEG = find(TmTor >= 0);
TmTor_Mot1(INDEX_TRQNEG) = [];
TmSpd_Mot1(INDEX_TRQNEG) = [];
INDEX_SPDZERO = find(TmSpd_Mot1 <= 0);
end
TmSpd_Mot2 = TmSpd_Mot1;
TmTor_Mot2 = TmTor_Mot1;
TmSpd_Mot2(INDEX_SPDZERO) = [];
TmTor_Mot2(INDEX_SPDZERO) = [];
end