diff --git a/Documentation/BusAuxCases with ESS_Formatted.xlsx b/Documentation/BusAuxCases with ESS_Formatted.xlsx index 9b4f926a7dc2e6baaac0fc92ae1a6551796da058..6bdc87d0dc23f53c90b0c5e001b9061f2bb13a02 100644 Binary files a/Documentation/BusAuxCases with ESS_Formatted.xlsx and b/Documentation/BusAuxCases with ESS_Formatted.xlsx differ diff --git a/VECTO/GUI/BatteryForm.vb b/VECTO/GUI/BatteryForm.vb index cf30bcab3743857266e033e96a92aaf45f4a4996..1061abaabcd73b6a2781d9ee01a382b4f7b953fa 100644 --- a/VECTO/GUI/BatteryForm.vb +++ b/VECTO/GUI/BatteryForm.vb @@ -425,7 +425,7 @@ Public Class BatteryForm Try Dim riFile As String = If(Not String.IsNullOrWhiteSpace(_batteryFile), Path.Combine(Path.GetDirectoryName(_batteryFile), tbRiCurve.Text), tbRiCurve.Text) - If File.Exists(riFile) Then riCurve = BatteryInternalResistanceReader.Create(VectoCSVFile.Read(riFile), 1) + If File.Exists(riFile) Then riCurve = BatteryInternalResistanceReader.Create(VectoCSVFile.Read(riFile)) Catch ex As Exception End Try @@ -450,15 +450,24 @@ Public Class BatteryForm End If If Not riCurve Is Nothing Then - Dim series As Series = New Series - series.Points.DataBindXY(riCurve.Entries.Select(Function(x) x.SoC * 100).ToArray(), - riCurve.Entries.Select(Function(x) x.Resistance.Value()).ToArray()) - series.ChartType = SeriesChartType.FastLine - series.MarkerSize = 3 - series.Color = Color.Red - series.Name = "Internal Resistance" - series.YAxisType = AxisType.Secondary - chart.Series.Add(series) + Dim series1 As Series = New Series + series1.Points.DataBindXY(riCurve.Entries.Select(Function(x) x.SoC * 100).ToArray(), + riCurve.Entries.Select(Function(x) x.Resistance.First.Item2.Value()).ToArray()) + series1.ChartType = SeriesChartType.FastLine + series1.MarkerSize = 3 + series1.Color = Color.MediumVioletRed + series1.Name = "Internal Resistance t_min" + series1.YAxisType = AxisType.Secondary + chart.Series.Add(series1) + Dim series2 As Series = New Series + series2.Points.DataBindXY(riCurve.Entries.Select(Function(x) x.SoC * 100).ToArray(), + riCurve.Entries.Select(Function(x) x.Resistance.Last().Item2.Value()).ToArray()) + series2.ChartType = SeriesChartType.FastLine + series2.MarkerSize = 3 + series2.Color = Color.PaleVioletRed + series2.Name = "Internal Resistance t_max" + series2.YAxisType = AxisType.Secondary + chart.Series.Add(series2) End If diff --git a/VECTO/GUI/MainForm.Designer.vb b/VECTO/GUI/MainForm.Designer.vb index 51d5dc164e6c7bd4aff2bc207f1395eadc8cd65a..166e0f94c6bd13858f9f3a9cd1831d37f39d0563 100644 --- a/VECTO/GUI/MainForm.Designer.vb +++ b/VECTO/GUI/MainForm.Designer.vb @@ -129,27 +129,26 @@ Partial Class MainForm Me.OpenInGraphWindowToolStripMenuItem = New System.Windows.Forms.ToolStripMenuItem() Me.ShowInFolderToolStripMenuItem = New System.Windows.Forms.ToolStripMenuItem() Me.ToolTip1 = New System.Windows.Forms.ToolTip(Me.components) - Me.StatusBAR.SuspendLayout() - Me.Label2 = New System.Windows.Forms.Label() - Me.TabControl1.SuspendLayout() - Me.TabPageGEN.SuspendLayout() - CType(Me.PictureBox1, System.ComponentModel.ISupportInitialize).BeginInit() - Me.TabPgOptions.SuspendLayout() - Me.PanelOptAllg.SuspendLayout() - Me.GroupBox5.SuspendLayout() - Me.GroupBox4.SuspendLayout() - Me.GroupBox3.SuspendLayout() - Me.GroupBox2.SuspendLayout() - Me.GroupBox1.SuspendLayout() - Me.TabPageDEV.SuspendLayout() - Me.ConMenFilelist.SuspendLayout() - CType(Me.SplitContainer1, System.ComponentModel.ISupportInitialize).BeginInit() - Me.SplitContainer1.Panel1.SuspendLayout() - Me.SplitContainer1.Panel2.SuspendLayout() - Me.SplitContainer1.SuspendLayout() - Me.ToolStrip1.SuspendLayout() - Me.CmOpenFile.SuspendLayout() - Me.SuspendLayout() + Me.StatusBAR.SuspendLayout + Me.TabControl1.SuspendLayout + Me.TabPageGEN.SuspendLayout + CType(Me.PictureBox1,System.ComponentModel.ISupportInitialize).BeginInit + Me.TabPgOptions.SuspendLayout + Me.PanelOptAllg.SuspendLayout + Me.GroupBox5.SuspendLayout + Me.GroupBox4.SuspendLayout + Me.GroupBox3.SuspendLayout + Me.GroupBox2.SuspendLayout + Me.GroupBox1.SuspendLayout + Me.TabPageDEV.SuspendLayout + Me.ConMenFilelist.SuspendLayout + CType(Me.SplitContainer1,System.ComponentModel.ISupportInitialize).BeginInit + Me.SplitContainer1.Panel1.SuspendLayout + Me.SplitContainer1.Panel2.SuspendLayout + Me.SplitContainer1.SuspendLayout + Me.ToolStrip1.SuspendLayout + Me.CmOpenFile.SuspendLayout + Me.SuspendLayout ' 'StatusBAR ' @@ -164,29 +163,29 @@ Partial Class MainForm ' Me.ToolStripLbStatus.Name = "ToolStripLbStatus" Me.ToolStripLbStatus.Size = New System.Drawing.Size(1030, 17) - Me.ToolStripLbStatus.Spring = True + Me.ToolStripLbStatus.Spring = true Me.ToolStripLbStatus.Text = "Status Text" Me.ToolStripLbStatus.TextAlign = System.Drawing.ContentAlignment.MiddleLeft ' 'ToolStripProgBarJob ' Me.ToolStripProgBarJob.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right - Me.ToolStripProgBarJob.AutoSize = False + Me.ToolStripProgBarJob.AutoSize = false Me.ToolStripProgBarJob.Name = "ToolStripProgBarJob" Me.ToolStripProgBarJob.Size = New System.Drawing.Size(100, 16) Me.ToolStripProgBarJob.Style = System.Windows.Forms.ProgressBarStyle.Continuous Me.ToolStripProgBarJob.ToolTipText = "overall progress" - Me.ToolStripProgBarJob.Visible = False + Me.ToolStripProgBarJob.Visible = false ' 'ToolStripProgBarOverall ' Me.ToolStripProgBarOverall.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right - Me.ToolStripProgBarOverall.AutoSize = False + Me.ToolStripProgBarOverall.AutoSize = false Me.ToolStripProgBarOverall.Name = "ToolStripProgBarOverall" Me.ToolStripProgBarOverall.Size = New System.Drawing.Size(100, 16) Me.ToolStripProgBarOverall.Style = System.Windows.Forms.ProgressBarStyle.Continuous Me.ToolStripProgBarOverall.ToolTipText = "job progress" - Me.ToolStripProgBarOverall.Visible = False + Me.ToolStripProgBarOverall.Visible = false ' 'TabControl1 ' @@ -222,34 +221,34 @@ Partial Class MainForm Me.TabPageGEN.Size = New System.Drawing.Size(1034, 302) Me.TabPageGEN.TabIndex = 0 Me.TabPageGEN.Text = "Job Files" - Me.TabPageGEN.UseVisualStyleBackColor = True + Me.TabPageGEN.UseVisualStyleBackColor = true ' 'btnImportXML ' - Me.btnImportXML.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles) + Me.btnImportXML.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left),System.Windows.Forms.AnchorStyles) Me.btnImportXML.Location = New System.Drawing.Point(460, 267) Me.btnImportXML.Name = "btnImportXML" Me.btnImportXML.Size = New System.Drawing.Size(115, 30) Me.btnImportXML.TabIndex = 23 Me.btnImportXML.Text = "Import from XML" - Me.btnImportXML.UseVisualStyleBackColor = True - Me.btnImportXML.Visible = False + Me.btnImportXML.UseVisualStyleBackColor = true + Me.btnImportXML.Visible = false ' 'btnExportXML ' - Me.btnExportXML.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles) - Me.btnExportXML.Enabled = False + Me.btnExportXML.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left),System.Windows.Forms.AnchorStyles) + Me.btnExportXML.Enabled = false Me.btnExportXML.Location = New System.Drawing.Point(344, 267) Me.btnExportXML.Name = "btnExportXML" Me.btnExportXML.Size = New System.Drawing.Size(115, 30) Me.btnExportXML.TabIndex = 22 Me.btnExportXML.Text = "Export as XML" - Me.btnExportXML.UseVisualStyleBackColor = True + Me.btnExportXML.UseVisualStyleBackColor = true ' 'Label6 ' - Me.Label6.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) - Me.Label6.AutoSize = True + Me.Label6.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Right),System.Windows.Forms.AnchorStyles) + Me.Label6.AutoSize = true Me.Label6.Location = New System.Drawing.Point(814, 268) Me.Label6.Name = "Label6" Me.Label6.Size = New System.Drawing.Size(217, 13) @@ -258,7 +257,7 @@ Partial Class MainForm ' 'btStartV3 ' - Me.btStartV3.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte)) + Me.btStartV3.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0,Byte)) Me.btStartV3.Image = Global.TUGraz.VECTO.My.Resources.Resources.Play_icon Me.btStartV3.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft Me.btStartV3.Location = New System.Drawing.Point(3, 56) @@ -268,80 +267,80 @@ Partial Class MainForm Me.btStartV3.Text = "START" Me.btStartV3.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText Me.ToolTip1.SetToolTip(Me.btStartV3, "Start Simulation") - Me.btStartV3.UseVisualStyleBackColor = True + Me.btStartV3.UseVisualStyleBackColor = true ' 'LbDecl ' - Me.LbDecl.AutoSize = True - Me.LbDecl.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(0, Byte)) + Me.LbDecl.AutoSize = true + Me.LbDecl.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(0,Byte)) Me.LbDecl.Location = New System.Drawing.Point(5, 109) Me.LbDecl.Name = "LbDecl" Me.LbDecl.Size = New System.Drawing.Size(107, 13) Me.LbDecl.TabIndex = 19 Me.LbDecl.Text = "Declaration Mode" - Me.LbDecl.Visible = False + Me.LbDecl.Visible = false ' 'PictureBox1 ' - Me.PictureBox1.Image = CType(resources.GetObject("PictureBox1.Image"), System.Drawing.Image) + Me.PictureBox1.Image = CType(resources.GetObject("PictureBox1.Image"),System.Drawing.Image) Me.PictureBox1.Location = New System.Drawing.Point(3, 3) Me.PictureBox1.Name = "PictureBox1" Me.PictureBox1.Size = New System.Drawing.Size(108, 47) Me.PictureBox1.TabIndex = 18 - Me.PictureBox1.TabStop = False + Me.PictureBox1.TabStop = false ' 'BtGENdown ' - Me.BtGENdown.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles) + Me.BtGENdown.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left),System.Windows.Forms.AnchorStyles) Me.BtGENdown.Image = Global.TUGraz.VECTO.My.Resources.Resources.Actions_arrow_down_icon Me.BtGENdown.Location = New System.Drawing.Point(307, 267) Me.BtGENdown.Name = "BtGENdown" Me.BtGENdown.Size = New System.Drawing.Size(30, 30) Me.BtGENdown.TabIndex = 6 Me.ToolTip1.SetToolTip(Me.BtGENdown, "Move job down one row") - Me.BtGENdown.UseVisualStyleBackColor = True + Me.BtGENdown.UseVisualStyleBackColor = true ' 'BtGENup ' - Me.BtGENup.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles) + Me.BtGENup.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left),System.Windows.Forms.AnchorStyles) Me.BtGENup.Image = Global.TUGraz.VECTO.My.Resources.Resources.Actions_arrow_up_icon Me.BtGENup.Location = New System.Drawing.Point(276, 267) Me.BtGENup.Name = "BtGENup" Me.BtGENup.Size = New System.Drawing.Size(30, 30) Me.BtGENup.TabIndex = 4 Me.ToolTip1.SetToolTip(Me.BtGENup, "Move job up one row") - Me.BtGENup.UseVisualStyleBackColor = True + Me.BtGENup.UseVisualStyleBackColor = true ' 'ChBoxAllGEN ' - Me.ChBoxAllGEN.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles) - Me.ChBoxAllGEN.AutoSize = True + Me.ChBoxAllGEN.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left),System.Windows.Forms.AnchorStyles) + Me.ChBoxAllGEN.AutoSize = true Me.ChBoxAllGEN.Location = New System.Drawing.Point(195, 274) Me.ChBoxAllGEN.Name = "ChBoxAllGEN" Me.ChBoxAllGEN.Size = New System.Drawing.Size(70, 17) Me.ChBoxAllGEN.TabIndex = 16 Me.ChBoxAllGEN.Text = "Select All" Me.ToolTip1.SetToolTip(Me.ChBoxAllGEN, "Select All / None") - Me.ChBoxAllGEN.UseVisualStyleBackColor = True + Me.ChBoxAllGEN.UseVisualStyleBackColor = true ' 'LvGEN ' - Me.LvGEN.AllowDrop = True - Me.LvGEN.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _ - Or System.Windows.Forms.AnchorStyles.Left) _ - Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) - Me.LvGEN.CheckBoxes = True + Me.LvGEN.AllowDrop = true + Me.LvGEN.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _ + Or System.Windows.Forms.AnchorStyles.Left) _ + Or System.Windows.Forms.AnchorStyles.Right),System.Windows.Forms.AnchorStyles) + Me.LvGEN.CheckBoxes = true Me.LvGEN.Columns.AddRange(New System.Windows.Forms.ColumnHeader() {Me.ColGENpath, Me.ColGENstatus}) - Me.LvGEN.FullRowSelect = True - Me.LvGEN.GridLines = True + Me.LvGEN.FullRowSelect = true + Me.LvGEN.GridLines = true Me.LvGEN.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable - Me.LvGEN.HideSelection = False - Me.LvGEN.LabelEdit = True + Me.LvGEN.HideSelection = false + Me.LvGEN.LabelEdit = true Me.LvGEN.Location = New System.Drawing.Point(114, 3) Me.LvGEN.Name = "LvGEN" Me.LvGEN.Size = New System.Drawing.Size(917, 263) Me.LvGEN.TabIndex = 14 - Me.LvGEN.UseCompatibleStateImageBehavior = False + Me.LvGEN.UseCompatibleStateImageBehavior = false Me.LvGEN.View = System.Windows.Forms.View.Details ' 'ColGENpath @@ -356,27 +355,27 @@ Partial Class MainForm ' 'ButtonGENremove ' - Me.ButtonGENremove.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles) - Me.ButtonGENremove.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(0, Byte)) + Me.ButtonGENremove.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left),System.Windows.Forms.AnchorStyles) + Me.ButtonGENremove.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(0,Byte)) Me.ButtonGENremove.Image = Global.TUGraz.VECTO.My.Resources.Resources.minus_circle_icon Me.ButtonGENremove.Location = New System.Drawing.Point(147, 267) Me.ButtonGENremove.Name = "ButtonGENremove" Me.ButtonGENremove.Size = New System.Drawing.Size(33, 30) Me.ButtonGENremove.TabIndex = 2 Me.ToolTip1.SetToolTip(Me.ButtonGENremove, "Remove selected entries") - Me.ButtonGENremove.UseVisualStyleBackColor = True + Me.ButtonGENremove.UseVisualStyleBackColor = true ' 'ButtonGENadd ' - Me.ButtonGENadd.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles) - Me.ButtonGENadd.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(0, Byte)) + Me.ButtonGENadd.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left),System.Windows.Forms.AnchorStyles) + Me.ButtonGENadd.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(0,Byte)) Me.ButtonGENadd.Image = Global.TUGraz.VECTO.My.Resources.Resources.plus_circle_icon Me.ButtonGENadd.Location = New System.Drawing.Point(113, 267) Me.ButtonGENadd.Name = "ButtonGENadd" Me.ButtonGENadd.Size = New System.Drawing.Size(33, 30) Me.ButtonGENadd.TabIndex = 1 Me.ToolTip1.SetToolTip(Me.ButtonGENadd, "Add Job File") - Me.ButtonGENadd.UseVisualStyleBackColor = True + Me.ButtonGENadd.UseVisualStyleBackColor = true ' 'TabPgOptions ' @@ -387,7 +386,7 @@ Partial Class MainForm Me.TabPgOptions.Size = New System.Drawing.Size(1034, 302) Me.TabPgOptions.TabIndex = 2 Me.TabPgOptions.Text = "Options" - Me.TabPgOptions.UseVisualStyleBackColor = True + Me.TabPgOptions.UseVisualStyleBackColor = true ' 'PanelOptAllg ' @@ -412,22 +411,22 @@ Partial Class MainForm Me.GroupBox5.Name = "GroupBox5" Me.GroupBox5.Size = New System.Drawing.Size(260, 100) Me.GroupBox5.TabIndex = 20 - Me.GroupBox5.TabStop = False + Me.GroupBox5.TabStop = false Me.GroupBox5.Text = "Look-Ahead Coasting Override" ' 'Label5 ' - Me.Label5.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Point, CType(0, Byte)) + Me.Label5.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Point, CType(0,Byte)) Me.Label5.Location = New System.Drawing.Point(7, 48) Me.Label5.Name = "Label5" Me.Label5.Size = New System.Drawing.Size(247, 36) Me.Label5.TabIndex = 4 - Me.Label5.Text = "Overrides Look-Ahead Coasting in declaration mode. Leave empty to use default beh" & + Me.Label5.Text = "Overrides Look-Ahead Coasting in declaration mode. Leave empty to use default beh"& _ "aviour." ' 'Label4 ' - Me.Label4.AutoSize = True + Me.Label4.AutoSize = true Me.Label4.Location = New System.Drawing.Point(10, 44) Me.Label4.Name = "Label4" Me.Label4.Size = New System.Drawing.Size(0, 13) @@ -442,7 +441,7 @@ Partial Class MainForm ' 'Label3 ' - Me.Label3.AutoSize = True + Me.Label3.AutoSize = true Me.Label3.Location = New System.Drawing.Point(158, 20) Me.Label3.Name = "Label3" Me.Label3.Size = New System.Drawing.Size(38, 13) @@ -451,12 +450,12 @@ Partial Class MainForm ' 'Label2 ' - Me.Label2.AutoSize = True - Me.Label2.Location = New System.Drawing.Point(7, 20) + Me.Label2.AutoSize = true + Me.Label2.Location = New System.Drawing.Point(7, 19) Me.Label2.Name = "Label2" - Me.Label2.Size = New System.Drawing.Size(64, 13) - Me.Label2.TabIndex = 0 - Me.Label2.Text = "Min. Speed:" + Me.Label2.Size = New System.Drawing.Size(84, 13) + Me.Label2.TabIndex = 1 + Me.Label2.Text = "Output Directory" ' 'GroupBox4 ' @@ -466,7 +465,7 @@ Partial Class MainForm Me.GroupBox4.Name = "GroupBox4" Me.GroupBox4.Size = New System.Drawing.Size(260, 46) Me.GroupBox4.TabIndex = 19 - Me.GroupBox4.TabStop = False + Me.GroupBox4.TabStop = false Me.GroupBox4.Text = "Output Directory" ' 'BtTCfileBrowse @@ -476,8 +475,8 @@ Partial Class MainForm Me.BtTCfileBrowse.Name = "BtTCfileBrowse" Me.BtTCfileBrowse.Size = New System.Drawing.Size(24, 24) Me.BtTCfileBrowse.TabIndex = 27 - Me.BtTCfileBrowse.TabStop = False - Me.BtTCfileBrowse.UseVisualStyleBackColor = True + Me.BtTCfileBrowse.TabStop = false + Me.BtTCfileBrowse.UseVisualStyleBackColor = true ' 'tbOutputFolder ' @@ -495,18 +494,18 @@ Partial Class MainForm Me.GroupBox3.Name = "GroupBox3" Me.GroupBox3.Size = New System.Drawing.Size(173, 110) Me.GroupBox3.TabIndex = 18 - Me.GroupBox3.TabStop = False + Me.GroupBox3.TabStop = false Me.GroupBox3.Text = "Misc" ' 'cbSaveVectoRunData ' - Me.cbSaveVectoRunData.AutoSize = True + Me.cbSaveVectoRunData.AutoSize = true Me.cbSaveVectoRunData.Location = New System.Drawing.Point(7, 86) Me.cbSaveVectoRunData.Name = "cbSaveVectoRunData" Me.cbSaveVectoRunData.Size = New System.Drawing.Size(166, 17) Me.cbSaveVectoRunData.TabIndex = 19 Me.cbSaveVectoRunData.Text = "Export ModelData (EXPERT!)" - Me.cbSaveVectoRunData.UseVisualStyleBackColor = True + Me.cbSaveVectoRunData.UseVisualStyleBackColor = true ' 'cbActVmod ' @@ -515,19 +514,19 @@ Partial Class MainForm Me.cbActVmod.Size = New System.Drawing.Size(167, 52) Me.cbActVmod.TabIndex = 18 Me.cbActVmod.Text = "Output values in vmod at beginning and end of simulation interval (EXPERT!)" - Me.cbActVmod.UseVisualStyleBackColor = True + Me.cbActVmod.UseVisualStyleBackColor = true ' 'cbValidateRunData ' - Me.cbValidateRunData.AutoSize = True - Me.cbValidateRunData.Checked = True + Me.cbValidateRunData.AutoSize = true + Me.cbValidateRunData.Checked = true Me.cbValidateRunData.CheckState = System.Windows.Forms.CheckState.Checked Me.cbValidateRunData.Location = New System.Drawing.Point(6, 19) Me.cbValidateRunData.Name = "cbValidateRunData" Me.cbValidateRunData.Size = New System.Drawing.Size(90, 17) Me.cbValidateRunData.TabIndex = 17 Me.cbValidateRunData.Text = "Validate Data" - Me.cbValidateRunData.UseVisualStyleBackColor = True + Me.cbValidateRunData.UseVisualStyleBackColor = true ' 'GroupBox2 ' @@ -537,30 +536,30 @@ Partial Class MainForm Me.GroupBox2.Name = "GroupBox2" Me.GroupBox2.Size = New System.Drawing.Size(173, 89) Me.GroupBox2.TabIndex = 16 - Me.GroupBox2.TabStop = False + Me.GroupBox2.TabStop = false Me.GroupBox2.Text = "Output" ' 'ChBoxModOut ' - Me.ChBoxModOut.AutoSize = True - Me.ChBoxModOut.Checked = True + Me.ChBoxModOut.AutoSize = true + Me.ChBoxModOut.Checked = true Me.ChBoxModOut.CheckState = System.Windows.Forms.CheckState.Checked Me.ChBoxModOut.Location = New System.Drawing.Point(6, 19) Me.ChBoxModOut.Name = "ChBoxModOut" Me.ChBoxModOut.Size = New System.Drawing.Size(115, 17) Me.ChBoxModOut.TabIndex = 0 Me.ChBoxModOut.Text = "Write modal results" - Me.ChBoxModOut.UseVisualStyleBackColor = True + Me.ChBoxModOut.UseVisualStyleBackColor = true ' 'ChBoxMod1Hz ' - Me.ChBoxMod1Hz.AutoSize = True + Me.ChBoxMod1Hz.AutoSize = true Me.ChBoxMod1Hz.Location = New System.Drawing.Point(6, 42) Me.ChBoxMod1Hz.Name = "ChBoxMod1Hz" Me.ChBoxMod1Hz.Size = New System.Drawing.Size(121, 17) Me.ChBoxMod1Hz.TabIndex = 16 Me.ChBoxMod1Hz.Text = "Modal results in 1Hz" - Me.ChBoxMod1Hz.UseVisualStyleBackColor = True + Me.ChBoxMod1Hz.UseVisualStyleBackColor = true ' 'GroupBox1 ' @@ -570,31 +569,31 @@ Partial Class MainForm Me.GroupBox1.Name = "GroupBox1" Me.GroupBox1.Size = New System.Drawing.Size(173, 72) Me.GroupBox1.TabIndex = 15 - Me.GroupBox1.TabStop = False + Me.GroupBox1.TabStop = false Me.GroupBox1.Text = "Mode" ' 'RbDev ' - Me.RbDev.AutoSize = True - Me.RbDev.Checked = True + Me.RbDev.AutoSize = true + Me.RbDev.Checked = true Me.RbDev.Location = New System.Drawing.Point(6, 42) Me.RbDev.Name = "RbDev" Me.RbDev.Size = New System.Drawing.Size(111, 17) Me.RbDev.TabIndex = 1 - Me.RbDev.TabStop = True + Me.RbDev.TabStop = true Me.RbDev.Text = "Engineering Mode" - Me.RbDev.UseVisualStyleBackColor = True + Me.RbDev.UseVisualStyleBackColor = true ' 'RbDecl ' - Me.RbDecl.AutoSize = True + Me.RbDecl.AutoSize = true Me.RbDecl.Location = New System.Drawing.Point(6, 19) Me.RbDecl.Name = "RbDecl" Me.RbDecl.Size = New System.Drawing.Size(109, 17) Me.RbDecl.TabIndex = 0 - Me.RbDecl.TabStop = True + Me.RbDecl.TabStop = true Me.RbDecl.Text = "Declaration Mode" - Me.RbDecl.UseVisualStyleBackColor = True + Me.RbDecl.UseVisualStyleBackColor = true ' 'TabPageDEV ' @@ -606,12 +605,12 @@ Partial Class MainForm Me.TabPageDEV.Size = New System.Drawing.Size(1034, 302) Me.TabPageDEV.TabIndex = 3 Me.TabPageDEV.Text = "Test" - Me.TabPageDEV.UseVisualStyleBackColor = True + Me.TabPageDEV.UseVisualStyleBackColor = true ' 'Label1 ' - Me.Label1.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles) - Me.Label1.AutoSize = True + Me.Label1.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left),System.Windows.Forms.AnchorStyles) + Me.Label1.AutoSize = true Me.Label1.Location = New System.Drawing.Point(1012, 283) Me.Label1.Name = "Label1" Me.Label1.Size = New System.Drawing.Size(106, 13) @@ -620,18 +619,19 @@ Partial Class MainForm ' 'LvDEVoptions ' - Me.LvDEVoptions.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _ - Or System.Windows.Forms.AnchorStyles.Left) _ - Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) + Me.LvDEVoptions.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _ + Or System.Windows.Forms.AnchorStyles.Left) _ + Or System.Windows.Forms.AnchorStyles.Right),System.Windows.Forms.AnchorStyles) Me.LvDEVoptions.Columns.AddRange(New System.Windows.Forms.ColumnHeader() {Me.ColumnHeader4, Me.ColumnHeader7, Me.ColumnHeader5, Me.ColumnHeader6, Me.ColumnHeader8, Me.ColumnHeader9}) - Me.LvDEVoptions.FullRowSelect = True - Me.LvDEVoptions.GridLines = True + Me.LvDEVoptions.FullRowSelect = true + Me.LvDEVoptions.GridLines = true + Me.LvDEVoptions.HideSelection = false Me.LvDEVoptions.Location = New System.Drawing.Point(6, 6) - Me.LvDEVoptions.MultiSelect = False + Me.LvDEVoptions.MultiSelect = false Me.LvDEVoptions.Name = "LvDEVoptions" Me.LvDEVoptions.Size = New System.Drawing.Size(1022, 277) Me.LvDEVoptions.TabIndex = 0 - Me.LvDEVoptions.UseCompatibleStateImageBehavior = False + Me.LvDEVoptions.UseCompatibleStateImageBehavior = false Me.LvDEVoptions.View = System.Windows.Forms.View.Details ' 'ColumnHeader4 @@ -668,7 +668,7 @@ Partial Class MainForm ' Me.ConMenFilelist.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.ShowInFolderMenuItem, Me.SaveListToolStripMenuItem, Me.LoadListToolStripMenuItem, Me.LoadDefaultListToolStripMenuItem, Me.ClearListToolStripMenuItem}) Me.ConMenFilelist.Name = "ConMenFilelist" - Me.ConMenFilelist.ShowImageMargin = False + Me.ConMenFilelist.ShowImageMargin = false Me.ConMenFilelist.Size = New System.Drawing.Size(151, 114) ' 'ShowInFolderMenuItem @@ -703,21 +703,22 @@ Partial Class MainForm ' 'LvMsg ' - Me.LvMsg.AllowColumnReorder = True + Me.LvMsg.AllowColumnReorder = true Me.LvMsg.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle Me.LvMsg.Columns.AddRange(New System.Windows.Forms.ColumnHeader() {Me.ColumnHeader1, Me.ColumnHeader2, Me.ColumnHeader3}) Me.LvMsg.Dock = System.Windows.Forms.DockStyle.Fill - Me.LvMsg.Font = New System.Drawing.Font("Courier New", 8.25!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte)) - Me.LvMsg.FullRowSelect = True - Me.LvMsg.GridLines = True + Me.LvMsg.Font = New System.Drawing.Font("Courier New", 8.25!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0,Byte)) + Me.LvMsg.FullRowSelect = true + Me.LvMsg.GridLines = true Me.LvMsg.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable - Me.LvMsg.LabelWrap = False + Me.LvMsg.HideSelection = false + Me.LvMsg.LabelWrap = false Me.LvMsg.Location = New System.Drawing.Point(0, 0) Me.LvMsg.Margin = New System.Windows.Forms.Padding(0) Me.LvMsg.Name = "LvMsg" Me.LvMsg.Size = New System.Drawing.Size(1045, 281) Me.LvMsg.TabIndex = 0 - Me.LvMsg.UseCompatibleStateImageBehavior = False + Me.LvMsg.UseCompatibleStateImageBehavior = false Me.LvMsg.View = System.Windows.Forms.View.Details ' 'ColumnHeader1 @@ -737,9 +738,9 @@ Partial Class MainForm ' 'SplitContainer1 ' - Me.SplitContainer1.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _ - Or System.Windows.Forms.AnchorStyles.Left) _ - Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) + Me.SplitContainer1.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _ + Or System.Windows.Forms.AnchorStyles.Left) _ + Or System.Windows.Forms.AnchorStyles.Right),System.Windows.Forms.AnchorStyles) Me.SplitContainer1.Location = New System.Drawing.Point(0, 27) Me.SplitContainer1.Margin = New System.Windows.Forms.Padding(0) Me.SplitContainer1.Name = "SplitContainer1" @@ -806,7 +807,7 @@ Partial Class MainForm ' Me.GENEditorToolStripMenuItem1.Image = Global.TUGraz.VECTO.My.Resources.Resources.F_VECTO Me.GENEditorToolStripMenuItem1.Name = "GENEditorToolStripMenuItem1" - Me.GENEditorToolStripMenuItem1.Size = New System.Drawing.Size(152, 22) + Me.GENEditorToolStripMenuItem1.Size = New System.Drawing.Size(254, 22) Me.GENEditorToolStripMenuItem1.Text = "Job Editor - Conventional Vehicle" ' 'JobEditorParallelHybridVehicleToolStripMenuItem @@ -834,52 +835,52 @@ Partial Class MainForm ' Me.EPTPJobEditorToolStripMenuItem.Image = Global.TUGraz.VECTO.My.Resources.Resources.F_VECTO Me.EPTPJobEditorToolStripMenuItem.Name = "EPTPJobEditorToolStripMenuItem" - Me.EPTPJobEditorToolStripMenuItem.Size = New System.Drawing.Size(152, 22) + Me.EPTPJobEditorToolStripMenuItem.Size = New System.Drawing.Size(254, 22) Me.EPTPJobEditorToolStripMenuItem.Text = "VTP Job Editor" ' 'VEHEditorToolStripMenuItem ' Me.VEHEditorToolStripMenuItem.Image = Global.TUGraz.VECTO.My.Resources.Resources.F_VEH Me.VEHEditorToolStripMenuItem.Name = "VEHEditorToolStripMenuItem" - Me.VEHEditorToolStripMenuItem.Size = New System.Drawing.Size(152, 22) + Me.VEHEditorToolStripMenuItem.Size = New System.Drawing.Size(254, 22) Me.VEHEditorToolStripMenuItem.Text = "Vehicle Editor" ' 'EngineEditorToolStripMenuItem ' Me.EngineEditorToolStripMenuItem.Image = Global.TUGraz.VECTO.My.Resources.Resources.F_ENG Me.EngineEditorToolStripMenuItem.Name = "EngineEditorToolStripMenuItem" - Me.EngineEditorToolStripMenuItem.Size = New System.Drawing.Size(152, 22) + Me.EngineEditorToolStripMenuItem.Size = New System.Drawing.Size(254, 22) Me.EngineEditorToolStripMenuItem.Text = "Engine Editor" ' 'GearboxEditorToolStripMenuItem ' Me.GearboxEditorToolStripMenuItem.Image = Global.TUGraz.VECTO.My.Resources.Resources.F_GBX Me.GearboxEditorToolStripMenuItem.Name = "GearboxEditorToolStripMenuItem" - Me.GearboxEditorToolStripMenuItem.Size = New System.Drawing.Size(152, 22) + Me.GearboxEditorToolStripMenuItem.Size = New System.Drawing.Size(254, 22) Me.GearboxEditorToolStripMenuItem.Text = "Gearbox Editor" ' 'GraphToolStripMenuItem ' Me.GraphToolStripMenuItem.Image = Global.TUGraz.VECTO.My.Resources.Resources.F_Graph Me.GraphToolStripMenuItem.Name = "GraphToolStripMenuItem" - Me.GraphToolStripMenuItem.Size = New System.Drawing.Size(152, 22) + Me.GraphToolStripMenuItem.Size = New System.Drawing.Size(254, 22) Me.GraphToolStripMenuItem.Text = "Graph" ' 'ToolStripSeparator6 ' Me.ToolStripSeparator6.Name = "ToolStripSeparator6" - Me.ToolStripSeparator6.Size = New System.Drawing.Size(149, 6) + Me.ToolStripSeparator6.Size = New System.Drawing.Size(251, 6) ' 'OpenLogToolStripMenuItem ' Me.OpenLogToolStripMenuItem.Name = "OpenLogToolStripMenuItem" - Me.OpenLogToolStripMenuItem.Size = New System.Drawing.Size(152, 22) + Me.OpenLogToolStripMenuItem.Size = New System.Drawing.Size(254, 22) Me.OpenLogToolStripMenuItem.Text = "Open Log" ' 'SettingsToolStripMenuItem ' Me.SettingsToolStripMenuItem.Name = "SettingsToolStripMenuItem" - Me.SettingsToolStripMenuItem.Size = New System.Drawing.Size(152, 22) + Me.SettingsToolStripMenuItem.Size = New System.Drawing.Size(254, 22) Me.SettingsToolStripMenuItem.Text = "Settings" ' 'ToolStripDrDnBtInfo @@ -923,7 +924,7 @@ Partial Class MainForm 'CmDEV ' Me.CmDEV.Name = "CmDEV" - Me.CmDEV.ShowImageMargin = False + Me.CmDEV.ShowImageMargin = false Me.CmDEV.Size = New System.Drawing.Size(36, 4) ' 'TmProgSec @@ -934,7 +935,7 @@ Partial Class MainForm ' Me.CmOpenFile.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.OpenWithToolStripMenuItem, Me.OpenInGraphWindowToolStripMenuItem, Me.ShowInFolderToolStripMenuItem}) Me.CmOpenFile.Name = "CmOpenFile" - Me.CmOpenFile.ShowImageMargin = False + Me.CmOpenFile.ShowImageMargin = false Me.CmOpenFile.Size = New System.Drawing.Size(174, 70) ' 'OpenWithToolStripMenuItem @@ -955,15 +956,6 @@ Partial Class MainForm Me.ShowInFolderToolStripMenuItem.Size = New System.Drawing.Size(173, 22) Me.ShowInFolderToolStripMenuItem.Text = "Show in Folder" ' - 'Label2 - ' - Me.Label2.AutoSize = true - Me.Label2.Location = New System.Drawing.Point(7, 19) - Me.Label2.Name = "Label2" - Me.Label2.Size = New System.Drawing.Size(84, 13) - Me.Label2.TabIndex = 1 - Me.Label2.Text = "Output Directory" - ' 'MainForm ' Me.AcceptButton = Me.btStartV3 diff --git a/VECTO/GUI/VehicleForm.vb b/VECTO/GUI/VehicleForm.vb index 17faa44e86d2b64f9a2babeaa29eaabb9763e9ba..5fb158ed5b16693a9e3fb40a0ef8534a5a32184e 100644 --- a/VECTO/GUI/VehicleForm.vb +++ b/VECTO/GUI/VehicleForm.vb @@ -1239,6 +1239,7 @@ Public Class VehicleForm If lvREESSPacks.SelectedItems.Count = 0 Then Exit Sub Dim entry As ListViewItem = lvREESSPacks.SelectedItems(0) + _reessPackDlg._vehFile = _vehFile _reessPackDlg.tbBattery.Text = entry.SubItems(REESPackTbl.ReessFile).Text _reessPackDlg.tbBatteryPackCnt.Text = entry.SubItems(REESPackTbl.Count).Text _reessPackDlg.tbStreamId.Text = entry.SubItems(REESPackTbl.StringId).Text @@ -1252,6 +1253,7 @@ Public Class VehicleForm Private Sub btnAddReessPack_Click(sender As Object, e As EventArgs) Handles btnAddReessPack.Click _reessPackDlg.Clear() + _reessPackDlg._vehFile = _vehFile If _reessPackDlg.ShowDialog() = DialogResult.OK Then lvREESSPacks.Items.Add(CreateREESSPackListViewItem(_reessPackDlg.tbBattery.Text, _reessPackDlg.tbBatteryPackCnt.Text.ToInt(0), _reessPackDlg.tbStreamId.Text.ToInt(0))) diff --git a/VectoCommon/VectoCommon/Resources/XMLNames.Designer.cs b/VectoCommon/VectoCommon/Resources/XMLNames.Designer.cs index 6e87b019a0c0d857210ce2529f06ebdf0727fcb5..cb581783da2d9e25a69528389ce9c48be079c89c 100644 --- a/VectoCommon/VectoCommon/Resources/XMLNames.Designer.cs +++ b/VectoCommon/VectoCommon/Resources/XMLNames.Designer.cs @@ -3787,7 +3787,7 @@ namespace TUGraz.VectoCommon.Resources { } /// <summary> - /// Looks up a localized string similar to ATEcoRollReleaseLockupClutch. + /// Looks up a localized string similar to APTEcoRollReleaseLockupClutch. /// </summary> public static string Vehicle_ADAS_ATEcoRollReleaseLockupClutch { get { diff --git a/VectoCommon/VectoCommon/Resources/XMLNames.resx b/VectoCommon/VectoCommon/Resources/XMLNames.resx index a5029ad819dc4661e6973774b7039c6fa2dfefa7..5bec7fe60f9e414a7e385302752e5729e1f2cc28 100644 --- a/VectoCommon/VectoCommon/Resources/XMLNames.resx +++ b/VectoCommon/VectoCommon/Resources/XMLNames.resx @@ -1135,7 +1135,7 @@ <value>TechnicalPermissibleMaximumLadenMass</value> </data> <data name="Vehicle_ADAS_ATEcoRollReleaseLockupClutch" xml:space="preserve"> - <value>ATEcoRollReleaseLockupClutch</value> + <value>APTEcoRollReleaseLockupClutch</value> </data> <data name="ManufacturerPrimaryVehicle" xml:space="preserve"> <value>ManufacturerPrimaryVehicle</value> diff --git a/VectoCore/VectoCore/InputData/Reader/ComponentData/BatteryInternalResistanceReader.cs b/VectoCore/VectoCore/InputData/Reader/ComponentData/BatteryInternalResistanceReader.cs index 4d5bebd0958b2bf2691ea9a65cf65ce7075a9f9b..51f34949584695a0cb0fdb0afe60a6ff6153f924 100644 --- a/VectoCore/VectoCore/InputData/Reader/ComponentData/BatteryInternalResistanceReader.cs +++ b/VectoCore/VectoCore/InputData/Reader/ComponentData/BatteryInternalResistanceReader.cs @@ -1,4 +1,6 @@ -using System.Data; +using System; +using System.Collections.Generic; +using System.Data; using System.IO; using System.Linq; using TUGraz.VectoCommon.Exceptions; @@ -11,27 +13,85 @@ namespace TUGraz.VectoCore.InputData.Reader.ComponentData { public static class BatteryInternalResistanceReader { - public static InternalResistanceMap Create(DataTable data, int packCount) + public static InternalResistanceMap Create(DataTable data) { - if (data.Columns.Count != 2) { - throw new VectoException("Internal Resistance Map data must contain exactly two columns: {0}, {1}",Fields.StateOfCharge, Fields.InternalResistance); + if (!(data.Columns.Count == 2 || data.Columns.Count == 4 || data.Columns.Count != 5)) { + throw new VectoException( + "Internal Resistance Map data must contain either two, four or five columns: {0}, {1}", + Fields.StateOfCharge, Fields.InternalResistance); } if (data.Rows.Count < 2) { throw new VectoException("Internal Resistance Map data must contain at least 2 entries!"); } - if (!data.Columns.Contains(Fields.StateOfCharge) || !data.Columns.Contains(Fields.InternalResistance)) { - data.Columns[0].ColumnName = Fields.StateOfCharge; - data.Columns[1].ColumnName = Fields.InternalResistance; - LoggingObject.Logger<InternalResistanceMap>().Warn("Internal Resistance Map Header is invalid. Expected: '{0}, {1}', Got: '{2}'. Falling back to column index.", - Fields.StateOfCharge, Fields.InternalResistance, string.Join(", ", data.Columns.Cast<DataColumn>().Select(c => c.ColumnName))); + if (data.Columns.Count == 2) { + if (!data.Columns.Contains(Fields.StateOfCharge) || !data.Columns.Contains(Fields.InternalResistance)) { + data.Columns[0].ColumnName = Fields.StateOfCharge; + data.Columns[1].ColumnName = Fields.InternalResistance; + LoggingObject.Logger<InternalResistanceMap>().Warn( + "Internal Resistance Map Header is invalid. Expected: '{0}, {1}', Got: '{2}'. Falling back to column index.", + Fields.StateOfCharge, Fields.InternalResistance, + string.Join(", ", data.Columns.Cast<DataColumn>().Select(c => c.ColumnName))); + } + + return new InternalResistanceMap(data.Rows.Cast<DataRow>().Select(row => { + var resistance = row.ParseDouble(Fields.InternalResistance).SI<Ohm>(); + return new InternalResistanceMap.InternalResistanceMapEntry() { + SoC = row.ParseDouble(Fields.StateOfCharge) / 100, + Resistance = new List<Tuple<Second, Ohm>>() { + Tuple.Create(0.SI<Second>(), resistance), + Tuple.Create(1e9.SI<Second>(), resistance) + } + }; + }).OrderBy(e => e.SoC).ToArray()); } - return new InternalResistanceMap(data.Rows.Cast<DataRow>().Select(row => new InternalResistanceMap.InternalResistanceMapEntry() { - SoC = row.ParseDouble(Fields.StateOfCharge) / 100, - Resistance = row.ParseDouble(Fields.InternalResistance).SI<Ohm>() / packCount - }).OrderBy(e => e.SoC).ToArray()); + var col1 = new[] { + Tuple.Create(2.SI<Second>(), Fields.InternalResistance_2), + Tuple.Create(10.SI<Second>(), Fields.InternalResistance_10), + Tuple.Create(20.SI<Second>(), Fields.InternalResistance_20), + }; + if (data.Columns.Count == col1.Length + 1) { + return ReadInternalResistanceMap(data, col1); + } + + var col2 = new[] { + Tuple.Create(2.SI<Second>(), Fields.InternalResistance_2), + Tuple.Create(10.SI<Second>(), Fields.InternalResistance_10), + Tuple.Create(20.SI<Second>(), Fields.InternalResistance_20), + Tuple.Create(120.SI<Second>(), Fields.InternalResistance_120) + }; + if (data.Columns.Count == col2.Length + 1) { + return ReadInternalResistanceMap(data, col2); + } + + + throw new VectoException("Failed to read InternalResistanceMap"); + } + + private static InternalResistanceMap ReadInternalResistanceMap(DataTable data, Tuple<Second, string>[] col1) + { + if ((!data.Columns.Contains(Fields.StateOfCharge) || !col1.All(x => data.Columns.Contains(x.Item2)))) { + for (var i = 0; i < col1.Length; i++) { + data.Columns[i].ColumnName = col1[i].Item2; + } + LoggingObject.Logger<InternalResistanceMap>().Warn( + "Internal Resistance Map Header is invalid. Expected: '{0}', Got: '{1}'. Falling back to column index.", + string.Join(", ", col1.Select(x => x.Item2)), + string.Join(", ", data.Columns.Cast<DataColumn>().Select(c => c.ColumnName))); + } + + + return new InternalResistanceMap(data.Rows.Cast<DataRow>().Select(row => { + var values = col1.Select(x => + row.Table.Columns.Contains(x.Item2) ? Tuple.Create(x.Item1, row.ParseDouble(x.Item2).SI<Ohm>()) : null) + .Where(x => x != null).ToList(); + return new InternalResistanceMap.InternalResistanceMapEntry() { + SoC = row.ParseDouble(Fields.StateOfCharge) / 100, + Resistance = values + }; + }).OrderBy(e => e.SoC).ToArray()); } public static class Fields @@ -39,11 +99,20 @@ namespace TUGraz.VectoCore.InputData.Reader.ComponentData public const string StateOfCharge = "SoC"; public const string InternalResistance = "Ri"; + + public const string InternalResistance_2 = "Ri-2"; + + public const string InternalResistance_10 = "Ri-10"; + + public const string InternalResistance_20 = "Ri-20"; + + public const string InternalResistance_120 = "Ri-120"; + } - public static InternalResistanceMap Create(Stream data, int packCount) + public static InternalResistanceMap Create(Stream data) { - return Create(VectoCSVFile.ReadStream(data), packCount); + return Create(VectoCSVFile.ReadStream(data)); } } } \ No newline at end of file diff --git a/VectoCore/VectoCore/InputData/Reader/ComponentData/BatteryMaxCurrentReader.cs b/VectoCore/VectoCore/InputData/Reader/ComponentData/BatteryMaxCurrentReader.cs index 8f09f43c4b718d2b3f4e310c57abee37acace5e3..5747491d5a31f6057510232f28f0b3051fcafd7a 100644 --- a/VectoCore/VectoCore/InputData/Reader/ComponentData/BatteryMaxCurrentReader.cs +++ b/VectoCore/VectoCore/InputData/Reader/ComponentData/BatteryMaxCurrentReader.cs @@ -11,7 +11,7 @@ namespace TUGraz.VectoCore.InputData.Reader.ComponentData { public static class BatteryMaxCurrentReader { - public static MaxCurrentMap Create(DataTable data, int packCount) + public static MaxCurrentMap Create(DataTable data) { if (data.Columns.Count != 3) { throw new VectoException("Max Current Map data must contain exactly three columns: {0}, {1}, {2}", Fields.StateOfCharge, Fields.MaxChargeCurrent, Fields.MaxDischargeCurrent); @@ -30,8 +30,8 @@ namespace TUGraz.VectoCore.InputData.Reader.ComponentData } return new MaxCurrentMap(data.Rows.Cast<DataRow>().Select(row => new MaxCurrentMap.MaxCurrentEntry() { SoC = row.ParseDouble(Fields.StateOfCharge) / 100, - MaxChargeCurrent = row.ParseDouble(Fields.MaxChargeCurrent).SI<Ampere>() * packCount, - MaxDischargeCurrent = -1 * row.ParseDouble(Fields.MaxDischargeCurrent).SI<Ampere>() * packCount + MaxChargeCurrent = row.ParseDouble(Fields.MaxChargeCurrent).SI<Ampere>(), + MaxDischargeCurrent = -1 * row.ParseDouble(Fields.MaxDischargeCurrent).SI<Ampere>() }).OrderBy(e => e.SoC).ToArray()); } @@ -46,9 +46,9 @@ namespace TUGraz.VectoCore.InputData.Reader.ComponentData } - public static MaxCurrentMap Create(Stream data, int packCount) + public static MaxCurrentMap Create(Stream data) { - return Create(VectoCSVFile.ReadStream(data), packCount); + return Create(VectoCSVFile.ReadStream(data)); } } } \ No newline at end of file diff --git a/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs b/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs index 4a5678830098b6b9a9e6060510ae5e9b42d49e24..c19b3ab671467f74d52973067f92dce741bb3b14 100644 --- a/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs +++ b/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs @@ -729,10 +729,10 @@ namespace TUGraz.VectoCore.InputData.Reader.DataObjectAdapter retVal.Batteries.Add(Tuple.Create(entry.StringId, new BatteryData() { MinSOC = b.MinSOC, MaxSOC = b.MaxSOC, - MaxCurrent = BatteryMaxCurrentReader.Create(b.MaxCurrentMap, entry.Count), + MaxCurrent = BatteryMaxCurrentReader.Create(b.MaxCurrentMap), Capacity = b.Capacity, InternalResistance = - BatteryInternalResistanceReader.Create(b.InternalResistanceCurve, 1), + BatteryInternalResistanceReader.Create(b.InternalResistanceCurve), SOCMap = BatterySOCReader.Create(b.VoltageCurve), })); } diff --git a/VectoCore/VectoCore/Models/Simulation/DataBus/IRESSInfo.cs b/VectoCore/VectoCore/Models/Simulation/DataBus/IRESSInfo.cs index 4f14b5555dc9342c1482cddf0792bb29becb88ec..9fc7a1afb1ac9b75bd62e4445b4a644d285a060b 100644 --- a/VectoCore/VectoCore/Models/Simulation/DataBus/IRESSInfo.cs +++ b/VectoCore/VectoCore/Models/Simulation/DataBus/IRESSInfo.cs @@ -19,5 +19,7 @@ namespace TUGraz.VectoCore.Models.Simulation.DataBus double MinSoC { get; } double MaxSoC { get; } + AmpereSecond Capacity { get; } + Volt NominalVoltage { get; } } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/SimulationComponent/DCDCConverter.cs b/VectoCore/VectoCore/Models/SimulationComponent/DCDCConverter.cs index c697576c804c6ab16502f78d5c0a4d9ad98ec549..fd0a9d86a575d6bec92fb8af61a2c77e5e059feb 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/DCDCConverter.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/DCDCConverter.cs @@ -31,7 +31,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent public Watt PowerDemand(Second absTime, Second dt, bool dryRun) { - if ((-DataBus.BatteryInfo.MaxDischargePower(dt) * dt).IsGreater(PreviousState.ConsumedEnergy)) { + var dischargeEnergy = (-DataBus.BatteryInfo.MaxDischargePower(dt) * dt); + var chargeEnergy = (-DataBus.BatteryInfo.MaxChargePower(dt) * dt); + if (PreviousState.ConsumedEnergy.IsBetween(chargeEnergy, dischargeEnergy)) { return PreviousState.ConsumedEnergy / dt / Efficiency; } diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/Battery/BatteryData.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/Battery/BatteryData.cs index 52ba4b9dbf2213fc9b2fcba8d1b0c987b657f813..2af79ad862de7515630af7a79d321f9ca293babe 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Data/Battery/BatteryData.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/Battery/BatteryData.cs @@ -25,7 +25,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Battery { (current, s) => current + Batteries.Where(x => x.Item1 == s).Min(x => x.Item2.Capacity)); } } - } + + + } public class BatteryData { @@ -116,12 +118,45 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Battery { Entries = entries; } - public Ohm Lookup(double SoC) + public Ohm Lookup(double SoC, Second tPulse) { var idx = FindIndex(SoC); - return VectoMath.Interpolate(Entries[idx - 1].SoC, Entries[idx].SoC, Entries[idx - 1].Resistance, - Entries[idx].Resistance, SoC); - } + var entry1 = Entries[idx - 1]; + var entry2 = Entries[idx]; + + var resistance1 = InterpolateResistance(entry1.Resistance, tPulse); + var resistance2 = InterpolateResistance(entry2.Resistance, tPulse); + + return VectoMath.Interpolate(entry1.SoC, entry2.SoC, resistance1, resistance2, SoC); + } + + private Ohm InterpolateResistance(List<Tuple<Second, Ohm>> resistance, Second tPulse) + { + + if (tPulse < resistance.First().Item1) { + return resistance.First().Item2; + } + + if (tPulse > resistance.Last().Item1) { + return resistance.Last().Item2; + } + + Tuple<Second, Ohm> entry1 = null; + Tuple<Second, Ohm> entry2 = null; + for (var index = 1; index < resistance.Count; index++) { + if (tPulse >= resistance[index - 1].Item1 && tPulse <= resistance[index].Item1) { + entry1 = resistance[index - 1]; + entry2 = resistance[index]; + } + } + + if (entry1 == null || entry2 == null) { + throw new VectoSimulationException("Failed to lookup internal resistance!"); + } + + return VectoMath.Interpolate(entry1.Item1, entry2.Item1, + entry1.Item2, entry2.Item2, tPulse); + } protected int FindIndex(double soc) { @@ -147,7 +182,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Battery { public class InternalResistanceMapEntry { [Required, Range(0, 1)] public double SoC; - [Required, SIRange(0, 1e6)] public Ohm Resistance; + [Required, SIRange(0, 1e6)] public List<Tuple<Second, Ohm>> Resistance; } } diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Battery.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Battery.cs index 7d01943df6670e6774b2ef8f1e3ba72f727c1845..2d131e2d6177c1e0abcbe683102e4037f6f22c30 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Battery.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Battery.cs @@ -24,6 +24,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl if (idx >= 0) { BatteryId = idx; } + CurrentState.PulseDuration = 0.SI<Second>(); + PreviousState.PulseDuration = 0.SI<Second>(); + PreviousState.PowerDemand = 0.SI<Watt>(); } #region Implementation of IBatteryProvider @@ -36,6 +39,10 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public void Initialize(double initialSoC) { + CurrentState.PulseDuration = 0.SI<Second>(); + PreviousState.PulseDuration = 0.SI<Second>(); + PreviousState.PowerDemand = 0.SI<Watt>(); + if (initialSoC.IsSmaller(ModelData.MinSOC) || initialSoC.IsGreater(ModelData.MaxSOC)) { throw new VectoException("SoC must be between {0} and {1}", ModelData.MinSOC, ModelData.MaxSOC); @@ -45,16 +52,21 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public IRESSResponse Request(Second absTime, Second dt, Watt powerDemand, bool dryRun = false) { + var tPulse = PreviousState.PowerDemand.Sign() == powerDemand.Sign() + ? PreviousState.PulseDuration + : 0.SI<Second>(); var maxChargePower = MaxChargePower(dt); var maxDischargePower = MaxDischargePower(dt); + if (powerDemand.IsGreater(maxChargePower, Constants.SimulationSettings.InterpolateSearchTolerance) || powerDemand.IsSmaller(maxDischargePower, Constants.SimulationSettings.InterpolateSearchTolerance)) { - return PowerDemandExceeded(absTime, dt, powerDemand, maxDischargePower, maxChargePower, dryRun); + return PowerDemandExceeded(absTime, dt, powerDemand, maxDischargePower, maxChargePower, tPulse, dryRun); } - var internalResistance = ModelData.InternalResistance.Lookup(PreviousState.StateOfCharge); + + var internalResistance = ModelData.InternalResistance.Lookup(PreviousState.StateOfCharge, tPulse); var current = 0.SI<Ampere>(); if (!powerDemand.IsEqual(0)) { @@ -106,7 +118,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl } private IRESSResponse PowerDemandExceeded(Second absTime, Second dt, Watt powerDemand, Watt maxDischargePower, - Watt maxChargePower, bool dryRun) + Watt maxChargePower, Second tPulse, bool dryRun) { var maxPower = powerDemand < 0 ? maxDischargePower : maxChargePower; @@ -116,7 +128,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl ModelData.MaxCurrent.LookupMaxDischargeCurrent(PreviousState.StateOfCharge)); var current = powerDemand < 0 ? maxDischargeCurrent : maxChargeCurrent; - var batteryLoss = current * ModelData.InternalResistance.Lookup(PreviousState.StateOfCharge) * current; + var batteryLoss = current * ModelData.InternalResistance.Lookup(PreviousState.StateOfCharge, tPulse) * current; AbstractRESSResponse response; if (dryRun) { @@ -146,11 +158,14 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl protected override void DoWriteModalResults(Second absTime, Second dt, IModalDataContainer container) { var cellVoltage = ModelData.SOCMap.Lookup(PreviousState.StateOfCharge); + var tPulse = PreviousState.PowerDemand.Sign() == CurrentState.PowerDemand.Sign() + ? PreviousState.PulseDuration + : 0.SI<Second>(); container[ModalResultField.U0_reess, BatteryId] = cellVoltage; container[ModalResultField.U_reess_terminal, BatteryId] = cellVoltage + CurrentState.TotalCurrent * - ModelData.InternalResistance.Lookup(PreviousState.StateOfCharge); // adding both terms because pos. current charges the battery! + ModelData.InternalResistance.Lookup(PreviousState.StateOfCharge, tPulse); // adding both terms because pos. current charges the battery! container[ModalResultField.I_reess, BatteryId] = CurrentState.TotalCurrent; container[ModalResultField.REESSStateOfCharge, BatteryId] = CurrentState.StateOfCharge.SI(); container[ModalResultField.P_reess_terminal, BatteryId] = CurrentState.PowerDemand; @@ -164,6 +179,10 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl protected override void DoCommitSimulationStep(Second time, Second simulationInterval) { + var tPulse = PreviousState.PowerDemand.Sign() == CurrentState.PowerDemand.Sign() + ? PreviousState.PulseDuration + : 0.SI<Second>(); + CurrentState.PulseDuration = tPulse + simulationInterval; AdvanceState(); } @@ -181,25 +200,27 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public Watt MaxChargePower(Second dt) { - //var maxChargeCurrent = VectoMath.Min((ModelData.MaxSOC - PreviousState.StateOfCharge) * ModelData.Capacity / dt, - // ModelData.MaxCurrent.LookupMaxChargeCurrent(PreviousState.StateOfCharge)); var maxChargeCurrent = MaxChargeCurrent(dt); + var tPulse = PreviousState.PowerDemand.Sign() > 0 // keep on charging? + ? PreviousState.PulseDuration + : 0.SI<Second>(); return InternalVoltage * maxChargeCurrent + - maxChargeCurrent * InternalResistance * maxChargeCurrent; + maxChargeCurrent * InternalResistance(tPulse) * maxChargeCurrent; } public Watt MaxDischargePower(Second dt) { - //var maxDischargeCurrent = VectoMath.Max( - // ((ModelData.MinSOC - PreviousState.StateOfCharge) * ModelData.Capacity / dt).LimitTo(ModelData.MaxCurrent.LookupMaxDischargeCurrent(PreviousState.StateOfCharge), - // 0.SI<Ampere>()), ModelData.MaxCurrent.LookupMaxDischargeCurrent(PreviousState.StateOfCharge)); var maxDischargeCurrent = MaxDischargeCurrent(dt); var cellVoltage = InternalVoltage; + var tPulse = PreviousState.PowerDemand.Sign() < 0 // keep on discharging? + ? PreviousState.PulseDuration + : 0.SI<Second>(); + var internalResistance = InternalResistance(tPulse); var maxDischargePower = InternalVoltage * maxDischargeCurrent + - maxDischargeCurrent * InternalResistance * maxDischargeCurrent; - var maxPower = -cellVoltage / (4 * InternalResistance) * cellVoltage; + maxDischargeCurrent * internalResistance * maxDischargeCurrent; + var maxPower = -cellVoltage / (4 * internalResistance) * cellVoltage; return VectoMath.Max(maxDischargePower, maxPower); } @@ -207,9 +228,15 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public double MaxSoC => ModelData.MaxSOC; - public Ohm InternalResistance => ModelData.InternalResistance.Lookup(PreviousState.StateOfCharge); - public AmpereSecond Capacity => ModelData.Capacity; + public Ohm InternalResistance(Second tPulse) + { + return ModelData.InternalResistance.Lookup(PreviousState.StateOfCharge, tPulse); + } + public AmpereSecond Capacity => ModelData.Capacity; + + public Volt NominalVoltage => ModelData.SOCMap.Lookup(0.5); + public Ampere MaxChargeCurrent(Second dt) { return VectoMath.Min( @@ -246,6 +273,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public Watt MaxChargePower; public Watt MaxDischargePower; public Watt BatteryLoss; + public Second PulseDuration; } diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/BatterySystem.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/BatterySystem.cs index 0d75b8ebf543e1e5d0960a801648da83651a7bb2..b2856aa3036b53f3113f3b609b6c23ce36512ab2 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/BatterySystem.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/BatterySystem.cs @@ -21,6 +21,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl protected readonly List<Battery> _batteries; private AmpereSecond _capacity; + private AmpereSecond _capacityMinSoc; + private AmpereSecond _capacityMaxSoc; public BatteryString() { @@ -38,21 +40,22 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public Volt OpenCircuitVoltage => _batteries.Sum(x => x.InternalVoltage); - public Ohm InternalResistance => _batteries.Sum(x => x.InternalResistance); + public Ohm InternalResistance(Second tPulse) => _batteries.Sum(x => x.InternalResistance(tPulse)); public AmpereSecond Capacity => _capacity ?? (_capacity = _batteries.Min(x => x.Capacity)); public double SoC => _batteries.Min(x => x.StateOfCharge * x.Capacity) / Capacity; public WattSecond StoredEnergy => _batteries.Min(x => x.StateOfCharge * x.Capacity) * OpenCircuitVoltage; - public Watt MaxDischargePower(Second dt) + public Watt MaxDischargePower(Second dt, Second tPulse) { var maxDischargeCurrent = MaxDischargeCurrent(dt); - var maxDischargePower = OpenCircuitVoltage * maxDischargeCurrent + - maxDischargeCurrent * InternalResistance * maxDischargeCurrent; - var maxPower = -OpenCircuitVoltage / (4 * InternalResistance) * OpenCircuitVoltage; - return VectoMath.Max(maxDischargePower, maxPower); - + var internalResistance = InternalResistance(tPulse); + var maxDischargePower = OpenCircuitVoltage * maxDischargeCurrent + + maxDischargeCurrent * internalResistance* maxDischargeCurrent; + var maxPower = -OpenCircuitVoltage / (4 * internalResistance) * OpenCircuitVoltage; + return VectoMath.Max(maxDischargePower, maxPower); + } public Ampere MaxChargeCurrent(Second dt) @@ -65,18 +68,18 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl return _batteries.Max(x => x.MaxDischargeCurrent(dt)); } - public Watt MaxChargePower(Second dt) + public Watt MaxChargePower(Second dt, Second tPulse) { var maxCurrent = MaxChargeCurrent(dt); return OpenCircuitVoltage * maxCurrent + - maxCurrent * InternalResistance * maxCurrent; + maxCurrent * InternalResistance(tPulse) * maxCurrent; } - public IList<IRESSResponse> Request(Second absTime, Second dt, Watt powerDemand, bool dryRun) + public IList<IRESSResponse> Request(Second absTime, Second dt, Watt powerDemand, Second tPulse, bool dryRun) { var current = 0.SI<Ampere>(); if (!powerDemand.IsEqual(0)) { - var solutions = VectoMath.QuadraticEquationSolver(InternalResistance.Value(), OpenCircuitVoltage.Value(), + var solutions = VectoMath.QuadraticEquationSolver(InternalResistance(tPulse).Value(), OpenCircuitVoltage.Value(), -powerDemand.Value()); current = SelectSolution(solutions, powerDemand.Value(), dt); } @@ -86,13 +89,21 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl } return _batteries.Select(x => { - var demand = (x.InternalVoltage + x.InternalResistance * current) * current; + var demand = (x.InternalVoltage + x.InternalResistance(tPulse) * current) * current; return x.Request(absTime, dt, demand, dryRun); }).ToList(); } public Ampere Current { get; set; } + public AmpereSecond CapacityMinSoc => + _capacityMinSoc ?? (_capacityMinSoc = _batteries.Min(x => x.Capacity * x.MinSoC)); + + public AmpereSecond CapacityMaxSoc => + _capacityMaxSoc ?? (_capacityMaxSoc = _batteries.Min(x => x.Capacity * x.MaxSoC)); + + public Volt NominalVoltage => Batteries.Sum(x => x.NominalVoltage); + private Ampere SelectSolution(double[] solutions, double sign, Second dt) { var maxCurrent = Math.Sign(sign) < 0 @@ -105,6 +116,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl protected internal readonly Dictionary<int, BatteryString> Batteries = new Dictionary<int, BatteryString>(); private AmpereSecond _totalCapacity; + private Scalar _minSoc; + private Scalar _maxSoc; public BatterySystem(IVehicleContainer dataBus, BatterySystemData batterySystemData) : base(dataBus) { @@ -116,6 +129,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl } Batteries[entry.Item1].AddBattery(bat); } + + PreviousState.PowerDemand = 0.SI<Watt>(); } #region Overrides of VectoSimulationComponent @@ -138,11 +153,14 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl protected override void DoWriteModalResults(Second time, Second simulationInterval, IModalDataContainer container) { var cellVoltage = InternalVoltage; + var tPulse = PreviousState.PowerDemand.Sign() == CurrentState.PowerDemand.Sign() + ? PreviousState.PulseDuration + : 0.SI<Second>(); container[ModalResultField.U0_reess] = cellVoltage; container[ModalResultField.U_reess_terminal] = cellVoltage + CurrentState.TotalCurrent * - InternalResistance; // adding both terms because pos. current charges the battery! + InternalResistance(tPulse); // adding both terms because pos. current charges the battery! container[ModalResultField.I_reess] = CurrentState.TotalCurrent; //container[ModalResultField.REESSStateOfCharge] = CurrentState.StateOfCharge.SI(); container[ModalResultField.P_reess_terminal] = CurrentState.PowerDemand; @@ -152,11 +170,15 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl container[ModalResultField.P_reess_discharge_max] = CurrentState.MaxDischargePower; } - public Ohm InternalResistance => (1 / Batteries.Sum(bs => 1 / bs.Value.InternalResistance.Value())).SI<Ohm>(); + public Ohm InternalResistance(Second tPulse) => (1 / Batteries.Sum(bs => 1 / bs.Value.InternalResistance(tPulse).Value())).SI<Ohm>(); protected override void DoCommitSimulationStep(Second time, Second simulationInterval) { - + var tPulse = PreviousState.PowerDemand.Sign() == CurrentState.PowerDemand.Sign() + ? PreviousState.PulseDuration + : 0.SI<Second>(); + CurrentState.PulseDuration = tPulse + simulationInterval; + AdvanceState(); } @@ -181,24 +203,35 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public Watt MaxChargePower(Second dt) { - return Batteries.Values.Sum(bs => bs.MaxChargePower(dt)); + var tPulse = PreviousState.PowerDemand.Sign() > 0 // keep on charging? + ? PreviousState.PulseDuration + : 0.SI<Second>(); + return Batteries.Values.Sum(bs => bs.MaxChargePower(dt, tPulse)); } public Watt MaxDischargePower(Second dt) { - return Batteries.Values.Sum(bs => bs.MaxDischargePower(dt)); + var tPulse = PreviousState.PowerDemand.Sign() < 0 // keep on discharging? + ? PreviousState.PulseDuration + : 0.SI<Second>(); + return Batteries.Values.Sum(bs => bs.MaxDischargePower(dt, tPulse)); } - public double MinSoC { get; } - public double MaxSoC { get; } + public double MinSoC => _minSoc ?? (_minSoc = Batteries.Values.Sum(x => x.CapacityMinSoc) / TotalCapacity); + public double MaxSoC => _maxSoc ?? (_maxSoc = Batteries.Values.Sum(x => x.CapacityMinSoc) / TotalCapacity); + public AmpereSecond Capacity => TotalCapacity; + public Volt NominalVoltage => Batteries.Values.Select(x => x.NominalVoltage).Average(); #endregion #region Implementation of IElectricEnergyStoragePort public void Initialize(double initialSoC) { + CurrentState.PulseDuration = 0.SI<Second>(); + PreviousState.PulseDuration = 0.SI<Second>(); + PreviousState.PowerDemand = 0.SI<Watt>(); foreach (var b in Batteries.Values.SelectMany(bs => bs.Batteries)) { b.Initialize(initialSoC); } @@ -209,12 +242,22 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl var maxChargePower = MaxChargePower(dt); var maxDischargePower = MaxDischargePower(dt); + var tPulse = PreviousState.PowerDemand.Sign() == powerDemand.Sign() + ? PreviousState.PulseDuration + : 0.SI<Second>(); + if (powerDemand.IsGreater(maxChargePower, Constants.SimulationSettings.InterpolateSearchTolerance) || powerDemand.IsSmaller(maxDischargePower, Constants.SimulationSettings.InterpolateSearchTolerance)) { - return PowerDemandExceeded(absTime, dt, powerDemand, maxDischargePower, maxChargePower, dryRun); + return PowerDemandExceeded(absTime, dt, powerDemand, maxDischargePower, maxChargePower, tPulse, dryRun); } - + var tPulseChg = PreviousState.PowerDemand.Sign() > 0 // keep on charging? + ? PreviousState.PulseDuration + : 0.SI<Second>(); + var tPulseDischg = PreviousState.PowerDemand.Sign() < 0 // keep on discharging? + ? PreviousState.PulseDuration + : 0.SI<Second>(); + var powerDemands = new Dictionary<int, Watt>(); var limitBB = new Dictionary<int, Watt>(); var distributedPower = 0.SI<Watt>(); @@ -230,8 +273,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl } var delta = 1 - Math.Sign(remainingPower.Value()) * (bs.Value.SoC - averageSoC) / averageSoC; var power = bs.Value.Capacity / totalCapacity * delta * remainingPower; - if (!power.IsBetween(bs.Value.MaxDischargePower(dt), bs.Value.MaxChargePower(dt))) { - limitBB[bs.Key] = power.LimitTo(bs.Value.MaxDischargePower(dt), bs.Value.MaxChargePower(dt)); + + if (!power.IsBetween(bs.Value.MaxDischargePower(dt, tPulseDischg), bs.Value.MaxChargePower(dt, tPulseChg))) { + limitBB[bs.Key] = power.LimitTo(bs.Value.MaxDischargePower(dt, tPulseDischg), bs.Value.MaxChargePower(dt, tPulseChg)); } else { powerDemands[bs.Key] = power; distributedPower += power; @@ -247,7 +291,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl var responses = new Dictionary<int, IList<IRESSResponse>>(); foreach (var entry in powerDemands) { - responses[entry.Key] = Batteries[entry.Key].Request(absTime, dt, entry.Value, dryRun); + responses[entry.Key] = Batteries[entry.Key].Request(absTime, dt, entry.Value, tPulse, dryRun); } if (dryRun) { @@ -269,7 +313,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl CurrentState.MaxChargePower = maxChargePower; CurrentState.MaxDischargePower = maxDischargePower; CurrentState.TotalCurrent = current; - CurrentState.BatteryLoss = current * InternalResistance * current; + CurrentState.BatteryLoss = current * InternalResistance(tPulse) * current; if (responses.All(bb => bb.Value.All(b => b is RESSResponseSuccess))) { return new RESSResponseSuccess(this) { @@ -287,14 +331,14 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl private IRESSResponse PowerDemandExceeded(Second absTime, Second dt, Watt powerDemand, Watt maxDischargePower, - Watt maxChargePower, bool dryRun) + Watt maxChargePower, Second tPulse, bool dryRun) { var maxPower = powerDemand < 0 ? maxDischargePower : maxChargePower; var maxChargeCurrent = Batteries.Values.Sum(bs => bs.MaxChargeCurrent(dt)); var maxDischargeCurrent = Batteries.Values.Sum(bs => bs.MaxDischargeCurrent(dt)); var current = powerDemand < 0 ? maxDischargeCurrent : maxChargeCurrent; - var internalResistance = (1 / Batteries.Values.Sum(bs => 1 / bs.InternalResistance.Value())).SI<Ohm>(); + var internalResistance = (1 / Batteries.Values.Sum(bs => 1 / bs.InternalResistance(tPulse).Value())).SI<Ohm>(); var batteryLoss = current * internalResistance * current; @@ -332,6 +376,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public Watt MaxChargePower; public Watt MaxDischargePower; public Watt BatteryLoss; + public Second PulseDuration; } } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/SuperCap.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/SuperCap.cs index f786f997b509c0a119549b553f7d252c6c777ef4..041129065c6396b2a5e366e47eb03ed60b4fb1ea 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/SuperCap.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/SuperCap.cs @@ -56,6 +56,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public double MinSoC => ModelData.MinVoltage / ModelData.MaxVoltage; public double MaxSoC => 1; + public AmpereSecond Capacity => null; + public Volt NominalVoltage => null; public void Initialize(double initialSoC) { diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Strategies/HybridStrategy.cs b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/HybridStrategy.cs index 792885f060097b46e1840b6f0255fb3e3a51b723..79f9e7d481a0897d5db65904b9ef073cf6b4d665 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Strategies/HybridStrategy.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/HybridStrategy.cs @@ -586,17 +586,17 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies shiftStrategyParameters.AllowedGearRangeFC = shiftStrategyParameters.AllowedGearRangeFC.LimitTo(1, 2); } - // TODO: MQ 20210712 how to handle with batterysystem - //var auxEnergyReserve = ModelData.ElectricAuxDemand * StrategyParameters.AuxReserveTime; - BatteryDischargeEnergyThreshold = 0.SI<WattSecond>(); - //if (auxEnergyReserve > 0) { - // var minSoc = Math.Max(ModelData.BatteryData?.MinSOC ?? ModelData.SuperCapData.MinVoltage / ModelData.SuperCapData.MaxVoltage, - // StrategyParameters.MinSoC); - // BatteryDischargeEnergyThreshold = - // ModelData.BatteryData.Capacity * minSoc * ModelData.BatteryData.SOCMap.Lookup(minSoc) + - // auxEnergyReserve; - //} - AllowEmergencyShift = false; + // TODO: MQ 20210712 how to handle with batterysystem + //var auxEnergyReserve = ModelData.ElectricAuxDemand * StrategyParameters.AuxReserveTime; + BatteryDischargeEnergyThreshold = 0.SI<WattSecond>(); + //if (auxEnergyReserve > 0) { + // var minSoc = Math.Max(ModelData.BatteryData?.MinSOC ?? ModelData.SuperCapData.MinVoltage / ModelData.SuperCapData.MaxVoltage, + // StrategyParameters.MinSoC); + // BatteryDischargeEnergyThreshold = + // ModelData.BatteryData.Capacity * minSoc * ModelData.BatteryData.SOCMap.Lookup(minSoc) + + // auxEnergyReserve; + //} + AllowEmergencyShift = false; } public virtual IHybridController Controller { protected get; set; } @@ -2261,14 +2261,13 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies } // TODO: MQ 20210712 how to handle with batterysystem - //var auxEnergyReserve = ModelData.ElectricAuxDemand * StrategyParameters.AuxReserveTime; - //if (auxEnergyReserve > 0) { - // var minSoc = Math.Max(ModelData.BatteryData?.MinSOC ?? ModelData.SuperCapData.MinVoltage / ModelData.SuperCapData.MaxVoltage, - // StrategyParameters.MinSoC); - // BatteryDischargeEnergyThreshold = - // ModelData.BatteryData.Capacity * minSoc * ModelData.BatteryData.SOCMap.Lookup(minSoc) + - // auxEnergyReserve; - //} + var auxEnergyReserve = ModelData.ElectricAuxDemand * StrategyParameters.AuxReserveTime; + if (auxEnergyReserve > 0) { + var minSoc = Math.Max(DataBus.BatteryInfo.MinSoC, StrategyParameters.MinSoC); + BatteryDischargeEnergyThreshold = + DataBus.BatteryInfo.Capacity * minSoc * DataBus.BatteryInfo.NominalVoltage + + auxEnergyReserve; + } PreviousState.AngularVelocity = outAngularVelocity; PreviousState.GearboxEngaged = true; diff --git a/VectoCore/VectoCore/Utils/VectoVersionCore.cs b/VectoCore/VectoCore/Utils/VectoVersionCore.cs index bba38738193877e65f3670651632df55a4604a0d..5ea7e6bda66b49bc3467f39edc19a968db8b600b 100644 --- a/VectoCore/VectoCore/Utils/VectoVersionCore.cs +++ b/VectoCore/VectoCore/Utils/VectoVersionCore.cs @@ -44,10 +44,25 @@ namespace TUGraz.VectoCore.Utils #endif #endif - public static string VersionNumber => "0.7.3.2247" + SUFFIX; + public static string VersionNumber + { + get { + return "0.7.5.2380" + SUFFIX; + } + } - public static string BranchSuffix => "-DEV"; + public static string BranchSuffix + { + get { + return "-DEV"; + } + } - public static string FullVersion => string.Format("VectoCore{1} {0}", VersionNumber, BranchSuffix); + public static string FullVersion + { + get { + return string.Format("VectoCore{1} {0}", VersionNumber, BranchSuffix); + } + } } } \ No newline at end of file diff --git a/VectoCore/VectoCoreTest/FileIO/JsonReadHybridTest.cs b/VectoCore/VectoCoreTest/FileIO/JsonReadHybridTest.cs index 47d5286c5f133309e0c9ce38f5495657ec7f9a0e..2f0115a5829d5aa77a5a9f096b6fb3f18c6f9ba7 100644 --- a/VectoCore/VectoCoreTest/FileIO/JsonReadHybridTest.cs +++ b/VectoCore/VectoCoreTest/FileIO/JsonReadHybridTest.cs @@ -211,8 +211,8 @@ namespace TUGraz.VectoCore.Tests.FileIO Assert.AreEqual(0.8, engineering.JobInputData.Vehicle.InitialSOC); var bat = engineering.JobInputData.Vehicle.Components.ElectricStorage.ElectricStorageElements.First().REESSPack as IBatteryPackEngineeringInputData; - var ri = BatteryInternalResistanceReader.Create(bat.InternalResistanceCurve, 1); - var imax = BatteryMaxCurrentReader.Create(bat.MaxCurrentMap, 1); + var ri = BatteryInternalResistanceReader.Create(bat.InternalResistanceCurve); + var imax = BatteryMaxCurrentReader.Create(bat.MaxCurrentMap); Assert.NotNull(bat); Assert.AreEqual(2, engineering.JobInputData.Vehicle.Components.ElectricStorage.ElectricStorageElements.First().Count); @@ -221,7 +221,7 @@ namespace TUGraz.VectoCore.Tests.FileIO Assert.AreEqual("375", bat.MaxCurrentMap.Rows[1][BatteryMaxCurrentReader.Fields.MaxDischargeCurrent]); Assert.AreEqual(375, imax.LookupMaxChargeCurrent(0.5).Value()); Assert.AreEqual(-375, imax.LookupMaxDischargeCurrent(0.5).Value()); - Assert.AreEqual(0.04, ri.Lookup(0.5).Value()); + Assert.AreEqual(0.04, ri.Lookup(0.5, 0.SI<Second>()).Value()); var em = engineering.JobInputData.Vehicle.Components.ElectricMachines; diff --git a/VectoCore/VectoCoreTest/Integration/Hybrid/ParallelHybridTest.cs b/VectoCore/VectoCoreTest/Integration/Hybrid/ParallelHybridTest.cs index e462b54c99d4f2170b0ed1108941c0200f8bbbce..8b81313065eef18eb73c750d8abf51bcaff8fe8c 100644 --- a/VectoCore/VectoCoreTest/Integration/Hybrid/ParallelHybridTest.cs +++ b/VectoCore/VectoCoreTest/Integration/Hybrid/ParallelHybridTest.cs @@ -409,7 +409,7 @@ namespace TUGraz.VectoCore.Tests.Integration.Hybrid TestCase(80, 0.5, -5, 0, TestName = "P2 Hybrid ConstantSpeed 80km/h SoC: 0.5, DH 5%"), TestCase(30, 0.25, 0, 1000, TestName = "P2 Hybrid ConstantSpeed 30km/h SoC: 0.25, level P_auxEl: 1kW"), - TestCase(30, 0.25, 0, 5000, TestName = "P2 Hybrid ConstantSpeed 30km/h SoC: 0.25, level P_auxEl: 5kW"), + TestCase(30, 0.25, 0, 0, TestName = "P2 Hybrid ConstantSpeed 30km/h SoC: 0.25, level P_auxEl: 0kW"), ] public void P2HybridConstantSpeed(double vmax, double initialSoC, double slope, double pAuxEl) { diff --git a/VectoCore/VectoCoreTest/Models/EngineeringMode/EngineeringModeBusAuxTest.cs b/VectoCore/VectoCoreTest/Models/EngineeringMode/EngineeringModeBusAuxTest.cs index ef74191115d8a0df945c2abd0c8fbd4e0fe6e092..1d3ff4dffd7fa6b55bbc0532b0aa539605b131e3 100644 --- a/VectoCore/VectoCoreTest/Models/EngineeringMode/EngineeringModeBusAuxTest.cs +++ b/VectoCore/VectoCoreTest/Models/EngineeringMode/EngineeringModeBusAuxTest.cs @@ -900,9 +900,9 @@ namespace TUGraz.VectoCore.Tests.Models.EngineeringMode MaxSOC = REESS_MaxSoC, SOCMap = BatterySOCReader.Create("SOC,V\n0,590\n100,658".ToStream()), InternalResistance = - BatteryInternalResistanceReader.Create("SoC, Ri\n0,0.02\n100,0.02".ToStream(), packCount), + BatteryInternalResistanceReader.Create("SoC, Ri\n0,0.02\n100,0.02".ToStream()), MaxCurrent = BatteryMaxCurrentReader.Create( - "SOC, I_charge, I_discharge\n0, 375, 573\n100, 375, 375".ToStream(), packCount), + "SOC, I_charge, I_discharge\n0, 375, 573\n100, 375, 375".ToStream()), }), }, InitialSoC = reessSoC.Value diff --git a/VectoCore/VectoCoreTest/Models/SimulationComponent/BatteryTest.cs b/VectoCore/VectoCoreTest/Models/SimulationComponent/BatteryTest.cs index a2a7a12d74cfe47cd2abc0427077d0210b3f8620..5d5196dfca0681b10d06d0a600bc94aa001d3a28 100644 --- a/VectoCore/VectoCoreTest/Models/SimulationComponent/BatteryTest.cs +++ b/VectoCore/VectoCoreTest/Models/SimulationComponent/BatteryTest.cs @@ -1,13 +1,19 @@ -using System.IO; +using System; +using System.Collections.Generic; +using System.IO; using System.Linq; using NUnit.Framework; using TUGraz.VECTO; using TUGraz.VectoCommon.InputData; using TUGraz.VectoCommon.Utils; using TUGraz.VectoCore.InputData.FileIO.JSON; +using TUGraz.VectoCore.InputData.Reader.ComponentData; using TUGraz.VectoCore.InputData.Reader.DataObjectAdapter; using TUGraz.VectoCore.Models.Connector.Ports.Impl; +using TUGraz.VectoCore.Models.Simulation.Data; using TUGraz.VectoCore.Models.SimulationComponent; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Battery; +using TUGraz.VectoCore.Models.SimulationComponent.Impl; using TUGraz.VectoCore.Tests.Utils; using Battery = TUGraz.VectoCore.Models.SimulationComponent.Impl.Battery; @@ -197,5 +203,440 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent Assert.AreEqual(auxPower, response.AuxPower.Value(), 1e-2); Assert.AreEqual(powerDemand - auxPower, response.RESSResponse.PowerDemand.Value(), 1e-2); } + + + public const double REESS_Capacity = 4.5; + public const double REESS_MinSoC = 0.2; + public const double REESS_MaxSoC = 0.8; + + [TestCase(0.5, 0.5, 5000), + TestCase(0.5, 0.5, -5000)] + public void BatteryTimeDependentInternalResistanceTest_ConstantLoad(double initialSoC, double dt, double powerDemand) + { + var r1 = 0.02; + var r2 = 0.04; + var r3 = 0.1; + + var batteryData = new BatterySystemData() { + Batteries = new List<Tuple<int, BatteryData>>() { + Tuple.Create(0, new BatteryData() { + Capacity = REESS_Capacity.SI(Unit.SI.Ampere.Hour).Cast<AmpereSecond>(), + MinSOC = REESS_MinSoC, + MaxSOC = REESS_MaxSoC, + SOCMap = BatterySOCReader.Create("SOC,V\n0,590\n100,658".ToStream()), + InternalResistance = + BatteryInternalResistanceReader.Create($"SoC, Ri-2, Ri-10, Ri-20\n0, {r1}, {r2}, {r3}\n100, {r1}, {r2}, {r3}".ToStream()), + MaxCurrent = BatteryMaxCurrentReader.Create( + "SOC, I_charge, I_discharge\n0, 375, 573\n100, 375, 375".ToStream()), + }) + } + }; + + var container = new MockVehicleContainer(); + var bat = new Battery(container, batteryData.Batteries.First().Item2); + var es = new ElectricSystem(container); + es.Connect(bat); + es.Connect(new MockElectricConsumer(0.SI<Watt>())); + bat.Initialize(initialSoC); + + var modData = new MockModalDataContainer(); + + var absTime = 0.SI<Second>(); + + var i = 0; + for (; i < 5; i++) { // constant for the first 2 sec + var response = es.Request(absTime, dt.SI<Second>(), powerDemand.SI<Watt>()); + Assert.IsInstanceOf<ElectricSystemResponseSuccess>(response); + bat.CommitSimulationStep(absTime, dt.SI<Second>(), modData); + + var current = (Ampere)modData[ModalResultField.I_reess]; + var rREESS = (Watt)modData[ModalResultField.P_reess_loss] / current / current; + Assert.AreEqual(r1, rREESS.Value(), 1e-9, $"{i} / {absTime}"); + + absTime += dt.SI<Second>(); + } + + for (; i < 21; i++) { // linear increase for the next 8s to 0.04 + var response = es.Request(absTime, dt.SI<Second>(), powerDemand.SI<Watt>()); + Assert.IsInstanceOf<ElectricSystemResponseSuccess>(response); + bat.CommitSimulationStep(absTime, dt.SI<Second>(), modData); + + var current = (Ampere)modData[ModalResultField.I_reess]; + var rREESS = (Watt)modData[ModalResultField.P_reess_loss] / current / current; + var slope = (r2 - r1) / (10 - 2); + var r = slope * absTime.Value() + r1 - slope * 2; + Assert.AreEqual(r, rREESS.Value(), 1e-9, $"{i} / {absTime}"); + + absTime += dt.SI<Second>(); + } + + for (; i < 41; i++) { // linear increase for the next 10s to 0.1 + var response = es.Request(absTime, dt.SI<Second>(), powerDemand.SI<Watt>()); + Assert.IsInstanceOf<ElectricSystemResponseSuccess>(response); + bat.CommitSimulationStep(absTime, dt.SI<Second>(), modData); + + var current = (Ampere)modData[ModalResultField.I_reess]; + var rREESS = (Watt)modData[ModalResultField.P_reess_loss] / current / current; + var slope = (r3 - r2) / (20 - 10); + var r = slope * absTime.Value() + r2 - slope * 10; + Assert.AreEqual(r, rREESS.Value(), 1e-9, $"{i} / {absTime}"); + + absTime += dt.SI<Second>(); + } + + for (; i < 100; i++) { // constant after 20 sec + var response = es.Request(absTime, dt.SI<Second>(), powerDemand.SI<Watt>()); + Assert.IsInstanceOf<ElectricSystemResponseSuccess>(response); + bat.CommitSimulationStep(absTime, dt.SI<Second>(), modData); + + var current = (Ampere)modData[ModalResultField.I_reess]; + var rREESS = (Watt)modData[ModalResultField.P_reess_loss] / current / current; + Assert.AreEqual(r3, rREESS.Value(), 1e-9, $"{i} / {absTime}"); + + absTime += dt.SI<Second>(); + } + } + + [TestCase(0.5, 0.5, 5000), + TestCase(0.5, 0.5, -5000)] + public void BatteryTimeDependentInternalResistanceTest_LoadChanges(double initialSoC, double dt, double powerDemand) + { + var r1 = 0.02; + var r2 = 0.04; + var r3 = 0.1; + + var batteryData = new BatterySystemData() { + Batteries = new List<Tuple<int, BatteryData>>() { + Tuple.Create(0, new BatteryData() { + Capacity = REESS_Capacity.SI(Unit.SI.Ampere.Hour).Cast<AmpereSecond>(), + MinSOC = REESS_MinSoC, + MaxSOC = REESS_MaxSoC, + SOCMap = BatterySOCReader.Create("SOC,V\n0,590\n100,658".ToStream()), + InternalResistance = + BatteryInternalResistanceReader.Create($"SoC, Ri-2, Ri-10, Ri-20\n0, {r1}, {r2}, {r3}\n100, {r1}, {r2}, {r3}".ToStream()), + MaxCurrent = BatteryMaxCurrentReader.Create( + "SOC, I_charge, I_discharge\n0, 375, 573\n100, 375, 375".ToStream()), + }) + } + }; + + var container = new MockVehicleContainer(); + var bat = new Battery(container, batteryData.Batteries.First().Item2); + var es = new ElectricSystem(container); + es.Connect(bat); + es.Connect(new MockElectricConsumer(0.SI<Watt>())); + bat.Initialize(initialSoC); + + var modData = new MockModalDataContainer(); + + var absTime = 0.SI<Second>(); + + var i = 0; + for (; i < 11; i++) { // constant for the first 5 sec + var response = es.Request(absTime, dt.SI<Second>(), -Math.Sign(powerDemand) * Math.Abs(powerDemand).SI<Watt>()); + Assert.IsInstanceOf<ElectricSystemResponseSuccess>(response); + bat.CommitSimulationStep(absTime, dt.SI<Second>(), modData); + + absTime += dt.SI<Second>(); + } + + for (; i < 11 + 5; i++) { // constant for the first 2 sec + var response = es.Request(absTime, dt.SI<Second>(), powerDemand.SI<Watt>()); + Assert.IsInstanceOf<ElectricSystemResponseSuccess>(response); + bat.CommitSimulationStep(absTime, dt.SI<Second>(), modData); + + var current = (Ampere)modData[ModalResultField.I_reess]; + var rREESS = (Watt)modData[ModalResultField.P_reess_loss] / current / current; + Assert.AreEqual(r1, rREESS.Value(), 1e-9, $"{i} / {absTime}"); + + absTime += dt.SI<Second>(); + } + + for (; i < 10 + 21; i++) { // linear increase for the next 8s to 0.04 + var response = es.Request(absTime, dt.SI<Second>(), powerDemand.SI<Watt>()); + Assert.IsInstanceOf<ElectricSystemResponseSuccess>(response); + bat.CommitSimulationStep(absTime, dt.SI<Second>(), modData); + + var current = (Ampere)modData[ModalResultField.I_reess]; + var rREESS = (Watt)modData[ModalResultField.P_reess_loss] / current / current; + var slope = (r2 - r1) / (10 - 2); + var r = slope * (absTime.Value() - 5.5) + r1 - slope * 2; + Assert.AreEqual(r, rREESS.Value(), 1e-9, $"{i} / {absTime}"); + + absTime += dt.SI<Second>(); + } + + for (; i < 10 + 41; i++) { // linear increase for the next 10s to 0.1 + var response = es.Request(absTime, dt.SI<Second>(), powerDemand.SI<Watt>()); + Assert.IsInstanceOf<ElectricSystemResponseSuccess>(response); + bat.CommitSimulationStep(absTime, dt.SI<Second>(), modData); + + var current = (Ampere)modData[ModalResultField.I_reess]; + var rREESS = (Watt)modData[ModalResultField.P_reess_loss] / current / current; + var slope = (r3 - r2) / (20 - 10); + var r = slope * (absTime.Value() - 5.5) + r2 - slope * 10; + Assert.AreEqual(r, rREESS.Value(), 1e-9, $"{i} / {absTime}"); + + absTime += dt.SI<Second>(); + } + + for (; i < 100; i++) { // constant after 20 sec + var response = es.Request(absTime, dt.SI<Second>(), powerDemand.SI<Watt>()); + Assert.IsInstanceOf<ElectricSystemResponseSuccess>(response); + bat.CommitSimulationStep(absTime, dt.SI<Second>(), modData); + + var current = (Ampere)modData[ModalResultField.I_reess]; + var rREESS = (Watt)modData[ModalResultField.P_reess_loss] / current / current; + Assert.AreEqual(r3, rREESS.Value(), 1e-9, $"{i} / {absTime}"); + + absTime += dt.SI<Second>(); + } + } + + + [TestCase(0.5, 0.5, 5000), + TestCase(0.5, 0.5, -5000)] + public void BatterySystemTimeDependentInternalResistanceTest_ConstantLoad(double initialSoC, double dt, double powerDemand) + { + var r1 = 0.02; + var r2 = 0.04; + var r3 = 0.1; + + var batteryData = new BatterySystemData() { + Batteries = new List<Tuple<int, BatteryData>>() { + Tuple.Create(0, new BatteryData() { + Capacity = REESS_Capacity.SI(Unit.SI.Ampere.Hour).Cast<AmpereSecond>(), + MinSOC = REESS_MinSoC, + MaxSOC = REESS_MaxSoC, + SOCMap = BatterySOCReader.Create("SOC,V\n0,590\n100,658".ToStream()), + InternalResistance = + BatteryInternalResistanceReader.Create($"SoC, Ri-2, Ri-10, Ri-20\n0, {r1}, {r2}, {r3}\n100, {r1}, {r2}, {r3}".ToStream()), + MaxCurrent = BatteryMaxCurrentReader.Create( + "SOC, I_charge, I_discharge\n0, 375, 573\n100, 375, 375".ToStream()), + }), + Tuple.Create(0, new BatteryData() { + Capacity = REESS_Capacity.SI(Unit.SI.Ampere.Hour).Cast<AmpereSecond>(), + MinSOC = REESS_MinSoC, + MaxSOC = REESS_MaxSoC, + SOCMap = BatterySOCReader.Create("SOC,V\n0,590\n100,658".ToStream()), + InternalResistance = + BatteryInternalResistanceReader.Create($"SoC, Ri-2, Ri-10, Ri-20\n0, {r1}, {r2}, {r3}\n100, {r1}, {r2}, {r3}".ToStream()), + MaxCurrent = BatteryMaxCurrentReader.Create( + "SOC, I_charge, I_discharge\n0, 375, 573\n100, 375, 375".ToStream()), + }), + Tuple.Create(1, new BatteryData() { + Capacity = REESS_Capacity.SI(Unit.SI.Ampere.Hour).Cast<AmpereSecond>(), + MinSOC = REESS_MinSoC, + MaxSOC = REESS_MaxSoC, + SOCMap = BatterySOCReader.Create("SOC,V\n0,590\n100,658".ToStream()), + InternalResistance = + BatteryInternalResistanceReader.Create($"SoC, Ri-2, Ri-10, Ri-20\n0, {r1}, {r2}, {r3}\n100, {r1}, {r2}, {r3}".ToStream()), + MaxCurrent = BatteryMaxCurrentReader.Create( + "SOC, I_charge, I_discharge\n0, 375, 573\n100, 375, 375".ToStream()), + }), + Tuple.Create(1, new BatteryData() { + Capacity = REESS_Capacity.SI(Unit.SI.Ampere.Hour).Cast<AmpereSecond>(), + MinSOC = REESS_MinSoC, + MaxSOC = REESS_MaxSoC, + SOCMap = BatterySOCReader.Create("SOC,V\n0,590\n100,658".ToStream()), + InternalResistance = + BatteryInternalResistanceReader.Create($"SoC, Ri-2, Ri-10, Ri-20\n0, {r1}, {r2}, {r3}\n100, {r1}, {r2}, {r3}".ToStream()), + MaxCurrent = BatteryMaxCurrentReader.Create( + "SOC, I_charge, I_discharge\n0, 375, 573\n100, 375, 375".ToStream()), + }) + } + }; + + var container = new MockVehicleContainer(); + var bat = new BatterySystem(container, batteryData); + var es = new ElectricSystem(container); + es.Connect(bat); + es.Connect(new MockElectricConsumer(0.SI<Watt>())); + bat.Initialize(initialSoC); + + var modData = new MockModalDataContainer(); + + var absTime = 0.SI<Second>(); + + var i = 0; + for (; i < 5; i++) { // constant for the first 2 sec + var response = es.Request(absTime, dt.SI<Second>(), powerDemand.SI<Watt>()); + Assert.IsInstanceOf<ElectricSystemResponseSuccess>(response); + bat.CommitSimulationStep(absTime, dt.SI<Second>(), modData); + + var current = (Ampere)modData[ModalResultField.I_reess]; + var rREESS = (Watt)modData[ModalResultField.P_reess_loss] / current / current; + Assert.AreEqual(r1, rREESS.Value(), 1e-9, $"{i} / {absTime}"); + + absTime += dt.SI<Second>(); + } + + for (; i < 21; i++) { // linear increase for the next 8s to 0.04 + var response = es.Request(absTime, dt.SI<Second>(), powerDemand.SI<Watt>()); + Assert.IsInstanceOf<ElectricSystemResponseSuccess>(response); + bat.CommitSimulationStep(absTime, dt.SI<Second>(), modData); + + var current = (Ampere)modData[ModalResultField.I_reess]; + var rREESS = (Watt)modData[ModalResultField.P_reess_loss] / current / current; + var slope = (r2 - r1) / (10 - 2); + var r = slope * absTime.Value() + r1 - slope * 2; + Assert.AreEqual(r, rREESS.Value(), 1e-9, $"{i} / {absTime}"); + + absTime += dt.SI<Second>(); + } + + for (; i < 41; i++) { // linear increase for the next 10s to 0.1 + var response = es.Request(absTime, dt.SI<Second>(), powerDemand.SI<Watt>()); + Assert.IsInstanceOf<ElectricSystemResponseSuccess>(response); + bat.CommitSimulationStep(absTime, dt.SI<Second>(), modData); + + var current = (Ampere)modData[ModalResultField.I_reess]; + var rREESS = (Watt)modData[ModalResultField.P_reess_loss] / current / current; + var slope = (r3 - r2) / (20 - 10); + var r = slope * absTime.Value() + r2 - slope * 10; + Assert.AreEqual(r, rREESS.Value(), 1e-9, $"{i} / {absTime}"); + + absTime += dt.SI<Second>(); + } + + for (; i < 100; i++) { // constant after 20 sec + var response = es.Request(absTime, dt.SI<Second>(), powerDemand.SI<Watt>()); + Assert.IsInstanceOf<ElectricSystemResponseSuccess>(response); + bat.CommitSimulationStep(absTime, dt.SI<Second>(), modData); + + var current = (Ampere)modData[ModalResultField.I_reess]; + var rREESS = (Watt)modData[ModalResultField.P_reess_loss] / current / current; + Assert.AreEqual(r3, rREESS.Value(), 1e-9, $"{i} / {absTime}"); + + absTime += dt.SI<Second>(); + } + } + + [TestCase(0.5, 0.5, 5000), + TestCase(0.5, 0.5, -5000)] + public void BatterySystemTimeDependentInternalResistanceTest_LoadChanges(double initialSoC, double dt, double powerDemand) + { + var r1 = 0.02; + var r2 = 0.04; + var r3 = 0.1; + + var batteryData = new BatterySystemData() { + Batteries = new List<Tuple<int, BatteryData>>() { + Tuple.Create(0, new BatteryData() { + Capacity = REESS_Capacity.SI(Unit.SI.Ampere.Hour).Cast<AmpereSecond>(), + MinSOC = REESS_MinSoC, + MaxSOC = REESS_MaxSoC, + SOCMap = BatterySOCReader.Create("SOC,V\n0,590\n100,658".ToStream()), + InternalResistance = + BatteryInternalResistanceReader.Create($"SoC, Ri-2, Ri-10, Ri-20\n0, {r1}, {r2}, {r3}\n100, {r1}, {r2}, {r3}".ToStream()), + MaxCurrent = BatteryMaxCurrentReader.Create( + "SOC, I_charge, I_discharge\n0, 375, 573\n100, 375, 375".ToStream()), + }), + Tuple.Create(0, new BatteryData() { + Capacity = REESS_Capacity.SI(Unit.SI.Ampere.Hour).Cast<AmpereSecond>(), + MinSOC = REESS_MinSoC, + MaxSOC = REESS_MaxSoC, + SOCMap = BatterySOCReader.Create("SOC,V\n0,590\n100,658".ToStream()), + InternalResistance = + BatteryInternalResistanceReader.Create($"SoC, Ri-2, Ri-10, Ri-20\n0, {r1}, {r2}, {r3}\n100, {r1}, {r2}, {r3}".ToStream()), + MaxCurrent = BatteryMaxCurrentReader.Create( + "SOC, I_charge, I_discharge\n0, 375, 573\n100, 375, 375".ToStream()), + }), + Tuple.Create(1, new BatteryData() { + Capacity = REESS_Capacity.SI(Unit.SI.Ampere.Hour).Cast<AmpereSecond>(), + MinSOC = REESS_MinSoC, + MaxSOC = REESS_MaxSoC, + SOCMap = BatterySOCReader.Create("SOC,V\n0,590\n100,658".ToStream()), + InternalResistance = + BatteryInternalResistanceReader.Create($"SoC, Ri-2, Ri-10, Ri-20\n0, {r1}, {r2}, {r3}\n100, {r1}, {r2}, {r3}".ToStream()), + MaxCurrent = BatteryMaxCurrentReader.Create( + "SOC, I_charge, I_discharge\n0, 375, 573\n100, 375, 375".ToStream()), + }), + Tuple.Create(1, new BatteryData() { + Capacity = REESS_Capacity.SI(Unit.SI.Ampere.Hour).Cast<AmpereSecond>(), + MinSOC = REESS_MinSoC, + MaxSOC = REESS_MaxSoC, + SOCMap = BatterySOCReader.Create("SOC,V\n0,590\n100,658".ToStream()), + InternalResistance = + BatteryInternalResistanceReader.Create($"SoC, Ri-2, Ri-10, Ri-20\n0, {r1}, {r2}, {r3}\n100, {r1}, {r2}, {r3}".ToStream()), + MaxCurrent = BatteryMaxCurrentReader.Create( + "SOC, I_charge, I_discharge\n0, 375, 573\n100, 375, 375".ToStream()), + }) + } + }; + + var container = new MockVehicleContainer(); + var bat = new BatterySystem(container, batteryData); + var es = new ElectricSystem(container); + es.Connect(bat); + es.Connect(new MockElectricConsumer(0.SI<Watt>())); + bat.Initialize(initialSoC); + + var modData = new MockModalDataContainer(); + + var absTime = 0.SI<Second>(); + + var i = 0; + + for (; i < 11; i++) { // constant for the first 2 sec + var response = es.Request(absTime, dt.SI<Second>(), -Math.Sign(powerDemand) * Math.Abs(powerDemand).SI<Watt>()); + Assert.IsInstanceOf<ElectricSystemResponseSuccess>(response); + bat.CommitSimulationStep(absTime, dt.SI<Second>(), modData); + + absTime += dt.SI<Second>(); + } + + for (; i < 11 + 5; i++) { // constant for the first 2 sec + var response = es.Request(absTime, dt.SI<Second>(), powerDemand.SI<Watt>()); + Assert.IsInstanceOf<ElectricSystemResponseSuccess>(response); + bat.CommitSimulationStep(absTime, dt.SI<Second>(), modData); + + var current = (Ampere)modData[ModalResultField.I_reess]; + var rREESS = (Watt)modData[ModalResultField.P_reess_loss] / current / current; + Assert.AreEqual(r1, rREESS.Value(), 1e-9, $"{i} / {absTime}"); + + absTime += dt.SI<Second>(); + } + + for (; i < 11 + 21; i++) { // linear increase for the next 8s to 0.04 + var response = es.Request(absTime, dt.SI<Second>(), powerDemand.SI<Watt>()); + Assert.IsInstanceOf<ElectricSystemResponseSuccess>(response); + bat.CommitSimulationStep(absTime, dt.SI<Second>(), modData); + + var current = (Ampere)modData[ModalResultField.I_reess]; + var rREESS = (Watt)modData[ModalResultField.P_reess_loss] / current / current; + var slope = (r2 - r1) / (10 - 2); + var r = slope * (absTime.Value() - 5.5) + r1 - slope * 2; + Assert.AreEqual(r, rREESS.Value(), 1e-9, $"{i} / {absTime}"); + + absTime += dt.SI<Second>(); + } + + for (; i < 11 + 41; i++) { // linear increase for the next 10s to 0.1 + var response = es.Request(absTime, dt.SI<Second>(), powerDemand.SI<Watt>()); + Assert.IsInstanceOf<ElectricSystemResponseSuccess>(response); + bat.CommitSimulationStep(absTime, dt.SI<Second>(), modData); + + var current = (Ampere)modData[ModalResultField.I_reess]; + var rREESS = (Watt)modData[ModalResultField.P_reess_loss] / current / current; + var slope = (r3 - r2) / (20 - 10); + var r = slope * (absTime.Value() - 5.5) + r2 - slope * 10; + Assert.AreEqual(r, rREESS.Value(), 1e-9, $"{i} / {absTime}"); + + absTime += dt.SI<Second>(); + } + + for (; i < 11 + 100; i++) { // constant after 20 sec + var response = es.Request(absTime, dt.SI<Second>(), powerDemand.SI<Watt>()); + Assert.IsInstanceOf<ElectricSystemResponseSuccess>(response); + bat.CommitSimulationStep(absTime, dt.SI<Second>(), modData); + + var current = (Ampere)modData[ModalResultField.I_reess]; + var rREESS = (Watt)modData[ModalResultField.P_reess_loss] / current / current; + Assert.AreEqual(r3, rREESS.Value(), 1e-9, $"{i} / {absTime}"); + + absTime += dt.SI<Second>(); + } + } } } \ No newline at end of file diff --git a/VectoCore/VectoCoreTest/TestData/Generic Vehicles/Engineering Mode/HeavyBusPrimary/HeavyBusPrimaryVehicle.vveh b/VectoCore/VectoCoreTest/TestData/Generic Vehicles/Engineering Mode/HeavyBusPrimary/HeavyBusPrimaryVehicle.vveh index 08fc17fd5e3ca1a5b942f21cd21b9ed83e7e7f64..166c5193b62fe068ae0d94a9ba7e8a781b2c706a 100644 --- a/VectoCore/VectoCoreTest/TestData/Generic Vehicles/Engineering Mode/HeavyBusPrimary/HeavyBusPrimaryVehicle.vveh +++ b/VectoCore/VectoCoreTest/TestData/Generic Vehicles/Engineering Mode/HeavyBusPrimary/HeavyBusPrimaryVehicle.vveh @@ -62,13 +62,15 @@ "SteeringPumpTechnology": [ "Dual displacement with mech. control" ], - "ElectricSupply": { - "Alternators": [ - { - "Technology": "standard alternator", - "Ratio": 1.0 - } - ], + "ElectricSupply": { + "Alternators": [ + { + "Technology": "standard alternator", + "Ratio": 1.0 + } + ], + "MaxAlternatorPower": 0, + "Technology": "conventional", "ResultCards": { "Idle": [ { @@ -114,7 +116,7 @@ ] }, "SmartElectrics": false - }, + }, "ElectricConsumers": { }, "PneumaticSupply": { diff --git a/VectoCore/VectoCoreTest/Utils/MockBattery.cs b/VectoCore/VectoCoreTest/Utils/MockBattery.cs index 03343905049a3d04963e294f2cefc340a7178e37..9dd7e3a1e68ed17246d03710a1091b9f26989ef5 100644 --- a/VectoCore/VectoCoreTest/Utils/MockBattery.cs +++ b/VectoCore/VectoCoreTest/Utils/MockBattery.cs @@ -40,6 +40,8 @@ namespace TUGraz.VectoCore.Tests.Utils { public double MinSoC => 0; public double MaxSoC => 1; + public AmpereSecond Capacity => null; + public Volt NominalVoltage => null; public IElectricEnergyStoragePort MainBatteryPort => this;