Changed from daily records to quarter hour records
This commit is contained in:
@@ -4,12 +4,9 @@ namespace BattSim.Models
|
|||||||
{
|
{
|
||||||
public class EnergyData
|
public class EnergyData
|
||||||
{
|
{
|
||||||
public DateOnly Date { get; set; }
|
public DateTime Time { get; set; }
|
||||||
public double DayConsumption { get; set; }
|
public bool DayTarif { get; set; }
|
||||||
public double NightConsumption { get; set; }
|
public double Consumption { get; set; }
|
||||||
public double TotalConsumption => DayConsumption + NightConsumption;
|
public double Production { get; set; }
|
||||||
public double DayProduction { get; set; }
|
|
||||||
public double NightProduction { get; set; }
|
|
||||||
public double TotalProduction => DayProduction + NightProduction;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -14,10 +14,10 @@
|
|||||||
@if (_isLoadingFile){ <p>Loading...</p> }
|
@if (_isLoadingFile){ <p>Loading...</p> }
|
||||||
@if (EnergyData.Length != 0){
|
@if (EnergyData.Length != 0){
|
||||||
<RadzenChart>
|
<RadzenChart>
|
||||||
<RadzenAreaSeries Smooth=true Data="@EnergyData" CategoryProperty="Date" Title="Consumption" ValueProperty="TotalConsumption">
|
<RadzenAreaSeries Smooth=true Data="@EnergyData" CategoryProperty="Time" Title="Consumption" ValueProperty="Consumption">
|
||||||
<RadzenChartTooltipOptions Visible="true" />
|
<RadzenChartTooltipOptions Visible="true" />
|
||||||
</RadzenAreaSeries>
|
</RadzenAreaSeries>
|
||||||
<RadzenAreaSeries Smooth=true Data="@EnergyData" CategoryProperty="Date" Title="Production" ValueProperty="TotalProduction">
|
<RadzenAreaSeries Smooth=true Data="@EnergyData" CategoryProperty="Time" Title="Production" ValueProperty="Production">
|
||||||
<RadzenChartTooltipOptions Visible="true" />
|
<RadzenChartTooltipOptions Visible="true" />
|
||||||
</RadzenAreaSeries>
|
</RadzenAreaSeries>
|
||||||
<RadzenCategoryAxis Formatter="@FormatObject" Padding="20" LabelAutoRotation="-45">
|
<RadzenCategoryAxis Formatter="@FormatObject" Padding="20" LabelAutoRotation="-45">
|
||||||
@@ -30,16 +30,7 @@
|
|||||||
</RadzenChart>
|
</RadzenChart>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@code{
|
||||||
<h2>Simulate Battery</h2>
|
|
||||||
<p>Set the battery capacity</p>
|
|
||||||
<InputNumber @bind-value="BatteryCapacity"/>
|
|
||||||
<Button @onclick="SimulateBattery">Simulate</Button>
|
|
||||||
|
|
||||||
<h2>Calculate Cost</h2>
|
|
||||||
|
|
||||||
|
|
||||||
@code {
|
|
||||||
EnergyData[] EnergyData = [];
|
EnergyData[] EnergyData = [];
|
||||||
bool _isLoadingFile = false;
|
bool _isLoadingFile = false;
|
||||||
|
|
||||||
@@ -72,24 +63,29 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _showProduction = true;
|
|
||||||
bool _showConsumption = true;
|
|
||||||
|
|
||||||
private void OnSeriesClick(){}
|
private void OnSeriesClick(){}
|
||||||
private string FormatObject(object value) {
|
private string FormatObject(object value) {
|
||||||
if(value is double d) return $"{value:0.##} kWh";
|
if(value is double d) return $"{value:0.##} kWh";
|
||||||
if(value is DateOnly date) return (date.Day == 1) ? date.ToString("MM/yyyy") : string.Empty;
|
if(value is DateOnly date) return (date.Day == 1) ? date.ToString("MM/yyyy") : string.Empty;
|
||||||
else return string.Empty;
|
else return string.Empty;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
<h2>Simulate Battery</h2>
|
||||||
|
<p>Set the battery capacity</p>
|
||||||
|
<InputNumber @bind-value="BatteryCapacity"/>
|
||||||
|
<Button @onclick="SimulateBattery">Simulate</Button>
|
||||||
|
|
||||||
|
<h2>Calculate Cost</h2>
|
||||||
|
|
||||||
|
|
||||||
|
@code {
|
||||||
double BatteryCapacity = 0.0;
|
double BatteryCapacity = 0.0;
|
||||||
BatteryDayResult[] SimulationData = [];
|
BatteryDayResult[] SimulationData = [];
|
||||||
|
|
||||||
|
|
||||||
private async Task SimulateBattery(){
|
private async Task SimulateBattery(){
|
||||||
Console.WriteLine("Simulating...");
|
Console.WriteLine("Simulating...");
|
||||||
SimulationData = BatterySimulator.SimulateBattery(EnergyData, BatteryCapacity).ToArray();
|
SimulationData = BatterySimulator.SimulateBattery(EnergyData, BatteryCapacity).ToArray();
|
||||||
Console.WriteLine("Done simulating!");
|
Console.WriteLine("Done simulating!");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
@page "/Test"
|
|
||||||
@using Radzen
|
|
||||||
@using Radzen.Blazor
|
|
||||||
@using System.Globalization
|
|
||||||
|
|
||||||
|
|
||||||
<PageTitle>Home</PageTitle>
|
|
||||||
|
|
||||||
<h1>Hello, world!</h1>
|
|
||||||
|
|
||||||
Welcome to your new app.
|
|
||||||
|
|
||||||
<h2>A Radzen chart:</h2>
|
|
||||||
|
|
||||||
<RadzenChart SeriesClick=@OnSeriesClick style="height: 400px">
|
|
||||||
<RadzenBarSeries Data="@revenue2024" CategoryProperty="Quarter" Title="2024" LineType="LineType.Dashed" ValueProperty="Revenue">
|
|
||||||
<RadzenSeriesDataLabels Visible="@showDataLabels" />
|
|
||||||
</RadzenBarSeries>
|
|
||||||
<RadzenBarSeries Data="@revenue2023" CategoryProperty="Quarter" Title="2023" ValueProperty="Revenue">
|
|
||||||
<RadzenSeriesDataLabels Visible="@showDataLabels" />
|
|
||||||
</RadzenBarSeries>
|
|
||||||
<RadzenValueAxis Formatter="@FormatAsUSD">
|
|
||||||
<RadzenGridLines Visible="true" />
|
|
||||||
<RadzenAxisTitle Text="Revenue in USD" />
|
|
||||||
</RadzenValueAxis>
|
|
||||||
<RadzenBarOptions Radius="5" />
|
|
||||||
</RadzenChart>
|
|
||||||
|
|
||||||
|
|
||||||
@code {
|
|
||||||
bool showDataLabels = false;
|
|
||||||
|
|
||||||
void OnSeriesClick(SeriesClickEventArgs args)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class DataItem
|
|
||||||
{
|
|
||||||
public string Quarter { get; set; }
|
|
||||||
public double Revenue { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
string FormatAsUSD(object value)
|
|
||||||
{
|
|
||||||
return ((double)value).ToString("C0", CultureInfo.CreateSpecificCulture("en-US"));
|
|
||||||
}
|
|
||||||
|
|
||||||
DataItem[] revenue2023 = new DataItem[]
|
|
||||||
{
|
|
||||||
new DataItem
|
|
||||||
{
|
|
||||||
Quarter = "Q1",
|
|
||||||
Revenue = 234000
|
|
||||||
},
|
|
||||||
new DataItem
|
|
||||||
{
|
|
||||||
Quarter = "Q2",
|
|
||||||
Revenue = 284000
|
|
||||||
},
|
|
||||||
new DataItem
|
|
||||||
{
|
|
||||||
Quarter = "Q3",
|
|
||||||
Revenue = 274000
|
|
||||||
},
|
|
||||||
new DataItem
|
|
||||||
{
|
|
||||||
Quarter = "Q4",
|
|
||||||
Revenue = 294000
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
DataItem[] revenue2024 = new DataItem[] {
|
|
||||||
new DataItem
|
|
||||||
{
|
|
||||||
Quarter = "Q1",
|
|
||||||
Revenue = 254000
|
|
||||||
},
|
|
||||||
new DataItem
|
|
||||||
{
|
|
||||||
Quarter = "Q2",
|
|
||||||
Revenue = 324000
|
|
||||||
},
|
|
||||||
new DataItem
|
|
||||||
{
|
|
||||||
Quarter = "Q3",
|
|
||||||
Revenue = 354000
|
|
||||||
},
|
|
||||||
new DataItem
|
|
||||||
{
|
|
||||||
Quarter = "Q4",
|
|
||||||
Revenue = 394000
|
|
||||||
},
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -4,8 +4,6 @@ using Radzen;
|
|||||||
using Microsoft.AspNetCore.Components.Web;
|
using Microsoft.AspNetCore.Components.Web;
|
||||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Setup Frontend
|
// Setup Frontend
|
||||||
var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
||||||
builder.RootComponents.Add<App>("#app");
|
builder.RootComponents.Add<App>("#app");
|
||||||
@@ -14,4 +12,5 @@ builder.RootComponents.Add<HeadOutlet>("head::after");
|
|||||||
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
|
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
|
||||||
builder.Services.AddRadzenComponents();
|
builder.Services.AddRadzenComponents();
|
||||||
|
|
||||||
|
|
||||||
await builder.Build().RunAsync();
|
await builder.Build().RunAsync();
|
||||||
@@ -12,31 +12,29 @@ namespace BattSim.Services
|
|||||||
|
|
||||||
foreach (var day in data)
|
foreach (var day in data)
|
||||||
{
|
{
|
||||||
// Charge battery from production
|
// // Charge battery from production
|
||||||
var totalProduction = day.DayProduction + day.NightProduction;
|
// var chargedEnergy = System.Math.Min(day.TotalProduction, batteryCapacity);
|
||||||
var chargedEnergy = System.Math.Min(totalProduction, batteryCapacity);
|
// var excessProduction = day.TotalProduction - chargedEnergy;
|
||||||
var excessProduction = totalProduction - chargedEnergy;
|
|
||||||
|
|
||||||
// Use battery for consumption
|
// // Use battery for consumption
|
||||||
var totalConsumption = day.DayConsumption + day.NightConsumption;
|
// var usedEnergy = System.Math.Min(chargedEnergy + remainingEnergy, day.TotalConsumption);
|
||||||
var usedEnergy = System.Math.Min(chargedEnergy + remainingEnergy, totalConsumption);
|
// var remainingAfterUse = chargedEnergy + remainingEnergy - usedEnergy;
|
||||||
var remainingAfterUse = chargedEnergy + remainingEnergy - usedEnergy;
|
|
||||||
|
|
||||||
// Calculate reduced values
|
// // Calculate reduced values
|
||||||
var reducedConsumption = System.Math.Min(usedEnergy, totalConsumption);
|
// var reducedConsumption = System.Math.Min(usedEnergy, day.TotalConsumption);
|
||||||
var reducedProduction = totalProduction - chargedEnergy;
|
// var reducedProduction = day.TotalProduction - chargedEnergy;
|
||||||
|
|
||||||
results.Add(new BatteryDayResult
|
// results.Add(new BatteryDayResult
|
||||||
{
|
// {
|
||||||
Date = day.Date,
|
// Date = day.Date,
|
||||||
ChargedEnergy = chargedEnergy,
|
// ChargedEnergy = chargedEnergy,
|
||||||
UsedEnergy = usedEnergy,
|
// UsedEnergy = usedEnergy,
|
||||||
RemainingEnergy = remainingAfterUse,
|
// RemainingEnergy = remainingAfterUse,
|
||||||
ReducedConsumption = reducedConsumption,
|
// ReducedConsumption = reducedConsumption,
|
||||||
ReducedProduction = reducedProduction
|
// ReducedProduction = reducedProduction
|
||||||
});
|
// });
|
||||||
|
|
||||||
remainingEnergy = remainingAfterUse;
|
// remainingEnergy = remainingAfterUse;
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@@ -13,61 +14,85 @@ namespace BattSim.Services
|
|||||||
{
|
{
|
||||||
public static async Task<List<EnergyData>> LoadAndProcessData(IBrowserFile file)
|
public static async Task<List<EnergyData>> LoadAndProcessData(IBrowserFile file)
|
||||||
{
|
{
|
||||||
var energyData = new List<EnergyData>();
|
var energyData = new ConcurrentBag<EnergyData>(); // Thread-safe collection
|
||||||
await using var stream = file.OpenReadStream();
|
await using var stream = file.OpenReadStream(maxAllowedSize: (int)1.0e9);
|
||||||
using var reader = new StreamReader(stream);
|
using var reader = new StreamReader(stream, bufferSize: (int)1.0e6);
|
||||||
|
|
||||||
// Skip header
|
// Skip header
|
||||||
await reader.ReadLineAsync();
|
await reader.ReadLineAsync();
|
||||||
|
|
||||||
|
// Read all lines into memory
|
||||||
|
var lines = new List<string>();
|
||||||
string line;
|
string line;
|
||||||
while ((line = await reader.ReadLineAsync()) != null)
|
while ((line = await reader.ReadLineAsync()) is not null)
|
||||||
|
{
|
||||||
|
lines.Add(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process lines in parallel
|
||||||
|
Parallel.ForEach(lines, line =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var parts = SplitLine(line);
|
||||||
|
DateTime time = ParseDateTime(parts[0..2]);
|
||||||
|
double volume = ParseVolume(parts[8]);
|
||||||
|
string register = parts[7].Trim();
|
||||||
|
bool dayTarif = register.Contains("Dag");
|
||||||
|
|
||||||
|
// Use ConcurrentBag for thread-safe additions
|
||||||
|
var entry = new EnergyData { Time = time, DayTarif = dayTarif };
|
||||||
|
if (register.Contains("Afname"))
|
||||||
|
entry.Consumption = volume;
|
||||||
|
else if (register.Contains("Injectie"))
|
||||||
|
entry.Production = volume;
|
||||||
|
else
|
||||||
|
throw new Exception("Unknown volume register");
|
||||||
|
|
||||||
|
energyData.Add(entry);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error parsing line: {line}. Skipping to next line. Exception: {e}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Group by Time and merge entries
|
||||||
|
var groupedData = energyData
|
||||||
|
.GroupBy(e => e.Time)
|
||||||
|
.Select(g =>
|
||||||
|
{
|
||||||
|
var first = g.First();
|
||||||
|
first.Consumption = g.Sum(e => e.Consumption);
|
||||||
|
first.Production = g.Sum(e => e.Production);
|
||||||
|
return first;
|
||||||
|
})
|
||||||
|
.OrderBy(e => e.Time)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return groupedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string[] SplitLine(string line)
|
||||||
{
|
{
|
||||||
var parts = line.Split(';');
|
var parts = line.Split(';');
|
||||||
if (parts.Length < 9)
|
if (parts.Length < 9)
|
||||||
{
|
throw new Exception($"Malformed line (too many parts): {line}");
|
||||||
Console.WriteLine($"Skipping malformed line: {line}");
|
return parts;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
private static DateTime ParseDateTime(string[] dateTimeStrings)
|
||||||
{
|
{
|
||||||
var date = DateOnly.ParseExact(parts[0].Length == 10 ? parts[0] : "0"+parts[0], "dd/MM/yyyy", CultureInfo.InvariantCulture);
|
string dateTimeString = dateTimeStrings[0] + " " + dateTimeStrings[1];
|
||||||
var register = parts[7].Trim();
|
return DateTime.ParseExact(dateTimeString, "dd-MM-yyyy HH:mm:ss", CultureInfo.GetCultureInfo("nl-BE"));
|
||||||
var volumeStr = parts[8].Trim();
|
}
|
||||||
var volume = string.IsNullOrEmpty(volumeStr)
|
|
||||||
|
private static double ParseVolume(string volumeString)
|
||||||
|
{
|
||||||
|
var volumeStr = volumeString.Trim();
|
||||||
|
return string.IsNullOrEmpty(volumeStr)
|
||||||
? 0
|
? 0
|
||||||
: double.Parse(volumeStr.Replace(",", "."), CultureInfo.InvariantCulture);
|
: double.Parse(volumeStr.Replace(",", "."), CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
var existing = energyData.FirstOrDefault(e => e.Date == date);
|
|
||||||
if (existing == null)
|
|
||||||
{
|
|
||||||
existing = new EnergyData { Date = date };
|
|
||||||
energyData.Add(existing);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (register)
|
|
||||||
{
|
|
||||||
case "Afname Dag":
|
|
||||||
existing.DayConsumption = volume;
|
|
||||||
break;
|
|
||||||
case "Afname Nacht":
|
|
||||||
existing.NightConsumption = volume;
|
|
||||||
break;
|
|
||||||
case "Injectie Dag":
|
|
||||||
existing.DayProduction = volume;
|
|
||||||
break;
|
|
||||||
case "Injectie Nacht":
|
|
||||||
existing.NightProduction = volume;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Error parsing line: {line}. Exception: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return energyData;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using BattSim.Models;
|
|
||||||
|
|
||||||
namespace BattSim.Services
|
|
||||||
{
|
|
||||||
public class ReportGenerator
|
|
||||||
{
|
|
||||||
public static void GenerateReport(List<EnergyData> originalData, Dictionary<int, List<BatteryDayResult>> scenarios)
|
|
||||||
{
|
|
||||||
using (var writer = new StreamWriter("../../../BatteryAnalysisReport.md"))
|
|
||||||
{
|
|
||||||
writer.WriteLine("# Battery Cost Analysis Report\n");
|
|
||||||
|
|
||||||
// Original data summary
|
|
||||||
writer.WriteLine("## Original Data Summary");
|
|
||||||
var totalConsumption = originalData.Sum(d => d.DayConsumption + d.NightConsumption);
|
|
||||||
var totalProduction = originalData.Sum(d => d.DayProduction + d.NightProduction);
|
|
||||||
writer.WriteLine($"Total Consumption: {totalConsumption:F2} kWh");
|
|
||||||
writer.WriteLine($"Total Production: {totalProduction:F2} kWh\n");
|
|
||||||
|
|
||||||
// Generate graph data
|
|
||||||
writer.WriteLine("### Energy Consumption and Production\n");
|
|
||||||
writer.WriteLine("```");
|
|
||||||
writer.WriteLine("Date,Total Production,Total Consumption");
|
|
||||||
foreach (var day in originalData)
|
|
||||||
{
|
|
||||||
var prod = day.DayProduction + day.NightProduction;
|
|
||||||
var cons = day.DayConsumption + day.NightConsumption;
|
|
||||||
writer.WriteLine($"{day.Date:yyyy-MM-dd},{prod:F2},{cons:F2}");
|
|
||||||
}
|
|
||||||
writer.WriteLine("```\n");
|
|
||||||
|
|
||||||
writer.WriteLine("");
|
|
||||||
writer.WriteLine("(Graph showing total production in green and total consumption in red)\n");
|
|
||||||
|
|
||||||
// Scenario analysis
|
|
||||||
foreach (var scenario in scenarios)
|
|
||||||
{
|
|
||||||
var batteryCount = scenario.Key;
|
|
||||||
var results = scenario.Value;
|
|
||||||
|
|
||||||
writer.WriteLine($"## Scenario with {batteryCount} Battery{(batteryCount > 1 ? "ies" : "")}");
|
|
||||||
writer.WriteLine($"Battery Capacity: {batteryCount * 2.6} kWh\n");
|
|
||||||
|
|
||||||
var totalReducedConsumption = results.Sum(r => r.ReducedConsumption);
|
|
||||||
var totalReducedProduction = results.Sum(r => r.ReducedProduction);
|
|
||||||
var savings = totalReducedConsumption * 0.30; // Assuming €0.30 per kWh
|
|
||||||
|
|
||||||
writer.WriteLine($"Total Reduced Consumption: {totalReducedConsumption:F2} kWh");
|
|
||||||
writer.WriteLine($"Total Reduced Production: {totalReducedProduction:F2} kWh");
|
|
||||||
writer.WriteLine($"Estimated Annual Savings: €{savings:F2}\n");
|
|
||||||
|
|
||||||
// Generate scenario graph data
|
|
||||||
writer.WriteLine($"### Battery Performance for {batteryCount} Battery{(batteryCount > 1 ? "ies" : "")}\n");
|
|
||||||
writer.WriteLine("```");
|
|
||||||
writer.WriteLine("Date,Charged Energy,Used Energy,Remaining Energy");
|
|
||||||
foreach (var result in results)
|
|
||||||
{
|
|
||||||
writer.WriteLine($"{result.Date:yyyy-MM-dd},{result.ChargedEnergy:F2},{result.UsedEnergy:F2},{result.RemainingEnergy:F2}");
|
|
||||||
}
|
|
||||||
writer.WriteLine("```\n");
|
|
||||||
|
|
||||||
writer.WriteLine($"");
|
|
||||||
writer.WriteLine("(Graph showing charged energy in blue, used energy in orange, and remaining energy in gray)\n");
|
|
||||||
|
|
||||||
// Detailed daily results
|
|
||||||
writer.WriteLine("### Daily Results");
|
|
||||||
writer.WriteLine("| Date | Charged (kWh) | Used (kWh) | Remaining (kWh) |");
|
|
||||||
writer.WriteLine("|------|---------------|------------|-----------------|");
|
|
||||||
|
|
||||||
foreach (var result in results.Take(10)) // Show first 10 days
|
|
||||||
{
|
|
||||||
writer.WriteLine($"| {result.Date:yyyy-MM-dd} | {result.ChargedEnergy:F2} | {result.UsedEnergy:F2} | {result.RemainingEnergy:F2} |");
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.WriteLine("\n---\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine("Report generated: BatteryAnalysisReport.md");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,3 +8,4 @@
|
|||||||
@using Microsoft.JSInterop
|
@using Microsoft.JSInterop
|
||||||
@using BattSim
|
@using BattSim
|
||||||
@using BattSim.Layout
|
@using BattSim.Layout
|
||||||
|
@using Radzen.Blazor
|
||||||
|
|||||||
Reference in New Issue
Block a user