using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.ComponentModel; namespace FLY.Simulation.Coating { public class Coating : INotifyPropertyChanged, Misc.ISaveToXml { public CoatingCtrl hmi_cc; public CoatingCtrl inner_cc; public HMI hmi; private FLY.Simulation.Coating.CoatingCtrl.COATINGMODE coatingmode = CoatingCtrl.COATINGMODE.Extrusion; /// <summary> /// 涂布类型 /// </summary> public FLY.Simulation.Coating.CoatingCtrl.COATINGMODE CoatingMode { get { return coatingmode; } set { if (coatingmode != value) { coatingmode = value; hmi_cc.CoatingMode = value; inner_cc.CoatingMode = value; } } } public int Port { get; set; } = 502; public class DataInfo { /// <summary> /// 上光纤是亮 /// </summary> public bool IsLight; /// <summary> /// 下光纤是亮 /// </summary> public bool IsLight2; /// <summary> /// 厚度值 /// </summary> public int Thick; } //当前数据 public List<DataInfo> Datas_Vertical = new List<DataInfo>();//纵向数据 public List<DataInfo> Datas_Horizontal = new List<DataInfo>();//横向数据 int datas_horizontal_avg = 0; int datas_vertical_position=0; //30m 后的数据 public List<DataInfo> Datas_Vertical_30m = new List<DataInfo>();//纵向数据 public List<DataInfo> Datas_Horizontal_30m = new List<DataInfo>();//横向数据 int datas_vertical_30m_position=0; /// <summary> /// 膜宽 /// </summary> public int FilmWidth => Datas_Horizontal.Count(); /// <summary> /// 膜速度 m/min /// </summary> public double FilmVelocity { get; set; } = 12; /// <summary> /// 辊周长 mm /// </summary> public double MmOfR=120*3.14; /// <summary> /// 辊信号长度 mm /// </summary> public double MmOfRSignal = 10; /// <summary> /// 当前辊位置 mm /// </summary> double RPosition = 0; /// <summary> /// 膜已经跑了的长度。m /// </summary> public double FilmLength { get; set; } /// <summary> /// 烘箱长度 30m /// </summary> public double OvenLength = 30; /// <summary> /// 辊信号 /// </summary> public bool RSignal; /// <summary> /// 上纵向信号 /// </summary> public bool VSignal; /// <summary> /// 下纵向信号 /// </summary> public bool VSignal2; /// <summary> /// 上横向信号 /// </summary> public bool HSignal; /// <summary> /// 下横向信号 /// </summary> public bool HSignal2; public bool DeviceState { get; set; } public double Avg { get; set; } void Load_Vertical() { Datas_Vertical.Clear(); using (StreamReader sr = new StreamReader(@"coating\datas_vertical.csv")) { string header = sr.ReadLine();//标题 , 位置(mm), 纵向信号,厚度 while (!sr.EndOfStream) { string s = sr.ReadLine(); string[] ss = s.Split(','); int pos_mm = int.Parse(ss[0]); bool isLight = bool.Parse(ss[1]); bool isLight2 = bool.Parse(ss[2]); int thick = (int)(double.Parse(ss[3]) * 100); Datas_Vertical.Add(new DataInfo() { IsLight = isLight, IsLight2 = isLight2, Thick = thick }); Datas_Vertical_30m.Add(new DataInfo() { IsLight = isLight, IsLight2 = isLight2, Thick = thick }); } sr.Close(); } } void Load_Horizontal() { Datas_Horizontal.Clear(); using (StreamReader sr = new StreamReader(@"coating\datas_horizontal.csv")) { string header = sr.ReadLine();//标题 , 位置(mm), 厚度 while (!sr.EndOfStream) { string s = sr.ReadLine(); string[] ss = s.Split(','); int pos_mm = int.Parse(ss[0]); bool isLight = bool.Parse(ss[1]); bool isLight2 = bool.Parse(ss[2]); int thick = (int)(double.Parse(ss[3]) * 100.0); Datas_Horizontal.Add(new DataInfo() { IsLight = isLight, IsLight2 = isLight2, Thick = thick }); Datas_Horizontal_30m.Add(new DataInfo() { IsLight = isLight, IsLight2 = isLight2, Thick = thick }); } sr.Close(); } } void Load() { Load_Vertical(); Load_Horizontal(); datas_horizontal_avg = (int)(Datas_Horizontal.Average((d) => { return d.Thick; })); Misc.SaveToXmlHepler.Load("simulation_coating.xml", this); } public void Save() { Misc.SaveToXmlHepler.Save("simulation_coating.xml", this); } public Coating() { hmi_cc = new CoatingCtrl(this); inner_cc = new CoatingCtrl(this); DeviceState = true; Load(); hmi = new HMI(this, hmi_cc, Port); this.PropertyChanged += new PropertyChangedEventHandler(Coating_PropertyChanged); } void Coating_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "CoatingMode") Save(); } /// <summary> /// 获取30m后的数据 /// </summary> /// <param name="mm"></param> /// <returns></returns> public int GetData30m(int mm) { if (mm < 0) return 0; if (mm >= FilmWidth) return 0; return (int)(Datas_Vertical_30m[datas_vertical_position].Thick * ((double)Datas_Horizontal_30m[mm].Thick) / datas_horizontal_avg); } public int GetData(int mm) { if (mm < 0) return 0; if (mm >= FilmWidth) return 0; return (int)(Datas_Vertical[datas_vertical_position].Thick * ((double)Datas_Horizontal[mm].Thick) / datas_horizontal_avg); } /// <summary> /// 上一个时间点 /// </summary> DateTime dtLast = DateTime.MinValue; public void OnPoll(DateTime now) { if (dtLast == DateTime.MinValue) { dtLast = now; return; } TimeSpan ts= now - dtLast; dtLast = now; if (!DeviceState)//没有涂布 return; double filmMove = ts.TotalMinutes * FilmVelocity; FilmLength += filmMove;//膜位置 int p1 = (int)(FilmLength * 1000 % Datas_Vertical.Count()); if (p1 != datas_vertical_position) { datas_vertical_position = p1; Avg = Datas_Vertical[datas_vertical_position].Thick / 100.0; if (AvgChanged != null) { AvgChanged(FilmLength, (int)(Avg*100)); } } datas_vertical_30m_position = (int)((FilmLength - OvenLength) * 1000 % Datas_Vertical.Count()); if (datas_vertical_30m_position < 0) datas_vertical_30m_position += Datas_Vertical.Count(); //更新纵向信号 VSignal = Datas_Vertical[datas_vertical_position].IsLight; VSignal2 = Datas_Vertical[datas_vertical_position].IsLight2; //更新辊信号 RPosition += filmMove * 1000; RPosition = RPosition % MmOfR; if (RPosition < MmOfRSignal) RSignal = true; else RSignal = false; hmi_cc.OnPoll(filmMove); inner_cc.OnPoll(filmMove); } /// <summary> /// 每1mm更新一次 /// </summary> public event Action<double, int> AvgChanged; public event Action DatasChanged; public event Action Datas30mChanged; public void NotifyDatasChanged() { if (DatasChanged != null) { DatasChanged(); } } public void NotifyDatas30mChanged() { if (Datas30mChanged != null) { Datas30mChanged(); } } protected void NotifyPropertyChanged(string propertyname) { if (PropertyChanged != null) { PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyname)); } } public event PropertyChangedEventHandler PropertyChanged; public string[] GetSavePropertyNames() { return new string[] { "Port", "CoatingMode" }; } } /// <summary> /// 涂布控制量 /// </summary> public class CoatingCtrlElement:INotifyPropertyChanged { /// <summary> /// 控制的时间 /// </summary> public DateTime Time = DateTime.Now; private double pump; public double Pump { get { return pump; } set { if (pump != value) { pump = value; NotifyPropertyChanged("Pump"); } } } private double left; public double LeftDis { get { return left; ; } set { if (left != value) { left = value; NotifyPropertyChanged("LeftDis"); } } } private double right; public double RightDis { get { return right; } set { if (right != value) { right = value; NotifyPropertyChanged("RightDis"); } } } /// <summary> /// 膜移动的距离 /// </summary> public double FilmMove=0; protected void NotifyPropertyChanged(string propertyname) { if (PropertyChanged != null) { PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyname)); } } public event PropertyChangedEventHandler PropertyChanged; } public class CoatingCtrl : INotifyPropertyChanged { Coating mCoating; #region 参数 public enum COATINGMODE { /// <summary> /// 挤压涂布 /// </summary> Extrusion, /// <summary> /// 转移涂布 /// </summary> Transfer } /// <summary> /// 涂布类型 /// </summary> public COATINGMODE CoatingMode = COATINGMODE.Extrusion; /// <summary> /// 泵速因子 1 个 面密度 = N个泵速, 只有挤压涂布有效 /// </summary> public double PumpFactor = 0.5; /// <summary> /// 左右刀因子 1个面密度 = N个左右刀 /// </summary> public double LeftRightFactor = 1; /// <summary> /// 当前涂布控制量 /// </summary> public CoatingCtrlElement NowCtrl; CoatingCtrlElement NowCtrl_30m; #endregion /// <summary> /// 控制量 /// </summary> List<CoatingCtrlElement> mCtrlElement = new List<CoatingCtrlElement>(); public CoatingCtrl(Coating coating) { mCoating = coating; NowCtrl = new CoatingCtrlElement() { FilmMove = 0, Pump = 90, LeftDis = 200, RightDis = 210 }; NowCtrl_30m = new CoatingCtrlElement() { FilmMove = 0, Pump = 90, LeftDis = 200, RightDis = 210 }; } public void OnPoll(double filmMove) { for (int i = 0; i < mCtrlElement.Count(); i++) { if (mCtrlElement[i].FilmMove<mCoating.OvenLength) { mCtrlElement[i].FilmMove += filmMove; } } for (int i = 0; i < mCtrlElement.Count(); i++) { if (mCtrlElement[i].FilmMove>=mCoating.OvenLength) { CoatingAction(NowCtrl_30m, mCtrlElement[i], mCoating.Datas_Vertical_30m, mCoating.Datas_Horizontal_30m, mCoating.NotifyDatas30mChanged); mCtrlElement.RemoveAt(i); i--; } else break; } } /// <summary> /// 控制量生效 /// </summary> /// <param name="element"></param> /// <param name="datas_vertical"></param> /// <param name="datas_horizontal"></param> void CoatingAction(CoatingCtrlElement now, CoatingCtrlElement element, List<Coating.DataInfo> datas_vertical, List<Coating.DataInfo> datas_horizontal, Action NotifyDatasChanged) { if (CoatingMode == COATINGMODE.Extrusion) { double d_left = element.LeftDis - now.LeftDis; double d_right = element.RightDis - now.RightDis; double d = (d_right - d_left) / LeftRightFactor * 100; for (int i = 0; i < datas_horizontal.Count(); i++) { datas_horizontal[i].Thick += (int)(d * i / (datas_horizontal.Count() - 1) - d / 2); } double d_pump = element.Pump - now.Pump; d = (d_pump / PumpFactor) * 100; for (int i = 0; i < datas_vertical.Count(); i++) { FLY.Simulation.Coating.Coating.DataInfo vi = datas_vertical[i]; vi.Thick += (int)d; datas_vertical[i] = vi; } } else { double d_left = element.LeftDis - now.LeftDis; double d_right = element.RightDis - now.RightDis; double d = (d_right - d_left) / LeftRightFactor * 100; for (int i = 0; i < datas_horizontal.Count(); i++) { datas_horizontal[i].Thick += (int)(d * i / (datas_horizontal.Count() - 1) - d / 2); } d = (d_left + d_right) / 2 / LeftRightFactor * 100; for (int i = 0; i < datas_vertical.Count(); i++) { FLY.Simulation.Coating.Coating.DataInfo vi = datas_vertical[i]; vi.Thick += (int)d; datas_vertical[i] = vi; } } now.Pump = element.Pump; now.LeftDis = element.LeftDis; now.RightDis = element.RightDis; now.Time = element.Time; NotifyDatasChanged(); } public void SetCoatingCtrl(double pump, double left, double right) { CoatingCtrlElement element = new CoatingCtrlElement() { Pump = pump, LeftDis = left, RightDis = right }; mCtrlElement.Add(element); CoatingAction(NowCtrl, element, mCoating.Datas_Vertical, mCoating.Datas_Horizontal, mCoating.NotifyDatasChanged); } protected void NotifyPropertyChanged(string propertyname) { if (PropertyChanged != null) { PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyname)); } } public event PropertyChangedEventHandler PropertyChanged; } }