/// <summary> /// Based on the commissioning graph, the power and speed coefficients of each draft between the ballast and the scanlt are obtained. /// </summary> /// <param name="shipParticular">Ship Basic Data</param> /// <param name="seaTrialPowerToSpeedAtBallast">Power Speed Conversion factor(ballast)</param> /// <param name="seaTrialPowerToSpeedAtScant">Power Speed Conversion factor(scant)</param> /// <returns>각 10cm 별 power speed 계수 배열</returns> public static List <double[]> PowerToSpeedTable(SHIP_PARTICULAR shipParticular, dynamic ballastValues, dynamic scantlingValues) { double seatrialdraftScantling = (scantlingValues.DRAFT_FORE + scantlingValues.DRAFT_AFT) * 0.5; //Draft (Scantling) Fore , Draft (Scantling) Aft double seaTrialdraftBallast = (ballastValues.DRAFT_FORE + ballastValues.DRAFT_AFT) * 0.5; //Draft (Ballast) Fore, Draft (Ballast) Aft List <double[]> draftTable = new List <double[]> { }; double startDraft = Math.Truncate((seaTrialdraftBallast - 7) * 10); // ref draft -2 부터 시작 (-2는 여유분) int numerOfDraft = (int)((Math.Truncate((seatrialdraftScantling + 7) * 10)) - (Math.Truncate((seaTrialdraftBallast - 7) * 10))); // 스캔틀링까지 소수점 한자리 까지 검색, 기준 draft보다 -2 +2 만큼 큼 int numberOfPwer = (int)(shipParticular.ME_POWER_MCR / 200); //ME_POWER_MCr double[] powerTable = new double[numberOfPwer]; // 확인 완 200 씩 파워 간격을 띄움 --> 커브피팅 알고리즘으로 x 축 배열 double[] speedTable = new double[numberOfPwer]; // 확인 완 파워 간격 만큼 스피드를 계산 --> 커브피팅 알고리즘으로 y 축 배열s for (int i = 0; i < numerOfDraft; i++) // 드라프트 간격 0.1 만큼 해상도의 커프피팅 테이블을 만듦 { for (int j = 0; j < numberOfPwer; j++) { powerTable[j] = (j + 1) * 200; speedTable[j] = ((scantlingValues.B_POWER_TO_SPEED * Math.Pow(powerTable[j], scantlingValues.A_POWER_TO_SPEED) - ballastValues.B_POWER_TO_SPEED * Math.Pow(powerTable[j], ballastValues.A_POWER_TO_SPEED)) / // Seatrial PowerToSpeed(Scant') (seatrialdraftScantling - seaTrialdraftBallast) * ((i + startDraft) * 0.1 - seaTrialdraftBallast) + (ballastValues.B_POWER_TO_SPEED * Math.Pow(powerTable[j], ballastValues.A_POWER_TO_SPEED))); // Seatrial PowerToSpeed(Ballast') } var curve = CurveFitting.powerRegression(powerTable, speedTable); draftTable.Add(curve); } return(draftTable); }
/// <summary> /// 선박 WindResistance 계산 - ISO15016,ISO19030 /// </summary> /// <param name="airDensityCoef">공기밀도계수 - 온도에 따라 값 결정</param> /// <param name="windCoeff">바람저항계수 - 풍행에 따라 값 결정</param> /// <param name="draft_ref">기준 draft 값 - draft에 따른 수선상 선박 넓이 계산</param> /// <param name="AT_ballast">ballast시 수선상 선박 넓이</param> /// <param name="breadth">선박넓이</param> /// <param name="draft">현재 draft 값</param> /// <param name="airTemp">공기 온도</param> /// <param name="relWindSpeed">상대 풍속(m/s)</param> /// <param name="relWindDir">상대 풍향(m/s)</param> /// <param name="speedVg">선박대지속도(knot)</param> /// <param name="etaD0"></param> /// <param name="etaDM"></param> /// <returns></returns> public double resistanceWind(SHIP_PARTICULAR shipParticular, double[] windCoeff, double draft_ref, double AT_ballast, double breadth, double draft, double airTemp, double airPressure, double relWindSpeed, double relWindDir, double speedVg) { if (relWindDir > 180) { relWindDir = 360 - relWindDir; // 상대풍속을 180도 이내로 제한 (커브피팅이 0 ~ 180도와 360 ~ 180 값이 동일) } else if (relWindDir < 0) { relWindDir = Math.Abs(relWindDir); } var airDensity = this.ConvertAirTempToAirDensity(20, 1013); // 날씨 데이터로 바꿀 것.!!!!!!!! double A_XV = AT_ballast + (draft_ref - draft) * breadth; // 수선상 트랜버스 면적을 드라프트 변화에 따라 계산 double coefRelWind = windCoeff[7] * Math.Pow(relWindDir, 6) + windCoeff[6] * Math.Pow(relWindDir, 5) + windCoeff[5] * Math.Pow(relWindDir, 4) + windCoeff[4] * Math.Pow(relWindDir, 3) + windCoeff[3] * Math.Pow(relWindDir, 2) + windCoeff[2] * relWindDir + windCoeff[1]; double coefZeroWind = windCoeff[1]; //WINDRESISTANCECoef[0] 값 double Rrw = 0.5 * airDensity * coefRelWind * A_XV * Math.Pow(relWindSpeed, 2) * -1; double R0w = 0.5 * airDensity * coefZeroWind * A_XV * Math.Pow(speedVg * 0.5144, 2) * -1; // knot ---> m/s 주의하자 double deltaRw = ((Rrw - R0w) * speedVg * 0.5144) / 1000; if (double.IsNaN(deltaRw) || double.IsInfinity(deltaRw)) { deltaRw = 0; } deltaRw = Math.Round(deltaRw, 2); return(deltaRw); // 풍향이 마이너스로 나온다 확인할거 }
//데이터 수집 public static bool DataRetrieval() { var functionResult = true; //Particular File load shipParticular = CsvFileController.ReadParticularFile("particular.csv"); //speed Power File Load speedPowerData = CsvFileController.ReadSpeedPowerDataFileToList("speedPower.csv"); //draft Data draft = CsvFileController.ReadDraftFile("draft.csv"); //선박 운항 데이터 불러오기 sailingData = CsvFileController.Read19030DataFileToList("voyageData.csv"); foreach (var _d in speedPowerData) { ballastPowerList.Add(_d.BALLAST_POWER); ballastSpeedList.Add(_d.BALLAST_SPEED); scantlingPowerList.Add(_d.SCANTLING_POWER); scantlingSpeedList.Add(_d.SCANTLING_SPEED); } if (shipParticular == null || sailingData == null) { functionResult = false; } return(functionResult); }
/// <summary> /// Create Wind Resistance Data /// </summary> /// <param name="shipParticular">Ship Basic Data</param> /// <param name="dataCount">Count of Sailing Data</param> /// <returns></returns> public static WindResistance CreateWindResistance(SHIP_PARTICULAR shipParticular, int dataCount) { var windResistance = new WindResistance(); //해당 클래스 부르고 windResistance.data = new WindResistanceData(); // 데이터 입력 windResistance.data.SetSize(dataCount); windResistance.data.isAveraging = false; windResistance.data.loa = shipParticular.LOA; windResistance.data.lbp = shipParticular.LOA; windResistance.data.breadth = shipParticular.BREADTH; windResistance.data.windChartType = Models.Enum.WindChartTypes.ITTC; //0 = fujiwara, 1 = ITTC, 2 = WindTunnel windResistance.data.iTTCChartType = Models.Enum.ITTCChartTypes.TankerConventionalLaden; // 0 = ContainerLadenContainer, 1 = ContainerLadenLashing, 2 = ContainerBallastLashing, 3 = ContainerBallast, 4 = TankerConventionalLaden, 5 = TankerConventionalBallast, 6 = TankerCylindericalBallast, 7 = CarCarrierAverage, 8 = LNGSpherical, 9 = LNGPrismaticExtended, 10 = LNGPrismaticIntegrated, 11 = GeneralCargoAverage, 12 = CruiseFerryAverage return(windResistance); }
public static List <ISO19030File> FilteringForReferenceCondition(List <ISO19030File> sailingData, SHIP_PARTICULAR shipParticular, dynamic ballastValues, dynamic scantlingValues, WindResistance windResistance) { int index = 0; foreach (var item in sailingData) { //if (item.VALID_CHAUVENT == true && item.VALID_VALIDATION == true && item.VALID_REFCONDITION == true) //{ var minDraft = (item.DRAFT_FORE + item.DRAFT_AFT) / 2; var deltaT = (ballastValues.DRAFT_FORE + ballastValues.DRAFT_AFT) / 2 - minDraft; var A = shipParticular.TRANSVERSE_PROJECTION_AREA_BALLAST + deltaT * shipParticular.BREADTH; var Za = 18.2 + deltaT; windResistance.data.zref[index] = (shipParticular.TRANSVERSE_PROJECTION_AREA_BALLAST * (10 + deltaT) + 0.5 * shipParticular.BREADTH * Math.Pow(deltaT, 2)) / A; windResistance.data.axv[index] = shipParticular.TRANSVERSE_PROJECTION_AREA_BALLAST + ((ballastValues.DRAFT_FORE + ballastValues.DRAFT_AFT) / 2 - minDraft) * shipParticular.BREADTH; windResistance.data.za[index] = /*shipModelTestData.ZA_BALLAST*/ 18.2 + ((ballastValues.DRAFT_FORE + ballastValues.DRAFT_AFT) / 2 - minDraft); windResistance.data.vg[index] = item.SPEED_VG * 0.5144; windResistance.data.psi0[index] = Math.PI * item.SHIP_HEADING / 180; windResistance.data.rhoair[index] = /*item.AMBIENT_DENSITY;*/ 1.225; windResistance.data.vwr[index] = item.REL_WIND_SPEED; windResistance.data.psiwr[index] = Math.PI * item.REL_WIND_DIR / 180; index++; //} } //바람 저항도 계산 windResistance.CalculateWindResistance(); index = 0; //마지막 필터 계산 foreach (var item in afterValID_shipdata) { var windSpeedTrue = windResistance.data.vwtref[item.ID]; var speedLw = item.SPEED_LW * 0.5144f; //수심의 깊이 체크 var waterDepth1 = 3 * Math.Sqrt(shipParticular.BREADTH * ((item.DRAFT_FORE + item.DRAFT_AFT) / 2)); var waterDepth2 = 2.75 * (speedLw * speedLw) / 9.80665; if (waterDepth1 < waterDepth2) { waterDepth1 = waterDepth2; } if (index == 22) { var check = 0; } if (item.WATER_DEPTH < -999) { item.WATER_DEPTH = 9999; } //수온이 너무 낮거나! 바람의 세기가 8이상 타각이 5이상인걸 날림 if (item.SW_TEMP < 2 || item.WATER_DEPTH <= waterDepth1 || windSpeedTrue > 7.9 || Math.Abs(item.RUDDER_ANGLE) > 5) { sailingData.ElementAt((int)item.ID).VALID_REFCONDITION = false; REF_CONDITION_COUNT++; FILTER_TOTAL_COUNT++; errorList.Add(item.ID); } else { //통과한 것만 넣음 afterRef_shipdata.Add(item); } index++; } return(sailingData); }