using Avalonia.Collections; using Avalonia.Controls; using OxyPlot; using OxyPlot.Series; using Shaker.Models; using ShakerApp.Tools; using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; namespace ShakerApp.ViewModels { public abstract class BaseDataReviewItemViewModel:DisplayViewModelBase,IDataReviewItem { public BaseDataReviewItemViewModel() { TimeDomainReview = new TimeDomainReviewViewModel(this); THDReview = new THDReviewViewModel(this); ButtonVisibily = false; } private protected ShakerConfigModel ShakerConfig = new ShakerConfigModel(); private protected ShakerControlModel ShakerControl = new ShakerControlModel(); private protected DeviceInfoModel DeviceInfo = new DeviceInfoModel(); private protected bool isopen = false; public bool IsOpen => isopen; public abstract MainPageType PageType { get; } public string File { get; } = string.Empty; [AllowNull] private protected TDMS.ITDMSFile tdmsfile; [AllowNull] public TimeDomainReviewViewModel TimeDomainReview { get; } [AllowNull] public THDReviewViewModel THDReview { get; } public virtual void OpenFile(string path) { tdmsfile?.Close(); tdmsfile?.Dispose(); tdmsfile = TDMS.TDMSDataBuilder.OpenExisting(path); isopen = true; InitConfig(); } public virtual void InitData(TDMS.ITDMSFile file) { tdmsfile?.Close(); tdmsfile?.Dispose(); tdmsfile = file; isopen = true; InitConfig(); } private protected virtual void InitConfig() { if (tdmsfile == null) return; var group = tdmsfile.Contains(nameof(ShakerConfigModel)) ? tdmsfile[nameof(ShakerConfigModel)] : null; if (group == null) return; GetConfig(ShakerConfig, group!); group = tdmsfile.Contains(nameof(ShakerControlModel)) ? tdmsfile[nameof(ShakerControlModel)] : null; if (group == null) return; GetConfig(ShakerControl, group!); group = tdmsfile.Contains(nameof(DeviceInfoModel)) ? tdmsfile[nameof(DeviceInfoModel)] : null; if (group == null) return; GetConfig(DeviceInfo, group!); TimeDomainReview.InitData(); THDReview.InitData(); InitData(); } private protected void GetConfig(T config,TDMS.ITDMSChannelGroup group) { typeof(T).GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public) .ToList() .ForEach(x => { if (x.FieldType.IsAssignableTo(typeof(IList)) || x.FieldType.IsArray) { if (group.TryGetProperty(x.Name, out var val) && !string.IsNullOrEmpty(val)) { byte[] bytes = new byte[val.Length / 2]; for (int i = 0; i < bytes.Length; i++) { bytes[i] = System.Convert.ToByte(val.Substring(i * 2, 2), 16); } x.SetValue(config,ShakerApp.Tools.Tools.Deserialize(x.FieldType, bytes)); } else { x.SetValue(config,Activator.CreateInstance(x.FieldType)); } } else if(x.FieldType == typeof(string)) { if (group.TryGetProperty(x.Name, out var val) && !string.IsNullOrEmpty(val)) { x.SetValue(config,val); } else { x.SetValue(config,string.Empty); } } else if (x.FieldType.IsEnum) { if (group.TryGetProperty(x.Name, out var val) && !string.IsNullOrEmpty(val)) { x.SetValue(config,Enum.Parse(x.FieldType, val)); } else { x.SetValue(config,Enum.GetValues(x.FieldType)); } } else if (x.FieldType == typeof(byte)) { if (group.TryGetProperty(x.Name, out var val) && !string.IsNullOrEmpty(val) && byte.TryParse(val, out var b)) { x.SetValue(config,b); } else { x.SetValue(config,(byte)0); } } else if (x.FieldType == typeof(sbyte)) { if (group.TryGetProperty(x.Name, out var val) && !string.IsNullOrEmpty(val) && sbyte.TryParse(val, out var b)) { x.SetValue(config,b); } else { x.SetValue(config,(sbyte)0); } } else if (x.FieldType == typeof(short)) { if (group.TryGetProperty(x.Name, out var val) && !string.IsNullOrEmpty(val) && short.TryParse(val, out var b)) { x.SetValue(config,b); } else { x.SetValue(config,(short)0); } } else if (x.FieldType == typeof(ushort)) { if (group.TryGetProperty(x.Name, out var val) && !string.IsNullOrEmpty(val) && ushort.TryParse(val, out var b)) { x.SetValue(config,b); } else { x.SetValue(config,(ushort)0); } } else if (x.FieldType == typeof(int)) { if (group.TryGetProperty(x.Name, out var val) && !string.IsNullOrEmpty(val) && int.TryParse(val, out var b)) { x.SetValue(config,b); } else { x.SetValue(config,(int)0); } } else if (x.FieldType == typeof(uint)) { if (group.TryGetProperty(x.Name, out var val) && !string.IsNullOrEmpty(val) && uint.TryParse(val, out var b)) { x.SetValue(config,b); } else { x.SetValue(config,(uint)0); } } else if (x.FieldType == typeof(long)) { if (group.TryGetProperty(x.Name, out var val) && !string.IsNullOrEmpty(val) && long.TryParse(val, out var b)) { x.SetValue(config,b); } else { x.SetValue(config,(long)0); } } else if (x.FieldType == typeof(ulong)) { if (group.TryGetProperty(x.Name, out var val) && !string.IsNullOrEmpty(val) && ulong.TryParse(val, out var b)) { x.SetValue(config,b); } else { x.SetValue(config,(ulong)0); } } else if (x.FieldType == typeof(float)) { if (group.TryGetProperty(x.Name, out var val) && !string.IsNullOrEmpty(val) && float.TryParse(val, out var b)) { x.SetValue(config,b); } else { x.SetValue(config,(float)0); } } else if (x.FieldType == typeof(double)) { if (group.TryGetProperty(x.Name, out var val) && !string.IsNullOrEmpty(val) && double.TryParse(val, out var b)) { x.SetValue(config,b); } else { x.SetValue(config,(double)0); } } else if (x.FieldType == typeof(bool)) { if (group.TryGetProperty(x.Name, out var val) && !string.IsNullOrEmpty(val) && bool.TryParse(val, out var b)) { x.SetValue(config,b); } else { x.SetValue(config,false); } } }); } public virtual void CloseFile() { tdmsfile?.Close(); tdmsfile?.Dispose(); tdmsfile = null; } public class TimeDomainReviewViewModel : DisplayViewModelBase { private bool isinint = false; List _LineSeries = new List(); public OxyPlot.PlotModel PlotModel { get; } = new OxyPlot.PlotModel(); private BaseDataReviewItemViewModel _Parent; public uint SampleRate { get => sampleRate; set =>SetProperty(ref sampleRate , value); } public uint TotalPages { get => Math.Clamp(totalPages, 1, uint.MaxValue); set { SetProperty(ref totalPages, value); OnPropertyChanged(nameof(MaxPageIndex)); OnPropertyChanged(nameof(MaxReadPages)); OnPropertyChanged(nameof(PageIndex)); OnPropertyChanged(nameof(ReadPages)); } } public uint PageIndex { get =>Math.Clamp(pageIndex,MinPageIndex,MaxPageIndex); set { SetProperty(ref pageIndex, value); OnPropertyChanged(nameof(MaxReadPages)); OnPropertyChanged(nameof(ReadPages)); LoadData(); } } public uint MinPageIndex => 1; public uint MaxPageIndex => TotalPages; public uint ReadPages { get =>Math.Clamp(readPages,MinReadPages,MaxReadPages); set { SetProperty(ref readPages, value); LoadData(); } } public uint MinReadPages => 1; public uint MaxReadPages => Math.Clamp(TotalPages - PageIndex + 1, 1, 10000); public TimeDomainReviewViewModel(BaseDataReviewItemViewModel parent) { _Parent = parent; PlotModel.Axes.Add(new OxyPlot.Axes.LinearAxis() { MajorGridlineStyle = OxyPlot.LineStyle.Solid, Position = OxyPlot.Axes.AxisPosition.Bottom, Key = "X", Title = App.Current?.FindResource("Time") +"", Unit = "s", MinimumPadding = 0, MaximumPadding = 0, }); PlotModel.Axes.Add(new OxyPlot.Axes.LinearAxis() { MajorGridlineStyle = OxyPlot.LineStyle.Solid, Position = OxyPlot.Axes.AxisPosition.Left, Key = "Y", Title = App.Current?.FindResource("")+"", MinimumPadding = 0, MaximumPadding = 0, }); PlotModel.Legends.Add(new OxyPlot.Legends.Legend() { IsLegendVisible = true, }); } private TDMS.ITDMSChannelGroup? _DataGroup; private List _Channels = new List(); private uint readPages; private uint pageIndex; private uint totalPages; private uint sampleRate; public override void InitData() { isinint = false; base.InitData(); _DataGroup = _Parent.tdmsfile.Contains(BaseMainPageViewModel.TimeDomainData) ? _Parent.tdmsfile[BaseMainPageViewModel.TimeDomainData] : null; if (_DataGroup == null) { DataReviewViewModel.Instance.ShowError(App.Current?.FindResource("TestFileReadError")+""); return; } _Channels.Clear(); _LineSeries.Clear(); PlotModel.Series.Clear(); if(_DataGroup.ChildCount ==0) { DataReviewViewModel.Instance.ShowError(App.Current?.FindResource("TestFileReadError") + ""); return; } PlotModel.InvalidatePlot(false); for(ulong i=0;i<_DataGroup.ChildCount;i++) { _Channels.Add(_DataGroup[(int)i]!); _LineSeries.Add(new OxyPlot.Series.LineSeries() { XAxisKey = "X", YAxisKey = "Y", DataFieldX = nameof(OxyPlot.DataPoint.X), DataFieldY = nameof(OxyPlot.DataPoint.Y), Title = App.Current?.FindResource(_Channels[^1].Name)+"", Tag = _Channels[^1].Unit, }); PlotModel.Series.Add(_LineSeries[^1]); } PlotModel.InvalidatePlot(true); SampleRate = _Parent.ShakerConfig.SampleRate; TotalPages = (uint)Math.Ceiling(_Channels[0].ChildCount / (double)SampleRate); ReadPages = 1; PageIndex = 1; isinint = true; LoadData(); } private void LoadData() { if (!isinint) return; uint start = (PageIndex - 1) * SampleRate; uint len = ReadPages * SampleRate; len = (uint)Math.Clamp(len, len, _Channels[^1].ChildCount - start); double pro = 1d / SampleRate; //var datas = Enumerable.Repeat(new OxyPlot.DataPoint(), 1000_000).ToList(); PlotModel.InvalidatePlot(false); for(int i=0;i<_Channels.Count;i++) { uint index = 0; _LineSeries[i].ItemsSource = _Channels[i].GetDataValues(start, len).Select(x => { return new OxyPlot.DataPoint((index++) * pro, x); }).ToList(); // _LineSeries[i].ItemsSource = datas; } PlotModel.InvalidatePlot(true); } } public class THDReviewViewModel:DisplayViewModelBase { private int[] indexLenght = new int[0]; private List channels = new List(); [AllowNull] TDMS.ITDMSChannel freqchannel; ulong datalen = 0; public uint MaxFrame => 10000; public uint Current { get => current; set { SetProperty(ref current, value); LoadData(); } } public AvaloniaList Frames { get; } = new AvaloniaList(); public bool IsFixed { get => isFixed; set =>SetProperty(ref isFixed ,value); } BaseDataReviewItemViewModel _parent; TDMS.ITDMSChannelGroup? _Group; private uint current = 1; private bool isFixed = true; public override string Title => IsFixed ? "SweepCount" : "THD"; public THDReviewViewModel(BaseDataReviewItemViewModel parent) { _parent = parent; PlotModel.Axes.Add(new OxyPlot.Axes.LinearAxis() { Position = OxyPlot.Axes.AxisPosition.Bottom, MajorGridlineStyle = OxyPlot.LineStyle.Solid, Key="X", Title = App.Current?.FindResource("FrameXTitle")+ "", }); PlotModel.Axes.Add(new OxyPlot.Axes.LinearAxis() { Position = OxyPlot.Axes.AxisPosition.Left, MajorGridlineStyle = OxyPlot.LineStyle.Solid, Title="THD", Unit ="%", Key ="Y", }); PlotModel.Legends.Add(new OxyPlot.Legends.Legend() { IsLegendVisible = true, }); } public override void InitData() { base.InitData(); if(_parent.PageType == MainPageType.SinePage && _parent is SineDataReviewViewModel sine) { if(sine.SweepConfig.SignalType == SignalType.Fixed) { PlotModel.Axes[0].Title = App.Current?.FindResource("FrameXTitle") + ""; PlotModel.Axes[0].Unit = ""; } else { PlotModel.Axes[0].Title = App.Current?.FindResource("Frequency") + ""; PlotModel.Axes[0].Unit = "Hz"; } IsFixed = sine.SweepConfig.SignalType == SignalType.Fixed; OnPropertyChanged(nameof(Title)); } channels.Clear(); PlotModel.Series.Clear(); _Group = _parent.tdmsfile.Contains(BaseMainPageViewModel.THDData) ? _parent.tdmsfile[BaseMainPageViewModel.THDData] : null; if(IsEnabled && _Group!=null) { for(int i=0; i < (int)_Group.ChildCount;i++) { var ch = _Group[i]; if (ch == null || !ShakerDataViewModel.Instance.AllowTHDChannels.Contains(ch.Name)) continue; channels.Add(ch); PlotModel.Series.Add(new OxyPlot.Series.LineSeries() { XAxisKey = "X", YAxisKey = "Y", DataFieldX = nameof(DataPoint.X), DataFieldY = nameof(DataPoint.Y), Title = App.Current?.FindResource(ch.Name)+"", }); } freqchannel = _Group.Contains(nameof(SweepData.Frequency)) ? _Group[nameof(SweepData.Frequency)] : null; var sweepindexchannel = _Group.Contains(nameof(SineMainPageViewModel.SweepIndex)) ? _Group[nameof(SineMainPageViewModel.SweepIndex)] : null; if(sweepindexchannel!=null) { var max = sweepindexchannel.GetDataValues((uint)sweepindexchannel.ChildCount-1, 1)[0]; indexLenght = new int[max+1]; int index = 0; for(int i=0;i((uint)index, readlen); int c = temp.Count(x => x == i); indexLenght[i] += c; if (c == readlen) { index += (int)readlen; continue; } else { if (temp[^1]!=i) { index += c; break; } } } } Frames.Clear(); Frames.AddRange(Enumerable.Range(1, max+1).Select(x => (uint)x).ToList()); } else { indexLenght = new int[0]; var total = (int)Math.Ceiling(datalen / (float)MaxFrame); Frames.Clear(); Frames.AddRange(Enumerable.Range(1, total).Select(x => (uint)x).ToList()); } datalen = channels.Min(x => x.ChildCount); Current = 1; } else { PlotModel.InvalidatePlot(false); PlotModel.InvalidatePlot(true); } OnPropertyChanged(nameof(Frames)); OnPropertyChanged(nameof(IsEnabled)); } private void LoadData() { if (datalen == 0) return; if (_parent is not SineDataReviewViewModel sine) return; uint start = (Current - 1) * MaxFrame; uint len = (uint)Math.Min(datalen - (ulong)start, (ulong)MaxFrame); PlotModel.InvalidatePlot(false); if(freqchannel==null || sine.SweepConfig.SignalType == SignalType.Fixed) { for (int i = 0; i < channels.Count; i++) { int index = 0; (PlotModel.Series[i] as LineSeries)!.ItemsSource = channels[i].GetDataValues(start, len).Select(x => { return new DataPoint(index++, x * 100); }).ToList(); } } else { start = 0; var indexindex = Frames.ToList().FindIndex(x => x == Current); if(indexindex>0) { start = (uint)indexLenght.Skip(indexindex).Sum(); } len = (uint)indexLenght[indexindex]; var freq = freqchannel.GetDataValues(start, len); for (int i = 0; i < channels.Count; i++) { int index = 0; (PlotModel.Series[i] as LineSeries)!.ItemsSource = channels[i].GetDataValues(start, len).Select(x => { return new DataPoint(freq[index++], x * 100); }).ToList(); } } PlotModel.InvalidatePlot(true); } public OxyPlot.PlotModel PlotModel { get; } = new OxyPlot.PlotModel(); public bool IsEnabled => _Group != null && _Group.ChildCount > 0; } } }