Beispiel #1
0
        public static void CreateFileForAutomationLab(Result result, string filePath)
        {
            using (StreamWriter outFile = new StreamWriter(filePath))
            {
                //Header Line
                outFile.WriteLine("Metric,Value");


                //Overall Section - Write the overall score
                FeatureDetail overallMOSDetail = result.GetOverallMOS();
                outFile.WriteLine("Overall - " + overallMOSDetail.ParameterName + "," + overallMOSDetail.Value + " +/- " + overallMOSDetail.StandardError);

                //Each Category
                foreach (Category category in result.outputCategoryList)
                {
                    foreach (FeatureDetail featureDetail in category.FeatureDetails)
                    {
                        outFile.WriteLine(category.Name + " - Aggregate - " + featureDetail.ParameterName + "," + featureDetail.Value + " +/- " + featureDetail.StandardError);
                    }
                }

                //Each Photo
                foreach (Category category in result.outputCategoryList)
                {
                    foreach (Photo photo in category.PhotoList)
                    {
                        foreach (PhotoDetail photoDetail in photo.PhotoDetails)
                        {
                            outFile.WriteLine(category.Name + " - " + photo.Filename + " - " + photoDetail.ParameterName + "," + photoDetail.Value);
                        }
                    }
                }
            }
        }
Beispiel #2
0
        private FeatureDetail AggregateValue(string parameterName, string displayPreference, List <double> valueList)
        {
            //Formulas used from http://www.sjsu.edu/faculty/gerstman/StatPrimer/estimation.pdf
            int n = valueList.Count;

            //Calculate Mean
            double mean = valueList.Average();

            //Calculate Standard Deviation
            double sumSquaredDifferences = 0.0;

            foreach (double value in valueList)
            {
                double difference = value - mean;
                sumSquaredDifferences += difference * difference;
            }
            double standardDeviation = Math.Sqrt(sumSquaredDifferences / n);

            //Calculate standard error
            double standardErrorOfMean = standardDeviation / Math.Sqrt(n);

            //Calculate error for 95% confidence
            double confidenceInterval = standardErrorOfMean * TStat(n);

            FeatureDetail aggregateValue = new FeatureDetail();

            aggregateValue.ParameterName        = parameterName;
            aggregateValue.Value                = Math.Round(mean, 1);
            aggregateValue.StandardDeviation    = Math.Round(standardDeviation, 1);
            aggregateValue.StandardError        = Math.Round(standardErrorOfMean, 1);
            aggregateValue.ConfidenceInterval95 = Math.Round(confidenceInterval, 1);
            aggregateValue.DisplayPreference    = displayPreference;
            return(aggregateValue);
        }
Beispiel #3
0
        public ResultPage(Result result, int backCount)
        {
            InitializeComponent();
            this.result          = result;
            this.resultTable     = new ResultTable(result.outputCategoryList);
            this.backCount       = backCount;
            this.DeviceName.Text = result.Name;

            //MOS
            FeatureDetail mosDetail      = this.result.GetOverallMOS();
            double        mosDetailValue = Math.Round(mosDetail.Value, 1);

            this.MOS.Text = double.IsNaN(mosDetail.Value)? Properties.Resources.NA : mosDetailValue.ToString("0.0");
            Grid[] stars = new Grid[5] {
                this.Star1, this.Star2, this.Star3, this.Star4, this.Star5
            };
            PopulateStars(mosDetailValue, stars);
            this.ConfidenceInterval.Text = "Variability: +/- " + mosDetail.StandardError.ToString("0.0");

            CheckErrors();

            //Category MOS
            this.CategoryMOSList.DataContext          = this.result.outputCategoryList;
            this.OverallDetailsListHeader.DataContext = this.result.outputCategoryList;
            this.OverallDetailsList.DataContext       = GetResultTableItems(this.result);

            ResultDetailPageInit();
        }
        private void DisplayResults()
        {
            List <Result> resultList = ResultStore.GetResultList();

            this.resultBrowserPageItems = new ObservableCollection <ResultBrowserPageItem>();
            foreach (Result result in resultList)
            {
                ResultBrowserPageItem resultDetailPageItem = new ResultBrowserPageItem();

                //Get Name
                resultDetailPageItem.Name = result.Name;

                //Get Photo Count
                resultDetailPageItem.PhotoCount = result.PhotoCount();

                //Get MOS
                FeatureDetail overallMOSDetail = result.GetOverallMOS();
                resultDetailPageItem.OverallMOS = double.IsNaN(overallMOSDetail.Value)? Properties.Resources.NA : overallMOSDetail.Value.ToString("0.0");

                //Get Category MOS
                foreach (Category category in result.outputCategoryList)
                {
                    resultDetailPageItem.CategoryMOSList.Add(category.MOSValue);
                }

                resultBrowserPageItems.Add(resultDetailPageItem);
            }
            this.ResultsListView.DataContext = resultBrowserPageItems;

            //Update Header
            if (resultList != null && resultList.Count > 0)
            {
                ObservableCollection <string> resultsHeaderItems = new ObservableCollection <string>();
                foreach (Category category in resultList[0].outputCategoryList)
                {
                    resultsHeaderItems.Add(category.Name);
                }
                this.ResultsHeaderListView.DataContext = resultsHeaderItems;
            }
        }
Beispiel #5
0
        public static void CreateFile(Result result, string filePath)
        {
            using (StreamWriter outFile = new StreamWriter(filePath))
            {
                //Write the overall score
                FeatureDetail overallMOSDetail  = result.GetOverallMOS();
                string        overallMOSHeading = "Overall " + overallMOSDetail.ParameterName + ",Standard Error ";
                string        overallMOS        = overallMOSDetail.Value.ToString("0.0") + "," + overallMOSDetail.StandardError.ToString("0.0");
                outFile.WriteLine(overallMOSHeading);
                outFile.WriteLine(overallMOS);

                outFile.WriteLine("");
                outFile.WriteLine("");

                //Heading for summary section
                string summaryHeading = "Category Name";
                foreach (FeatureDetail featureDetail in result.outputCategoryList.ElementAt(0).FeatureDetails)
                {
                    summaryHeading += "," + featureDetail.ParameterName + ",Standard Error";
                }
                outFile.WriteLine(summaryHeading);

                //Write a summary for each category
                foreach (Category category in result.outputCategoryList)
                {
                    string categorySummary = category.Name;
                    foreach (FeatureDetail featureDetail in category.FeatureDetails)
                    {
                        if (category.MOSValue.Equals(Properties.Resources.NA))
                        {
                            categorySummary += "," + Properties.Resources.NA + "," + Properties.Resources.NA;
                        }
                        else
                        {
                            categorySummary += "," + featureDetail.Value + "," + featureDetail.StandardError;
                        }
                    }
                    outFile.WriteLine(categorySummary);
                }


                outFile.WriteLine("");
                outFile.WriteLine("");

                //Photo Detal Section
                if (result.outputCategoryList.Count > 0)
                {
                    //Use the first photo of the first category to populate the heading for the photo detail section (Data for each file)
                    string commaSeparatedPhotoParameterNames = string.Empty;
                    foreach (PhotoDetail photoDetail in result.outputCategoryList[0].PhotoList[0].PhotoDetails)
                    {
                        commaSeparatedPhotoParameterNames += "," + photoDetail.ParameterName;
                    }
                    commaSeparatedPhotoParameterNames += "," + "Category";
                    outFile.WriteLine("Filename" + commaSeparatedPhotoParameterNames);

                    foreach (Category category in result.outputCategoryList)
                    {
                        if (category.PhotoList.Count > 0)
                        {
                            //Write Each File Parameter
                            foreach (Photo photo in category.PhotoList)
                            {
                                string commaSeparatedPhotoDetails = string.Empty;
                                foreach (PhotoDetail photoDetail in photo.PhotoDetails)
                                {
                                    commaSeparatedPhotoDetails += "," + photoDetail.Value;
                                }
                                commaSeparatedPhotoDetails += "," + category.Name;

                                outFile.WriteLine(photo.Filename + commaSeparatedPhotoDetails);
                            }
                        }
                    }
                }
            }
        }
Beispiel #6
0
        public FeatureDetail GetOverallMOS()
        {
            //Check if any category is empty or Does not have 5 Photos
            foreach (Category category in this.outputCategoryList)
            {
                if (category.MOSValue.Equals(Properties.Resources.NA))
                {
                    FeatureDetail incompleteMOS = new FeatureDetail();

                    //We use the first element for the Parameter name and display preference
                    incompleteMOS.ParameterName = "MOS";
                    incompleteMOS.Value = double.NaN;
                    incompleteMOS.StandardDeviation = Math.Round(0.0, 1);
                    incompleteMOS.StandardError = Math.Round(0.0, 1);
                    incompleteMOS.ConfidenceInterval95 = Math.Round(0.0, 1);

                    return incompleteMOS;
                }
            }

            int lcm = 1;
            foreach (Category category in this.outputCategoryList)
            {
                lcm = LCM(lcm, category.PhotoList.Count);
            }

            //Create a mosList of items where we have equal number of items for each category
            List<double> mosList = new List<double>();
            foreach (Category category in this.outputCategoryList)
            {
                int copyCount = lcm / category.PhotoList.Count;

                foreach (Photo photo in category.PhotoList)
                {
                    foreach (PhotoDetail photoDetail in photo.PhotoDetails)
                    {
                        if (photoDetail.ParameterName == "MOS")
                        {
                            for (int copies = 0; copies < copyCount; copies++)
                            {
                                mosList.Add(photoDetail.Value);
                            }
                        }
                    }
                }
            }

            //Calculate mean
            double mean = mosList.Average();

            //Calculate Standard Deviation
            double sumSquaredDifferences = 0.0;
            foreach (double value in mosList)
            {
                double difference = value - mean;
                sumSquaredDifferences += difference * difference;
            }
            double standardDeviation = Math.Sqrt(sumSquaredDifferences / mosList.Count);

            //Calculate standard error
            double standardErrorOfMean = standardDeviation / Math.Sqrt(mosList.Count);

            FeatureDetail aggregateMOS = new FeatureDetail();

            //We use the first element for the Parameter name and display preference
            aggregateMOS.ParameterName = "MOS";
            aggregateMOS.Value = Math.Round(mean, 1);
            aggregateMOS.StandardDeviation = Math.Round(standardDeviation, 1);
            aggregateMOS.StandardError = Math.Round(standardErrorOfMean, 1);
            aggregateMOS.ConfidenceInterval95 = Math.Round(1.96 * standardDeviation, 1);

            return aggregateMOS;
        }
        public static void CreateFile(Result result, string filePath)
        {
            using (StreamWriter outFile = new StreamWriter(filePath))
            {
                XmlWriterSettings settings = new XmlWriterSettings();
                settings.Async               = false;
                settings.Indent              = true;
                settings.IndentChars         = "\t";
                settings.NewLineOnAttributes = true;

                using (XmlWriter writer = XmlWriter.Create(outFile, settings))
                {
                    //Write the top level Result info
                    writer.WriteStartElement("Result");
                    writer.WriteAttributeString("DeviceName", result.Name);
                    writer.WriteAttributeString("PhotoCount", result.PhotoCount().ToString());

                    //Overall Score
                    FeatureDetail overallMOSDetail = result.GetOverallMOS();
                    writer.WriteStartElement("OverallScore");
                    writer.WriteStartElement("Property");
                    writer.WriteAttributeString("Name", overallMOSDetail.ParameterName);
                    writer.WriteAttributeString("Value", overallMOSDetail.Value.ToString());
                    writer.WriteAttributeString("StandardError", overallMOSDetail.StandardError.ToString());
                    writer.WriteEndElement();
                    writer.WriteEndElement();

                    //Categories
                    writer.WriteStartElement("Categories");
                    foreach (Category category in result.outputCategoryList)
                    {
                        writer.WriteStartElement("Category");
                        writer.WriteAttributeString("Name", category.Name);
                        writer.WriteAttributeString("Value", category.PhotoList.Count.ToString());

                        //Category Score
                        writer.WriteStartElement("Categories");
                        foreach (FeatureDetail featureDetail in category.FeatureDetails)
                        {
                            writer.WriteStartElement("Property");
                            writer.WriteAttributeString("Name", featureDetail.ParameterName);
                            if (category.MOSValue.Equals(Properties.Resources.NA))
                            {
                                writer.WriteAttributeString("Value", Properties.Resources.NA);
                            }
                            else
                            {
                                writer.WriteAttributeString("Value", featureDetail.Value.ToString());
                            }
                            writer.WriteAttributeString("StandardError", featureDetail.StandardError.ToString());
                            writer.WriteEndElement();
                        }
                        writer.WriteEndElement();


                        //Photos
                        writer.WriteStartElement("Photos");
                        foreach (Photo photo in category.PhotoList)
                        {
                            writer.WriteStartElement("Photo");
                            writer.WriteAttributeString("Filename", photo.Filename);
                            writer.WriteAttributeString("Filepath", photo.SourceFilePath);

                            //Photo Details
                            foreach (PhotoDetail photoDetail in photo.PhotoDetails)
                            {
                                if (photoDetail.DisplayPreference == Constants.DisplayPreference.DETAIL_PAGE || photoDetail.DisplayPreference == Constants.DisplayPreference.RESULT_AND_DETAIL_PAGE)
                                {
                                    writer.WriteStartElement("PhotoDetail");
                                    writer.WriteAttributeString("Name", photoDetail.ParameterName);
                                    writer.WriteAttributeString("Value", photoDetail.Value.ToString());
                                    writer.WriteEndElement();
                                }
                            }
                            writer.WriteEndElement();
                        }
                        writer.WriteEndElement();

                        writer.WriteEndElement();
                    }
                    writer.WriteEndElement();

                    writer.WriteEndElement();
                }
            }
        }
Beispiel #8
0
        public FeatureDetail GetOverallMOS()
        {
            //Check if any category is empty or Does not have 5 Photos
            foreach (Category category in this.outputCategoryList)
            {
                if (category.MOSValue.Equals(Properties.Resources.NA))
                {
                    FeatureDetail incompleteMOS = new FeatureDetail();

                    //We use the first element for the Parameter name and display preference
                    incompleteMOS.ParameterName        = "MOS";
                    incompleteMOS.Value                = double.NaN;
                    incompleteMOS.StandardDeviation    = Math.Round(0.0, 1);
                    incompleteMOS.StandardError        = Math.Round(0.0, 1);
                    incompleteMOS.ConfidenceInterval95 = Math.Round(0.0, 1);

                    return(incompleteMOS);
                }
            }

            int lcm = 1;

            foreach (Category category in this.outputCategoryList)
            {
                lcm = LCM(lcm, category.PhotoList.Count);
            }

            //Create a mosList of items where we have equal number of items for each category
            List <double> mosList = new List <double>();

            foreach (Category category in this.outputCategoryList)
            {
                int copyCount = lcm / category.PhotoList.Count;

                foreach (Photo photo in category.PhotoList)
                {
                    foreach (PhotoDetail photoDetail in photo.PhotoDetails)
                    {
                        if (photoDetail.ParameterName == "MOS")
                        {
                            for (int copies = 0; copies < copyCount; copies++)
                            {
                                mosList.Add(photoDetail.Value);
                            }
                        }
                    }
                }
            }

            //Calculate mean
            double mean = mosList.Average();

            //Calculate Standard Deviation
            double sumSquaredDifferences = 0.0;

            foreach (double value in mosList)
            {
                double difference = value - mean;
                sumSquaredDifferences += difference * difference;
            }
            double standardDeviation = Math.Sqrt(sumSquaredDifferences / mosList.Count);

            //Calculate standard error
            double standardErrorOfMean = standardDeviation / Math.Sqrt(mosList.Count);

            FeatureDetail aggregateMOS = new FeatureDetail();

            //We use the first element for the Parameter name and display preference
            aggregateMOS.ParameterName        = "MOS";
            aggregateMOS.Value                = Math.Round(mean, 1);
            aggregateMOS.StandardDeviation    = Math.Round(standardDeviation, 1);
            aggregateMOS.StandardError        = Math.Round(standardErrorOfMean, 1);
            aggregateMOS.ConfidenceInterval95 = Math.Round(1.96 * standardDeviation, 1);

            return(aggregateMOS);
        }
Beispiel #9
0
        static Document CreateDocument(Result result)
        {
            // Create a new MigraDoc document
            Document document = new Document();

            #region Introduction Section

            Section introductionSection = document.AddSection();

            // Page Title
            Paragraph titleParagraph = introductionSection.AddParagraph();
            titleParagraph.Format.Alignment = ParagraphAlignment.Center;
            titleParagraph.AddFormattedText(Properties.Resources.ProductDescription, StyleLibrary.BlackTitleFont);
            titleParagraph.AddFormattedText(" (" + Properties.Resources.ProductName + ")", StyleLibrary.BlackTitleFont);

            // Introductory paragraph Title
            Paragraph introParagraphTitle = introductionSection.AddParagraph();
            introParagraphTitle.AddLineBreak();
            introParagraphTitle.AddLineBreak();
            introParagraphTitle.AddFormattedText("Introduction", StyleLibrary.HeadingFont);

            // Introductory paragraph
            Paragraph introParagraph = introductionSection.AddParagraph();
            introParagraph.AddLineBreak();
            introParagraph.AddFormattedText("VIQET is an easy to use no-reference photo quality evaluation tool. In order to perform photo quality evaluation, VIQET requires a set of photos " +
                                            "from a test device. It computes an overall image MOS score for a device based on the individual computed photo qualities of each image in the set. " +
                                            "The overall MOS is computed based on a number of features extracted from each image. The mapping from extracted features to MOS is based on a " +
                                            "psychophysics study that was conducted to create a large dataset of photos and associated subjective mean opinion ratings. The study was used to learn " +
                                            "a mapping from features to scores. The predicted quality score falls in the range of 1 to 5, where 1 corresponds to a low quality score and 5 corresponds to excellent quality", StyleLibrary.TextFont);

            Paragraph overallParagraphTitle = introductionSection.AddParagraph();
            overallParagraphTitle.AddLineBreak();
            overallParagraphTitle.AddLineBreak();
            overallParagraphTitle.AddFormattedText("Test Results", StyleLibrary.HeadingFont);

            // Overall Scores
            Paragraph overallScoreTitle = introductionSection.AddParagraph();
            overallScoreTitle.AddLineBreak();
            overallScoreTitle.AddFormattedText("Device Name: " + result.Name, StyleLibrary.TextFont);
            overallScoreTitle.AddLineBreak();
            overallScoreTitle.AddFormattedText("Total number of photos: " + result.PhotoList.Count, StyleLibrary.TextFont);
            overallScoreTitle.AddLineBreak();
            overallScoreTitle.AddFormattedText("Tool Version: " + Properties.Resources.VersionName + " " + Constants.Version, StyleLibrary.TextFont);

            FeatureDetail overallMOSDetail = result.GetOverallMOS();
            string        overallMOS       = double.IsNaN(overallMOSDetail.Value) ? "N/A" : overallMOSDetail.Value.ToString("0.0") + " +/-" + overallMOSDetail.StandardError.ToString("0.0");
            overallScoreTitle.AddLineBreak();
            overallScoreTitle.AddLineBreak();
            overallScoreTitle.AddFormattedText("Overall Score: " + overallMOS, StyleLibrary.HeadingFont);

            #endregion

            #region Summary for Categories

            // Categories Summary Section
            Section categoriesSummarySection = document.AddSection();

            // Introductory paragraph
            Paragraph categoriesSummaryParagraphTitle = categoriesSummarySection.AddParagraph();
            categoriesSummaryParagraphTitle.AddFormattedText("Photo Category Results", StyleLibrary.HeadingFont);


            foreach (Category outputCategory in result.outputCategoryList)
            {
                Paragraph categoriesSummaryParagraph = categoriesSummarySection.AddParagraph();
                categoriesSummaryParagraph.AddLineBreak();
                categoriesSummaryParagraph.AddLineBreak();
                categoriesSummaryParagraph.AddFormattedText("Category Name: " + outputCategory.Name, StyleLibrary.TextFontBold);
                categoriesSummaryParagraph.AddLineBreak();

                foreach (FeatureDetail featureDetail in outputCategory.FeatureDetails)
                {
                    if (featureDetail.DisplayPreference == Constants.DisplayPreference.RESULT_PAGE || featureDetail.DisplayPreference == Constants.DisplayPreference.RESULT_AND_DETAIL_PAGE)
                    {
                        categoriesSummaryParagraph.AddLineBreak();
                        if (outputCategory.MOSValue.Equals(Properties.Resources.NA))
                        {
                            categoriesSummaryParagraph.AddFormattedText(featureDetail.ParameterName + ": " + Properties.Resources.NA, StyleLibrary.TextFont);
                        }
                        else
                        {
                            categoriesSummaryParagraph.AddFormattedText(featureDetail.ParameterName + ": " + featureDetail.Value.ToString("0.00") + " +/- " + featureDetail.StandardError.ToString("0.00"), StyleLibrary.TextFont);
                        }
                    }
                }
            }

            #endregion


            #region Photo Details Section

            foreach (Category category in result.outputCategoryList)
            {
                bool firstLine = true;

                foreach (Photo photo in category.PhotoList)
                {
                    // Category Details Section
                    Section categoryDetailsSection = document.AddSection();

                    if (firstLine)
                    {
                        // Introductory paragraph
                        Paragraph categoryDetailsParagraphTitle = categoryDetailsSection.AddParagraph();
                        categoryDetailsParagraphTitle.AddFormattedText("Photos in  " + category.Name + " Category (" + category.PhotoList.Count + " photos)", StyleLibrary.HeadingFont);

                        firstLine = false;
                    }

                    // Introductory paragraph
                    Paragraph paragraphTitle = categoryDetailsSection.AddParagraph();
                    paragraphTitle.AddLineBreak();
                    paragraphTitle.AddFormattedText("Details for " + photo.Filename, StyleLibrary.TextFontBold);
                    paragraphTitle.AddLineBreak();
                    paragraphTitle.AddLineBreak();

                    //Add the source photo
                    Image sourceImage = new Image(photo.SourceFilePath);
                    sourceImage.Height = 200;
                    sourceImage.Width  = 400;

                    Paragraph sourceImageParagraph = categoryDetailsSection.AddParagraph();
                    sourceImageParagraph.Format.Alignment = ParagraphAlignment.Center;
                    sourceImageParagraph.Add(sourceImage);
                    sourceImageParagraph.AddLineBreak();
                    sourceImageParagraph.AddFormattedText("Source Photo", StyleLibrary.TextFont);
                    sourceImageParagraph.AddLineBreak();
                    sourceImageParagraph.AddLineBreak();

                    //Table with values for this photo
                    Table photoDetailsTable = categoryDetailsSection.AddTable();

                    Column photoParameterColumn = photoDetailsTable.AddColumn(Unit.FromCentimeter(6));
                    photoParameterColumn.Format.Alignment = ParagraphAlignment.Left;

                    Column photoValueColumn = photoDetailsTable.AddColumn(Unit.FromCentimeter(3));
                    photoValueColumn.Format.Alignment = ParagraphAlignment.Right;

                    //Add Header Row
                    Row photoHeaderRow = photoDetailsTable.AddRow();
                    photoHeaderRow.Cells[0].AddParagraph().AddFormattedText("Parameter", StyleLibrary.TextFontBold);
                    photoHeaderRow.Cells[1].AddParagraph().AddFormattedText("Value", StyleLibrary.TextFontBold);

                    //Add the details
                    foreach (PhotoDetail photoDetail in photo.PhotoDetails)
                    {
                        if (photoDetail.DisplayPreference == Constants.DisplayPreference.DETAIL_PAGE || photoDetail.DisplayPreference == Constants.DisplayPreference.RESULT_AND_DETAIL_PAGE)
                        {
                            Row detailRow = photoDetailsTable.AddRow();
                            detailRow.Cells[0].AddParagraph().AddFormattedText(photoDetail.ParameterName, StyleLibrary.TextFont);
                            detailRow.Cells[1].AddParagraph().AddFormattedText(photoDetail.Value.ToString("0.00"), StyleLibrary.TextFont);
                        }
                    }

                    //Add the visualization images
                    Section visualizationSection = document.AddSection();
                    foreach (VisualizationImage visualizationImage in photo.VisualizationImages)
                    {
                        Image image = new Image(visualizationImage.FilePath);
                        image.Height = 200;
                        image.Width  = 400;

                        Paragraph visualizationImageParagraph = visualizationSection.AddParagraph();
                        visualizationImageParagraph.AddLineBreak();
                        visualizationImageParagraph.Format.Alignment = ParagraphAlignment.Center;
                        visualizationImageParagraph.Add(image);
                        visualizationImageParagraph.AddLineBreak();
                        visualizationImageParagraph.AddFormattedText(visualizationImage.Visualization, StyleLibrary.TextFont);
                    }
                }
            }

            #endregion

            return(document);
        }
Beispiel #10
0
        private FeatureDetail AggregateValue(string parameterName, string displayPreference, List<double> valueList)
        {
            //Formulas used from http://www.sjsu.edu/faculty/gerstman/StatPrimer/estimation.pdf
            int n = valueList.Count;

            //Calculate Mean
            double mean = valueList.Average();

            //Calculate Standard Deviation
            double sumSquaredDifferences = 0.0;
            foreach (double value in valueList)
            {
                double difference = value - mean;
                sumSquaredDifferences += difference * difference;
            }
            double standardDeviation = Math.Sqrt(sumSquaredDifferences / n);

            //Calculate standard error
            double standardErrorOfMean = standardDeviation / Math.Sqrt(n);

            //Calculate error for 95% confidence
            double confidenceInterval = standardErrorOfMean * TStat(n);

            FeatureDetail aggregateValue = new FeatureDetail();
            aggregateValue.ParameterName = parameterName;
            aggregateValue.Value = Math.Round(mean, 1);
            aggregateValue.StandardDeviation = Math.Round(standardDeviation,1);
            aggregateValue.StandardError = Math.Round(standardErrorOfMean,1);
            aggregateValue.ConfidenceInterval95 = Math.Round(confidenceInterval, 1);
            aggregateValue.DisplayPreference = displayPreference;
            return aggregateValue;
        }