|
@@ -1,100 +1,148 @@
|
|
|
-using Shaker.Models;
|
|
|
+using MathNet.Numerics;
|
|
|
+using Shaker.Models;
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.ComponentModel;
|
|
|
using System.Linq;
|
|
|
using System.Net.Http.Headers;
|
|
|
+using System.Numerics;
|
|
|
using System.Text;
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
namespace ShakerService.ViewModel
|
|
|
{
|
|
|
- internal class PSDCache
|
|
|
- {
|
|
|
- private List<double[]> LinearAverageCache = new List<double[]>();
|
|
|
- public List<double[]> ExponentialAverageCache= new List<double[]>();
|
|
|
- public void Clear()
|
|
|
- {
|
|
|
- LinearAverageCache.Clear();
|
|
|
- ExponentialAverageCache.Clear();
|
|
|
- }
|
|
|
- public double[] CalcPSD(double[] data)
|
|
|
- {
|
|
|
- if(data ==null || data.Length ==0)return new double[0];
|
|
|
- if (ServiceRandomConfigViewModel.Instance.LinearAverage > 1)
|
|
|
- {
|
|
|
- if (LinearAverageCache.Count == ServiceRandomConfigViewModel.Instance.LinearAverage)
|
|
|
- {
|
|
|
- for(int i=0;i<LinearAverageCache.Count-1;i++)
|
|
|
- {
|
|
|
- if (i == 0)
|
|
|
- {
|
|
|
- ServiceDataCacheViewModel.Instance.Calc.Add.Add(ref LinearAverageCache[i][0], ref LinearAverageCache[i + 1][0], (uint)data.Length, ref data[0]);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- ServiceDataCacheViewModel.Instance.Calc.Add.Add(ref data[0], ref LinearAverageCache[i + 1][0], (uint)data.Length);
|
|
|
- }
|
|
|
- }
|
|
|
- ServiceDataCacheViewModel.Instance.Calc.Division.Division(ref data[0], LinearAverageCache.Count, (uint)data.Length);
|
|
|
- LinearAverageCache.Clear();
|
|
|
-
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- LinearAverageCache.Add(data);
|
|
|
- }
|
|
|
- }
|
|
|
- if (ServiceRandomConfigViewModel.Instance.ExponentialAverage > 1)
|
|
|
- {
|
|
|
- ExponentialAverageCache.Add(data);
|
|
|
- if (ExponentialAverageCache.Count > ServiceRandomConfigViewModel.Instance.ExponentialAverage)
|
|
|
- {
|
|
|
- ExponentialAverageCache.RemoveRange(0, (int)ServiceRandomConfigViewModel.Instance.ExponentialAverage - ExponentialAverageCache.Count);
|
|
|
- }
|
|
|
- if (ExponentialAverageCache.Count == 0 || ExponentialAverageCache.Count == 1) return data;
|
|
|
- for(int i=0;i< ExponentialAverageCache.Count-2;i++)
|
|
|
- {
|
|
|
- if(i==0)
|
|
|
- {
|
|
|
- ServiceDataCacheViewModel.Instance.Calc.Add.Add(ref ExponentialAverageCache[i][0], ref ExponentialAverageCache[i + 1][0], (uint)data.Length, ref ExponentialAverageCache[^1][0]);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- ServiceDataCacheViewModel.Instance.Calc.Add.Add(ref ExponentialAverageCache[^1][0], ref ExponentialAverageCache[i + 1][0], (uint)data.Length);
|
|
|
- }
|
|
|
- }
|
|
|
- ServiceDataCacheViewModel.Instance.Calc.Division.Division(ref ExponentialAverageCache[^1][0], ExponentialAverageCache.Count, (uint)data.Length);
|
|
|
- return ExponentialAverageCache[^1];
|
|
|
- }
|
|
|
- else return data;
|
|
|
- }
|
|
|
- }
|
|
|
internal class ServiceRandomDataViewModel : BaseServiceViewModel<RandomDataModel>,IData
|
|
|
{
|
|
|
+ public double[] IdentifyFirstDriver { get; set; } = new double[0];
|
|
|
+ public bool HastIdentifyFirstDriver { get; private set; }
|
|
|
private List<PSDCache> AccelerationPSDCache { get; }= new List<PSDCache>();
|
|
|
private PSDCache DriverCache { get; }= new PSDCache();
|
|
|
public double CurrentIdentifyDisplacement { get => Model.CurrentIdentifyDisplacement; set => Model.CurrentIdentifyDisplacement = value; }
|
|
|
public double CurrentIdentifyRms { get => Model.CurrentIdentifyRms; set => Model.CurrentIdentifyRms = value; }
|
|
|
public int IdentifyIndex { get => Model.IdentifyIndex; set => Model.IdentifyIndex = value; }
|
|
|
public List<double[]> CurrentAccelerationPSD { get => Model.CurrentAccelerationPSD; set => Model.CurrentAccelerationPSD = value; }
|
|
|
+ public List<double> CurrentAccelerationSpectrumRMS { get; } = new List<double>();
|
|
|
public RandomTestStep RandomTestStep{ get => Model.RandomTestStep; set => Model.RandomTestStep = value; }
|
|
|
public double[] CurrentAccelerationSynthesisPSD { get => Model.CurrentAccelerationSynthesisPSD; set => Model.CurrentAccelerationSynthesisPSD = value; }
|
|
|
+ public double CurrentAccelerationSynthesisSpectrumRMS { get; private set; }
|
|
|
+
|
|
|
public double[] TransferFunction { get => Model.TransferFunction; set => Model.TransferFunction = value; }
|
|
|
public double[] DriverPSD { get => Model.DriverPSD; set => Model.DriverPSD = value; }
|
|
|
public double CurrentTestLevel { get => Model.CurrentTestLevel; set => Model.CurrentTestLevel = value; }
|
|
|
public double CurrentTestTime { get => Model.CurrentTestTime; set => Model.CurrentTestTime = value; }
|
|
|
+ public RandomStatus RandomStatus { get => Model.RandomStatus; set => Model.RandomStatus = value; }
|
|
|
public MainPageType MainPageType => Model.MainPageType;
|
|
|
+ public double[] AddAccelerationPSD(int index, double[] accpsd, bool avg = true)
|
|
|
+ {
|
|
|
+ CurrentAccelerationPSD[index] = AccelerationPSDCache[index].AveragePSD(accpsd, avg);
|
|
|
+ return CurrentAccelerationPSD[index];
|
|
|
+ }
|
|
|
+ public double[] AddDriverPSD(double[] driverpsd,bool avg = true)
|
|
|
+ {
|
|
|
+ DriverPSD = DriverCache.AveragePSD(driverpsd, avg);
|
|
|
+ return DriverPSD;
|
|
|
+ }
|
|
|
+
|
|
|
public void InitCache()
|
|
|
{
|
|
|
AccelerationPSDCache.Clear();
|
|
|
AccelerationPSDCache.AddRange(Enumerable.Range(0, ServiceShakerConfigViewModel.Instance.AccelerationSensorCount).Select(x => new PSDCache()));
|
|
|
+ CurrentAccelerationPSD = Enumerable.Range(0,ServiceShakerConfigViewModel.Instance.AccelerationSensorCount).Select(x => new double[0]).ToList();
|
|
|
+ CurrentAccelerationSpectrumRMS.Clear();
|
|
|
+ CurrentAccelerationSpectrumRMS.AddRange(Enumerable.Repeat(0d, ServiceShakerConfigViewModel.Instance.AccelerationSensorCount));
|
|
|
+ CurrentAccelerationSynthesisSpectrumRMS = 0;
|
|
|
DriverCache.Clear();
|
|
|
}
|
|
|
public void ClearCache()
|
|
|
{
|
|
|
AccelerationPSDCache.ForEach(x => x.Clear());
|
|
|
+ CurrentAccelerationPSD = Enumerable.Range(0, ServiceShakerConfigViewModel.Instance.AccelerationSensorCount).Select(x => new double[0]).ToList();
|
|
|
DriverCache.Clear();
|
|
|
+ HastIdentifyFirstDriver = false;
|
|
|
+ IdentifyIndex++;
|
|
|
+ CurrentAccelerationSpectrumRMS.Clear();
|
|
|
+ CurrentAccelerationSpectrumRMS.AddRange(Enumerable.Repeat(0d, ServiceShakerConfigViewModel.Instance.AccelerationSensorCount));
|
|
|
+ RandomStatus = RandomStatus.Start;
|
|
|
+ }
|
|
|
+ public double[] CalcIdentifyFirstDriver()
|
|
|
+ {
|
|
|
+ if (HastIdentifyFirstDriver) return IdentifyFirstDriver;
|
|
|
+ Random rdm = new Random();
|
|
|
+ int n_down = 0;
|
|
|
+ int n_up = 0;
|
|
|
+ var freqs = Enumerable.Range(0, ServiceRandomConfigViewModel.Instance.FFTFrameLength).Select(x => x * ServiceRandomConfigViewModel.Instance.FrequencyResolution).ToArray();
|
|
|
+ n_down = Array.FindLastIndex(freqs, x => x < ServiceRandomConfigViewModel.Instance.SpectralTables[0].TurningFrequency);
|
|
|
+ n_up = Array.FindLastIndex(freqs, x => x < ServiceRandomConfigViewModel.Instance.SpectralTables[^1].TurningFrequency) + 1;
|
|
|
+ double[] tempvalue = Enumerable.Repeat(8e-14, ServiceRandomConfigViewModel.Instance.FFTHalfFrameLength).ToArray();
|
|
|
+ for (int i = 0; i < n_up - n_down; i++)
|
|
|
+ {
|
|
|
+ int index = i + n_down;
|
|
|
+ double currentfreq = freqs[index];
|
|
|
+ int currenfreqindex = ServiceRandomConfigViewModel.Instance.SpectralTables.FindIndex(x => currentfreq < x.TurningFrequency);
|
|
|
+ if (currenfreqindex > 0)
|
|
|
+ {
|
|
|
+ double v1 = Math.Log10(ServiceRandomConfigViewModel.Instance.SpectralTables[currenfreqindex].SqrtValue);
|
|
|
+ double v2 = Math.Log10(ServiceRandomConfigViewModel.Instance.SpectralTables[currenfreqindex - 1].SqrtValue);
|
|
|
+
|
|
|
+ double f1 = Math.Log10(ServiceRandomConfigViewModel.Instance.SpectralTables[currenfreqindex].TurningFrequency);
|
|
|
+ double f2 = Math.Log10(ServiceRandomConfigViewModel.Instance.SpectralTables[currenfreqindex - 1].TurningFrequency);
|
|
|
+
|
|
|
+ tempvalue[currenfreqindex] = Math.Pow(10, (v1 - v2) / (f1 - f2) * (v2 - Math.Log10(currentfreq)) + v2);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ tempvalue[n_up] = ServiceRandomConfigViewModel.Instance.SpectralTables[^1].SqrtValue;
|
|
|
+ Complex[] random = Enumerable.Range(0, ServiceRandomConfigViewModel.Instance.FFTHalfFrameLength).Select(x => Complex.Exp(new Complex(0, rdm.NextDouble() * 4 * Math.PI)) * tempvalue[x]).ToArray();
|
|
|
+ Complex[] value = new Complex[ServiceRandomConfigViewModel.Instance.FFTFrameLength];
|
|
|
+ value[0] = new Complex(tempvalue[0], 0);
|
|
|
+ Array.Copy(random, 0, value, 1, value.Length);
|
|
|
+ for (int i = 1; i < random.Length; i++)
|
|
|
+ {
|
|
|
+ value[^i] = new Complex(random[i].Real, -random[i].Imaginary);
|
|
|
+ }
|
|
|
+ MathNet.Numerics.IntegralTransforms.Fourier.Inverse(value, options: MathNet.Numerics.IntegralTransforms.FourierOptions.Matlab);
|
|
|
+ IdentifyFirstDriver = value.Select(x => x.Real).ToArray();
|
|
|
+ HastIdentifyFirstDriver = true;
|
|
|
+ return IdentifyFirstDriver;
|
|
|
+ }
|
|
|
+ public double[] CalcIdentifyDriver(RandomTestStep step,double level)
|
|
|
+ {
|
|
|
+ double[] driver = CalcIdentifyFirstDriver();
|
|
|
+ switch (step)
|
|
|
+ {
|
|
|
+ case RandomTestStep.Start:
|
|
|
+ ServiceDataCacheViewModel.Instance.Calc.Multiply.Multiply(ref driver[0], ref ServiceRandomConfigViewModel.Instance.StartWindow[0], (uint)driver.Length);
|
|
|
+ break;
|
|
|
+ case RandomTestStep.Stop:
|
|
|
+ ServiceDataCacheViewModel.Instance.Calc.Multiply.Multiply(ref driver[0], ref ServiceRandomConfigViewModel.Instance.StartWindow[0], (uint)driver.Length);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ double dispvalue = Shaker.Models.Tools.Tools.QuantitiesToVoltage(level, ServiceShakerConfigViewModel.Instance.DisplacementSensitivity);
|
|
|
+ double max = Math.Max(Math.Abs(driver.Max()), Math.Abs(driver.Min()));
|
|
|
+ ServiceDataCacheViewModel.Instance.Calc.Multiply.Multiply(ref driver[0], dispvalue / max, (uint)driver.Length);
|
|
|
+ double[] result = new double[driver.Length * ServiceShakerConfigViewModel.Instance.SampleRate / ServiceRandomConfigViewModel.Instance.RandomSampleRate];
|
|
|
+ var linear = MathNet.Numerics.Interpolate.Linear(Enumerable.Range(0, driver.Length).Select(x => (double)x), driver);
|
|
|
+ for(int i=0;i<result.Length;i++)
|
|
|
+ {
|
|
|
+ result[i] = linear.Integrate((double)i / result.Length * driver.Length);
|
|
|
+ };
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ public double[] CalcPSD(double[] data)
|
|
|
+ {
|
|
|
+ double[] result = new double[ServiceRandomConfigViewModel.Instance.FFTFrameLength];
|
|
|
+ for(int i=0;i<result.Length;i++)
|
|
|
+ {
|
|
|
+ result[i] = data[i * ServiceRandomConfigViewModel.Instance.RandomSampleRate / ServiceShakerConfigViewModel.Instance.SampleRate];
|
|
|
+ }
|
|
|
+ ServiceDataCacheViewModel.Instance.Calc.Multiply.Multiply(ref result[0], ref ServiceRandomConfigViewModel.Instance.HanningWindow[0], (uint)result.Length);
|
|
|
+ double[] img = new double[result.Length];
|
|
|
+ ServiceDataCacheViewModel.Instance.Calc.FFT.FFT(result, img);
|
|
|
+ result = result.Take(ServiceRandomConfigViewModel.Instance.FFTHalfFrameLength).ToArray();
|
|
|
+ ServiceDataCacheViewModel.Instance.Calc.Multiply.Multiply(ref result[0], 1.4142135624 / result.Length, (uint)result.Length);
|
|
|
+ ServiceDataCacheViewModel.Instance.Calc.Multiply.Multiply(ref result[0], ref result[0], (uint)result.Length);
|
|
|
+ ServiceDataCacheViewModel.Instance.Calc.Division.Division(ref result[0], ServiceRandomConfigViewModel.Instance.FrequencyResolution*ServiceRandomConfigViewModel.Instance.HanningWindowCompensationCoefficient, (uint)result.Length);
|
|
|
+ ServiceDataCacheViewModel.Instance.Calc.Multiply.Multiply(ref result[0], ref ServiceRandomConfigViewModel.Instance.PSDWindow[0], (uint)result.Length);
|
|
|
+ return result;
|
|
|
}
|
|
|
public void ReadFpgaData()
|
|
|
{
|