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; /// /// 涂布类型 /// 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 { /// /// 上光纤是亮 /// public bool IsLight; /// /// 下光纤是亮 /// public bool IsLight2; /// /// 厚度值 /// public int Thick; } //当前数据 public List Datas_Vertical = new List();//纵向数据 public List Datas_Horizontal = new List();//横向数据 int datas_horizontal_avg = 0; int datas_vertical_position=0; //30m 后的数据 public List Datas_Vertical_30m = new List();//纵向数据 public List Datas_Horizontal_30m = new List();//横向数据 int datas_vertical_30m_position=0; /// /// 膜宽 /// public int FilmWidth => Datas_Horizontal.Count(); /// /// 膜速度 m/min /// public double FilmVelocity { get; set; } = 12; /// /// 辊周长 mm /// public double MmOfR=120*3.14; /// /// 辊信号长度 mm /// public double MmOfRSignal = 10; /// /// 当前辊位置 mm /// double RPosition = 0; /// /// 膜已经跑了的长度。m /// public double FilmLength { get; set; } /// /// 烘箱长度 30m /// public double OvenLength = 30; /// /// 辊信号 /// public bool RSignal; /// /// 上纵向信号 /// public bool VSignal; /// /// 下纵向信号 /// public bool VSignal2; /// /// 上横向信号 /// public bool HSignal; /// /// 下横向信号 /// 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(); } /// /// 获取30m后的数据 /// /// /// 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); } /// /// 上一个时间点 /// 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); } /// /// 每1mm更新一次 /// public event Action 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" }; } } /// /// 涂布控制量 /// public class CoatingCtrlElement:INotifyPropertyChanged { /// /// 控制的时间 /// 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"); } } } /// /// 膜移动的距离 /// 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 { /// /// 挤压涂布 /// Extrusion, /// /// 转移涂布 /// Transfer } /// /// 涂布类型 /// public COATINGMODE CoatingMode = COATINGMODE.Extrusion; /// /// 泵速因子 1 个 面密度 = N个泵速, 只有挤压涂布有效 /// public double PumpFactor = 0.5; /// /// 左右刀因子 1个面密度 = N个左右刀 /// public double LeftRightFactor = 1; /// /// 当前涂布控制量 /// public CoatingCtrlElement NowCtrl; CoatingCtrlElement NowCtrl_30m; #endregion /// /// 控制量 /// List mCtrlElement = new List(); 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) { CoatingAction(NowCtrl_30m, mCtrlElement[i], mCoating.Datas_Vertical_30m, mCoating.Datas_Horizontal_30m, mCoating.NotifyDatas30mChanged); mCtrlElement.RemoveAt(i); i--; } else break; } } /// /// 控制量生效 /// /// /// /// void CoatingAction(CoatingCtrlElement now, CoatingCtrlElement element, List datas_vertical, List 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; } }