//public void EmulatePCMSync() //{ // double[] returnArray = new double[2]; // returnArray[0] = double.NaN; // returnArray[1] = double.NaN; // if (fordPCMHelper == null) // { // MessageBox.Show("You must load a .CSV file first!"); // return; // } // if (!fordPCMHelper.fileLoaded) // { // MessageBox.Show("You must load a .HPT file first!"); // return; // } // int indexOfPulse, indexOfCalculatedLoad, indexOfMAP, indexOfTPS, indexOfCamAngle, indexOfRPM, indexOfMapPerAirmass, indexOfMapPerZeroAirmass, indexOfAirMass, indexOfFuelMassViaSD, indexOfFuelMassViaInjMs, indexOfCalculatedInjectorPW, indexOfCalculatedAFR, indexOfCalculatedInjectorPWTrimmed, indexOfFuelTrim; // indexOfCamAngle = Array.FindIndex(csvHeaders, x => (x.IndexOf("cam angle", StringComparison.OrdinalIgnoreCase) >= 0)); // indexOfRPM = Array.FindIndex(csvHeaders, x => (x.IndexOf("rpm", StringComparison.OrdinalIgnoreCase) >= 0)); // indexOfTPS = Array.FindIndex(csvHeaders, x => (x.IndexOf("ETC throttle", StringComparison.OrdinalIgnoreCase) >= 0)); // indexOfMAP = Array.FindIndex(csvHeaders, x => (x.IndexOf("MANIFOLD ABSOLUTE PRESSURE", StringComparison.OrdinalIgnoreCase) >= 0)); // indexOfPulse = Array.FindIndex(csvHeaders, x => (x.IndexOf("FUEL PULSEWIDTH", StringComparison.OrdinalIgnoreCase) >= 0)); // indexOfFuelTrim = Array.FindIndex(csvHeaders, x => (x.IndexOf("FUEL TRIM", StringComparison.OrdinalIgnoreCase) >= 0)); // if (indexOfMAP == -1) // { // MessageBox.Show("Couldn't find MAP entry in csv data!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); // return; // } // if (indexOfCamAngle == -1) // { // MessageBox.Show("Couldn't find cam angle entry in csv data!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); // return; // } // if (indexOfRPM == -1) // { // MessageBox.Show("Couldn't find rpm entry in csv data!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); // return; // } // if (indexOfTPS == -1) // { // MessageBox.Show("Couldn't find TPS entry in csv data, we will assume commanded lambda is always 1.0", "Error", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); // return; // } // indexOfMapPerAirmass = Array.IndexOf(csvHeaders, "Map per Airmass"); // indexOfMapPerZeroAirmass = Array.IndexOf(csvHeaders, "Map per Zero Airmass"); // indexOfAirMass = Array.IndexOf(csvHeaders, "Calculated Airmass"); // indexOfFuelMassViaSD = Array.IndexOf(csvHeaders, "Calculated Fuel Mass via SD"); // indexOfFuelMassViaInjMs = Array.IndexOf(csvHeaders, "Calculated Fuel Mass via Pulsewidth"); // indexOfCalculatedInjectorPW = Array.IndexOf(csvHeaders, "Calculated Injector Pulsewidth"); // indexOfCalculatedInjectorPWTrimmed = Array.IndexOf(csvHeaders, "Calculated Injector Pulsewidth With Fuel Trim"); // indexOfCalculatedAFR = Array.IndexOf(csvHeaders, "Calculated Commanded AFR"); // indexOfCalculatedLoad = Array.IndexOf(csvHeaders, "Calculated Load"); // int arrayResizeAmount = 0; // if (indexOfMapPerAirmass == -1) // { // indexOfMapPerAirmass = csvHeaders.Length; // arrayResizeAmount++; // } // if (indexOfMapPerZeroAirmass == -1) // { // indexOfMapPerZeroAirmass = csvHeaders.Length + arrayResizeAmount; // arrayResizeAmount++; // } // if (indexOfAirMass == -1) // { // indexOfAirMass = csvHeaders.Length + arrayResizeAmount; // arrayResizeAmount++; // } // if (indexOfFuelMassViaSD == -1) // { // indexOfFuelMassViaSD = csvHeaders.Length + arrayResizeAmount; // arrayResizeAmount++; // } // if (indexOfFuelMassViaInjMs == -1) // { // indexOfFuelMassViaInjMs = csvHeaders.Length + arrayResizeAmount; // arrayResizeAmount++; // } // if (indexOfCalculatedInjectorPW == -1) // { // indexOfCalculatedInjectorPW = csvHeaders.Length + arrayResizeAmount; // arrayResizeAmount++; // } // if (indexOfCalculatedInjectorPWTrimmed == -1) // { // indexOfCalculatedInjectorPWTrimmed = csvHeaders.Length + arrayResizeAmount; // arrayResizeAmount++; // } // if (indexOfCalculatedAFR == -1) // { // indexOfCalculatedAFR = csvHeaders.Length + arrayResizeAmount; // arrayResizeAmount++; // } // if (indexOfCalculatedLoad == -1) // { // indexOfCalculatedLoad = csvHeaders.Length + arrayResizeAmount; // arrayResizeAmount++; // } // //Create new arrays with 3 extra values, // string[] newCsvHeaders = new string[csvHeaders.Length + arrayResizeAmount]; // double[][] newCsvData = new double[csvData.Length][]; ////Copy the previous data // Array.Copy(csvHeaders, newCsvHeaders, csvHeaders.Length); // csvHeaders.CopyTo(newCsvHeaders, 0); // for (int i = 0; i < csvData.Length; i++) // { // newCsvData[i] = new double[csvData[0].Length + arrayResizeAmount]; // for (int j = 0; j < csvData[0].Length; j++) // { // newCsvData[i][j] = csvData[i][j]; // } // } // //Add the new headers // newCsvHeaders[indexOfMapPerAirmass] = "Map per Airmass"; // newCsvHeaders[indexOfMapPerZeroAirmass] = "Map per Zero Airmass"; // newCsvHeaders[indexOfAirMass] = "Calculated Airmass"; // newCsvHeaders[indexOfFuelMassViaSD] = "Calculated Fuel Mass via SD"; // newCsvHeaders[indexOfFuelMassViaInjMs] = "Calculated Fuel Mass via Pulsewidth"; // newCsvHeaders[indexOfCalculatedInjectorPW] = "Calculated Injector Pulsewidth"; // newCsvHeaders[indexOfCalculatedInjectorPWTrimmed] = "Calculated Injector Pulsewidth With Fuel Trim"; // newCsvHeaders[indexOfCalculatedAFR] = "Calculated Commanded AFR"; // newCsvHeaders[indexOfCalculatedLoad] = "Calculated Load"; // //get stoich // double stoichAFR; // if (!fordPCMHelper.TryGetDouble(2300, out stoichAFR)) // { // MessageBox.Show("Couldn't read Stoich AFR value (2300), we will assume 14.64", "Error", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); // stoichAFR = 14.64; // } // Boolean calculatePulseWidth = true; // //get low slope // double lowSlope; // if (!fordPCMHelper.TryGetDouble(12010, out lowSlope)) // { // MessageBox.Show("Couldn't read Injector Low Slope (12010), we will not be able to calculate pulse width!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); // calculatePulseWidth = false; // } // lowSlope /= 3600.0; // //get high slope // double highSlope; // if (!fordPCMHelper.TryGetDouble(12011, out highSlope)) // { // MessageBox.Show("Couldn't read Injector High Slope (12010), we will not be able to calculate pulse width!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); // calculatePulseWidth = false; // } // highSlope /= 3600.0; // //get offset // double breakpoint; // if (!fordPCMHelper.TryGetDouble(12012, out breakpoint)) // { // MessageBox.Show("Couldn't read Injector breakpoint (12012), we will not be able to calculate pulse width!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); // calculatePulseWidth = false; // } // //get offset // double offset; // if (!fordPCMHelper.TryGetDouble(32050, out offset)) // { // MessageBox.Show("Couldn't read Injector offset at 12.0V (32050), we will not be able to calculate pulse width!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); // //calculatePulseWidth = false; // offset = 0.00146499997936189; // } // double displacement; // if (!fordPCMHelper.TryGetDouble(50000, out displacement)) // { // MessageBox.Show("Couldn't read engine displacement (50000), we will assume 4.0L (0.00172 lb)", "Error", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); // displacement = 0.00172; // } // Boolean lambdaErrorIssued = false; // //int samplesProcessed = 0; // int totalCount = csvData.Length; // //totalCount = 1200; // //for (int i = 0; i < csvData.GetLength(0); i++) // for (int i = 0; i < totalCount; i++) // //Parallel.For(0, csvData.GetLength(0), i => // //Parallel.For(0, totalCount, i => // { // double camAngle = csvData[i][indexOfCamAngle]; // double rpm = csvData[i][indexOfRPM]; // double map = csvData[i][indexOfMAP]; // double csvPulseWidthSeconds = csvData[i][indexOfPulse]; // double fuelTrim = csvData[i][indexOfFuelTrim]; // double TPS = -1.0; // double commandedLambda = 1.0; // //Get the commanded lambda value // if (indexOfTPS != -1) // { // TPS = csvData[i][indexOfTPS]; // TPS *= 1.25; // if (!fordPCMHelper.TryGetTableValue(rpm, TPS, 50151, out commandedLambda)) // { // if (!lambdaErrorIssued) MessageBox.Show(String.Format("Failed to get commanded lambda for {0}rpm {1}TPS%, we will use 1.0 from now on and no longer report anymore errors of this type", rpm, TPS)); // lambdaErrorIssued = true; // commandedLambda = 1.0; // } // } // newCsvData[i][indexOfCalculatedAFR] = commandedLambda; // //interpolate the map per airmass values // double mapPerAirmass; // double mapPerZeroAirmass; // if (!fordPCMHelper.TryGetTableValue(rpm, camAngle, 50051, out mapPerZeroAirmass)) // { // MessageBox.Show(String.Format("Failed to get Map per Zero Airmass for {0}rpm {1} Cam Angle, this is a fatal error, giving up, sorry bro", rpm, camAngle)); // return; // } // if (!fordPCMHelper.TryGetTableValue(rpm, camAngle, 50055, out mapPerAirmass)) // { // MessageBox.Show(String.Format("Failed to get Map per Airmass for {0}rpm {1} Cam Angle, this is a fatal error, giving up, sorry bro", rpm, camAngle)); // return; // } // newCsvData[i][ indexOfMapPerAirmass] = mapPerAirmass; // newCsvData[i][ indexOfMapPerZeroAirmass] = mapPerZeroAirmass; // //Calculate the airmass // double airMassLbs = (map - mapPerZeroAirmass) / mapPerAirmass; // newCsvData[i][indexOfAirMass] = airMassLbs; // //Calculate the load // newCsvData[i][indexOfCalculatedLoad] = airMassLbs / displacement; // //Calculate the fuelmass via the SD maps // double fuelMassViaSD = airMassLbs / (stoichAFR * commandedLambda); // newCsvData[i][indexOfFuelMassViaSD] = fuelMassViaSD; // //Calculate the pulse width // double calculatedPulseWidthSec; // //When below the breakpoint // if (fuelMassViaSD <= breakpoint) // { // calculatedPulseWidthSec = (fuelMassViaSD / lowSlope) + offset; // } // else // { // //fuelmass=high*(ms-(breakpoint*((1/low)-(1/high))+offset)) // //ms=(breakpoint*((1/low)-(1/high))+(fuelmass/highslope)+offset // calculatedPulseWidthSec = (breakpoint * ((1 / lowSlope) - (1 / highSlope))) + (fuelMassViaSD / highSlope) + offset; // } // double calculatedPulseWithMs = (calculatedPulseWidthSec - offset) * 1000.0; // //double calculatedPulseWithMs = (calculatedPulseWidthSec) * 1000.0; // //This is the low cut off // if (calculatedPulseWithMs < 0.2) calculatedPulseWithMs = 0.2; // double csvPulseWidthMs = csvPulseWidthSeconds * 1000.0; // newCsvData[i][indexOfCalculatedInjectorPW] = calculatedPulseWithMs; // double trimmedInjPulse = calculatedPulseWithMs * fuelTrim; // newCsvData[i][indexOfCalculatedInjectorPWTrimmed] = trimmedInjPulse; // //Calculate the fuel mass via a reverse calc of the injector pulse width // double breakpointMs = ((breakpoint / lowSlope) + offset) * 1000.0; // double fuelMassViaInjectorMs; // if(csvPulseWidthMs < breakpointMs) // { // //fuelMassViaInjectorMs = lowSlope * (csvPulseWidthSeconds - offset); // fuelMassViaInjectorMs = lowSlope * (csvPulseWidthSeconds); // } // else // { // //fuelMassViaInjectorMs = highSlope * (csvPulseWidthSeconds - (breakpoint * ((1 / lowSlope) - (1 / highSlope)) + offset)); // fuelMassViaInjectorMs = highSlope * (csvPulseWidthSeconds - (breakpoint * ((1 / lowSlope) - (1 / highSlope)))); // } // newCsvData[i][indexOfFuelMassViaInjMs] = fuelMassViaInjectorMs; // newCsvData[i][indexOfPulse] = newCsvData[i][indexOfPulse] * 1000.0; // } // //}); // //Calculate the R² value // double errorOfCalculatedInjPulse = GetRSquared(newCsvData, indexOfCalculatedInjectorPW, indexOfPulse, 1.0, 1000.0); // double errorOfCalculatedInjPulseTrimmed = GetRSquared(newCsvData, indexOfCalculatedInjectorPWTrimmed, indexOfPulse, 1.0, 1000.0); // double errorOfCalculatedFuelMassPulse = GetRSquared(newCsvData, indexOfFuelMassViaSD, indexOfFuelMassViaInjMs, 1.0, 1.0); // csvHeaders = newCsvHeaders; // csvData = newCsvData; // HelperMethods.WriteCSV(@"C:\temp\test.csv", csvHeaders, csvData); // returnArray[0] = errorOfCalculatedInjPulse; // returnArray[1] = errorOfCalculatedInjPulseTrimmed; // returnArray[2] = errorOfCalculatedFuelMassPulse; // if (HelperMethods.IsValidDouble(returnArray[0])) calculatedInjectorPulseErrorTextBox.Text = String.Format("{0:0.###}", returnArray[0]); // if (HelperMethods.IsValidDouble(returnArray[1])) calculatedInjectorTrimmedPulseErrorTextBox.Text = String.Format("{0:0.###}", returnArray[1]); // if (HelperMethods.IsValidDouble(returnArray[2])) calculatedFuelMassErrorTextBox.Text = String.Format("{0:0.###}", returnArray[2]); // return; //} async Task EmulatePCM(IProgress <int> progress, CancellationToken cts) { Boolean failed = false; double[] results = await Task.Run <double[]>(() => { double[] returnArray = new double[2]; returnArray[0] = double.NaN; returnArray[1] = double.NaN; if (fordPCMHelper == null) { MessageBox.Show("You must load a .CSV file first!"); return(returnArray); } if (!fordPCMHelper.fileLoaded) { MessageBox.Show("You must load a .HPT file first!"); return(returnArray); } int indexOfPulse, indexOfCalculatedLoad, indexOfMAP, indexOfTPS, indexOfCamAngle, indexOfRPM, indexOfMapPerAirmass, indexOfMapPerZeroAirmass, indexOfAirMass, indexOfFuelMassViaSD, indexOfFuelMassViaInjMs, indexOfCalculatedInjectorPW, indexOfCalculatedAFR, indexOfCalculatedInjectorPWTrimmed, indexOfFuelTrim; indexOfCamAngle = Array.FindIndex(csvHeaders, x => (x.IndexOf("cam angle", StringComparison.OrdinalIgnoreCase) >= 0)); indexOfRPM = Array.FindIndex(csvHeaders, x => (x.IndexOf("rpm", StringComparison.OrdinalIgnoreCase) >= 0)); indexOfTPS = Array.FindIndex(csvHeaders, x => (x.IndexOf("ETC throttle", StringComparison.OrdinalIgnoreCase) >= 0)); indexOfMAP = Array.FindIndex(csvHeaders, x => (x.IndexOf("MANIFOLD ABSOLUTE PRESSURE", StringComparison.OrdinalIgnoreCase) >= 0)); indexOfPulse = Array.FindIndex(csvHeaders, x => (x.IndexOf("FUEL PULSEWIDTH", StringComparison.OrdinalIgnoreCase) >= 0)); indexOfFuelTrim = Array.FindIndex(csvHeaders, x => (x.IndexOf("FUEL TRIM", StringComparison.OrdinalIgnoreCase) >= 0)); if (indexOfMAP == -1) { MessageBox.Show("Couldn't find MAP entry in csv data!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return(returnArray); } if (indexOfCamAngle == -1) { MessageBox.Show("Couldn't find cam angle entry in csv data!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return(returnArray); } if (indexOfRPM == -1) { MessageBox.Show("Couldn't find rpm entry in csv data!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return(returnArray); } if (indexOfTPS == -1) { MessageBox.Show("Couldn't find TPS entry in csv data, we will assume commanded lambda is always 1.0", "Error", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); return(returnArray); } indexOfMapPerAirmass = Array.IndexOf(csvHeaders, "Map per Airmass"); indexOfMapPerZeroAirmass = Array.IndexOf(csvHeaders, "Map per Zero Airmass"); indexOfAirMass = Array.IndexOf(csvHeaders, "Calculated Airmass"); indexOfFuelMassViaSD = Array.IndexOf(csvHeaders, "Calculated Fuel Mass via SD"); indexOfFuelMassViaInjMs = Array.IndexOf(csvHeaders, "Calculated Fuel Mass via Pulsewidth"); indexOfCalculatedInjectorPW = Array.IndexOf(csvHeaders, "Calculated Injector Pulsewidth"); indexOfCalculatedInjectorPWTrimmed = Array.IndexOf(csvHeaders, "Calculated Injector Pulsewidth With Fuel Trim"); indexOfCalculatedAFR = Array.IndexOf(csvHeaders, "Calculated Commanded AFR"); indexOfCalculatedLoad = Array.IndexOf(csvHeaders, "Calculated Load"); int arrayResizeAmount = 0; if (indexOfMapPerAirmass == -1) { indexOfMapPerAirmass = csvHeaders.Length; arrayResizeAmount++; } if (indexOfMapPerZeroAirmass == -1) { indexOfMapPerZeroAirmass = csvHeaders.Length + arrayResizeAmount; arrayResizeAmount++; } if (indexOfAirMass == -1) { indexOfAirMass = csvHeaders.Length + arrayResizeAmount; arrayResizeAmount++; } if (indexOfFuelMassViaSD == -1) { indexOfFuelMassViaSD = csvHeaders.Length + arrayResizeAmount; arrayResizeAmount++; } if (indexOfFuelMassViaInjMs == -1) { indexOfFuelMassViaInjMs = csvHeaders.Length + arrayResizeAmount; arrayResizeAmount++; } if (indexOfCalculatedInjectorPW == -1) { indexOfCalculatedInjectorPW = csvHeaders.Length + arrayResizeAmount; arrayResizeAmount++; } if (indexOfCalculatedInjectorPWTrimmed == -1) { indexOfCalculatedInjectorPWTrimmed = csvHeaders.Length + arrayResizeAmount; arrayResizeAmount++; } if (indexOfCalculatedAFR == -1) { indexOfCalculatedAFR = csvHeaders.Length + arrayResizeAmount; arrayResizeAmount++; } if (indexOfCalculatedLoad == -1) { indexOfCalculatedLoad = csvHeaders.Length + arrayResizeAmount; arrayResizeAmount++; } //Create new arrays with 3 extra values, string[] newCsvHeaders = new string[csvHeaders.Length + arrayResizeAmount]; double[][] newCsvData = new double[csvData.Length][]; //Copy the previous data Array.Copy(csvHeaders, newCsvHeaders, csvHeaders.Length); csvHeaders.CopyTo(newCsvHeaders, 0); for (int i = 0; i < csvData.Length; i++) { newCsvData[i] = new double[csvData[0].Length + arrayResizeAmount]; for (int j = 0; j < csvData[0].Length; j++) { newCsvData[i][j] = csvData[i][j]; } } //Add the new headers newCsvHeaders[indexOfMapPerAirmass] = "Map per Airmass"; newCsvHeaders[indexOfMapPerZeroAirmass] = "Map per Zero Airmass"; newCsvHeaders[indexOfAirMass] = "Calculated Airmass"; newCsvHeaders[indexOfFuelMassViaSD] = "Calculated Fuel Mass via SD"; newCsvHeaders[indexOfFuelMassViaInjMs] = "Calculated Fuel Mass via Pulsewidth"; newCsvHeaders[indexOfCalculatedInjectorPW] = "Calculated Injector Pulsewidth"; newCsvHeaders[indexOfCalculatedInjectorPWTrimmed] = "Calculated Injector Pulsewidth With Fuel Trim"; newCsvHeaders[indexOfCalculatedAFR] = "Calculated Commanded AFR"; newCsvHeaders[indexOfCalculatedLoad] = "Calculated Load"; //get stoich double stoichAFR; if (!fordPCMHelper.TryGetDouble(2300, out stoichAFR)) { MessageBox.Show("Couldn't read Stoich AFR value (2300), we will assume 14.64", "Error", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); stoichAFR = 14.64; } Boolean calculatePulseWidth = true; //get low slope double lowSlope; if (!fordPCMHelper.TryGetDouble(12010, out lowSlope)) { MessageBox.Show("Couldn't read Injector Low Slope (12010), we will not be able to calculate pulse width!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); calculatePulseWidth = false; } lowSlope /= 3600.0; //get high slope double highSlope; if (!fordPCMHelper.TryGetDouble(12011, out highSlope)) { MessageBox.Show("Couldn't read Injector High Slope (12010), we will not be able to calculate pulse width!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); calculatePulseWidth = false; } highSlope /= 3600.0; //get offset double breakpoint; if (!fordPCMHelper.TryGetDouble(12012, out breakpoint)) { MessageBox.Show("Couldn't read Injector breakpoint (12012), we will not be able to calculate pulse width!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); calculatePulseWidth = false; } //get offset double offset; if (!fordPCMHelper.TryGetDouble(32050, out offset)) { MessageBox.Show("Couldn't read Injector offset at 12.0V (32050), we will not be able to calculate pulse width!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); //calculatePulseWidth = false; offset = 0.00146499997936189; } double displacement; if (!fordPCMHelper.TryGetDouble(50000, out displacement)) { MessageBox.Show("Couldn't read engine displacement (50000), we will assume 4.0L (0.00172 lb)", "Error", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); displacement = 0.00172; } Boolean lambdaErrorIssued = false; int samplesProcessed = 0; int totalCount = csvData.Length; Parallel.For(0, totalCount, i => { if (failed) { return; } double camAngle = csvData[i][indexOfCamAngle]; double rpm = csvData[i][indexOfRPM]; double map = csvData[i][indexOfMAP]; double csvPulseWidthSeconds = csvData[i][indexOfPulse]; double fuelTrim = csvData[i][indexOfFuelTrim]; double TPS = -1.0; double commandedLambda = 1.0; //Get the commanded lambda value if (indexOfTPS != -1) { TPS = csvData[i][indexOfTPS]; TPS *= 1.25; if (!fordPCMHelper.TryGetTableValue(rpm, TPS, 50151, out commandedLambda)) { if (!lambdaErrorIssued) { MessageBox.Show(String.Format("Failed to get commanded lambda for {0}rpm {1}TPS%, we will use 1.0 from now on and no longer report anymore errors of this type", rpm, TPS)); } lambdaErrorIssued = true; commandedLambda = 1.0; } } newCsvData[i][indexOfCalculatedAFR] = commandedLambda; //interpolate the map per airmass values double mapPerAirmass; double mapPerZeroAirmass; if (!fordPCMHelper.TryGetTableValue(rpm, camAngle, 50051, out mapPerZeroAirmass)) { MessageBox.Show(String.Format("Failed to get Map per Zero Airmass for {0}rpm {1} Cam Angle, this is a fatal error, giving up, sorry bro", rpm, camAngle)); failed = true; return; } if (!fordPCMHelper.TryGetTableValue(rpm, camAngle, 50055, out mapPerAirmass)) { MessageBox.Show(String.Format("Failed to get Map per Airmass for {0}rpm {1} Cam Angle, this is a fatal error, giving up, sorry bro", rpm, camAngle)); failed = true; return; } newCsvData[i][indexOfMapPerAirmass] = mapPerAirmass; newCsvData[i][indexOfMapPerZeroAirmass] = mapPerZeroAirmass; //Calculate the airmass double airMassLbs = (map - mapPerZeroAirmass) / mapPerAirmass; newCsvData[i][indexOfAirMass] = airMassLbs; //Calculate the load newCsvData[i][indexOfCalculatedLoad] = airMassLbs / displacement; //Calculate the fuelmass via the SD maps double fuelMassViaSD = airMassLbs / (stoichAFR *commandedLambda); newCsvData[i][indexOfFuelMassViaSD] = fuelMassViaSD; //Calculate the pulse width double calculatedPulseWidthSec; //When below the breakpoint if (fuelMassViaSD <= breakpoint) { calculatedPulseWidthSec = (fuelMassViaSD / lowSlope) + offset; } else { //fuelmass=high*(ms-(breakpoint*((1/low)-(1/high))+offset)) //ms=(breakpoint*((1/low)-(1/high))+(fuelmass/highslope)+offset calculatedPulseWidthSec = (breakpoint * ((1 / lowSlope) - (1 / highSlope))) + (fuelMassViaSD / highSlope) + offset; } double calculatedPulseWithMs = (calculatedPulseWidthSec - offset) * 1000.0; //This is the low cut off if (calculatedPulseWithMs < 0.2) { calculatedPulseWithMs = 0.2; } double csvPulseWidthMs = csvPulseWidthSeconds * 1000.0; newCsvData[i][indexOfCalculatedInjectorPW] = calculatedPulseWithMs; double trimmedInjPulse = calculatedPulseWithMs *fuelTrim; newCsvData[i][indexOfCalculatedInjectorPWTrimmed] = trimmedInjPulse; //Calculate the fuel mass via a reverse calc of the injector pulse width double breakpointMs = ((breakpoint / lowSlope) + offset) * 1000.0; double fuelMassViaInjectorMs; if (csvPulseWidthMs < breakpointMs) { fuelMassViaInjectorMs = lowSlope * (csvPulseWidthSeconds); } else { fuelMassViaInjectorMs = highSlope * (csvPulseWidthSeconds - (breakpoint * ((1 / lowSlope) - (1 / highSlope)))); } newCsvData[i][indexOfFuelMassViaInjMs] = fuelMassViaInjectorMs; newCsvData[i][indexOfPulse] = newCsvData[i][indexOfPulse] * 1000.0; samplesProcessed++; if (samplesProcessed % 120 == 0) { progress.Report((samplesProcessed * 100 / totalCount)); } }); if (failed) { return(null); } //Calculate the R² value double errorOfCalculatedInjPulse = GetRSquared(newCsvData, indexOfCalculatedInjectorPW, indexOfPulse, 1.0, 1000.0); double errorOfCalculatedInjPulseTrimmed = GetRSquared(newCsvData, indexOfCalculatedInjectorPWTrimmed, indexOfPulse, 1.0, 1000.0); double errorOfCalculatedFuelMassPulse = GetRSquared(newCsvData, indexOfFuelMassViaSD, indexOfFuelMassViaInjMs, 1.0, 1.0); csvHeaders = newCsvHeaders; csvData = newCsvData; HelperMethods.WriteCSV(@"C:\temp\test.csv", csvHeaders, csvData); returnArray[0] = errorOfCalculatedInjPulse; returnArray[1] = errorOfCalculatedInjPulseTrimmed; returnArray[2] = errorOfCalculatedFuelMassPulse; return(returnArray); }); if (failed) { return; } if (HelperMethods.IsValidDouble(results[0])) { calculatedInjectorPulseErrorTextBox.Text = String.Format("{0:0.###}", results[0]); } if (HelperMethods.IsValidDouble(results[1])) { calculatedInjectorTrimmedPulseErrorTextBox.Text = String.Format("{0:0.###}", results[1]); } if (HelperMethods.IsValidDouble(results[2])) { calculatedFuelMassErrorTextBox.Text = String.Format("{0:0.###}", results[2]); } }
static public double GetRSquared(double[][] array1, int index1, int index2, double scale1, double scale2) { double R = 0; try { // sum(xy) int invalidEntries = 0; double sumXY = 0; for (int c = 0; c <= array1.Length - 1; c++) { double number1 = (array1[c][index1] * scale1); double number2 = (array1[c][index2] * scale2); if (!HelperMethods.IsValidDouble(number1) || !HelperMethods.IsValidDouble(number2)) { invalidEntries++; continue; } sumXY = sumXY + (array1[c][index1] * scale1) * (array1[c][index2] * scale2); } // sum(x) double sumX = 0; for (int c = 0; c <= array1.Length - 1; c++) { sumX = sumX + (array1[c][index1] * scale1); } // sum(y) double sumY = 0; for (int c = 0; c <= array1.Length - 1; c++) { sumY = sumY + (array1[c][index2] * scale2); } // sum(x^2) double sumXX = 0; for (int c = 0; c <= array1.Length - 1; c++) { sumXX = sumXX + (array1[c][index1] * scale1) * (array1[c][index1] * scale1); } // sum(y^2) double sumYY = 0; for (int c = 0; c <= array1.Length - 1; c++) { sumYY = sumYY + (array1[c][index2] * scale2) * (array1[c][index2] * scale2); } // n int n = array1.Length - invalidEntries; R = (n * sumXY - sumX * sumY) / (Math.Pow((n * sumXX - Math.Pow(sumX, 2)), 0.5) * Math.Pow((n * sumYY - Math.Pow(sumY, 2)), 0.5)); } catch (Exception ex) { throw (ex); } return(R * R); }