/// <summary> /// Generates a 3-letter pillow profile using an intelligent algorithm for the specified customer. /// </summary> /// <param name="position"></param> /// <param name="pressureMeasurementSupine">Expects 12 measurement values between 0 and 100 millibar as measured with the test person laying on the back.</param> /// <param name="pressureMeasurementLateral">Expects 12 measurement values between 0 and 100 millibar as measured with the test person laying on the side.</param> /// <param name="gender"></param> /// <param name="result">Holds the resulting pillow setup that was generated through this algorithm.</param> /// <returns>NULL if everything went fine or an exception.</returns> public static Exception GenerateProfileBasedOnPressureMapping(TestpersonSleepPositions sleepPosition, int[] pressureMeasurementSupine, int[] pressureMeasurementLateral, Genders gender, out PillowProfileGenerationResult result) { try { PillowBaseModuleVariants baseModule = PillowBaseModuleVariants.NoRole; PillowInsertVariants inserts = PillowInsertVariants.None; PillowWedgeVariants wedge = PillowWedgeVariants.None; if (sleepPosition == TestpersonSleepPositions.Lateral) //calculation for lateral position is more complex than the other 2 { #region Lateral sleeping position int shoulderIndex; /* Determine shoudler index (highest pressure from roles 1-4) */ int[] shoulderAreaArray = pressureMeasurementLateral; shoulderIndex = GenerationUtils.GetIndexOfMaximum(shoulderAreaArray, 0, 3); if (!GenerationUtils.IsLeftSideEqual(shoulderIndex, shoulderAreaArray) && shoulderIndex < 3 && GenerationUtils.IsRightSideEqual(shoulderIndex, shoulderAreaArray)) //if the value to the right is the same, move the shoulder index one to the right (e.g. 17 19 19 15) { shoulderIndex++; } else if (shoulderIndex == 0 && GenerationUtils.IsRightSideEqual(shoulderIndex, shoulderAreaArray) && shoulderAreaArray[2] == shoulderAreaArray[0]) //e.g. 17 17 17 19 { shoulderIndex = 1; } int shoulderIndexPressureValue = pressureMeasurementLateral[shoulderIndex]; //the absolute pressure value in millibar baseModule = PillowBaseModuleVariants.WithRole; //we always have the base module if (gender == Genders.Female) { if (shoulderIndexPressureValue < 8) { inserts = PillowInsertVariants.Thin; wedge = PillowWedgeVariants.ThickTowardsHeadEnd; } else if (shoulderIndexPressureValue < 14) { inserts = PillowInsertVariants.Thick; wedge = PillowWedgeVariants.ThickTowardsHeadEnd; } else { inserts = PillowInsertVariants.Both; wedge = PillowWedgeVariants.ThickTowardsHeadEnd; } } else { if (shoulderIndexPressureValue < 7) { inserts = PillowInsertVariants.Thin; wedge = PillowWedgeVariants.ThickTowardsHeadEnd; } else if (shoulderIndexPressureValue < 13) { inserts = PillowInsertVariants.Thick; wedge = PillowWedgeVariants.ThickTowardsHeadEnd; } else { inserts = PillowInsertVariants.Both; wedge = PillowWedgeVariants.ThickTowardsHeadEnd; } } #endregion } else if (sleepPosition == TestpersonSleepPositions.Supine) { //supine position only adds a wedge for males if (gender == Genders.Male) { baseModule = PillowBaseModuleVariants.WithRole; wedge = PillowWedgeVariants.ThickTowardsHeadEnd; } else { baseModule = PillowBaseModuleVariants.WithRole; } } else if (sleepPosition == TestpersonSleepPositions.Prone) { //prone position is always only with the base module; nothing else baseModule = PillowBaseModuleVariants.WithRole; } //concat the resulting pillow code string code = ((int)baseModule).ToString() + ((int)inserts).ToString() + ((int)wedge).ToString(); result = new PillowProfileGenerationResult() { PillowCode = code, BaseModule = baseModule, Inserts = inserts, Wedge = wedge }; return(null); } catch (Exception ex) { result = default(PillowProfileGenerationResult); return(ex); } }
/// <summary> /// Generates a support profile using an intelligent algorithm for the specified customer. /// </summary> /// <param name="position"></param> /// <param name="pressureMeasurementSupine">Expects 12 measurement values between 0 and 100 millibar as measured with the test person laying on the back.</param> /// <param name="pressureMeasurementLateral">Expects 12 measurement values between 0 and 100 millibar as measured with the test person laying on the side.</param> /// <param name="gender"></param> /// <param name="personHeightCm">The height of the test person in centimeters.</param> /// <param name="personWeightKg">The weight of the test person in kilogram.</param> /// <param name="neutralProfileLetter">The letter representing the neutral (middle) stamp firmness on which the profile is based. For example, Vitario uses 'S' and Ergomometer NL uses 'D' as neutral stamp.</param> /// <param name="result">Holds the resulting profile that was generated through this algorithm. NULL if something went wrong.</param> /// <returns>Null if everything went fine or an exception.</returns> public static Exception GenerateProfileBasedOnPressureMapping(MeasurementPositions position, int[] pressureMeasurementSupine, int[] pressureMeasurementLateral, Genders gender, int personHeightCm, int personWeightKg, char neutralProfileLetter, out StampProfileGenerationResult result) { try { result = default(StampProfileGenerationResult); if (position == MeasurementPositions.Lateral) { int shoulderIndex, lordosisIndex, pelvisIndex = pressureMeasurementSupine.Length - 1; //generate the standard profile string profile = string.Join("", Enumerable.Repeat(neutralProfileLetter, 12)); bool personLyingPositionWrong = false; #region Shoulder /*Shoulder area is always stamps 1-4. If the measurement in supine position is bad (equal values), the measurement in lateral position is used. */ int[] shoulderAreaArray = position == MeasurementPositions.Supine ? pressureMeasurementSupine : pressureMeasurementLateral; shoulderIndex = GenerationUtils.GetIndexOfMaximum(shoulderAreaArray, 0, 3); if (GenerationUtils.IsLeftSideEqual(shoulderIndex, shoulderAreaArray) || shoulderIndex < 3 && GenerationUtils.IsRightSideEqual(shoulderIndex, shoulderAreaArray)) //if one of the values around the shoulder index is the same { shoulderAreaArray = position == MeasurementPositions.Supine ? pressureMeasurementLateral : pressureMeasurementSupine; shoulderIndex = GenerationUtils.GetIndexOfMaximum(shoulderAreaArray, 0, 3); } if (!GenerationUtils.IsLeftSideEqual(shoulderIndex, shoulderAreaArray) && shoulderIndex < 3 && GenerationUtils.IsRightSideEqual(shoulderIndex, shoulderAreaArray)) //if the value to the right is the same, move the shoulder index one to the right (e.g. 17 19 19 15) { shoulderIndex++; } else if (shoulderIndex == 0 && GenerationUtils.IsRightSideEqual(shoulderIndex, shoulderAreaArray) && shoulderAreaArray[2] == shoulderAreaArray[0]) //e.g. 17 17 17 19 { shoulderIndex = 1; } //now generate the profile for this area if (shoulderIndex == 0) { profile = profile.ReplaceAtIndex(0, 'T'); profile = profile.ReplaceAtIndex(1, 'K'); profile = profile.ReplaceAtIndex(2, 'K'); if (GenerationUtils.IsInRange(shoulderAreaArray[0], shoulderAreaArray[1], 2)) //if the first 2 values are similar, the profile changes a bit { profile = profile.ReplaceAtIndex(1, 'T'); profile = profile.ReplaceAtIndex(3, 'K'); } } else if (shoulderIndex == 1) { profile = profile.ReplaceAtIndex(0, 'K'); profile = profile.ReplaceAtIndex(1, 'T'); profile = profile.ReplaceAtIndex(2, 'K'); //if the values around the shoulder index are similar, the profile changes a bit if (GenerationUtils.IsInRange(shoulderAreaArray[0], shoulderAreaArray[1], 2)) { profile = profile.ReplaceAtIndex(0, 'T'); profile = profile.ReplaceAtIndex(3, 'K'); } if (GenerationUtils.IsInRange(shoulderAreaArray[1], shoulderAreaArray[2], 2)) { profile = profile.ReplaceAtIndex(2, 'T'); profile = profile.ReplaceAtIndex(3, 'K'); } } else if (shoulderIndex == 2 || shoulderIndex == 3) //indices at position 2 and 3 are treated the same, but an index at 3 hints that the person is not properly positioned on the mattress { profile = profile.ReplaceAtIndex(0, 'K'); profile = profile.ReplaceAtIndex(1, 'K'); profile = profile.ReplaceAtIndex(2, 'T'); profile = profile.ReplaceAtIndex(3, 'K'); if (shoulderAreaArray[1] + 2 >= shoulderAreaArray[2]) //if the value before the shoulder index is no more less than 2, the profile changes { if (gender == Genders.Female) { profile = profile.ReplaceAtIndex(0, 'T'); profile = profile.ReplaceAtIndex(1, 'T'); } else { profile = profile.ReplaceAtIndex(0, 'W'); profile = profile.ReplaceAtIndex(1, 'T'); } } if (shoulderIndex == 3) { personLyingPositionWrong = true; } } #endregion #region Pelvis area /*Pelvis area is always the peak value from right to left in a specific area. */ int[] pelvisAreaArray = position == MeasurementPositions.Supine ? pressureMeasurementSupine : pressureMeasurementLateral; if (personHeightCm >= 170) { //get the pelvis index (peak value from bottom to top, taking 6 values into account) for (int i = pelvisAreaArray.Length - 1; i >= 6; i--) { if (pelvisAreaArray[i] >= pelvisAreaArray[pelvisIndex]) { pelvisIndex = i; } else { break; } } } if (personHeightCm >= 160) { //get the pelvis index (peak value from bottom to top, taking 4 values into account) for (int i = pelvisAreaArray.Length - 3; i >= 6; i--) { if (pelvisAreaArray[i] >= pelvisAreaArray[pelvisIndex]) { pelvisIndex = i; } else { break; } } } else if (personHeightCm >= 150) { //get the pelvis index (peak value from bottom-3 to top, taking 3 values into account) for (int i = pelvisAreaArray.Length - 4; i >= 6; i--) { if (pelvisAreaArray[i] >= pelvisAreaArray[pelvisIndex]) { pelvisIndex = i; } else { break; } } } else //small persons < 150cm { //get the pelvis index (peak value from bottom-3 to top, taking 4 values into account) for (int i = pelvisAreaArray.Length - 4; i >= 5; i--) { if (pelvisAreaArray[i] >= pelvisAreaArray[pelvisIndex]) { pelvisIndex = i; } else { break; } } } if (pelvisIndex == 11 && personHeightCm < 190) //pelvis area cannot be at the last stamp for person smaller than 190cm { pelvisIndex = 10; } //modify profile profile = profile.ReplaceAtIndex(pelvisIndex, 'K'); if (gender == Genders.Male) //males have a smaller pelvis area --> smaller range of values (+/- 3) and allow only 2 "K"-stamps { if (GenerationUtils.IsInRange(pelvisAreaArray[pelvisIndex], pelvisAreaArray[pelvisIndex - 1], 3)) //if the value before the pelvis index is within 3mB, change its corresponding profile stamp { profile = profile.ReplaceAtIndex(pelvisIndex - 1, 'K'); } } else //females have a bigger pelvis area --> higher range of values (+/- 5) { if (pelvisIndex < 11 && GenerationUtils.IsInRange(pelvisAreaArray[pelvisIndex], pelvisAreaArray[pelvisIndex + 1], 5)) //if the value after the pelvis index is within 4mB, change its corresponding profile stamp { profile = profile.ReplaceAtIndex(pelvisIndex + 1, 'K'); } if (GenerationUtils.IsInRange(pelvisAreaArray[pelvisIndex], pelvisAreaArray[pelvisIndex - 1], 5)) //if the value before the pelvis index is within 5mB, change its corresponding profile stamp { profile = profile.ReplaceAtIndex(pelvisIndex - 1, 'K'); } } #endregion #region Lordosis area /* Lordosis area is between shoulder and pelvis area and can never be before stamp 5. The lordosis index is always the index of the lowest value between shoulder and pelvis. */ //calculate the BMI of the test person (determines which stamp is used in the lordosis area) double heightM = personHeightCm / 100d; double bmi = personWeightKg / (heightM * heightM); //body mass index int[] lordosisAreaArray = position == MeasurementPositions.Supine ? pressureMeasurementSupine : pressureMeasurementLateral; lordosisIndex = GenerationUtils.GetIndexOfMinimum(lordosisAreaArray, 4, pelvisIndex - 1); if (bmi > 30) //special rule: if the person is overweight, the lordosis index should be calculated based on the supine measurement { int lordosisIdxSupine = GenerationUtils.GetIndexOfMinimum(pressureMeasurementSupine, 4, pelvisIndex - 1); int lordosisIdxLateral = GenerationUtils.GetIndexOfMinimum(pressureMeasurementLateral, 4, pelvisIndex - 1); if (lordosisIdxSupine > lordosisIdxLateral) { lordosisIndex = lordosisIdxSupine; } } //this step is useless because we always use the lateral values here if (lordosisAreaArray[lordosisIndex - 1] == lordosisAreaArray[lordosisIndex] && lordosisAreaArray[lordosisIndex + 1] == lordosisAreaArray[lordosisIndex]) //if the values around the lordosis index are equal, try to get a better result by using the lateral measurement { lordosisAreaArray = pressureMeasurementLateral; lordosisIndex = GenerationUtils.GetIndexOfMinimum(lordosisAreaArray, 4, pelvisIndex - 1); } if (personHeightCm > 155 && lordosisIndex <= 4 && gender == Genders.Male) //special rule: lordosis area cannot be at stamp 5 or below for small persons { lordosisIndex = 5; } else if (personHeightCm > 160 && lordosisIndex <= 4 && gender == Genders.Female) //special rule: lordosis area cannot be at stamp 5 or below for small persons { lordosisIndex = 5; } if (pelvisIndex - lordosisIndex > 3) //special rule: if the distance between pelvis and lordosis is more than 2 stamps, something is wrong --> "move" the lordosis index closer to the pelvis index { lordosisIndex = pelvisIndex - 3; } if (pelvisIndex - lordosisIndex == 1) //special rule: if lordosis and pelvis indices were determined to be next to each other, they have to be separated by 1 stamp { lordosisIndex = lordosisIndex - 1; } //modify the profile if ((gender == Genders.Male && bmi < 20) || (gender == Genders.Female && bmi < 19)) //person appears to be underweight --> neutral ("D" or "S") stamp (so the same stamp as in surrounding area) { profile = profile.ReplaceAtIndex(lordosisIndex, neutralProfileLetter); } else if (bmi > 30) //person appears to be clearly overweight --> "B" stamp { profile = profile.ReplaceAtIndex(lordosisIndex, 'B'); } else { profile = profile.ReplaceAtIndex(lordosisIndex, 'L'); //normal weight --> "L" stamp } if (lordosisIndex == pelvisIndex - 1 && profile[lordosisIndex] == 'K') //if the lordosis index is directly before the pelvis index, no 'K'-stamp is allowed in the lordosis area (which can't happen with the current algorithm anyways) { profile = profile.ReplaceAtIndex(lordosisIndex, 'L'); } //special rule: "K" must not come directly after "L" if (profile.Contains("LK")) //"L" must not immediately followed by "K" (distance between lordosis and pelvis area is at least 1 neutral stamp) { profile = profile.Replace("LK", "L" + neutralProfileLetter.ToString()); if (profile.Contains("L" + neutralProfileLetter + neutralProfileLetter)) //e.g. "LDD" { profile = profile.Replace("L" + neutralProfileLetter + neutralProfileLetter, "L" + neutralProfileLetter + "K"); //add the replaced "K" at the end of the pelvis area } } //special rule: if the lordosis index is on stamp 5, stamp 4 must be neutral and stamp 3 must not be "T" if (lordosisIndex == 4) { profile = profile.ReplaceAtIndex(3, neutralProfileLetter); if (profile[2] == 'T') { profile = profile.ReplaceAtIndex(2, 'K'); } } #endregion result = new StampProfileGenerationResult() { SupportProfile = profile.Select(s => s.ToString()).ToArray(), IsPersonLyingPositionWrong = personLyingPositionWrong }; return(null); } else if (position == MeasurementPositions.Supine) { int shoulderIndex, lordosisIndex, pelvisIndex = pressureMeasurementSupine.Length - 1; //generate the standard profile string profile = string.Join("", Enumerable.Repeat(neutralProfileLetter, 12)); bool personLyingPositionWrong = false; #region Shoulder /*Shoulder area is always stamps 1-3. */ int[] shoulderAreaArray = pressureMeasurementSupine; shoulderIndex = GenerationUtils.GetIndexOfMaximum(shoulderAreaArray, 0, 2); //now generate the profile for this area if (shoulderIndex == 0) { profile = profile.ReplaceAtIndex(0, 'T'); profile = profile.ReplaceAtIndex(1, 'K'); profile = profile.ReplaceAtIndex(2, 'K'); } else if (shoulderIndex == 1 || shoulderIndex == 2) { profile = profile.ReplaceAtIndex(0, 'K'); profile = profile.ReplaceAtIndex(1, 'T'); profile = profile.ReplaceAtIndex(2, 'K'); } #endregion #region Pelvis area /*Pelvis area is always the peak value from right to left in a specific area. */ int[] pelvisAreaArray = position == MeasurementPositions.Supine ? pressureMeasurementSupine : pressureMeasurementLateral; if (personHeightCm >= 170) { //get the pelvis index (peak value from bottom to top, taking 6 values into account) for (int i = pelvisAreaArray.Length - 1; i >= 6; i--) { if (pelvisAreaArray[i] >= pelvisAreaArray[pelvisIndex]) { pelvisIndex = i; } else { break; } } } if (personHeightCm >= 160) { //get the pelvis index (peak value from bottom to top, taking 4 values into account) for (int i = pelvisAreaArray.Length - 3; i >= 6; i--) { if (pelvisAreaArray[i] >= pelvisAreaArray[pelvisIndex]) { pelvisIndex = i; } else { break; } } } else if (personHeightCm >= 150) { //get the pelvis index (peak value from bottom-3 to top, taking 3 values into account) for (int i = pelvisAreaArray.Length - 4; i >= 6; i--) { if (pelvisAreaArray[i] >= pelvisAreaArray[pelvisIndex]) { pelvisIndex = i; } else { break; } } } else //small persons < 150cm { //get the pelvis index (peak value from bottom-3 to top, taking 4 values into account) for (int i = pelvisAreaArray.Length - 4; i >= 5; i--) { if (pelvisAreaArray[i] >= pelvisAreaArray[pelvisIndex]) { pelvisIndex = i; } else { break; } } } if (pelvisIndex == 11 && personHeightCm < 190) //pelvis area cannot be at the last stamp for person smaller than 190cm { pelvisIndex = 10; } //modify profile profile = profile.ReplaceAtIndex(pelvisIndex, 'K'); #endregion #region Lordosis area /* Lordosis area is between shoulder and pelvis area and can never be before stamp 5. The lordosis index is always the index of the lowest value between shoulder and pelvis. */ //calculate the BMI of the test person (determines which stamp is used in the lordosis area) double heightM = personHeightCm / 100d; double bmi = personWeightKg / (heightM * heightM); //body mass index int[] lordosisAreaArray = pressureMeasurementSupine; lordosisIndex = GenerationUtils.GetIndexOfMinimum(lordosisAreaArray, 4, pelvisIndex - 1); if (personHeightCm > 155 && lordosisIndex <= 4 && gender == Genders.Male) //special rule: lordosis area cannot be at stamp 5 or below for small persons { lordosisIndex = 5; } else if (personHeightCm > 160 && lordosisIndex <= 4 && gender == Genders.Female) //special rule: lordosis area cannot be at stamp 5 or below for small persons { lordosisIndex = 5; } if (pelvisIndex - lordosisIndex == 1) //special rule: if lordosis and pelvis indices were determined to be next to each other, they have to be separated by 1 stamp { lordosisIndex = lordosisIndex - 1; } //modify the profile if ((gender == Genders.Male && bmi < 20) || (gender == Genders.Female && bmi < 19)) //person appears to be underweight --> neutral ("D" or "S") stamp (so the same stamp as in surrounding area) { profile = profile.ReplaceAtIndex(lordosisIndex, neutralProfileLetter); } else if (bmi > 30) //person appears to be clearly overweight --> "B" stamp { profile = profile.ReplaceAtIndex(lordosisIndex, 'B'); } else { profile = profile.ReplaceAtIndex(lordosisIndex, 'L'); //normal weight --> "L" stamp } #endregion result = new StampProfileGenerationResult() { SupportProfile = profile.Select(s => s.ToString()).ToArray(), IsPersonLyingPositionWrong = personLyingPositionWrong }; return(null); } else { return(null); } } catch (Exception ex) { result = default(StampProfileGenerationResult); return(ex); } }
/// <summary> /// Generates a support profile using an intelligent algorithm for the specified customer. /// </summary> /// <param name="position"></param> /// <param name="pressureMeasurementSupine">Expects 12 measurement values between 0 and 100 millibar as measured with the test person laying on the back.</param> /// <param name="pressureMeasurementLateral">Expects 12 measurement values between 0 and 100 millibar as measured with the test person laying on the side.</param> /// <param name="gender"></param> /// <param name="personHeightCm">The height of the test person in centimeters.</param> /// <param name="personWeightKg">The weight of the test person in kilogram.</param> /// <param name="neutralProfileLetter">The letter representing the neutral (middle) role firmness on which the profile is based. For example, Vitario uses 'S' and Ergomometer NL uses 'D' as neutral element.</param> /// <param name="result">Holds the resulting profile that was generated through this algorithm. NULL if something went wrong.</param> /// <returns>Null if everything went fine or an exception.</returns> public static Exception GenerateProfileBasedOnPressureMapping(MeasurementPositions position, int[] pressureMeasurementSupine, int[] pressureMeasurementLateral, Genders gender, int personHeightCm, int personWeightKg, char neutralProfileLetter, out RoleProfileGenerationResult result) { try { result = default(RoleProfileGenerationResult); if (position == MeasurementPositions.Lateral) { int shoulderIndex, lordosisIndex, pelvisIndex = pressureMeasurementSupine.Length - 1; //generate the standard profile string profile = string.Join("", Enumerable.Repeat(neutralProfileLetter, 12)); bool personLyingPositionWrong = false; #region Shoulder /*Shoulder area is always roles 1-4. If the measurement in supine position is bad (equal values), the measurement in lateral position is used. */ int[] shoulderAreaArray = position == MeasurementPositions.Supine ? pressureMeasurementSupine : pressureMeasurementLateral; shoulderIndex = GenerationUtils.GetIndexOfMaximum(shoulderAreaArray, 0, 3); if (GenerationUtils.IsLeftSideEqual(shoulderIndex, shoulderAreaArray) || shoulderIndex < 3 && GenerationUtils.IsRightSideEqual(shoulderIndex, shoulderAreaArray)) //if one of the values around the shoulder index is the same { shoulderAreaArray = position == MeasurementPositions.Supine ? pressureMeasurementLateral : pressureMeasurementSupine; shoulderIndex = GenerationUtils.GetIndexOfMaximum(shoulderAreaArray, 0, 3); } if (!GenerationUtils.IsLeftSideEqual(shoulderIndex, shoulderAreaArray) && shoulderIndex < 3 && GenerationUtils.IsRightSideEqual(shoulderIndex, shoulderAreaArray)) //if the value to the right is the same, move the shoulder index one to the right (e.g. 17 19 19 15) { shoulderIndex++; } else if (shoulderIndex == 0 && GenerationUtils.IsRightSideEqual(shoulderIndex, shoulderAreaArray) && shoulderAreaArray[2] == shoulderAreaArray[0]) //e.g. 17 17 17 19 { shoulderIndex = 1; } //now generate the profile for this area if (shoulderIndex == 0) { profile = profile.ReplaceAtIndex(0, 'T'); profile = profile.ReplaceAtIndex(1, 'K'); profile = profile.ReplaceAtIndex(2, 'K'); if (GenerationUtils.IsInRange(shoulderAreaArray[0], shoulderAreaArray[1], 2)) //if the first 2 values are similar, the profile changes a bit { profile = profile.ReplaceAtIndex(1, 'T'); profile = profile.ReplaceAtIndex(3, 'K'); } } else if (shoulderIndex == 1) { profile = profile.ReplaceAtIndex(0, 'K'); profile = profile.ReplaceAtIndex(1, 'T'); profile = profile.ReplaceAtIndex(2, 'K'); //if the values around the shoulder index are similar, the profile changes a bit if (GenerationUtils.IsInRange(shoulderAreaArray[0], shoulderAreaArray[1], 2)) { profile = profile.ReplaceAtIndex(0, 'T'); profile = profile.ReplaceAtIndex(3, 'K'); } if (GenerationUtils.IsInRange(shoulderAreaArray[1], shoulderAreaArray[2], 2)) { profile = profile.ReplaceAtIndex(2, 'T'); profile = profile.ReplaceAtIndex(3, 'K'); } } else if (shoulderIndex == 2 || shoulderIndex == 3) //indices at position 2 and 3 are treated the same, but an index at 3 hints that the person is not properly positioned on the mattress { profile = profile.ReplaceAtIndex(0, 'K'); profile = profile.ReplaceAtIndex(1, 'K'); profile = profile.ReplaceAtIndex(2, 'T'); profile = profile.ReplaceAtIndex(3, 'K'); if (shoulderAreaArray[1] + 2 >= shoulderAreaArray[2]) //if the value before the shoulder index is no more less than 2, the profile changes { if (gender == Genders.Female) { profile = profile.ReplaceAtIndex(0, 'T'); profile = profile.ReplaceAtIndex(1, 'T'); } else { profile = profile.ReplaceAtIndex(0, 'W'); profile = profile.ReplaceAtIndex(1, 'T'); } } if (shoulderIndex == 3) { personLyingPositionWrong = true; } } #endregion #region Pelvis area /*Pelvis area is always the peak value from right to left. */ int[] pelvisAreaArray = position == MeasurementPositions.Supine ? pressureMeasurementSupine : pressureMeasurementLateral; //get the pelvis index (peak value from bottom to top, taking 6 values into account) for (int i = pelvisAreaArray.Length - 1; i >= 6; i--) { if (pelvisAreaArray[i] >= pelvisAreaArray[pelvisIndex]) { pelvisIndex = i; } else { break; } } if (pelvisIndex == 11 && personHeightCm < 190) //pelvis area cannot be at the last role for person smaller than 190cm { pelvisIndex = 10; } //modify profile profile = profile.ReplaceAtIndex(pelvisIndex, 'K'); if (gender == Genders.Male) //males have a smaller pelvis area --> smaller range of values (+/- 3) and allow only 2 "K"-roles { if (GenerationUtils.IsInRange(pelvisAreaArray[pelvisIndex], pelvisAreaArray[pelvisIndex - 1], 3)) //if the value before the pelvis index is within 4mB, change its corresponding profile role { profile = profile.ReplaceAtIndex(pelvisIndex - 1, 'K'); } } else //females have a bigger pelvis area --> higher range of values (+/- 5) { if (pelvisIndex < 11 && GenerationUtils.IsInRange(pelvisAreaArray[pelvisIndex], pelvisAreaArray[pelvisIndex + 1], 5)) //if the value after the pelvis index is within 4mB, change its corresponding profile role { profile = profile.ReplaceAtIndex(pelvisIndex + 1, 'K'); } if (GenerationUtils.IsInRange(pelvisAreaArray[pelvisIndex], pelvisAreaArray[pelvisIndex - 1], 5)) //if the value before the pelvis index is within 4mB, change its corresponding profile role { profile = profile.ReplaceAtIndex(pelvisIndex - 1, 'K'); } } #endregion #region Lordosis area /* Lordosis area is between shoulder and pelvis area and can never be before role 5. The lordosis index is always the index of the lowest value between shoulder and pelvis. */ //calculate the BMI of the test person (determines which role is used in the lordosis area) double heightM = personHeightCm / 100d; double bmi = personWeightKg / (heightM * heightM); //body mass index int[] lordosisAreaArray = pressureMeasurementSupine; lordosisIndex = GenerationUtils.GetIndexOfMinimum(lordosisAreaArray, 4, pelvisIndex - 1); if (personHeightCm > 155 && lordosisIndex <= 4 && gender == Genders.Male) //special rule: lordosis area cannot be at role 5 or below for small persons { lordosisIndex = 5; } else if (personHeightCm > 160 && lordosisIndex <= 4 && gender == Genders.Female) //special rule: lordosis area cannot be at role 5 or below for small persons { lordosisIndex = 5; } if (pelvisIndex - lordosisIndex == 1) //special rule: if lordosis and pelvis indices were determined to be next to each other, they have to be separated by 1 role { lordosisIndex = lordosisIndex - 1; } //modify the profile if (bmi > 30) //person appears to be clearly overweight --> "B" element { profile = profile.ReplaceAtIndex(lordosisIndex, 'B'); } else { profile = profile.ReplaceAtIndex(lordosisIndex, neutralProfileLetter); //normal weight --> neutral element } //special rule: "K" must not come directly after "B" if (profile.Contains("BK")) //"B" must not be immediately followed by "K" (distance between lordosis and pelvis area is at least 1 neutral role) { profile = profile.Replace("BK", "B" + neutralProfileLetter).Replace("B" + neutralProfileLetter + neutralProfileLetter, "B" + neutralProfileLetter + "K"); //also add the replaced "K" at the end of the pelvis area } #endregion result = new RoleProfileGenerationResult() { SupportProfile = profile.Select(s => s.ToString()).ToArray(), IsPersonLyingPositionWrong = personLyingPositionWrong }; return(null); } else if (position == MeasurementPositions.Supine) { int shoulderIndex, lordosisIndex, pelvisIndex = pressureMeasurementSupine.Length - 1; //generate the standard profile string profile = string.Join("", Enumerable.Repeat(neutralProfileLetter, 12)); bool personLyingPositionWrong = false; #region Shoulder /*Shoulder area is always roles 1-3. Ony stam 1 and 2 can be changed to 'T'. */ int[] shoulderAreaArray = pressureMeasurementSupine; shoulderIndex = GenerationUtils.GetIndexOfMaximum(shoulderAreaArray, 0, 2); //now generate the profile for this area if (shoulderIndex == 0) { profile = profile.ReplaceAtIndex(0, 'T'); profile = profile.ReplaceAtIndex(1, 'K'); profile = profile.ReplaceAtIndex(2, 'K'); } else if (shoulderIndex == 1 || shoulderIndex == 2) { profile = profile.ReplaceAtIndex(0, 'K'); profile = profile.ReplaceAtIndex(1, 'T'); profile = profile.ReplaceAtIndex(2, 'K'); } #endregion #region Pelvis area /*Pelvis area is always the peak value from right to left. */ int[] pelvisAreaArray = pressureMeasurementSupine; //get the pelvis index (peak value from bottom to top, taking 6 values into account) for (int i = pelvisAreaArray.Length - 1; i >= 6; i--) { if (pelvisAreaArray[i] >= pelvisAreaArray[pelvisIndex]) { pelvisIndex = i; } else { break; } } if (pelvisIndex == 11 && personHeightCm < 190) //pelvis area cannot be at the last role for person smaller than 190cm { pelvisIndex = 10; } //modify profile profile = profile.ReplaceAtIndex(pelvisIndex, 'K'); #endregion #region Lordosis area /* Lordosis area is between shoulder and pelvis area and can never be before role 5. The lordosis index is always the index of the lowest value between shoulder and pelvis. */ //calculate the BMI of the test person (determines which role is used in the lordosis area) double heightM = personHeightCm / 100d; double bmi = personWeightKg / (heightM * heightM); //body mass index int[] lordosisAreaArray = pressureMeasurementSupine; lordosisIndex = GenerationUtils.GetIndexOfMinimum(lordosisAreaArray, 4, pelvisIndex - 1); if (personHeightCm > 155 && lordosisIndex <= 4 && gender == Genders.Male) //special rule: lordosis area cannot be at role 5 or below for small persons { lordosisIndex = 5; } else if (personHeightCm > 160 && lordosisIndex <= 4 && gender == Genders.Female) //special rule: lordosis area cannot be at role 5 or below for small persons { lordosisIndex = 5; } if (pelvisIndex - lordosisIndex == 1) //special rule: if lordosis and pelvis indices were determined to be next to each other, they have to be separated by 1 role { lordosisIndex = lordosisIndex - 1; } //modify the profile if (bmi > 30) //person appears to be clearly overweight --> "B" role { profile = profile.ReplaceAtIndex(lordosisIndex, 'B'); } else { profile = profile.ReplaceAtIndex(lordosisIndex, neutralProfileLetter); //normal weight --> neutral role } //special rule: "K" must not come directly after "B" if (profile.Contains("BK")) //"B" must not immediately followed by "K" (distance between lordosis and pelvis area is at least 1 neutral role) { profile = profile.Replace("BK", "B" + neutralProfileLetter).Replace("B" + neutralProfileLetter + neutralProfileLetter, "B" + neutralProfileLetter + "K"); //also add the replaced "K" at the end of the pelvis area } #endregion result = new RoleProfileGenerationResult() { SupportProfile = profile.Select(s => s.ToString()).ToArray(), IsPersonLyingPositionWrong = personLyingPositionWrong }; return(null); } else { return(null); } } catch (Exception ex) { result = default(RoleProfileGenerationResult); return(ex); } }
/// <summary> /// Generates a profile based in the input person data. /// An Liegesimulator_2._0 profile consists of 4 letters. 3 of these letters are the same, the other one is individual. The individual one can have 1 out of 3 available firmnesses. /// The position of the individual profile role is based on the position of the person's lordosis area. /// This algorithm attempts to find the position and hardness of the individual role and returns a support profile. /// Currently, the lordosis is considered to be between then 6th and the 9th role and thus one of these roles has to be the individual one. All other roles are set to the neutral letter 'N'. /// </summary> /// <param name="gender"></param> /// <param name="height">Height in cm.</param> /// <param name="weight">Weight in kg.</param> /// <param name="pressureMeasurementValues">4 measurement values from the simulator's pressure measurement.</param> /// <returns></returns> public static Exception GetProfileForPerson(MeasurementPositions position, Genders gender, int height, int weight, int[] pressureMeasurementSupine, int[] pressureMeasurementLateral, out SfContactProfile result) { result = default(SfContactProfile); if (pressureMeasurementSupine == null || pressureMeasurementSupine.Length != 12) { return(new ArgumentException("Measurement values invalid!", "pressureMeasurementSupine")); } if (pressureMeasurementLateral == null || pressureMeasurementLateral.Length != 12) { return(new ArgumentException("Measurement values invalid!", "pressureMeasurementLateral")); } if (height < 1 || weight < 1) { return(new ArgumentException("Body data invalid!", "height/weight")); } result = new SfContactProfile() { Gender = gender, Height = height, Weight = weight }; result.SupportProfile = "NNNN".ToStringArray(); /*Pelvis area is always the peak value from right to left. */ int[] measurementArray = position == MeasurementPositions.Supine ? pressureMeasurementSupine : pressureMeasurementLateral; int pelvisIndex = measurementArray.Length - 1; //get the pelvis index (peak value from bottom to top, taking 6 values into account) for (int i = measurementArray.Length - 1; i >= 6; i--) { if (measurementArray[i] >= measurementArray[pelvisIndex]) { pelvisIndex = i; } else if (measurementArray[i] < measurementArray[pelvisIndex]) { break; } } if (pelvisIndex == 11 && height < 190) //pelvis area cannot be at the last stamp for person smaller than 190cm { pelvisIndex = 10; } if (measurementArray[pelvisIndex] == measurementArray[pelvisIndex - 1]) { pelvisIndex--; } /* now try to find the position of the lordosis role in order to be able to modify the hardness of the role in that position */ int lordosisIndex = GenerationUtils.GetIndexOfMinimum(measurementArray, 5, pelvisIndex - 1); /*special rules to make sure the profile makes sense */ if (lordosisIndex + 1 == pelvisIndex) //lordosis and pelvis index must not be after one another { lordosisIndex--; } if (lordosisIndex < 5) { lordosisIndex = 5; //lordosis must always be between role 6 and role 9 } else if (lordosisIndex > 8) { lordosisIndex = 8; //lordosis must always be between role 6 and role 9 } //calculate BMI double bmi = weight / (Math.Pow((double)height / 100d, 2)); //determine the position and hardness of the individual lordosis role string replacementLetter = bmi < 20 ? "G" : bmi < 27 ? "R" : "B"; //< 20 means underweight person --> soft role. 20-27 = normal. >27 = overweight person --> firm role. int replacementIndex = lordosisIndex - 5; //-5 because the 4 roles used in Liegesimulator_2._0 are roles 6 through 9 (and the indices represent roles 1 through 12) result.SupportProfile = result.SupportProfile.ReplaceAtIndex(replacementIndex, replacementLetter[0]); //replace the normal role in the standard profile with the individual role that was generated by the algorithm result.FirmRoleIndex = lordosisIndex; return(null); }
/// <summary> /// Generates a profile based in the input person data. /// An Ergo 4 profile consists of 4 letters. 3 of these letters are the same, the other one is individual. /// The position of the individual profile role is based on the position of the person's lordosis area and the firmness of the role is based on the body mass index of the person. /// This algorithm attempts to find the position and firmness of the individual role as well as the firmness of the 3 remaining roles and returns a support profile. /// </summary> /// <param name="gender"></param> /// <param name="height"></param> /// <param name="weight"></param> /// <param name="pressureMeasurementValues"></param> /// <returns></returns> public static Exception GenerateProfileBasedOnPressureMapping(Genders gender, int height, int weight, int[] pressureMeasurementValuesComplete, out Ergo4ProfileGenerationResult result) { try { result = null; if (pressureMeasurementValuesComplete == null || pressureMeasurementValuesComplete.Length != 12) { return(new ArgumentException("pressureMeasurementValuesComplete is invalid: required length is 12.")); } int[] pressureMeasurementValues = new int[4]; //Ergo 4 only has individual roles in the lordosis area Array.Copy(pressureMeasurementValuesComplete, 4, pressureMeasurementValues, 0, 4); result = new Ergo4ProfileGenerationResult(); //calculate BMI double bmi = weight / (Math.Pow(((double)height) / 100, 2)); char replacementLetter = ' '; //this is used to hold the letter of the individual role int replacementIndex = -1; //this holds the position of the individual role in the profile if (gender == Genders.Female) { //determine mattress hardness and standard profile based on BMI if (bmi < 19) { result.Firmness = FirmnessLevels.H1; result.SupportProfile = "0000"; replacementLetter = '1'; } else if (bmi < 25) { result.Firmness = FirmnessLevels.H2; result.SupportProfile = "1111"; replacementLetter = '2'; } else if (bmi < 29) { result.Firmness = FirmnessLevels.H3; result.SupportProfile = "2111"; replacementLetter = '3'; } else { result.Firmness = FirmnessLevels.H4; result.SupportProfile = "2111"; replacementLetter = '3'; } } else { //determine mattress hardness and standard profile based on BMI if (bmi < 20) { result.Firmness = FirmnessLevels.H1; result.SupportProfile = "0000"; replacementLetter = '1'; } else if (bmi < 26) { result.Firmness = FirmnessLevels.H2; result.SupportProfile = "1111"; replacementLetter = '2'; } else if (bmi < 30) { result.Firmness = FirmnessLevels.H3; result.SupportProfile = "2111"; replacementLetter = '3'; } else { result.Firmness = FirmnessLevels.H4; result.SupportProfile = "2111"; replacementLetter = '3'; } } /*now try to find the position of the lordosis role in order to be able to modify the hardness of the role in that position */ int maxIndex = GenerationUtils.GetIndexOfMaximum(pressureMeasurementValues, 0, pressureMeasurementValues.Length - 1); int maxValue = pressureMeasurementValues[maxIndex]; bool maxValueIsDistinct = GenerationUtils.IsValueDistinct(maxValue, pressureMeasurementValues); //make sure that the max value only occurs once //method 1: if the highest value is on position 2, 3 or 4, take the role before that if (maxValueIsDistinct && maxIndex > 0) { replacementIndex = maxIndex - 1; //role before the one with the highest pressure is individual result.GenerationMethod = "1"; } else if (pressureMeasurementValues[1] > pressureMeasurementValues[0] && pressureMeasurementValues[1] > pressureMeasurementValues[3] && pressureMeasurementValues[1] == pressureMeasurementValues[2]) { //if the 2 middle values are equal and both are higher than the first and last value (e.g. 7 11 11 6) replacementIndex = 1; //the second role is individual result.GenerationMethod = "2"; } else if (pressureMeasurementValues[3] > pressureMeasurementValues[0] && pressureMeasurementValues[3] > pressureMeasurementValues[1] && pressureMeasurementValues[3] == pressureMeasurementValues[2]) { //if the 2 last values are equal and the highest ones (e.g. 6 7 11 11) replacementIndex = 2; //the third role is individual result.GenerationMethod = "3"; } else //standard method (no pattern recognized): set individual role based on height and BMI { if (gender == Genders.Female) { if (height < 166) { replacementIndex = 0; } else if (height < 180) { replacementIndex = 1; } else { replacementIndex = 2; } } else { if (height < 166) { replacementIndex = 0; } else if (height < 180) { replacementIndex = 1; } else if (height < 190) { replacementIndex = 2; } else { replacementIndex = 3; } } result.GenerationMethod = "Std"; } if (replacementIndex < 0 || (replacementLetter == ' ')) //could not generate a profile, should not happen { return(null); } //replace one neutral role in the standard profile with the individual role that was defined by the algorithm string numberProfile = GenerationUtils.ReplaceAtIndex(result.SupportProfile, replacementIndex, replacementLetter); //convert the number indexes in roles result.SupportProfile = ReplaceNumbersProfileWithLetters(numberProfile); return(null); } catch (Exception ex) { result = null; return(ex); } }