#--------------------------------------------------------------------- #Name: d0014_drive_cycle_efficiency.py #Menu-en: Calculate Efficiency from Drive Mode #Menu-ja: 走行モードから効率を計算 #Type: Python #Create: October 15, 2020 JSOL Corporation #Comment-en:Uses results of the efficiency map analysis study to calculate efficiency of electric vehicles in a specified drive mode. #Comment-ja:効率マップ解析スタディの結果を使用して、指定された走行モードにおける電気自動車などの効率を算出します。 #Copyright: (c) JSOL Corporation. All Rights Reserved. #--------------------------------------------------------------------- import csv import os import math import sys import numpy as np def main(): confirm_title_en = "Warning" confirm_title_ja = "ワーニング" confirm_msg_en = "Running this script will delete all existing operating points. Do you wish to proceed?" confirm_msg_ja = "スクリプトの実行によって既存の動作点は削除されます。実行を続けますか?" check = show_confirm_message(confirm_title_en, confirm_title_ja, confirm_msg_en, confirm_msg_ja) if check == 0: cancel_message_en = "Process is canceled." cancel_message_ja = "処理が中断されました。" show_cancel_exit_message(cancel_message_en, cancel_message_ja) return app = designer.GetApplication() study = app.GetCurrentStudy() dialog = app.CreateDialogBox() if study.NumEfficiencyMapDefinitions() > 1: confirm_msg_en = "This script will use the first efficiency map plot for calculation." confirm_msg_ja = "このスクリプトは、スタディの中で1番目の効率マップを計算に使用します。" show_message(confirm_title_en, confirm_title_ja, confirm_msg_en, confirm_msg_ja) title_ja = "走行モードから効率を計算" title_en = "Calculate Efficiency from Drive Mode" csv_file_en = "Drive Mode CSV File" csv_file_ja = "走行モードCSVファイル" tire_diameter_ja = "タイヤ直径, mm" tire_diameter_en = "Tire Diameter, mm" gear_ratio_ja = "最終減速比" gear_ratio_en = "Final Reduction Ratio" rolling_resistance_ja = "転がり抵抗係数" rolling_resistance_en = "Rolling Resistance Coefficient" air_density_ja = "空気密度, kg/m^3" air_density_en = "Air Density, kg/m^3" drag_coefficient_ja = "Cd値" drag_coefficient_en = "Drag Coefficient" cross_sectional_ja = "前面投影面積, m^2" cross_sectional_en = "Cross Sectional Area of Vehicle, m^2" total_weight_ja="総重量, kg" total_weight_en = "Total Weight, kg" gravity_ja = "重力加速度, m/s^2" gravity_en = "Gravitational Acceleration, m/s^2" loss_factor_ja = "駆動系損失係数" loss_factor_en = "Drive System Loss Factor" cancel_message_en = "Process is canceled." cancel_message_ja = "処理が中断されました。" map_plot_error_en = "Current Study has no map." map_plot_error_ja = "選択されているスタディにマップが存在しません。" study_select_error_en = "Current Study is not Efficiency Map Study." study_select_error_ja = "選択されているスタディは効率マップ解析スタディではありません。" currentStudyType = study.GetScriptTypeName() if not currentStudyType.endswith("Response"): show_error_exit_message(study_select_error_en, study_select_error_ja) return if study.NumEfficiencyMapDefinitions() == 0: show_error_exit_message(map_plot_error_en, map_plot_error_ja) return plot = study.GetEfficiencyMapPlot(0) if not plot.IsValid(): show_error_exit_message(map_plot_error_en, map_plot_error_ja) return plot_def = study.GetEfficiencyMapDefinition(0) case = study.GetCurrentCase() MaxI = plot_def.MaxVoltage() MaxV = plot_def.MaxCurrent() dialog.SetTranslation(title_en, title_ja) dialog.SetTranslation(csv_file_en, csv_file_ja) dialog.SetTranslation(tire_diameter_en, tire_diameter_ja) dialog.SetTranslation(gear_ratio_en, gear_ratio_ja) dialog.SetTranslation(rolling_resistance_en, rolling_resistance_ja) dialog.SetTranslation(air_density_en, air_density_ja) dialog.SetTranslation(drag_coefficient_en, drag_coefficient_ja) dialog.SetTranslation(cross_sectional_en, cross_sectional_ja) dialog.SetTranslation(total_weight_en, total_weight_ja) dialog.SetTranslation(gravity_en, gravity_ja) dialog.SetTranslation(loss_factor_en, loss_factor_ja) dialog.SetTitle(title_en) dialog.SetModal(False) dialog.AddOpenFilename("File_drive_cycle", csv_file_en, "", "") dialog.AddReal("TireD", tire_diameter_en, 742) dialog.AddReal("GearRatio", gear_ratio_en, 8) dialog.AddReal("Dair", air_density_en, 1.205) dialog.AddReal("Cd", drag_coefficient_en, 0.3) dialog.AddReal("Area", cross_sectional_en, 2.88) dialog.AddReal("Rrote", rolling_resistance_en, 0.008) dialog.AddReal("Mass", total_weight_en, 1760) dialog.AddReal("Grav", gravity_en, 9.81) ret = dialog.Show() if ret==0: show_cancel_exit_message(cancel_message_en, cancel_message_ja) return File_drive_cycle = dialog.GetValue("File_drive_cycle").decode("utf-8") if len(File_drive_cycle) == 0: message_en = "Please specify CSV file name." message_ja = "CSVファイル名を指定してください." show_error_exit_message(message_en, message_ja) return if not os.path.isfile(File_drive_cycle): message_en = "The specified file does not exist." message_ja = "指定されたファイルが存在しません。" show_error_exit_message(message_en, message_ja) return #Parameter for the vehicle model TireD = dialog.GetValue("TireD") GearRatio = dialog.GetValue("GearRatio") Dair = dialog.GetValue("Dair") Cd = dialog.GetValue("Cd") Area = dialog.GetValue("Area") Rrote = dialog.GetValue("Rrote") Mass = dialog.GetValue("Mass") Grav = dialog.GetValue("Grav") if TireD <= 0: message_en = "The value for Tire Diameter is invalid." message_ja = "タイヤ直径の値が無効です。" show_error_exit_message(message_en, message_ja) return if GearRatio <= 0: message_en = "The value for Gear Ratio is invalid." message_ja = "最終減衰ギアの値が無効です。" show_error_exit_message(message_en, message_ja) return if Rrote <= 0: message_en = "The value for Rolling Resistance is invalid." message_ja = "転がり抵抗の値が無効です。" show_error_exit_message(message_en, message_ja) return if Dair <= 0: message_en = "The value for Air Density is invalid." message_ja = "空気密度の値が無効です。" show_error_exit_message(message_en, message_ja) return if Cd <= 0: message_en = "The value for Drag Coefficient is invalid." message_ja = "Cd値が無効です。" show_error_exit_message(message_en, message_ja) return if Area <= 0: message_en = "The value for Cross Sectional Area of Vehicle is invalid." message_ja = "前面投影面積の値が無効です。" show_error_exit_message(message_en, message_ja) return if Mass <= 0: message_en = "The value for Total Weight is invalid." message_ja = "総重量の値が無効です。" show_error_exit_message(message_en, message_ja) return if Grav <= 0: message_en = "The value for Gravity is invalid." message_ja = "重力加速度の値が無効です。" show_error_exit_message(message_en, message_ja) return #Read drive cycle try: Drive_cycle = np.loadtxt(File_drive_cycle, delimiter=",", skiprows=1, ndmin=2) except: message_en = "Error opening CSV file." message_ja = "CSVファイルの読み込みにエラーが発生しました。" show_error_exit_message(message_en, message_ja) return Car_speed = Drive_cycle[:,1] Time = Drive_cycle[:,0] Length = Time.size if Length < 2: message_en = "There is insufficient data in the drive mode CSV file.\nAt least 2 data points must be included." message_ja = "走行モードCSVファイルに含まれるデータが不足しています。\n2点以上のデータが含まれている必要があります。" show_error_exit_message(message_en, message_ja) return for a, b in zip(Time[:-1], Time[1:]): if a > b: message_en = "The time data in the drive mode CSV file is not in ascending order.\nPlease sort the data by time in ascending order." message_ja = "走行モードCSVファイルの速度点列の時刻が昇順ではありません。\n時刻を昇順に並べ替えてください。" show_error_exit_message(message_en, message_ja) return #_______________________________________________________ #Calculate the Torque and speed from the Drive cycle Speed = Car_speed*1/(TireD*math.pi*3.6/1000)*60*GearRatio T1 = (0.5*Dair*Cd*Area*(np.square(Car_speed)/(3.6)**2)+Rrote*Mass*Grav)*TireD/2000/GearRatio DSpeed = np.divide(Car_speed-np.concatenate((Car_speed[0], Car_speed[0:Length-1]), axis=None), Time-np.concatenate((-Time[1], Time[0:Length-1]), axis=None)) T2 = (DSpeed*Mass*1/3.6)*TireD/2/1000/GearRatio Torque = T1 + T2 Duty_cycle = np.transpose(np.stack([Speed, Torque])) #resulting duty cycle #_______________________________________________________ #Get max speed and max torque max_speed = max(Speed) max_torque = max(Torque) is_outside_map = False Eff = 0 Energy = 0 for i in range(Length): if plot.IsValidPoint(Speed[i], Torque[i]): res = plot.GetPointResult('efficiency', Speed[i], Torque[i]) Eff = Eff+res if i==0: Energy = 0 elif res==0: dt = Time[i]-Time[i-1] Energy=Energy+dt*3*MaxI*MaxV else: dt = Time[i]-Time[i-1] if Torque[i] >= 0: Energy = Energy+dt*math.pi*100*Speed[i]*Torque[i]/res/30 else: Energy = Energy+dt*math.pi*Speed[i]*Torque[i]*res/100/30 else: Eff = 0 Energy = 3*MaxI*MaxV*Time[Length-1] is_outside_map = True break if is_outside_map: outside_map_en = "The results are outside of the map." outside_map_ja = "ポイントが効率マップに存在しません。" show_error_exit_message(outside_map_en, outside_map_ja) return plot.DeleteAllPoints() plot.AddPoints(list(zip(Speed, Torque))) Eff=Eff/Length Energy=Energy/1000000 # Set response variable app.GetCurrentStudy().SetUserResponseVariable(u"AveEff", case, Eff) app.GetCurrentStudy().SetUserResponseVariable(u"Energy", app.GetCurrentStudy().GetCurrentCase(), float(Energy)) app.GetCurrentStudy().SetUserResponseVariable(u"MaxSpeed", case, float(max_speed)) app.GetCurrentStudy().SetUserResponseVariable(u"MaxTorque", case, float(max_torque)) results_en = "Average Efficiency, % = " + str(round(Eff, 2)) + "\nTotal Energy, MJ = " + str(round(Energy, 2)) + "\nMaximum Speed of Drive Cycle, r/min = " + str(round(max_speed, 2)) + "\nMaximum Torque of Drive Cycle, Nm = " + str(round(max_torque, 2)) + "\n\nTo check the operating points, please close and re-open the efficiency map window." results_ja = "平均効率, % = " + str(round(Eff, 2)) + "\n消費された全エネルギ, MJ = " + str(round(Energy, 2)) + "\n最大速度, r/min = " + str(round(max_speed, 2)) + "\n最大トルク, Nm = " + str(round(max_torque, 2)) + "\n\n動作点を確認するためには、効率マップウィンドウを一度閉じて、再度開いてください。" result_title_en = "Results" result_title_ja = "結果" show_message(result_title_en, result_title_ja, results_en, results_ja) def show_error_exit_message(message_en, message_ja): title_en = "Error" title_ja = "エラー" show_message(title_en, title_ja, message_en, message_ja) def show_cancel_exit_message(message_en, message_ja): title_en = "Cancel" title_ja = "キャンセル" show_message(title_en, title_ja, message_en, message_ja) def show_message(title_en, title_ja, message_en, message_ja): app = designer.GetApplication() msgdlg = app.CreateDialogBox() msgdlg.SetTranslation(title_en, title_ja) msgdlg.SetTranslation(message_en, message_ja) msgdlg.SetCancelButtonVisible(False) msgdlg.SetTitle(title_en) msgdlg.AddLabel(message_en) msgdlg.Show() def show_confirm_message(title_en, title_ja, message_en, message_ja): app = designer.GetApplication() msgdlg = app.CreateDialogBox() msgdlg.SetTranslation(title_en, title_ja) msgdlg.SetTranslation(message_en, message_ja) msgdlg.SetTitle(title_en) msgdlg.AddLabel(message_en) return msgdlg.Show() main()