721 lines
25 KiB
C#
721 lines
25 KiB
C#
namespace Xylem.Common.Ui.GenesisToolBox.Infrastructure
|
|
{
|
|
using Newtonsoft.Json;
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Net.Http;
|
|
using System.Net.Http.Headers;
|
|
using System.Runtime.InteropServices;
|
|
using System.Timers;
|
|
using System.Windows;
|
|
|
|
using SystemThreadingThread = System.Threading.Thread;
|
|
|
|
internal interface ITempMeterForm
|
|
{
|
|
void AddMessage(string message);
|
|
|
|
double AvgTOF();
|
|
|
|
IAsyncResult BeginInvoke(Delegate @delegate);
|
|
|
|
void StartRecording();
|
|
}
|
|
|
|
partial class AutomaticTemperatureCalibration
|
|
{
|
|
private const string BASE_ADDRESS = "http://sla12iis01.emea.sensus.net/LaaProductionWeb";
|
|
// private const string BASE_ADDRESS = "http://localhost:52822/LaaProductionWeb";
|
|
private const string WORKING_DIR = @"temperature_calibrations";
|
|
private const string MESSUREMENTS_FILE = @"_messurements.txt";
|
|
private const string AGGREGATIONS_FILE = @"_aggregations.txt";
|
|
private const string BACKWARDS_FILE = @"_backwards.txt";
|
|
|
|
private readonly string pcbId;
|
|
private readonly string messurementsFile;
|
|
private readonly string aggregationsFile;
|
|
private readonly string backwardsFile;
|
|
private readonly ITempMeterForm tempMeterForm;
|
|
|
|
private TemperatureSource temperatureSource;
|
|
private Timer longTimer;
|
|
private Timer shortTimer;
|
|
private Timer stopTimer;
|
|
private bool messuring;
|
|
|
|
public AutomaticTemperatureCalibration(string pcbId, ITempMeterForm genesisMeter)
|
|
{
|
|
this.pcbId = pcbId;
|
|
this.tempMeterForm = genesisMeter;
|
|
|
|
if (int.TryParse($"{this.pcbId}", out int pcb))
|
|
{
|
|
this.messurementsFile = this.GetOrCreateFile(this.pcbId, MESSUREMENTS_FILE);
|
|
this.aggregationsFile = this.GetOrCreateFile(this.pcbId, AGGREGATIONS_FILE);
|
|
this.backwardsFile = this.GetOrCreateFile(this.pcbId, BACKWARDS_FILE);
|
|
}
|
|
|
|
this.temperatureSource = new TemperatureSource();
|
|
}
|
|
|
|
public void StartMessuring()
|
|
{
|
|
this.messuring = false;
|
|
this.temperatureSource = new TemperatureSource();
|
|
|
|
this.shortTimer = new Timer(Appsettings.MessurementStepMs)
|
|
{
|
|
Enabled = true,
|
|
AutoReset = true
|
|
};
|
|
this.shortTimer.Elapsed += this.ShortTimerElapsed;
|
|
this.shortTimer.Stop();
|
|
|
|
this.longTimer = new Timer(Appsettings.MessurementDauerMs)
|
|
{
|
|
Enabled = true,
|
|
AutoReset = true
|
|
};
|
|
this.longTimer.Elapsed += this.LongTimerElapsed;
|
|
this.LongTimerElapsed(null, null);
|
|
this.longTimer.Start();
|
|
|
|
if (Appsettings.MessurementStopHours > 0)
|
|
{
|
|
this.stopTimer = new Timer(Appsettings.MessurementStopHours * 60 * 60 * 1000)
|
|
{
|
|
Enabled = true,
|
|
AutoReset = true
|
|
};
|
|
this.stopTimer.Elapsed += (sender, args) => this.StopMessuring();
|
|
this.stopTimer.Start();
|
|
}
|
|
|
|
File.AppendAllText(this.aggregationsFile, Environment.NewLine);
|
|
}
|
|
|
|
public void StopMessuring()
|
|
{
|
|
this.shortTimer?.Stop();
|
|
this.shortTimer?.Dispose();
|
|
this.shortTimer = null;
|
|
|
|
this.longTimer?.Stop();
|
|
this.longTimer?.Dispose();
|
|
this.longTimer = null;
|
|
|
|
this.stopTimer?.Stop();
|
|
this.stopTimer?.Dispose();
|
|
this.stopTimer = null;
|
|
|
|
this.temperatureSource?.Dispose();
|
|
this.temperatureSource = null;
|
|
}
|
|
|
|
private void LongTimerElapsed(Object sender, ElapsedEventArgs _)
|
|
{
|
|
this.messuring = !this.messuring;
|
|
|
|
SystemThreadingThread.Sleep(1_000);
|
|
|
|
if (this.messuring)
|
|
{
|
|
this.shortTimer.Start();
|
|
}
|
|
else
|
|
{
|
|
this.shortTimer.Stop();
|
|
this.ParseMessurements();
|
|
}
|
|
}
|
|
|
|
private void ShortTimerElapsed(Object sender, ElapsedEventArgs args)
|
|
{
|
|
lock (this.shortTimer)
|
|
{
|
|
this.tempMeterForm.BeginInvoke(new Action(() =>
|
|
{
|
|
var messurement = !this.TryGetTOFandT(out double currentTOF, out double currentT)
|
|
? $"[{args.SignalTime:yyyy-MM-dd hh:mm:ss}]\t invalid record (TOF: {currentTOF} & T: {currentT})"
|
|
: $"[{args.SignalTime:yyyy-MM-dd hh:mm:ss}]\t{this.pcbId,9}\t{currentT,5:00.00}\t{currentTOF,14:0.000000000000}";
|
|
|
|
if (this.messuring)
|
|
{
|
|
this.tempMeterForm.AddMessage(messurement);
|
|
File.AppendAllLines(this.messurementsFile, new[] { messurement });
|
|
}
|
|
}));
|
|
}
|
|
}
|
|
|
|
private String GetOrCreateFile(string pcbId, string fileBase)
|
|
{
|
|
Directory.CreateDirectory(WORKING_DIR);
|
|
|
|
var filePath = Path.Combine(".", WORKING_DIR, $"{pcbId}{fileBase}");
|
|
|
|
if (!File.Exists(filePath))
|
|
{
|
|
File.WriteAllText(filePath, string.Empty);
|
|
}
|
|
|
|
return filePath;
|
|
}
|
|
|
|
private void ParseMessurements()
|
|
{
|
|
var messurementLines = File.ReadAllLines(this.messurementsFile);
|
|
var messurements = new Messurements(this.pcbId);
|
|
var skipCount = 2;
|
|
|
|
File.WriteAllText(this.messurementsFile, string.Empty);
|
|
|
|
foreach (var messurementLine in messurementLines)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(messurementLine))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (skipCount > 0)
|
|
{
|
|
skipCount--;
|
|
|
|
continue;
|
|
}
|
|
|
|
var tokens = messurementLine
|
|
.Split(new[] { '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
|
|
|
if (tokens.Length != 4)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var dateString = tokens[0];
|
|
var pcbString = tokens[1];
|
|
var tString = tokens[2];
|
|
var tofString = tokens[3];
|
|
|
|
var currentT = default(double);
|
|
var currentTOF = default(double);
|
|
|
|
try
|
|
{
|
|
var tParsed = tString.TryParse(out currentT);
|
|
var tofParsed = tofString.TryParse(out currentTOF);
|
|
|
|
if (!tParsed || !tofParsed)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
continue;
|
|
}
|
|
|
|
messurements.Add(currentT, currentTOF);
|
|
}
|
|
|
|
File.AppendAllLines(this.aggregationsFile, new[] { messurements.ToString() });
|
|
}
|
|
|
|
internal IEnumerable<Messurement> AggregationsFor(string pcb)
|
|
{
|
|
var aggregations = new List<Messurement>();
|
|
var aggregationsFile = $"{WORKING_DIR}\\{pcb}{AGGREGATIONS_FILE}";
|
|
|
|
var existingAggregations = this.RequestAggregations(pcb);
|
|
var aggregationsLines = new List<string>();
|
|
|
|
if (File.Exists(aggregationsFile))
|
|
{
|
|
aggregationsLines = File
|
|
.ReadAllLines(aggregationsFile)
|
|
.Skip(1)
|
|
.ToList();
|
|
}
|
|
|
|
if (aggregationsLines.Count <= 0)
|
|
{
|
|
aggregations = existingAggregations.ToList();
|
|
aggregations.ForEach(x => x.Selected = true);
|
|
}
|
|
|
|
foreach (var line in aggregationsLines)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(line))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var tokens = line.Split(new[] { '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
|
|
|
if (tokens.Length != 10)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var pcbString = tokens[0] ?? string.Empty;
|
|
var avgTString = tokens[3] ?? string.Empty;
|
|
var difTString = tokens[7] ?? string.Empty;
|
|
var avgTOFString = tokens[4] ?? string.Empty;
|
|
var difTOFString = tokens[8] ?? string.Empty;
|
|
var secondsString = tokens[9] ?? string.Empty;
|
|
|
|
var pcbId = default(int);
|
|
var avgT = default(double);
|
|
var difT = default(double);
|
|
var avgTOF = default(double);
|
|
var difTOF = default(double);
|
|
var seconds = default(int);
|
|
|
|
var pcbParsed = int.TryParse(pcbString, out pcbId);
|
|
var tParsed = avgTString.TryParse(out avgT);
|
|
var dtParsed = difTString.TryParse(out difT);
|
|
var secParsed = int.TryParse(secondsString, out seconds) || int.TryParse(secondsString, out seconds);
|
|
var tofParsed = avgTOFString.TryParse(out avgTOF);
|
|
var dtofParsed = difTOFString.TryParse(out difTOF);
|
|
|
|
if (!pcbParsed || !tParsed || !tofParsed || !dtParsed || !dtofParsed)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
aggregations.Add(new Messurement
|
|
{
|
|
PcbId = pcbId,
|
|
AvgT = avgT,
|
|
DiffT = difT,
|
|
AvgTOF = avgTOF,
|
|
DiffTOF = difTOF,
|
|
Seconds = seconds,
|
|
Selected = existingAggregations.Any(x => x.AvgT == avgT)
|
|
});
|
|
}
|
|
|
|
return aggregations
|
|
.OrderBy(x => x.PcbId)
|
|
.ThenBy(x => x.AvgT)
|
|
.ThenBy(x => x.AvgTOF)
|
|
.Select((messurement, index) =>
|
|
{
|
|
messurement.Id = index + 1;
|
|
|
|
return messurement;
|
|
})
|
|
.ToList();
|
|
}
|
|
|
|
internal IEnumerable<Messurement> RequestAggregations(string pcb)
|
|
{
|
|
var aggregations = Array.Empty<Messurement>();
|
|
|
|
try
|
|
{
|
|
using (var httpClient = new HttpClient())
|
|
{
|
|
using (var httpRequestMessage = new HttpRequestMessage())
|
|
{
|
|
httpRequestMessage.Method = HttpMethod.Get;
|
|
httpRequestMessage.Headers.Authorization = Software.AuthorizationHeader;
|
|
httpRequestMessage.RequestUri = new Uri($"{BASE_ADDRESS}/API/Production/TempMeter/{pcb}");
|
|
|
|
using (var httpResponseMessage = httpClient.SendAsync(httpRequestMessage).Result)
|
|
{
|
|
if (httpResponseMessage.StatusCode == HttpStatusCode.OK)
|
|
{
|
|
var content = httpResponseMessage
|
|
.Content
|
|
.ReadAsStringAsync()
|
|
.Result;
|
|
|
|
aggregations = JsonConvert.DeserializeObject<Messurement[]>($"{content}");
|
|
}
|
|
else
|
|
{
|
|
MessageBox.Show($"HTTP! {(int)httpResponseMessage.StatusCode} - {httpResponseMessage.ReasonPhrase}.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
MessageBox.Show($"Failed! {e.Message}");
|
|
}
|
|
|
|
return aggregations;
|
|
}
|
|
|
|
internal async void UpdateAggregations(IEnumerable<Messurement> messurements)
|
|
{
|
|
var message = "Succeeded!";
|
|
|
|
try
|
|
{
|
|
using (var httpClient = new HttpClient())
|
|
{
|
|
using (var httpRequestMessage = new HttpRequestMessage())
|
|
{
|
|
httpRequestMessage.Method = HttpMethod.Post;
|
|
httpRequestMessage.Headers.Authorization = Software.AuthorizationHeader;
|
|
httpRequestMessage.RequestUri = new Uri($"{BASE_ADDRESS}/API/Production/TempMeter/Update");
|
|
httpRequestMessage.Content = new StringContent(JsonConvert.SerializeObject(messurements));
|
|
httpRequestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
|
|
|
using (var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage))
|
|
{
|
|
if (httpResponseMessage.StatusCode == HttpStatusCode.OK)
|
|
{
|
|
var added = await httpResponseMessage.Content.ReadAsStringAsync();
|
|
|
|
message = $"Succeeded! {added} records added.";
|
|
}
|
|
else if (httpResponseMessage.StatusCode == HttpStatusCode.NotModified)
|
|
{
|
|
message = $"Failed! No messurements to add.";
|
|
}
|
|
else if (httpResponseMessage.StatusCode == HttpStatusCode.Conflict)
|
|
{
|
|
message = $"Failed! More than 1 pcb's sent.";
|
|
}
|
|
else
|
|
{
|
|
message = $"HTTP! {(int)httpResponseMessage.StatusCode} - {httpResponseMessage.ReasonPhrase}.";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
message = $"Failed! {e.Message}";
|
|
}
|
|
|
|
MessageBox.Show(message);
|
|
}
|
|
|
|
internal IEnumerable<string> AvailableAggregationPcbs()
|
|
{
|
|
var existingPcbs = this.GetAllPcbs();
|
|
var localPcbs = Directory
|
|
.CreateDirectory(WORKING_DIR)
|
|
.GetFiles($"*{AGGREGATIONS_FILE}")
|
|
.Select(x => x.Name
|
|
.Split(new[] { '_' }, StringSplitOptions.RemoveEmptyEntries)
|
|
.FirstOrDefault());
|
|
|
|
return existingPcbs
|
|
.Union(localPcbs)
|
|
.OrderBy(x => x)
|
|
.ToHashSet();
|
|
}
|
|
|
|
private IEnumerable<string> GetAllPcbs()
|
|
{
|
|
var pcbs = Array.Empty<string>();
|
|
|
|
try
|
|
{
|
|
using (var httpClient = new HttpClient())
|
|
{
|
|
using (var httpRequestMessage = new HttpRequestMessage())
|
|
{
|
|
httpRequestMessage.Method = HttpMethod.Get;
|
|
httpRequestMessage.Headers.Authorization = Software.AuthorizationHeader;
|
|
httpRequestMessage.RequestUri = new Uri($"{BASE_ADDRESS}/API/Production/TempMeter/Pcbs");
|
|
|
|
using (var httpResponseMessage = httpClient.SendAsync(httpRequestMessage)
|
|
.ConfigureAwait(true)
|
|
.GetAwaiter()
|
|
.GetResult())
|
|
{
|
|
if (httpResponseMessage.StatusCode == HttpStatusCode.OK)
|
|
{
|
|
var content = httpResponseMessage
|
|
.Content
|
|
.ReadAsStringAsync()
|
|
.ConfigureAwait(true)
|
|
.GetAwaiter()
|
|
.GetResult();
|
|
|
|
pcbs = JsonConvert
|
|
.DeserializeObject<int[]>($"{content}")
|
|
?.Select(x => x.ToString())
|
|
?.ToArray()
|
|
?? pcbs;
|
|
}
|
|
else
|
|
{
|
|
MessageBox.Show($"HTTP! {(int)httpResponseMessage.StatusCode} - {httpResponseMessage.ReasonPhrase}.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
MessageBox.Show($"Failed! {e.Message}");
|
|
}
|
|
|
|
return pcbs;
|
|
}
|
|
|
|
internal void StartBackward()
|
|
{
|
|
this.temperatureSource = new TemperatureSource();
|
|
this.shortTimer = new Timer(Appsettings.BackwardsStepMs)
|
|
{
|
|
Enabled = true,
|
|
AutoReset = true
|
|
};
|
|
this.shortTimer.Elapsed += this.BackwardsElapsed;
|
|
this.shortTimer.Start();
|
|
}
|
|
|
|
private void BackwardsElapsed(object sender, ElapsedEventArgs args)
|
|
{
|
|
this.tempMeterForm.BeginInvoke(new Action(() =>
|
|
{
|
|
var messurement = !this.TryGetTOFandT(out double currentTOF, out double currentT)
|
|
? $"[{args.SignalTime:yyyy-MM-dd hh:mm:ss}]\t invalid record (TOF: {currentTOF} & T: {currentT})"
|
|
: $"[{args.SignalTime:yyyy-MM-dd hh:mm:ss}]\t{this.pcbId,9}\t{currentT,5:00.00}\t{currentTOF,14:0.000000000000}";
|
|
|
|
this.tempMeterForm.AddMessage(messurement);
|
|
File.AppendAllLines(this.backwardsFile, new[] { messurement });
|
|
}));
|
|
}
|
|
|
|
private bool TryGetTOFandT(out double actualTOF, out double actualT)
|
|
{
|
|
actualTOF = this.tempMeterForm.AvgTOF();
|
|
actualT = this.temperatureSource.GetTemperature();
|
|
|
|
this.tempMeterForm.StartRecording();
|
|
|
|
if (actualTOF >= 1 || actualT <= double.MinValue)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
internal IEnumerable<string> AvailableCheckPcbs()
|
|
=> Directory
|
|
.CreateDirectory(WORKING_DIR)
|
|
.GetFiles($"*{BACKWARDS_FILE}")
|
|
.Select(x => x.Name
|
|
.Split(new[] { '_' }, StringSplitOptions.RemoveEmptyEntries)
|
|
.FirstOrDefault())
|
|
.OrderBy(x => x)
|
|
.ToHashSet();
|
|
|
|
internal IEnumerable<InterpolationResult> TemperatureChecksFor(String pcb)
|
|
{
|
|
var backwardsFile = Path.Combine(".", WORKING_DIR, $"{pcb}{BACKWARDS_FILE}");
|
|
|
|
if (!File.Exists(backwardsFile))
|
|
{
|
|
return Array.Empty<InterpolationResult>();
|
|
}
|
|
|
|
var backwardsMessurements = new List<Messurement>();
|
|
|
|
foreach (var line in File.ReadAllLines(backwardsFile))
|
|
{
|
|
if (string.IsNullOrWhiteSpace(line))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var tokens = line.Split(new[] { '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
|
|
|
if (tokens.Length != 4)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var pcbString = tokens[1] ?? string.Empty;
|
|
var avgTString = tokens[2] ?? string.Empty;
|
|
var avgTOFString = tokens[3] ?? string.Empty;
|
|
|
|
var pcbId = default(int);
|
|
var avgT = default(double);
|
|
var avgTOF = default(double);
|
|
|
|
var pcbParsed = int.TryParse(pcbString, out pcbId);
|
|
var tParsed = avgTString.TryParse(out avgT);
|
|
var tofParsed = avgTOFString.TryParse(out avgTOF);
|
|
|
|
if (!pcbParsed || !tParsed || !tofParsed)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
backwardsMessurements.Add(new Messurement
|
|
{
|
|
PcbId = pcbId,
|
|
AvgT = avgT,
|
|
AvgTOF = avgTOF
|
|
});
|
|
}
|
|
|
|
var localAggregations = this.AggregationsFor(pcb) ?? Array.Empty<Messurement>();
|
|
var temperatureLUT = localAggregations.OrderBy(x => x.AvgTOF).ToArray();
|
|
var temperatureChecks = new List<InterpolationResult>();
|
|
|
|
foreach (var check in backwardsMessurements)
|
|
{
|
|
var interpolatedResult = this.InterpolateTOF2T(check.AvgTOF, temperatureLUT);
|
|
|
|
interpolatedResult.PcbId = check.PcbId;
|
|
interpolatedResult.CurrentT = check.AvgT;
|
|
|
|
temperatureChecks.Add(interpolatedResult);
|
|
}
|
|
|
|
return temperatureChecks;
|
|
}
|
|
|
|
private InterpolationResult InterpolateTOF2T(double currentTOF, params Messurement[] temperatureLUT)
|
|
{
|
|
var interpolationResult = new InterpolationResult
|
|
{
|
|
CalculatedT = 1,
|
|
CurrentTOF = currentTOF
|
|
};
|
|
|
|
var length = temperatureLUT?.Length ?? 0;
|
|
var last = length - 1;
|
|
|
|
if (last <= 0 || temperatureLUT[0].AvgTOF > currentTOF || temperatureLUT[last].AvgTOF < currentTOF)
|
|
{
|
|
return interpolationResult;
|
|
}
|
|
|
|
var prevTOF = default(double);
|
|
var prevT = default(double);
|
|
var nextTOF = default(double);
|
|
var nextT = default(double);
|
|
|
|
|
|
for (int i = 1; i < length; i++)
|
|
{
|
|
if (temperatureLUT[i].AvgTOF >= currentTOF)
|
|
{
|
|
prevTOF = temperatureLUT[i - 1].AvgTOF;
|
|
prevT = temperatureLUT[i - 1].AvgT;
|
|
nextTOF = temperatureLUT[i].AvgTOF;
|
|
nextT = temperatureLUT[i].AvgT;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
var currentT = (nextT - prevT) / (nextTOF - prevTOF) * (currentTOF - prevTOF) + prevT;
|
|
|
|
interpolationResult.CalculatedT = currentT;
|
|
interpolationResult.PrevTOF = prevTOF;
|
|
interpolationResult.PrevT = prevT;
|
|
interpolationResult.NextTOF = nextTOF;
|
|
interpolationResult.NextT = nextT;
|
|
|
|
return interpolationResult;
|
|
}
|
|
}
|
|
|
|
class InterpolationResult
|
|
{
|
|
public int PcbId { get; set; }
|
|
|
|
public double PrevT { get; set; }
|
|
|
|
public double PrevTOF { get; set; }
|
|
|
|
public double CurrentT { get; set; }
|
|
|
|
public double CalculatedT { get; set; }
|
|
|
|
public double CurrentTOF { get; set; }
|
|
|
|
public double NextT { get; set; }
|
|
|
|
public double NextTOF { get; set; }
|
|
|
|
public double DiffT => Math.Abs(this.CurrentT - this.CalculatedT);
|
|
}
|
|
|
|
class Messurement
|
|
{
|
|
public int PcbId { get; set; }
|
|
|
|
public int Id { get; set; }
|
|
|
|
public double AvgT { get; set; }
|
|
|
|
public double AvgTOF { get; set; }
|
|
|
|
public double DiffT { get; set; }
|
|
|
|
public double DiffTOF { get; set; }
|
|
|
|
public int Seconds { get; set; }
|
|
|
|
public bool Selected { get; set; }
|
|
}
|
|
|
|
class Messurements
|
|
{
|
|
private readonly string pcbId;
|
|
|
|
// _______________________________ t _____ tof _________________
|
|
private readonly ICollection<Tuple<double, double>> messurements
|
|
= new List<Tuple<double, double>>();
|
|
|
|
public Messurements(string pcbId)
|
|
=> this.pcbId = pcbId;
|
|
|
|
public double MinT => this.messurements.Min(x => x.Item1);
|
|
|
|
public double MinTOF => this.messurements.Min(x => x.Item2);
|
|
|
|
public double AvgT => this.messurements.Average(x => x.Item1);
|
|
|
|
public double AvgTOF => this.messurements.Average(x => x.Item2);
|
|
|
|
public double MaxT => this.messurements.Max(x => x.Item1);
|
|
|
|
public double MaxTOF => this.messurements.Max(x => x.Item2);
|
|
|
|
public double DifT => Math.Abs(this.MinT - this.MaxT);
|
|
|
|
public double DifTOF => Math.Abs(this.MinTOF - this.MaxTOF);
|
|
|
|
public int Count => this.messurements.Count;
|
|
|
|
public override String ToString()
|
|
=> $"{this.pcbId}"
|
|
+ $"\t{this.MinT:0.00}"
|
|
+ $"\t{this.MinTOF:0.0000000000}"
|
|
+ $"\t{this.AvgT:0.00}"
|
|
+ $"\t{this.AvgTOF:0.0000000000}"
|
|
+ $"\t{this.MaxT:0.00}"
|
|
+ $"\t{this.MaxTOF:0.0000000000}"
|
|
+ $"\t{this.DifT:0.00}"
|
|
+ $"\t{this.DifTOF:0.0000000000}"
|
|
+ $"\t{this.Count}";
|
|
|
|
public void Add(double t, double tof)
|
|
=> this.messurements.Add(new Tuple<double, double>(t, tof));
|
|
|
|
public static string Header
|
|
=> $"Pcb Id\tMin °C\tMin TOF\tAvg °C\tAvg TOF\tMax °C\tMax TOF\tDif °C\tDif TOF\tCount";
|
|
}
|
|
} |