Package: xyw-utils
10分钟快速开始前言一些常用的工具函数，主要为客车整车试验数据处理相关内容。本文仅介绍了部分常用函数，data模块中还有许多函数没有涉及，详细用法请参考源码中的函数说明。文中出现的所有演示素材都可以在库安装路径下的examples文件夹中找到。数据处理基本操作读取表格文件目前只封装了xlsx、xls和csv格式的文件读取函数，其他pandas支持的文件格式可以直接使用pandas内置的函数读取：importxyw_utilsasxyprocessor=xy.data.FileProcessorFacade()df=processor.read('CCBC.csv')>>>dfTime[s]uDCDCInUnnamed:2Time[s].1...Time[s].11rBattSOCUnnamed:35Unnamed:3600.01149617.0NaN0.01207...0.0904697.6NaNNaN14.01241617.0NaN4.01299...0.1904997.6NaNNaN25.01263617.0NaN5.01320...0.2905497.6NaNNaN36.01286617.0NaN6.01344...3.4905997.6NaNNaN47.01309617.0NaN7.01367...3.5903697.6NaNNaN..............................13265NaNNaNNaNNaN...1329.6451096.4NaNNaN13266NaNNaNNaNNaN...1329.7450996.4NaNNaN13267NaNNaNNaNNaN...1329.8451196.4NaNNaN13268NaNNaNNaNNaN...1329.9450196.4NaNNaN13269NaNNaNNaNNaN...NaNNaNNaNNaN[13270rowsx37columns]对于只有单一时间序列的数据，使用上述命令就可以直接生成以表格中第一行为列名的pandas.DataFrame数据，不过对于每一信号都有单独时间序列的数据则需要继续进行如下操作：dfs=xy.data.init_split(df)>>>dfs[Time[s]uDCDCIn00.01149617.014.01241617.025.01263617.036.01286617.047.01309617.0.........13221325.31101617.013231326.31125617.013241327.31149617.013251328.31172617.013261329.31193617.0[1327rowsx2columns],Time[s]iDCDCIn00.012072.014.012993.025.013202.036.013443.047.013672.0.........13221325.311583.013231326.311832.013241327.312072.013251328.312292.013261329.312512.0[1327rowsx2columns],Time[s]iMCU00.026742.010.126682.020.226692.033.526882.043.626862.0.........132631329.597823.0132641329.697953.0132651329.797833.0132661329.897843.0132671329.997903.0[13268rowsx2columns],Time[s]uMCU00.02674617.010.12668617.020.22669617.033.52688617.043.62686617.0.........132631329.59782617.0132641329.69795617.0132651329.79783617.0132661329.89784617.0132671329.99790617.0[13268rowsx2columns],Time[s]vVehSpdAbs00.027300.010.127250.020.227250.033.527440.043.627420.0.........132631329.598370.0132641329.698510.0132651329.798390.0132661329.898390.0132671329.998460.0[13268rowsx2columns],Time[s]iSPCOut00.05502110.15502020.25507133.45522143.555711.........132651329.560531132661329.660521132671329.760501132681329.860481132691329.960461[13270rowsx2columns],Time[s]uSPCOut00.0550222210.1550222220.2550723033.4552222243.55571222.........132651329.56053223132661329.66052223132671329.76050223132681329.86048222132691329.96046222[13270rowsx2columns],Time[s]iAPCOut00.07561210.17561220.27562233.47580043.575810.........132651329.600610132661329.700750132671329.800630132681329.900630132691330.001790[13270rowsx2columns],Time[s]uAPCOut00.0756132710.1756132720.2756232633.47580043.575810.........132651329.600610132661329.700750132671329.800630132681329.900630132691330.001790[13270rowsx2columns],Time[s]iBattCurr00.090463.610.190493.820.290543.433.490591.243.590361.2.........132641329.545371.2132651329.645101.2132661329.745091.2132671329.845111.2132681329.945011.2[13269rowsx2columns],Time[s]uBattVltg00.09046617.710.19049617.720.29054617.733.49059617.943.59036617.9.........132641329.54537617.9132651329.64510617.9132661329.74509617.9132671329.84511617.9132681329.94501617.9[13269rowsx2columns],Time[s]rBattSOC00.0904697.610.1904997.620.2905497.633.4905997.643.5903697.6.........132641329.5453796.4132651329.6451096.4132661329.7450996.4132671329.8451196.4132681329.9450196.4[13269rowsx2columns]]df=xy.data.merge_all(dfs)>>>dfTime[s]uDCDCIniDCDCIniMCUuMCU...iAPCOutuAPCOutiBattCurruBattVltgrBattSOC00.01149617.0NaNNaNNaN...NaNNaNNaNNaNNaN10.01207NaN2.0NaNNaN...NaNNaNNaNNaNNaN20.02674NaNNaN2.0617.0...NaNNaNNaNNaNNaN30.02730NaNNaNNaNNaN...NaNNaNNaNNaNNaN40.05502NaNNaNNaNNaN...NaNNaNNaNNaNNaN....................................689941329.94501NaNNaNNaNNaN...NaNNaN1.2617.996.4689951329.96046NaNNaNNaNNaN...NaNNaNNaNNaNNaN689961329.99790NaNNaN3.0617.0...NaNNaNNaNNaNNaN689971329.99846NaNNaNNaNNaN...NaNNaNNaNNaNNaN689981330.00179NaNNaNNaNNaN...0.00.0NaNNaNNaN[68999rowsx13columns]处理到这一步时，已经将各时间序列的数据统一到了同一个总的时间轴上，不过每一个信号列中都会有许多NaN的无效数据，可以使用下面的方法进行插值：df=xy.data.interpolate_nan(df,drop=False)>>>dfTime[s]uDCDCIniDCDCIniMCUuMCU...iAPCOutuAPCOutiBattCurruBattVltgrBattSOC00.01149617.0NaNNaNNaN...NaNNaNNaNNaNNaN10.01207617.02.000000NaNNaN...NaNNaNNaNNaNNaN20.02674617.02.0036672.0617.0...NaNNaNNaNNaNNaN30.02730617.02.0038072.0617.0...NaNNaNNaNNaNNaN40.05502617.02.0107352.0617.0...NaNNaNNaNNaNNaN....................................689941329.94501NaNNaN3.0617.0...0.00.01.2617.996.4689951329.96046NaNNaN3.0617.0...0.00.0NaNNaNNaN689961329.99790NaNNaN3.0617.0...0.00.0NaNNaNNaN689971329.99846NaNNaNNaNNaN...0.00.0NaNNaNNaN689981330.00179NaNNaNNaNNaN...0.00.0NaNNaNNaN[68999rowsx13columns]注意：当把drop参数设为False时，首尾无法插值的部分数据依旧会保持为NaN。当确认不需要这部分数据时，可以直接将drop设为True，舍去该部分数据；也可以使用xy.data.remove_nan()方法手动删去所有带有NaN数据的行：df=xy.data.remove_nan(df)>>>dfTime[s]uDCDCIniDCDCIniMCUuMCU...iAPCOutuAPCOutiBattCurruBattVltgrBattSOC00.09046617.02.0195932.0617.0...2.0327.03.600000617.797.610.12668617.02.0286462.0617.0...2.0327.03.672418617.797.620.12725617.02.0287882.0617.0...2.0327.03.673558617.797.630.15502617.02.0357292.0617.0...2.0327.03.729081617.797.640.17561617.02.0408762.0617.0...2.0327.03.770249617.797.6....................................689521329.26058617.02.0000003.0617.0...0.00.01.200000617.996.4689531329.29780617.02.0000003.0617.0...0.00.01.200000617.996.4689541329.29836617.02.0000003.0617.0...0.00.01.200000617.996.4689551329.30060617.02.0000003.0617.0...0.00.01.200000617.996.4689561329.31193617.02.0000003.0617.0...0.00.01.200000617.996.4[68957rowsx13columns]保存数据保存的格式与读取时的限制相同：processor.write(df,'re.xlsx')积分封装了两种常用的离散数据积分方法，辛普森法和复杂梯形法，这里以积分电池能耗为例：df['pb']=df['iBattCurr']*df['uBattVltg']df['wb']=xy.data.get_integral(df[['Time [s]','pb']],method='trapz',last_only=False)/3600000>>>dfTime[s]uDCDCIniDCDCIniMCUuMCU...iBattCurruBattVltgrBattSOCpbwb00.09046617.02.0195932.0617.0...3.600000617.797.62223.7200000.00000010.12668617.02.0286462.0617.0...3.672418617.797.62268.4527680.00002320.12725617.02.0287882.0617.0...3.673558617.797.62269.1567350.00002330.15502617.02.0357292.0617.0...3.729081617.797.62303.4535040.00004140.17561617.02.0408762.0617.0...3.770249617.797.62328.8827610.000054....................................689521329.26058617.02.0000003.0617.0...1.200000617.996.4741.4800002.526091689531329.29780617.02.0000003.0617.0...1.200000617.996.4741.4800002.526098689541329.29836617.02.0000003.0617.0...1.200000617.996.4741.4800002.526099689551329.30060617.02.0000003.0617.0...1.200000617.996.4741.4800002.526099689561329.31193617.02.0000003.0617.0...1.200000617.996.4741.4800002.526101[68957rowsx15columns]注意：method参数只支持‘simps’以及‘trapz’两种，last_only设为True时，只返回最终积分结果，可以大大减少运算时间，此例中即2.526101。对于求电量积分这一操作，也可以使用xy.vehicle_test.energy_consumption_test()这一专用函数：df['wb']=xy.vehicle_test.energy_consumption_test(df,1,'Time [s]','iBattCurr','uBattVltg',last_only=False)>>>dfTime[s]uDCDCIniDCDCIniMCUuMCU...iBattCurruBattVltgrBattSOCpbwb00.09046617.02.0195932.0617.0...3.600000617.797.62223.7200000.00000010.12668617.02.0286462.0617.0...3.672418617.797.62268.4527680.00002320.12725617.02.0287882.0617.0...3.673558617.797.62269.1567350.00002330.15502617.02.0357292.0617.0...3.729081617.797.62303.4535040.00004140.17561617.02.0408762.0617.0...3.770249617.797.62328.8827610.000054....................................689521329.26058617.02.0000003.0617.0...1.200000617.996.4741.4800002.526091689531329.29780617.02.0000003.0617.0...1.200000617.996.4741.4800002.526098689541329.29836617.02.0000003.0617.0...1.200000617.996.4741.4800002.526099689551329.30060617.02.0000003.0617.0...1.200000617.996.4741.4800002.526099689561329.31193617.02.0000003.0617.0...1.200000617.996.4741.4800002.526101[68957rowsx15columns]整车试验常用操作行驶阻力系数根据车辆总质量和车型，按照GB/T 18386-2017附录A中表格估算车辆行驶阻力系数：f=xy.vehicle_test.driving_resistance(13500,'coach')>>>print(f)20.154x+5.95x+751.3>>>print(type(f))<class'numpy.poly1d'>>>>print(f.c)[1.5400e-015.9500e+007.5135e+02]>>>print(f(60))1662.75稳态回转稳态回转试验数据处理，主要参考：《GB/T 6323-2014 汽车操纵稳定性试验方法》10.4：# 读取数据，第三个工作表中df=processor.read('steady_static_circular_test.xlsx',2)# 移除数据中的无效值行df=xy.data.remove_nan(df)# 进行稳态回转的数据处理，df、轴距、各数据所在列名称res=xy.vehicle_test.steady_static_circular_test(df,4.050,'Time [s]','AccY_Comp [m/s/s]','V_X [km/h]','YAWRATE [deg/s]','Roll [deg]')# 打印结果字典forkey,valueinres.items():print('{}:{}'.format(key,value))>>>df:ta_yv_x...rratio_rd_sideslip_angle03.76-0.5387048.191092...13.8986341.0106490.17779813.77-0.5171558.227018...14.0211791.0195600.32371923.78-0.4794468.262943...13.6996230.996178-0.06473633.79-0.4794468.298869...13.8583171.0077180.12922643.80-0.5063818.334795...13.8982831.0106240.177376.....................122216.00-4.37427329.818448...15.3997341.1198031.805226122316.01-4.53049729.818448...15.3382171.1153301.744792122416.02-4.56820629.854374...15.2015101.1053891.608740122516.03-4.31501629.854374...15.2888371.1117391.695929122616.04-4.23421029.854374...15.3703411.1176661.776411[1227rowsx9columns]charts:(<pygal.graph.xy.XYobjectat0x000001B1736D8C10>,<pygal.graph.xy.XYobjectat0x000001B1736D8BB0>,<pygal.graph.xy.XYobjectat0x000001B172F35700>)curves:(poly1d([3.88131566e-04,2.98285198e-03,-1.73719579e-02,1.00000000e+00]),poly1d([0.00586082,0.03784224,-0.29914155,0.]),poly1d([-0.01398442,-0.87342555,-0.38406029]))results:('left',13.752182739265344,array([6.80479099,-2.50024479]),0.35138275155465365,0.8454567089306112)# 打印试验结果results='方向：{}；\n初始圆半径：{}m；\n中性转向点侧向加速度：{}m/s^2；\n'\'不足转向度：{}(°)/(m/s^2)；\n车身侧倾度：{}(°)/(m/s^2)。'.format(*res['results'])>>>print(results)方向：left；初始圆半径：13.752182739265344m；中性转向点侧向加速度：[6.80479099-2.50024479]m/s^2；不足转向度：0.35138275155465365(°)/(m/s^2)；车身侧倾度：0.8454567089306112(°)/(m/s^2)。# 绘制试验结果曲线，res['charts']中依次为转向半径比特性图、前后轴侧偏角特性图、车厢侧倾角特性图res['charts'][0].render_in_browser()# 渲染到默认浏览器res['charts'][0].render_to_png('re.png')# 保存为png图片res['charts'][0].render_to_file('re.svg')# 保存为svg图片注意：保存为png格式的图片需要额外的程序支持，windows平台请下载安装gtk2-runtime-2.24.10-2012-10-10-ash.exe。低速转向回正低速转向回正试验数据处理，主要参考：《GB/T 6323-2014 汽车操纵稳定性试验方法》8.4：# 读取数据，第三个工作表中df=processor.read('returnability_test.xlsx',2)# 移除数据中的无效值行df=xy.data.remove_nan(df)# 进行低速转向回正的数据处理，df、松方向盘时刻、各数据所在列名称res=xy.vehicle_test.returnability_test(df,143.3,'Time [s]','YAWRATE [deg/s]','ANGLE [deg]')# 打印结果字典，图片分别为横摆角速度时域曲线、转向盘转角时域曲线，# 结果分别为残余横摆角速度（正负表示方向）、横摆角速度总方差forkey,valueinres.items():print('{}:{}'.format(key,value))>>>charts:(<pygal.graph.xy.XYobjectat0x000001B1737AAF70>,<pygal.graph.xy.XYobjectat0x000001B173756430>)results:(-2.211031768936606,0.8667891047150287)转向轻便性转向轻便性试验数据处理，主要参考：《GB/T 6323-2014 汽车操纵稳定性试验方法》9.4：# 读取数据，第一个工作表中df=processor.read('steering_efforts_test.xlsx',0)# 进行转向轻便性的数据处理，df、转向盘直径（m）、各数据所在列名称res=xy.vehicle_test.steering_efforts_test(df,0.48,'t','v_x','angle','torque')# 打印结果字典，图片为转向盘力矩转角曲线，# 结果分别为绕双纽线时的平均车速、左转转向盘最大转角、右转转向盘最大转角、转向盘最大作用力矩、转向盘最大作用力、绕双纽线路径一周的转向盘作用功、转向盘平均摩擦力矩、转向盘平均摩擦力forkey,valueinres.items():print('{}:{}'.format(key,value))>>>results:(10.922474511888389,-645.404377133912,661.401071702456,6.60583377038265,27.524307376594376,94.27873879648446,2.06678577735684,8.611607405653501)chart:<pygal.graph.xy.XYobjectat0x000002AB49C38520>注意：df数据需要自行剪切所需数据段后再传入函数，演示所用文件为经过剪切预处理后保存的数据，非原始数据。双纽线摆桩绘制双纽线摆桩图，主要参考：《GB/T 6323-2014 汽车操纵稳定性试验方法》9.3.1：# 计算双纽线，第一个参数车辆最小转弯半径（左右转中取大的），第二个为车辆宽度res=xy.vehicle_test.draw_lemniscate(15.94/2,width=2.2)# 打印结果字典，图片为双纽线摆桩示意图，# 结果分别为16个摆桩点坐标、双纽线最小曲率半径、x轴最大值、摆桩的偏移量、双纽线y轴最高点x坐标、双纽线y轴最高点y坐标forkey,valueinres.items():print('{}:{}'.format(key,value))>>>chart:<pygal.graph.xy.XYobjectat0x000002AB49C38AC0>results:([(25.151000000000003,0),(27.451,0),(16.106007431235092,8.148807725993692),(16.106007431235092,10.448807725993692),(16.106007431235092,-10.448807725993692),(16.106007431235092,-8.148807725993692),(1.1500000000000001,0),(-25.151000000000003,0),(-27.451,0),(-16.106007431235092,8.148807725993692),(-16.106007431235092,10.448807725993692),(-16.106007431235092,-10.448807725993692),(-16.106007431235092,-8.148807725993692),(-1.1500000000000001,0),(0,-1.1500000000000001),(0,1.1500000000000001)],8.767000000000001,26.301000000000002,1.1500000000000001,16.106007431235092,9.298807725993692)pdf常用操作图片转pdf推荐将需要转换合并的图片文件以001.jpg、002.jpg、003.jpg的形式顺序命名后放在同一文件夹下：importglobfromxyw_utils.pdfimportimg_to_pdf,merge_pdfs# 获取imgs文件夹下所有jpg后缀的文件名列表imgs=glob.glob(r'imgs/*.jpg')# 降序排列列表imgs.sort()# 将图片转为pdf并合并为一个文件img_to_pdf(imgs,'imgs.pdf')拼接合并pdf文件将多个pdf文件拼接合并到同一文件中：# 在pdfs文件下创建五个pdf文件foriinrange(5):img_to_pdf('imgs/00{}.jpg'.format(i+1),'pdfs/{}.pdf'.format(i+1))# 将刚才创建的五个文件合并为一个merge_pdfs(['pdfs/1.pdf','pdfs/2.pdf','pdfs/3.pdf','pdfs/4.pdf','pdfs/5.pdf'],'merge.pdf')如果需要对pdf文件进行更多操作，可以使用pikepdf库，此处只是封装了其中两个小功能。Release Notes0.0.10vehicle_test模块新增按固定步长提取数据点的函数新增充分发出的平均制动减速度的计算函数0.0.9修复了双纽线摆桩图生成函数中的标桩间隙错误0.0.8添加了说明文档《10分钟快速开始》0.0.1首次上传