コード例 #1
0
ファイル: ChangeReason.cs プロジェクト: rwlamont/AllItUp
        public static ChangeReason AddNewChangeReason(string reason)
        {
            var changeReason = new ChangeReason(ChangeReasons.Count + 1, reason);
            if (reason != null)
            {
                ChangeReasons.Add(changeReason);
                SaveChangeReasons();
            }
            else
                return new ChangeReason(-1, "Reason not specified");

            return changeReason;
        }
コード例 #2
0
ファイル: SensorState.cs プロジェクト: zhangzheng1205/B3
        /// <summary>
        /// Creates a new sensor state with the specified timestamp representing the date it was last edited, a list of values representing data values recorded in this state, and a reason for the changes stored in this state.
        /// </summary>
        /// <param name="owner">The sensor the sensor state belongs to</param>
        /// <param name="editTimestamp">A DateTime object representing the last edit date and time for this sensor state.</param>
        /// <param name="valueList">A list of data values, representing values recorded in this sensor state.</param>
        /// <param name="reason">A string indicating the reason for the changes made in this state.</param>
        /// <param name="isRaw">Whether or not this represents the sensors raw data.</param>
        /// <param name="changes">The list of changes that have occured for this sensor</param>
        public SensorState(Sensor owner, DateTime editTimestamp, Dictionary <DateTime, float> valueList, ChangeReason reason, bool isRaw, Dictionary <DateTime, LinkedList <int> > changes)
        {
            if (valueList == null)
            {
                throw new ArgumentNullException("valueList");
            }

            _reason        = reason;
            _editTimestamp = editTimestamp;
            _valueList     = valueList;
            _isRaw         = isRaw;
            _changes       = changes ?? new Dictionary <DateTime, LinkedList <int> >();
            _owner         = owner;
        }
コード例 #3
0
        public static ChangeReason AddNewChangeReason(string reason)
        {
            var changeReason = new ChangeReason(ChangeReasons.Count + 1, reason);

            if (reason != null)
            {
                ChangeReasons.Add(changeReason);
                SaveChangeReasons();
            }
            else
            {
                return(new ChangeReason(-1, "Reason not specified"));
            }

            return(changeReason);
        }
コード例 #4
0
ファイル: SensorState.cs プロジェクト: zhangzheng1205/B3
        /// <summary>
        /// Returns a new sensor state where the given values are removed
        /// </summary>
        /// <param name="values">The values to remove</param>
        /// <param name="reason">The reason for the change</param>
        /// <returns>The new sensor state</returns>
        public SensorState RemoveValues(List <DateTime> values, ChangeReason reason)
        {
            if (values == null)
            {
                throw new ArgumentException("A non-null list to be removed must be specified");
            }

            var newState = Clone();

            newState.Reason = reason;

            foreach (var time in values)
            {
                newState.Values.Remove(time);
                newState.AddToChanges(time, reason.ID);
            }

            return(newState);
        }
コード例 #5
0
ファイル: SensorState.cs プロジェクト: zhangzheng1205/B3
        public SensorState ChangeToValue(List <DateTime> values, float value, ChangeReason reason)
        {
            if (values == null)
            {
                throw new ArgumentNullException("A non-null list of keys to set as " + value + " must be specified.");
            }

            var newState = Clone();

            newState.Reason = reason;

            foreach (var time in values)
            {
                newState.Values[time] = value;
                newState.AddToChanges(time, reason.ID);
            }

            return(newState);
        }
コード例 #6
0
ファイル: SensorState.cs プロジェクト: rwlamont/AllItUp
 public SensorState(Sensor owner, Dictionary<DateTime, float> valueList, ChangeReason reason, Dictionary<DateTime, LinkedList<int>> changes)
     : this(owner, DateTime.Now, valueList, reason, false, changes)
 {
 }
コード例 #7
0
ファイル: SensorState.cs プロジェクト: rwlamont/AllItUp
        /// <summary>
        /// Given a timestamp which represents a missing value, interpolates the dataset using the first known point before the given point, and the first known point after the given point in the list of keys.
        /// </summary>
        /// <param name="valuesToInterpolate">A list of data point 'keys' where values are missing.</param>
        /// <param name="ds">A dataset to use, which indicates the length of time that elapses between readings.</param>
        /// <returns>A sensor state with the interpolated data.</returns>
        public SensorState Interpolate(List<DateTime> valuesToInterpolate, Dataset ds, ChangeReason reason)
        {
            EventLogger.LogInfo(_owner.Owner, GetType().ToString(), "Starting extrapolation process");

            if (valuesToInterpolate == null)
                throw new ArgumentNullException("valuesToInterpolate");

            if (valuesToInterpolate.Count == 0)
                throw new ArgumentException("You must specify at least one value to use for extrapolation.");

            if (ds == null)
                throw new ArgumentNullException("ds");

            //First remove values
            var newState = RemoveValues(valuesToInterpolate, reason);
            newState.Reason = reason;

            foreach (var time in valuesToInterpolate)
            {
                if (newState.Values.ContainsKey(time))
                    continue;

                DateTime startValue;
                try
                {
                    startValue = newState.FindPrevValue(time);
                }
                catch (Exception)
                {
                    Debug.WriteLine("Failed to find start value continuing");
                    continue;
                }

                DateTime endValue;
                try
                {
                    endValue = newState.FindNextValue(time);
                }
                catch (Exception)
                {
                    Debug.WriteLine("Failed to find end value continuing");
                    continue;
                }

                var timeDiff = endValue.Subtract(startValue).TotalMinutes;
                var valDiff = newState.Values[endValue] - newState.Values[startValue];
                var step = valDiff / (timeDiff / ds.DataInterval);
                var value = newState.Values[startValue] + step;

                for (var i = ds.DataInterval; i < timeDiff; i += ds.DataInterval)
                {
                    newState.Values[startValue.AddMinutes(i)] = (float)Math.Round(value, 2);

                    newState.AddToChanges(startValue.AddMinutes(i), reason.ID);

                    value += step;
                }
            }

            /* ==OLD METHOD==
                var first = valuesToInterpolate[0];
                DateTime startValue;
                try
                {
                    startValue = FindPrevValue(first, ds);
                }
                catch(Exception e)
                {
                    throw new DataException("No start value");
                }
                var endValue = DateTime.MinValue;
                var time = 0;
                try
                {
                    while (endValue == DateTime.MinValue)
                    {
                        endValue = (Values.ContainsKey(first.AddMinutes(time))
                                        ? first.AddMinutes(time)
                                        : DateTime.MinValue);
                        time += ds.DataInterval;
                    }
                }
                catch(Exception e)
                {
                    throw new DataException("No end value");
                }

                var timeDiff = endValue.Subtract(startValue).TotalMinutes;
                var valDiff = Values[endValue] - Values[startValue];
                var step = valDiff / (timeDiff / ds.DataInterval);
                var value = Values[startValue] + step;

                var newState = Clone();

                for (var i = ds.DataInterval; i < timeDiff; i += ds.DataInterval)
                {
                    newState.Values.Add(startValue.AddMinutes(i), (float)Math.Round(value, 2));
                    value += step;
                }

                EventLogger.LogInfo(GetType().ToString(), "Completing extrapolation process");*/

            return newState;
        }
コード例 #8
0
ファイル: SensorState.cs プロジェクト: rwlamont/AllItUp
 public SensorState ChangeToZero(List<DateTime> values, ChangeReason reason)
 {
     return ChangeToValue(values, 0, reason);
 }
コード例 #9
0
ファイル: SensorState.cs プロジェクト: zhangzheng1205/B3
        /// <summary>
        /// Returns a calibrated state
        /// </summary>
        /// <param name="start">The start timestamp for the calibration</param>
        /// <param name="end">The end timestamp for the calibration</param>
        /// <param name="origA">The original high</param>
        /// <param name="origB">The original low</param>
        /// <param name="newA">The calibrated high</param>
        /// <param name="newB">The calibrated low</param>
        /// <param name="reason">The reason for the calibration</param>
        /// <returns>The calibrated sensor state</returns>
        public SensorState Calibrate(DateTime start, DateTime end, double origA, double origB, double newA, double newB, ChangeReason reason)
        {
            if (start >= end)
            {
                throw new ArgumentException("End time must be greater than start time");
            }

            if (origB > origA)
            {
                throw new ArgumentException("Calibrated B value must be less than the calibrated A value");
            }

            if (newB > newA)
            {
                throw new ArgumentException("Current B value must be less than the current A value");
            }

            //The total minutes in the time span
            double totalMinutes = end.Subtract(start).TotalMinutes;

            //The distance from the median line to the A and B points
            double origMedianDistance = (origA - origB) / 2;
            double newMedianDistance  = (newA - newB) / 2;

            //The largest distance the points must move to normalise them with the median line
            double normalisationDistance = newMedianDistance - origMedianDistance;

            //The largest distance the points must move from the normalised position, to the calibrated (correct) position
            double calibrationDistance = (newB + newMedianDistance) - (origB + origMedianDistance);

            //The increment that must be made per minute to normalise the points above and below the median line
            double normalisationIncrement = normalisationDistance / totalMinutes;
            double calibrationIncrement   = calibrationDistance / totalMinutes;

            //The gradients of the lines
            double slopeA      = (newA - origA) / totalMinutes;
            double slopeMedian = ((newB + newMedianDistance) - (origB + origMedianDistance)) / totalMinutes;

            //The y-intercepts of the lines
            double interceptA      = origA;
            double interceptMedian = origB + origMedianDistance;

            //Copy!
            SensorState newState = Clone();

            foreach (var value in Values)
            {
                if (value.Key < start || value.Key > end)
                {
                    continue;
                }

                double timeDiff           = value.Key.Subtract(start).TotalMinutes;
                double normalisationScale = GetRelativePositionBetweenLines(interceptA, interceptMedian, slopeA, slopeMedian, timeDiff, value.Value);

                newState.Values[value.Key] = (float)(value.Value - (normalisationScale * normalisationIncrement + calibrationIncrement) * timeDiff);
                newState.AddToChanges(value.Key, reason.ID);
            }

            return(newState);
        }
コード例 #10
0
        /// <summary>
        /// Builds the calibration tab item (beware dragons!)
        /// </summary>
        /// <returns>The constructed tab item</returns>
        private TabItem GenerateCalibrationTabItem()
        {
            var tabItem = new TabItem { Header = "Calibration", IsEnabled = FeaturesEnabled };

            //Build the Grid to base it all on and add it
            var tabItemGrid = new Grid();
            tabItem.Content = tabItemGrid;

            tabItemGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }); //Formula area

            var contentGrid = new Grid();
            Grid.SetRow(contentGrid, 0);
            tabItemGrid.Children.Add(contentGrid);

            contentGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });
            contentGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });

            var aboutButton = new Button
            {
                Content = new Image
                {
                    Source = new BitmapImage(new Uri("pack://application:,,,/Images/help_32.png", UriKind.Absolute)),
                    Width = 16,
                    Height = 16
                },
                Margin = new Thickness(3),
                HorizontalAlignment = HorizontalAlignment.Right,
                HorizontalContentAlignment = HorizontalAlignment.Center
            };
            aboutButton.Click +=
                (o, e) =>
                {
                    var message =
                        "This method is used to post-calibrate a range of data using a mathematical formula. It can also be used to perform unit conversions on sensor data.\r\n\nYou may select a range of data to modify by holding the shift key, and click-dragging the mouse over a range of data on the graph to the right. If no range is selected, then the formula will be applied to the date range that is displayed on the graph.\r\n\nUse ‘Formula’ mode to apply an equation to the data. Each sensor has an identifier (‘Variable’ in the sensor metadata) that can be used in formulas. Formulas can also relate one sensor to another (e.g. to calculate dissolved oxygen concentration from % saturation and water temperature measurements). If you wish to retain the original data, you can create a new sensor and use formula mode to derive values for it.\r\n\nUse ‘Drift adjustment’ mode to adjust for linear drift between sensor calibrations. Calibration logs can be stored in sensor metadata. You can enter a two point calibration (e.g. 0% and 100% following dissolved oxygen sensor calibration), and then enter corresponding values at the end of a period of drift (e.g. 4.3% and 115% after six months of dissolved oxygen sensor deployment). Click ‘Apply’ and the data over the period selected will have a linear back-correction applied in order to compensate for (assumed linear) drift in the electronic response of the instrument.\r\n\nYou can use ‘Preview’ to view the calibration change before applying it.\r\n\n";

                    if (Sensors.Count > 1)
                        message +=
                           "The program applies the formula entered across all sensors data points within the specified range.\n" +
                           "The following gives an indication of the operations and syntax.\n\n" +
                           "Mathematical operations\t [ -, +, *, % ]\n" +
                           "Mathematical functions\t [ Sin(y), Cos(y), Tan(y), Pi, Pow(x,y) ]\n\n" +
                           "To set a data points value for a particular sensor, use that sensors variable followed by a space and an equals sign, then by the value.\n" +
                           "   eg: To set the values of the sensor " + Sensors[0].Name + " to 5 for all points, use '" + Sensors[0].Variable.VariableName + " = 5' \n\n" +
                           "To use a sensors values in a calculation, use that sesnors variable.\n" +
                           "   eg: To make all the values of the sensor " + Sensors[0].Name + " equal to " + Sensors[1].Name +
                               ", use " + Sensors[0].Variable.VariableName + " = " + Sensors[1].Variable.VariableName + "\n\n" +
                           "To use the data points time stamp in calculations use 'time.' followed by the time part desired.\n" +
                           "   eg: time.Year, time.Month, time.Day, time.Hour, time.Minute, time.Second\n\n" +
                           "Note: Variables must be seperated out by whitespace like so \" a \"" +
                           "Examples:\n" +
                           "'x = x + 1'\n" +
                           "'x = time.Date'\n" +
                           "'x = x * Cos( x + 1) + 2'";
                    else
                        message +=
                            "The program applies the formula entered across all sensors data points within the specified range.\n" +
                                       "The following gives an indication of the operations and syntax.\n\n" +
                                       "Mathematical operations\t [ -, +, *, ^, % ]\n" +
                                       "Mathematical functions\t [ Sin(y), Cos(y), Tan(y), Pi ]\n\n" +
                                       "Examples:\n" +
                                       "'x = x + 1'\n" +
                                       "'x = time.Date'\n" +
                                       "'x = x * Cos(x + 1) + 2'";

                    Common.ShowMessageBox("About Calibration",
                                          message
                                          , false, false);
                };
            Grid.SetRow(aboutButton, 0);
            contentGrid.Children.Add(aboutButton);

            var calibrationMethodStackPanel = new StackPanel { Margin = new Thickness(5), Orientation = Orientation.Horizontal };
            Grid.SetRow(calibrationMethodStackPanel, 0);
            contentGrid.Children.Add(calibrationMethodStackPanel);
            calibrationMethodStackPanel.Children.Add(new TextBlock
                                                         {
                                                             Text = "Calibration Method:    "
                                                         });
            var useManualCalibrationRadio = new RadioButton
                                                {
                                                    Content = "Formula    ",
                                                    IsChecked = true
                                                };
            var manualAutoTabControl = new TabControl
                                            {
                                                Padding = new Thickness(0),
                                                Margin = new Thickness(5),
                                                BorderThickness = new Thickness(0),
                                                TabStripPlacement = Dock.Top,
                                                ItemContainerStyle = Application.Current.FindResource("HiddenTabHeaders") as Style
                                            };
            useManualCalibrationRadio.Checked += (o, e) =>
                                                     {
                                                         manualAutoTabControl.SelectedIndex = 0;
                                                     };
            useManualCalibrationRadio.Unchecked += (o, e) =>
                                                       {
                                                           manualAutoTabControl.SelectedIndex = 1;
                                                       };
            calibrationMethodStackPanel.Children.Add(useManualCalibrationRadio);
            calibrationMethodStackPanel.Children.Add(new RadioButton
                                                         {
                                                             Content = "Drift Adjustment"
                                                         });
            Grid.SetRow(manualAutoTabControl, 1);
            contentGrid.Children.Add(manualAutoTabControl);

            #region Manual Tab

            Formula formula = null;

            var manualTabItem = new TabItem
                                    {
                                        Header = "Manual"
                                    };
            manualAutoTabControl.Items.Add(manualTabItem);

            var manualTabGrid = new Grid();
            manualTabItem.Content = manualTabGrid;

            manualTabGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });
            manualTabGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
            manualTabGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });

            var manualTextBlock = new TextBlock
                                      {
                                          Text = "Enter Formula Below:",
                                          Margin = new Thickness(0, 5, 0, 5)
                                      };
            Grid.SetRow(manualTextBlock, 0);
            manualTabGrid.Children.Add(manualTextBlock);

            var manualFormulaTextBox = new TextBox
                                           {
                                               BorderBrush = Brushes.OrangeRed,
                                               Margin = new Thickness(0, 0, 0, 10),
                                               VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
                                               TextWrapping = TextWrapping.Wrap,
                                               AcceptsReturn = true,
                                               IsEnabled = CurrentDataSetNotNull
                                           };
            PropertyChanged += (o, e) =>
                                   {
                                       if (e.PropertyName == "CurrentDataSetNotNull")
                                       {
                                           manualFormulaTextBox.IsEnabled = CurrentDataSetNotNull;
                                       }
                                   };
            var applyFormulaButton = new Button
                                         {
                                             FontSize = 15,
                                             HorizontalAlignment = HorizontalAlignment.Right,
                                             Margin = new Thickness(5, 0, 0, 0),
                                             VerticalAlignment = VerticalAlignment.Bottom,
                                             VerticalContentAlignment = VerticalAlignment.Bottom,
                                             IsEnabled = !Properties.Settings.Default.EvaluateFormulaOnKeyUp
                                         };
            var previewFormulaButton = new Button
                                           {
                                               FontSize = 15,
                                               HorizontalAlignment = HorizontalAlignment.Right,
                                               Margin = new Thickness(5, 0, 0, 0),
                                               VerticalAlignment = VerticalAlignment.Bottom,
                                               VerticalContentAlignment = VerticalAlignment.Bottom,
                                               IsEnabled = !Properties.Settings.Default.EvaluateFormulaOnKeyUp
                                           };

            manualFormulaTextBox.KeyUp += (o, e) =>
                                              {
                                                  if (_manualPreviewTextBlock.Text == "Reject")
                                                  {
                                                      foreach (var graphableSensor in GraphableSensors)
                                                      {
                                                          graphableSensor.RemovePreview();
                                                      }
                                                      UpdateGraph(false);
                                                      _manualPreviewTextBlock.Text = "Preview";
                                                  }

                                                  if (!Properties.Settings.Default.EvaluateFormulaOnKeyUp)
                                                      return;
                                                  bool validFormula;
                                                  if (string.IsNullOrWhiteSpace(manualFormulaTextBox.Text))
                                                  {
                                                      validFormula = false;
                                                  }
                                                  else
                                                  {
                                                      formula = _evaluator.CompileFormula(manualFormulaTextBox.Text);
                                                      validFormula = formula.IsValid;
                                                  }

                                                  manualFormulaTextBox.Background = !validFormula && Properties.Settings.Default.EvaluateFormulaOnKeyUp ? new SolidColorBrush(Color.FromArgb(126, 255, 69, 0)) : new SolidColorBrush(Colors.White);
                                                  applyFormulaButton.IsEnabled = validFormula;
                                                  previewFormulaButton.IsEnabled = validFormula;
                                              };
            Grid.SetRow(manualFormulaTextBox, 1);
            manualTabGrid.Children.Add(manualFormulaTextBox);

            var buttonsWrapper = new WrapPanel
                                     {
                                         HorizontalAlignment = HorizontalAlignment.Right,
                                         Margin = new Thickness(0, 5, 0, 0),
                                     };
            Grid.SetRow(buttonsWrapper, 2);
            manualTabGrid.Children.Add(buttonsWrapper);

            applyFormulaButton.Click += (sender, eventArgs) =>
                                            {
                                                if (_manualPreviewTextBlock.Text == "Reject")
                                                {
                                                    foreach (var graphableSensor in GraphableSensors)
                                                    {
                                                        graphableSensor.RemovePreview();
                                                    }
                                                    UpdateGraph(false);
                                                    _manualPreviewTextBlock.Text = "Preview";
                                                }

                                                var validFormula = false;
                                                if (!string.IsNullOrWhiteSpace(manualFormulaTextBox.Text))
                                                {
                                                    formula = _evaluator.CompileFormula(manualFormulaTextBox.Text);
                                                    validFormula = formula.IsValid;
                                                }

                                                if (validFormula)
                                                {
                                                    var useSelected = Selection != null;
                                                    var skipMissingValues = false;
                                                    var detector = new MissingValuesDetector();

                                                    //Detect if missing values
                                                    var missingSensors = formula.SensorsUsed.Where(sensorVariable => detector.GetDetectedValues(sensorVariable.Sensor).Count > 0).Aggregate("", (current, sensorVariable) => current + ("\t" + sensorVariable.Sensor.Name + " (" + sensorVariable.VariableName + ")\n"));

                                                    if (missingSensors != "")
                                                    {
                                                        var specify =
                                                            (SpecifyValueViewModel)_container.GetInstance(typeof(SpecifyValueViewModel), "SpecifyValueViewModel");
                                                        specify.Title = "Missing Values Detected";
                                                        specify.Message =
                                                            "The following sensors you have used in the formula contain missing values:\n\n" + missingSensors + "\nPlease select an action to take.";
                                                        specify.ShowComboBox = true;
                                                        specify.ShowCancel = true;
                                                        specify.CanEditComboBox = false;
                                                        specify.ComboBoxItems =
                                                            new List<string>(new[] { "Treat all missing values as zero", "Skip over all missing values" });
                                                        specify.ComboBoxSelectedIndex = 1;

                                                        _windowManager.ShowDialog(specify);

                                                        if (specify.WasCanceled) return;
                                                        skipMissingValues = specify.ComboBoxSelectedIndex == 1;
                                                    }

                                                    var reason = Common.RequestReason(_container, _windowManager, 12);

                                                    if (reason == null)
                                                        return;

                                                    ApplicationCursor = Cursors.Wait;

                                                    var result = useSelected ? _evaluator.EvaluateFormula(formula, Selection.LowerX.Round(TimeSpan.FromMinutes(CurrentDataset.DataInterval)), Selection.UpperX, skipMissingValues, reason) : _evaluator.EvaluateFormula(formula, StartTime.Round(TimeSpan.FromMinutes(CurrentDataset.DataInterval)), EndTime, skipMissingValues, reason);

                                                    if (result.Key == null)
                                                    {
                                                        Common.ShowMessageBox("Formula failed", "Failed to apply the formula to the sensor(s) involved",
                                                                          false, false);
                                                        return;
                                                    }

                                                    result.Key.AddState(result.Value);
                                                    result.Key.CurrentState.LogChange(result.Key.Name,
                                                                                      string.Format(
                                                                                          "Applied formula: {0} [Formula:{1}]", reason, manualFormulaTextBox.Text));

                                                    ApplicationCursor = Cursors.Arrow;
                                                    EventLogger.LogInfo(_currentDataset, "Formula Applied", "Formula " + manualFormulaTextBox.Text + "applied to sensors. (" + reason.ID + ") " + reason.Reason);
                                                    Common.ShowMessageBox("Formula applied", "The formula was successfully applied to the sensor(s) involved.",
                                                                          false, false);
                                                    var sensorsUsed = formula.SensorsUsed.Select(x => x.Sensor);
                                                    foreach (var sensor in sensorsUsed)
                                                    {
                                                        Debug.Print("The sensor {0} was used", sensor.Name);
                                                        sensor.CurrentState.LogChange(sensor.Name, string.Format(
                                                                                  "Applied formula: {0} \n\r Between date range {1} - {2}", manualFormulaTextBox.Text, (useSelected) ? Selection.LowerX.Round(TimeSpan.FromMinutes(CurrentDataset.DataInterval)) : StartTime.Round(TimeSpan.FromMinutes(CurrentDataset.DataInterval)), (useSelected) ? Selection.UpperX : EndTime));
                                                    }
                                                    foreach (var graphableSensor in GraphableSensors)
                                                    {
                                                        graphableSensor.RefreshDataPoints();
                                                        Debug.Print("The sensor {0} points were updated", graphableSensor.Sensor.Name);
                                                    }
                                                    UpdateGraph(false);
                                                    UpdateUndoRedo();
                                                    EventLogger.LogInfo(_currentDataset, "Formula Applied", "Formula " + formula + "applied to sensors." + reason);
                                                }
                                                else
                                                {
                                                    var errorString = "";

                                                    if (formula != null && formula.CompilerResults.Errors.Count > 0)
                                                        errorString = formula.CompilerResults.Errors.Cast<CompilerError>().Aggregate(errorString, (current, error) => current + (error.ErrorText + "\n"));

                                                    Common.ShowMessageBoxWithExpansion("Unable to Apply Formula",
                                                                                       "An error was encounted when trying to apply the formula.\nPlease check the formula syntax.",
                                                                                       false, true, errorString);
                                                }
                                            };

            var applyFormulaButtonStackPanel = new StackPanel
                                                    {
                                                        Orientation = Orientation.Horizontal
                                                    };
            applyFormulaButton.Content = applyFormulaButtonStackPanel;
            applyFormulaButtonStackPanel.Children.Add(new Image
                                                        {
                                                            Width = 32,
                                                            Height = 32,
                                                            Source = new BitmapImage(new Uri("pack://application:,,,/Images/right_32.png", UriKind.Absolute))
                                                        });
            applyFormulaButtonStackPanel.Children.Add(new TextBlock
                                                        {
                                                            Text = "Apply",
                                                            VerticalAlignment = VerticalAlignment.Center,
                                                            Margin = new Thickness(5)
                                                        });

            previewFormulaButton.Click += (sender, args) =>
                                              {
                                                  if (_manualPreviewTextBlock.Text == "Reject")
                                                  {
                                                      foreach (var graphableSensor in GraphableSensors)
                                                      {
                                                          graphableSensor.RemovePreview();
                                                      }
                                                      UpdateGraph(false);
                                                      _manualPreviewTextBlock.Text = "Preview";
                                                      return;
                                                  }

                                                  var validFormula = false;
                                                  if (!string.IsNullOrWhiteSpace(manualFormulaTextBox.Text))
                                                  {
                                                      formula = _evaluator.CompileFormula(manualFormulaTextBox.Text);
                                                      validFormula = formula.IsValid;
                                                  }

                                                  if (validFormula)
                                                  {
                                                      var useSelected = Selection != null;
                                                      var skipMissingValues = false;
                                                      var detector = new MissingValuesDetector();

                                                      //Detect if missing values
                                                      var missingSensors = formula.SensorsUsed.Where(sensorVariable => detector.GetDetectedValues(sensorVariable.Sensor).Count > 0).Aggregate("", (current, sensorVariable) => current + ("\t" + sensorVariable.Sensor.Name + " (" + sensorVariable.VariableName + ")\n"));

                                                      if (missingSensors != "")
                                                      {
                                                          var specify =
                                                              (SpecifyValueViewModel)_container.GetInstance(typeof(SpecifyValueViewModel), "SpecifyValueViewModel");
                                                          specify.Title = "Missing Values Detected";
                                                          specify.Message =
                                                              "The following sensors you have used in the formula contain missing values:\n\n" + missingSensors + "\nPlease select an action to take.";
                                                          specify.ShowComboBox = true;
                                                          specify.ShowCancel = true;
                                                          specify.CanEditComboBox = false;
                                                          specify.ComboBoxItems =
                                                              new List<string>(new[] { "Treat all missing values as zero", "Skip over all missing values" });
                                                          specify.ComboBoxSelectedIndex = 1;

                                                          _windowManager.ShowDialog(specify);

                                                          if (specify.WasCanceled) return;
                                                          skipMissingValues = specify.ComboBoxSelectedIndex == 1;
                                                      }

                                                      var reason = new ChangeReason(-1, "Preview");

                                                      ApplicationCursor = Cursors.Wait;

                                                      var result = useSelected ? _evaluator.EvaluateFormula(formula, Selection.LowerX.Round(TimeSpan.FromMinutes(CurrentDataset.DataInterval)), Selection.UpperX, skipMissingValues, reason) : _evaluator.EvaluateFormula(formula, StartTime.Round(TimeSpan.FromMinutes(CurrentDataset.DataInterval)), EndTime, skipMissingValues, reason);

                                                      if (result.Key == null)
                                                      {
                                                          Common.ShowMessageBox("Formula failed", "Failed to apply the formula for the preview of sensor(s) involved",
                                                                            false, false);
                                                          return;
                                                      }

                                                      var gSensor = GraphableSensors.First(x => x.Sensor == result.Key);

                                                      gSensor.GeneratePreview(result.Value);

                                                      ApplicationCursor = Cursors.Arrow;
                                                      _manualPreviewTextBlock.Text = "Reject";
                                                      UpdateGraph(false);
                                                      EventLogger.LogInfo(_currentDataset, "Formula Applied", "Formula " + formula + "applied to sensors.");

                                                  }
                                                  else
                                                  {
                                                      var errorString = "";

                                                      if (formula != null && formula.CompilerResults.Errors.Count > 0)
                                                          errorString = formula.CompilerResults.Errors.Cast<CompilerError>().Aggregate(errorString, (current, error) => current + (error.ErrorText + "\n"));

                                                      Common.ShowMessageBoxWithExpansion("Unable to Preview Formula",
                                                                                         "An error was encounted when trying to preview the formula.\nPlease check the formula syntax.",
                                                                                         false, true, errorString);
                                                  }
                                              };

            var previewFormulaButtonStackPanel = new StackPanel
                                                     {
                                                         Orientation = Orientation.Horizontal
                                                     };
            previewFormulaButton.Content = previewFormulaButtonStackPanel;
            previewFormulaButtonStackPanel.Children.Add(new Image
                                                            {
                                                                Width = 32,
                                                                Height = 32,
                                                                Source =
                                                                    new BitmapImage(
                                                                    new Uri(
                                                                        "pack://application:,,,/Images/preview_32.png",
                                                                        UriKind.Absolute))
                                                            });
            previewFormulaButtonStackPanel.Children.Add(_manualPreviewTextBlock);

            var clearButton = new Button
                                {
                                    FontSize = 15,
                                    HorizontalAlignment = HorizontalAlignment.Right,
                                    Margin = new Thickness(5, 0, 0, 0),
                                    VerticalAlignment = VerticalAlignment.Bottom,
                                    VerticalContentAlignment = VerticalAlignment.Bottom
                                };
            clearButton.Click += (o, e) =>
                                     {
                                         manualFormulaTextBox.Text = "";
                                         applyFormulaButton.IsEnabled = !Properties.Settings.Default.EvaluateFormulaOnKeyUp;
                                     };

            var clearButtonStackPanel = new StackPanel
                                            {
                                                Orientation = Orientation.Horizontal
                                            };
            clearButton.Content = clearButtonStackPanel;
            clearButtonStackPanel.Children.Add(new Image
                                                {
                                                    Width = 32,
                                                    Height = 32,
                                                    Source = new BitmapImage(new Uri("pack://application:,,,/Images/delete_32.png", UriKind.Absolute))
                                                });
            clearButtonStackPanel.Children.Add(new TextBlock
                                                    {
                                                        Text = "Clear",
                                                        VerticalAlignment = VerticalAlignment.Center,
                                                        Margin = new Thickness(5)
                                                    });

            #region Add Buttons to Wrapper
            buttonsWrapper.Children.Add(clearButton);
            buttonsWrapper.Children.Add(previewFormulaButton);
            buttonsWrapper.Children.Add(applyFormulaButton);
            #endregion

            #endregion

            #region Automatic Tab

            var autoApplyButton = new Button
                                      {
                                          FontSize = 15,
                                          HorizontalAlignment = HorizontalAlignment.Right,
                                          Margin = new Thickness(5, 0, 5, 0),
                                          VerticalAlignment = VerticalAlignment.Bottom,
                                          VerticalContentAlignment = VerticalAlignment.Bottom,
                                          IsEnabled = false
                                      };

            var autoPreviewButton = new Button
                                        {
                                            FontSize = 15,
                                            HorizontalAlignment = HorizontalAlignment.Right,
                                            Margin = new Thickness(5, 0, 5, 0),
                                            VerticalAlignment = VerticalAlignment.Bottom,
                                            VerticalContentAlignment = VerticalAlignment.Bottom,
                                            IsEnabled = false
                                        };

            var automaticTabItem = new TabItem
                                       {
                                           Header = "Automatic"
                                       };
            manualAutoTabControl.Items.Add(automaticTabItem);

            var automaticGrid = new Grid();
            automaticTabItem.Content = automaticGrid;

            automaticGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });
            automaticGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });
            automaticGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });
            automaticGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
            automaticGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });

            var applyToStackPanel = new StackPanel
                                        {
                                            Orientation = Orientation.Horizontal
                                        };
            Grid.SetRow(applyToStackPanel, 0);
            automaticGrid.Children.Add(applyToStackPanel);

            applyToStackPanel.Children.Add(new TextBlock
                                               {
                                                   Text = "Apply To:",
                                                   Margin = new Thickness(0, 0, 15, 0),
                                                   VerticalAlignment = VerticalAlignment.Center
                                               });

            var applyToCombo = new ComboBox
                                   {
                                       Width = 130
                                   };
            applyToStackPanel.Children.Add(applyToCombo);

            applyToCombo.Items.Add("All graphed sensors");
            applyToCombo.SelectedIndex = 0;
            SensorsToCheckMethodsAgainst.CollectionChanged += (o, e) => applyToCombo.Dispatcher.BeginInvoke(
                DispatcherPriority.Input,
                new ThreadStart(() =>
                                    {
                                        applyToCombo.Items.Clear();
                                        applyToCombo.Items.Add("All graphed sensors");
                                        SensorsForEditing.ForEach(x =>
                                                                  applyToCombo.Items.Add(x.Name));
                                        applyToCombo.SelectedIndex = 0;
                                    }));

            var automaticTextBlock = new TextBlock
                                         {
                                             Text = "Enter the calibration values below:",
                                             Margin = new Thickness(0, 5, 0, 5)
                                         };
            Grid.SetRow(automaticTextBlock, 1);
            automaticGrid.Children.Add(automaticTextBlock);

            var automaticValuesGrid = new Grid
                                          {
                                              Margin = new Thickness(5)
                                          };
            Grid.SetRow(automaticValuesGrid, 2);
            automaticGrid.Children.Add(automaticValuesGrid);

            automaticValuesGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(24) });
            automaticValuesGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(26) });
            automaticValuesGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(26) });

            automaticValuesGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(100) });
            automaticValuesGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
            automaticValuesGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });

            var calibratedTextBlock = new TextBlock
                                          {
                                              Text = "Start of Period",
                                              VerticalAlignment = VerticalAlignment.Center,
                                              HorizontalAlignment = HorizontalAlignment.Center
                                          };
            Grid.SetRow(calibratedTextBlock, 0);
            Grid.SetColumn(calibratedTextBlock, 1);
            automaticValuesGrid.Children.Add(calibratedTextBlock);

            var currentTextBlock = new TextBlock
                                       {
                                           Text = "End of Period",
                                           VerticalAlignment = VerticalAlignment.Center,
                                           HorizontalAlignment = HorizontalAlignment.Center
                                       };
            Grid.SetRow(currentTextBlock, 0);
            Grid.SetColumn(currentTextBlock, 2);
            automaticValuesGrid.Children.Add(currentTextBlock);

            var aTextBlock = new TextBlock
                                 {
                                     Text = "Span (High)",
                                     VerticalAlignment = VerticalAlignment.Center,
                                     HorizontalAlignment = HorizontalAlignment.Center
                                 };
            Grid.SetRow(aTextBlock, 2);
            Grid.SetColumn(aTextBlock, 0);
            automaticValuesGrid.Children.Add(aTextBlock);

            var bTextBlock = new TextBlock
                                 {
                                     Text = "Offset (Low)",
                                     VerticalAlignment = VerticalAlignment.Center,
                                     HorizontalAlignment = HorizontalAlignment.Center
                                 };
            Grid.SetRow(bTextBlock, 1);
            Grid.SetColumn(bTextBlock, 0);
            automaticValuesGrid.Children.Add(bTextBlock);

            var calibratedAValue = 0d;
            var calibratedAValid = false;
            var calibratedBValue = 0d;
            var calibratedBValid = false;
            var currentAValue = 0d;
            var currentAValid = false;
            var currentBValue = 0d;
            var currentBValid = false;

            var calibratedATextBox = new TextBox
                                       {
                                           VerticalAlignment = VerticalAlignment.Center,
                                           Margin = new Thickness(2),
                                           TabIndex = 1
                                       };
            calibratedATextBox.KeyUp += (o, e) =>
                                            {
                                                calibratedAValid = double.TryParse(calibratedATextBox.Text, out calibratedAValue);
                                                calibratedATextBox.Background = calibratedAValid ? new SolidColorBrush(Colors.White) : new SolidColorBrush(Color.FromArgb(126, 255, 69, 0));
                                                // ReSharper disable AccessToModifiedClosure
                                                autoApplyButton.IsEnabled = calibratedAValid && calibratedBValid && currentAValid && currentBValid;
                                                autoPreviewButton.IsEnabled = autoApplyButton.IsEnabled;
                                                // ReSharper restore AccessToModifiedClosure
                                                if (String.CompareOrdinal(_automaticPreviewTextBlock.Text, "Reject") != 0)
                                                    return;

                                                foreach (var gSensor in _sensorsToGraph)
                                                {
                                                    gSensor.RemovePreview();
                                                }
                                                _automaticPreviewTextBlock.Text = "Preview";
                                                SampleValues(Common.MaximumGraphablePoints, _sensorsToGraph, "AutoCalibration");
                                            };

            Grid.SetRow(calibratedATextBox, 2);
            Grid.SetColumn(calibratedATextBox, 1);
            automaticValuesGrid.Children.Add(calibratedATextBox);

            var calibratedBTextBox = new TextBox
                                         {
                                             VerticalAlignment = VerticalAlignment.Center,
                                             Margin = new Thickness(2),
                                             TabIndex = 0
                                         };
            calibratedBTextBox.KeyUp += (o, e) =>
                                            {
                                                calibratedBValid = double.TryParse(calibratedBTextBox.Text, out calibratedBValue);
                                                calibratedBTextBox.Background = calibratedBValid ? new SolidColorBrush(Colors.White) : new SolidColorBrush(Color.FromArgb(126, 255, 69, 0));
                                                // ReSharper disable AccessToModifiedClosure
                                                autoApplyButton.IsEnabled = calibratedAValid && calibratedBValid && currentAValid && currentBValid;
                                                autoPreviewButton.IsEnabled = autoApplyButton.IsEnabled;
                                                // ReSharper restore AccessToModifiedClosure
                                                if (String.CompareOrdinal(_automaticPreviewTextBlock.Text, "Reject") != 0)
                                                    return;

                                                foreach (var gSensor in _sensorsToGraph)
                                                {
                                                    gSensor.RemovePreview();
                                                }
                                                _automaticPreviewTextBlock.Text = "Preview";
                                                SampleValues(Common.MaximumGraphablePoints, _sensorsToGraph, "AutoCalibration");
                                            };
            Grid.SetRow(calibratedBTextBox, 1);
            Grid.SetColumn(calibratedBTextBox, 1);
            automaticValuesGrid.Children.Add(calibratedBTextBox);

            var currentATextBox = new TextBox
                                         {
                                             VerticalAlignment = VerticalAlignment.Center,
                                             Margin = new Thickness(2),
                                             TabIndex = 3
                                         };
            currentATextBox.KeyUp += (o, e) =>
                                         {
                                             currentAValid = double.TryParse(currentATextBox.Text, out currentAValue);
                                             currentATextBox.Background = currentAValid ? new SolidColorBrush(Colors.White) : new SolidColorBrush(Color.FromArgb(126, 255, 69, 0));
                                             // ReSharper disable AccessToModifiedClosure
                                             autoApplyButton.IsEnabled = calibratedAValid && calibratedBValid && currentAValid && currentBValid;
                                             autoPreviewButton.IsEnabled = autoApplyButton.IsEnabled;
                                             // ReSharper restore AccessToModifiedClosure
                                             if (String.CompareOrdinal(_automaticPreviewTextBlock.Text, "Reject") != 0)
                                                 return;

                                             foreach (var gSensor in _sensorsToGraph)
                                             {
                                                 gSensor.RemovePreview();
                                             }
                                             _automaticPreviewTextBlock.Text = "Preview";
                                             SampleValues(Common.MaximumGraphablePoints, _sensorsToGraph, "AutoCalibration");
                                         };
            Grid.SetRow(currentATextBox, 2);
            Grid.SetColumn(currentATextBox, 2);
            automaticValuesGrid.Children.Add(currentATextBox);

            var currentBTextBox = new TextBox
                                         {
                                             VerticalAlignment = VerticalAlignment.Center,
                                             Margin = new Thickness(2),
                                             TabIndex = 2
                                         };
            currentBTextBox.KeyUp += (o, e) =>
                                         {
                                             currentBValid = double.TryParse(currentBTextBox.Text, out currentBValue);
                                             currentBTextBox.Background = currentBValid ? new SolidColorBrush(Colors.White) : new SolidColorBrush(Color.FromArgb(126, 255, 69, 0));
                                             // ReSharper disable AccessToModifiedClosure
                                             autoApplyButton.IsEnabled = calibratedAValid && calibratedBValid && currentAValid && currentBValid;
                                             autoPreviewButton.IsEnabled = autoApplyButton.IsEnabled;
                                             // ReSharper restore AccessToModifiedClosure
                                             if (String.CompareOrdinal(_automaticPreviewTextBlock.Text, "Reject") != 0)
                                                 return;

                                             foreach (var gSensor in _sensorsToGraph)
                                             {
                                                 gSensor.RemovePreview();
                                             }
                                             _automaticPreviewTextBlock.Text = "Preview";
                                             SampleValues(Common.MaximumGraphablePoints, _sensorsToGraph, "AutoCalibration");
                                         };
            Grid.SetRow(currentBTextBox, 1);
            Grid.SetColumn(currentBTextBox, 2);
            automaticValuesGrid.Children.Add(currentBTextBox);

            var autoButtonsWrapPanel = new WrapPanel
                                           {
                                               Orientation = Orientation.Horizontal,
                                               HorizontalAlignment = HorizontalAlignment.Right
                                           };
            Grid.SetRow(autoButtonsWrapPanel, 4);
            automaticGrid.Children.Add(autoButtonsWrapPanel);

            autoApplyButton.Click += (o, e) =>
                                         {
                                             if (String.CompareOrdinal(_automaticPreviewTextBlock.Text, "Reject") == 0)
                                             {
                                                 foreach (var gSensor in _sensorsToGraph)
                                                 {
                                                     gSensor.RemovePreview();
                                                 }
                                                 _automaticPreviewTextBlock.Text = "Preview";
                                             }

                                             var useSelected = Selection != null;
                                             //if (Selection != null)
                                             //    useSelected = Common.Confirm("Should we use your selection?",
                                             //                                 "Should we use the date range of your selection for to apply the formula on?");
                                             var reason = Common.RequestReason(_container, _windowManager, 4);
                                             if (reason == null)
                                                 return;
                                             var successfulSensors = new List<Sensor>();
                                             foreach (var sensor in SensorsToCheckMethodsAgainst.Where(x => (string)applyToCombo.SelectedItem == "All graphed sensors" || (string)applyToCombo.SelectedItem == x.Name))
                                             {
                                                 try
                                                 {
                                                     sensor.AddState(useSelected
                                                                         ? sensor.CurrentState.Calibrate(
                                                                             Selection.LowerX, Selection.UpperX,
                                                                             calibratedAValue, calibratedBValue,
                                                                             currentAValue, currentBValue, reason)
                                                                         : sensor.CurrentState.Calibrate(StartTime,
                                                                                                         EndTime,
                                                                                                         calibratedAValue,
                                                                                                         calibratedBValue,
                                                                                                         currentAValue,
                                                                                                         currentBValue, reason));
                                                     sensor.CurrentState.Reason = reason;
                                                     sensor.CurrentState.LogChange(sensor.Name, "Automatic Calibration");
                                                     successfulSensors.Add(sensor);
                                                 }
                                                 catch (Exception ex)
                                                 {
                                                     Common.ShowMessageBox("An Error Occured", ex.Message, false, true);
                                                 }
                                             }

                                             foreach (var graphableSensor in GraphableSensors.Where(x => successfulSensors.Contains(x.Sensor)))
                                                 graphableSensor.RefreshDataPoints();
                                             SampleValues(Common.MaximumGraphablePoints, _sensorsToGraph, "AutoCalibration");
                                             UpdateUndoRedo();
                                         };

            var autoApplyButtonStackPanel = new StackPanel
                                                {
                                                    Orientation = Orientation.Horizontal
                                                };
            autoApplyButton.Content = autoApplyButtonStackPanel;
            autoApplyButtonStackPanel.Children.Add(new Image
                                                       {
                                                           Width = 32,
                                                           Height = 32,
                                                           Source =
                                                               new BitmapImage(
                                                               new Uri("pack://application:,,,/Images/right_32.png",
                                                                       UriKind.Absolute))
                                                       });
            autoApplyButtonStackPanel.Children.Add(new TextBlock
                                                       {
                                                           Text = "Apply",
                                                           VerticalAlignment = VerticalAlignment.Center,
                                                           Margin = new Thickness(5)
                                                       });

            var autoPreviewButtonStackPanel = new StackPanel
                                                  {
                                                      Orientation = Orientation.Horizontal
                                                  };
            autoPreviewButton.Content = autoPreviewButtonStackPanel;
            autoPreviewButtonStackPanel.Children.Add(new Image
                                                         {
                                                             Width = 32,
                                                             Height = 32,
                                                             Source =
                                                                 new BitmapImage(
                                                                 new Uri("pack://application:,,,/Images/preview_32.png",
                                                                         UriKind.Absolute))
                                                         });

            autoPreviewButtonStackPanel.Children.Add(_automaticPreviewTextBlock);

            autoPreviewButton.Click += (o, e) =>
                                           {
                                               if (String.CompareOrdinal(_automaticPreviewTextBlock.Text, "Preview") == 0)
                                               {
                                                   var useSelected = Selection != null;
                                                   //if (Selection != null)
                                                   //    useSelected = Common.Confirm("Should we use your selection?",
                                                   //                                 "Should we use the date range of your selection for to apply the formula on?");
                                                   foreach (var sensor in SensorsToCheckMethodsAgainst.Where(x => (string)applyToCombo.SelectedItem == "All graphed sensors" || (string)applyToCombo.SelectedItem == x.Name))
                                                   {
                                                       var gSensor =
                                                           _sensorsToGraph.FirstOrDefault(x => x.Sensor == sensor);
                                                       if (gSensor == null)
                                                           continue;
                                                       try
                                                       {
                                                           gSensor.GeneratePreview(useSelected
                                                                                       ? sensor.CurrentState.Calibrate(
                                                                                           Selection.LowerX,
                                                                                           Selection.UpperX,
                                                                                           calibratedAValue,
                                                                                           calibratedBValue,
                                                                                           currentAValue, currentBValue,
                                                                                           new ChangeReason(-1,
                                                                                                            "Preview"))
                                                                                       : sensor.CurrentState.Calibrate(
                                                                                           StartTime,
                                                                                           EndTime,
                                                                                           calibratedAValue,
                                                                                           calibratedBValue,
                                                                                           currentAValue,
                                                                                           currentBValue,
                                                                                           new ChangeReason(-1,
                                                                                                            "Preview")));
                                                       }
                                                       catch (Exception ex)
                                                       {
                                                           Common.ShowMessageBox("An Error Occured", ex.Message, false,
                                                                                 true);
                                                       }
                                                   }
                                                   _automaticPreviewTextBlock.Text = "Reject";
                                               }
                                               else
                                               {
                                                   foreach (var gSensor in _sensorsToGraph)
                                                   {
                                                       gSensor.RemovePreview();
                                                   }
                                                   _automaticPreviewTextBlock.Text = "Preview";
                                               }
                                               SampleValues(Common.MaximumGraphablePoints, _sensorsToGraph, "AutoCalibratePreview");
                                           };

            var autoClearButton = new Button
                                  {
                                      FontSize = 15,
                                      HorizontalAlignment = HorizontalAlignment.Right,
                                      Margin = new Thickness(5, 0, 5, 0),
                                      VerticalAlignment = VerticalAlignment.Bottom,
                                      VerticalContentAlignment = VerticalAlignment.Bottom
                                  };
            autoClearButton.Click += (o, e) =>
                                         {
                                             calibratedATextBox.Text = "";
                                             calibratedBTextBox.Text = "";
                                             currentATextBox.Text = "";
                                             currentBTextBox.Text = "";
                                             _automaticPreviewTextBlock.Text = "Preview";
                                             autoApplyButton.IsEnabled = false;
                                             autoPreviewButton.IsEnabled = false;
                                             var previewMade = GraphableSensors.FirstOrDefault(x => x.PreviewDataPoints != null) != null;
                                             if (previewMade)
                                             {
                                                 GraphableSensors.ForEach(x => x.RemovePreview());
                                                 SampleValues(Common.MaximumGraphablePoints, _sensorsToGraph, "PreviewResetFromAutoClear");
                                             }
                                         };

            var autoClearButtonStackPanel = new StackPanel
                                            {
                                                Orientation = Orientation.Horizontal
                                            };
            autoClearButton.Content = autoClearButtonStackPanel;
            autoClearButtonStackPanel.Children.Add(new Image
                                                   {
                                                       Width = 32,
                                                       Height = 32,
                                                       Source =
                                                           new BitmapImage(
                                                           new Uri("pack://application:,,,/Images/delete_32.png",
                                                                   UriKind.Absolute))
                                                   });
            autoClearButtonStackPanel.Children.Add(new TextBlock
                                                   {
                                                       Text = "Clear",
                                                       VerticalAlignment = VerticalAlignment.Center,
                                                       Margin = new Thickness(5)
                                                   });

            #region Add Buttons to Wrapper
            autoButtonsWrapPanel.Children.Add(autoClearButton);
            autoButtonsWrapPanel.Children.Add(autoPreviewButton);
            autoButtonsWrapPanel.Children.Add(autoApplyButton);
            #endregion

            #endregion

            return tabItem;
        }
コード例 #11
0
ファイル: FormulaEvaluator.cs プロジェクト: zhangzheng1205/B3
        /// <summary>
        /// Evaluates a formula
        /// </summary>
        /// <param name="formula">The formula to evaluate</param>
        /// <param name="startTime">The start time to evaluate from</param>
        /// <param name="endTime">The end time to stop evaluating from</param>
        /// <param name="skipMissingValues">Whether or not to skip missing values</param>
        /// <param name="reason">The reason for the evaluation</param>
        /// <returns>The sensor used and the newly evaulated state</returns>
        public KeyValuePair <Sensor, SensorState> EvaluateFormula(Formula formula, DateTime startTime, DateTime endTime, bool skipMissingValues, ChangeReason reason)
        {
            if (startTime >= endTime)
            {
                throw new ArgumentException("End time must be greater than start time");
            }

            // if the code compiled okay,
            // run the code using the new assembly (which is inside the results)
            if (formula.CompilerResults != null && formula.CompilerResults.CompiledAssembly != null)
            {
                // run the evaluation function
                return(RunCode(formula, startTime, endTime, skipMissingValues, reason));
            }

            Debug.WriteLine("Could not evaluate formula");
            return(new KeyValuePair <Sensor, SensorState>(null, null));
        }
コード例 #12
0
ファイル: SensorState.cs プロジェクト: rwlamont/AllItUp
        /// <summary>
        /// Returns a new sensor state where the given values are removed
        /// </summary>
        /// <param name="values">The values to remove</param>
        /// <param name="reason">The reason for the change</param>
        /// <returns>The new sensor state</returns>
        public SensorState RemoveValues(List<DateTime> values, ChangeReason reason)
        {
            if (values == null)
                throw new ArgumentException("A non-null list to be removed must be specified");

            var newState = Clone();
            newState.Reason = reason;

            foreach (var time in values)
            {
                newState.Values.Remove(time);
                newState.AddToChanges(time, reason.ID);
            }

            return newState;
        }
コード例 #13
0
ファイル: SensorState.cs プロジェクト: zhangzheng1205/B3
 public SensorState ChangeToZero(List <DateTime> values, ChangeReason reason)
 {
     return(ChangeToValue(values, 0, reason));
 }
コード例 #14
0
ファイル: SensorState.cs プロジェクト: zhangzheng1205/B3
 /// <summary>
 /// Returns a new sensor state where the given values are set to zero
 /// </summary>
 /// <param name="values">The values to set to zero</param>
 /// <param name="reason">The reason to make them zero</param>
 /// <returns>The new sensor state</returns>
 public SensorState MakeZero(List <DateTime> values, ChangeReason reason)
 {
     return(MakeValue(values, 0, reason));
 }
コード例 #15
0
ファイル: SensorState.cs プロジェクト: zhangzheng1205/B3
        /// <summary>
        /// Given a timestamp which represents a missing value, interpolates the dataset using the first known point before the given point, and the first known point after the given point in the list of keys.
        /// </summary>
        /// <param name="valuesToInterpolate">A list of data point 'keys' where values are missing.</param>
        /// <param name="ds">A dataset to use, which indicates the length of time that elapses between readings.</param>
        /// <returns>A sensor state with the interpolated data.</returns>
        public SensorState Interpolate(List <DateTime> valuesToInterpolate, Dataset ds, ChangeReason reason)
        {
            EventLogger.LogInfo(_owner.Owner, GetType().ToString(), "Starting extrapolation process");

            if (valuesToInterpolate == null)
            {
                throw new ArgumentNullException("valuesToInterpolate");
            }

            if (valuesToInterpolate.Count == 0)
            {
                throw new ArgumentException("You must specify at least one value to use for extrapolation.");
            }

            if (ds == null)
            {
                throw new ArgumentNullException("ds");
            }

            //First remove values
            var newState = RemoveValues(valuesToInterpolate, reason);

            newState.Reason = reason;

            foreach (var time in valuesToInterpolate)
            {
                if (newState.Values.ContainsKey(time))
                {
                    continue;
                }

                DateTime startValue;
                try
                {
                    startValue = newState.FindPrevValue(time);
                }
                catch (Exception)
                {
                    Debug.WriteLine("Failed to find start value continuing");
                    continue;
                }

                DateTime endValue;
                try
                {
                    endValue = newState.FindNextValue(time);
                }
                catch (Exception)
                {
                    Debug.WriteLine("Failed to find end value continuing");
                    continue;
                }

                var timeDiff = endValue.Subtract(startValue).TotalMinutes;
                var valDiff  = newState.Values[endValue] - newState.Values[startValue];
                var step     = valDiff / (timeDiff / ds.DataInterval);
                var value    = newState.Values[startValue] + step;

                for (var i = ds.DataInterval; i < timeDiff; i += ds.DataInterval)
                {
                    newState.Values[startValue.AddMinutes(i)] = (float)Math.Round(value, 2);

                    newState.AddToChanges(startValue.AddMinutes(i), reason.ID);

                    value += step;
                }
            }

            /* ==OLD METHOD==
             *  var first = valuesToInterpolate[0];
             *  DateTime startValue;
             *  try
             *  {
             *          startValue = FindPrevValue(first, ds);
             *  }
             *  catch(Exception e)
             *  {
             *          throw new DataException("No start value");
             *  }
             *  var endValue = DateTime.MinValue;
             *  var time = 0;
             *  try
             *  {
             *          while (endValue == DateTime.MinValue)
             *          {
             *                  endValue = (Values.ContainsKey(first.AddMinutes(time))
             *                                                  ? first.AddMinutes(time)
             *                                                  : DateTime.MinValue);
             *                  time += ds.DataInterval;
             *          }
             *  }
             *  catch(Exception e)
             *  {
             *          throw new DataException("No end value");
             *  }
             *
             *  var timeDiff = endValue.Subtract(startValue).TotalMinutes;
             *  var valDiff = Values[endValue] - Values[startValue];
             *  var step = valDiff / (timeDiff / ds.DataInterval);
             *  var value = Values[startValue] + step;
             *
             *  var newState = Clone();
             *
             *  for (var i = ds.DataInterval; i < timeDiff; i += ds.DataInterval)
             *  {
             *          newState.Values.Add(startValue.AddMinutes(i), (float)Math.Round(value, 2));
             *          value += step;
             *  }
             *
             *  EventLogger.LogInfo(GetType().ToString(), "Completing extrapolation process");*/

            return(newState);
        }
コード例 #16
0
ファイル: SensorState.cs プロジェクト: rwlamont/AllItUp
        /// <summary>
        /// Returns a new sensor state where the given values are set to a specific value
        /// </summary>
        /// <param name="values">The values to set</param>
        /// <param name="value">The value to set to</param>
        /// <param name="reason">The reson for the change</param>
        /// <returns>The new sensor state</returns>
        public SensorState MakeValue(List<DateTime> values, float value, ChangeReason reason)
        {
            if (values == null)
                throw new ArgumentNullException("A non-null list of keys to set as " + value + " must be specified.");

            var newState = Clone();
            newState.Reason = reason;

            foreach (var time in values)
            {
                newState.Values[time] = value;
                newState.AddToChanges(time, reason.ID);
            }

            return newState;
        }
コード例 #17
0
ファイル: SensorState.cs プロジェクト: rwlamont/AllItUp
 /// <summary>
 /// Returns a new sensor state where the given values are set to zero
 /// </summary>
 /// <param name="values">The values to set to zero</param>
 /// <param name="reason">The reason to make them zero</param>
 /// <returns>The new sensor state</returns>
 public SensorState MakeZero(List<DateTime> values, ChangeReason reason)
 {
     return MakeValue(values, 0, reason);
 }
コード例 #18
0
ファイル: FormulaEvaluator.cs プロジェクト: rwlamont/AllItUp
        /// <summary>
        /// Evaluates a formula
        /// </summary>
        /// <param name="formula">The formula to evaluate</param>
        /// <param name="startTime">The start time to evaluate from</param>
        /// <param name="endTime">The end time to stop evaluating from</param>
        /// <param name="skipMissingValues">Whether or not to skip missing values</param>
        /// <param name="reason">The reason for the evaluation</param>
        /// <returns>The sensor used and the newly evaulated state</returns>
        public KeyValuePair<Sensor, SensorState> EvaluateFormula(Formula formula, DateTime startTime, DateTime endTime, bool skipMissingValues, ChangeReason reason)
        {
            if (startTime >= endTime)
                throw new ArgumentException("End time must be greater than start time");

            // if the code compiled okay,
            // run the code using the new assembly (which is inside the results)
            if (formula.CompilerResults != null && formula.CompilerResults.CompiledAssembly != null)
            {
                // run the evaluation function
                return RunCode(formula, startTime, endTime, skipMissingValues, reason);
            }

            Debug.WriteLine("Could not evaluate formula");
            return new KeyValuePair<Sensor, SensorState>(null, null);
        }
コード例 #19
0
ファイル: Common.cs プロジェクト: zhangzheng1205/B3
        public static ChangeReason RequestReason(SimpleContainer container, IWindowManager windowManager, int defaultReasonNumber)
        {
            var specify = (SpecifyValueViewModel)container.GetInstance(typeof(SpecifyValueViewModel), "SpecifyValueViewModel");

            specify.Title         = "Log Reason";
            specify.Message       = "Please specify a reason for this change:";
            specify.ShowComboBox  = true;
            specify.ComboBoxItems = ChangeReason.ChangeReasons.Where(x => !x.Reason.StartsWith("[Importer]")).Select(x => x.Reason).ToList();
            specify.ShowCancel    = true;

            var defaultReason = ChangeReason.ChangeReasons.FirstOrDefault(x => x.ID == defaultReasonNumber);

            if (defaultReason != null)
            {
                specify.ComboBoxSelectedIndex = specify.ComboBoxItems.IndexOf(defaultReason.Reason);
            }

            windowManager.ShowDialog(specify);

            if (specify.WasCanceled)
            {
                return(null);
            }

            return(ChangeReason.ChangeReasons.FirstOrDefault(x => x.Reason == specify.Text) ?? ChangeReason.AddNewChangeReason(specify.Text));
        }
コード例 #20
0
ファイル: FormulaEvaluator.cs プロジェクト: rwlamont/AllItUp
        /// <summary>
        /// Runs the formula
        /// </summary>
        /// <param name="formula">The formula to run</param>
        /// <param name="startTime">The start time to evaluate from</param>
        /// <param name="endTime">The end time to stop evaluating from</param>
        /// <param name="skipMissingValues">Whether or not to skip missing values</param>
        /// <param name="reason">The reason for the evaluation</param>
        /// <returns>The sensor used and the newly evaulated state</returns>
        private KeyValuePair<Sensor, SensorState> RunCode(Formula formula, DateTime startTime, DateTime endTime, bool skipMissingValues, ChangeReason reason)
        {
            var executingAssembly = formula.CompilerResults.CompiledAssembly;
            try
            {
                //cant call the entry method if the assembly is null
                if (executingAssembly != null)
                {
                    var assemblyInstance = executingAssembly.CreateInstance("IndiaTango.Calculator");
                    //Use reflection to call the static Main function

                    var modules = executingAssembly.GetModules(false);
                    var types = modules[0].GetTypes();

                    //loop through each class that was defined and look for the first occurrance of the entry point method
                    foreach (var mi in from type in types select type.GetMethods() into mis from mi in mis where mi.Name == "ApplyFormula" select mi)
                    {
                        return (KeyValuePair<Sensor, SensorState>)mi.Invoke(assemblyInstance, new object[] { _sensorVariables, formula.SensorAppliedTo, startTime, endTime, skipMissingValues, reason });
                    }

                }
            }
            catch (Exception ex)
            {
                Common.ShowMessageBoxWithException("Error", "An exception occurred while executing the script", false, true, ex);
                Debug.WriteLine("Error:  An exception occurred while executing the script: \n" + ex);
            }

            return new KeyValuePair<Sensor, SensorState>(null, null);
        }
コード例 #21
0
ファイル: FormulaEvaluator.cs プロジェクト: zhangzheng1205/B3
        /// <summary>
        /// Runs the formula
        /// </summary>
        /// <param name="formula">The formula to run</param>
        /// <param name="startTime">The start time to evaluate from</param>
        /// <param name="endTime">The end time to stop evaluating from</param>
        /// <param name="skipMissingValues">Whether or not to skip missing values</param>
        /// <param name="reason">The reason for the evaluation</param>
        /// <returns>The sensor used and the newly evaulated state</returns>
        private KeyValuePair <Sensor, SensorState> RunCode(Formula formula, DateTime startTime, DateTime endTime, bool skipMissingValues, ChangeReason reason)
        {
            var executingAssembly = formula.CompilerResults.CompiledAssembly;

            try
            {
                //cant call the entry method if the assembly is null
                if (executingAssembly != null)
                {
                    var assemblyInstance = executingAssembly.CreateInstance("IndiaTango.Calculator");
                    //Use reflection to call the static Main function

                    var modules = executingAssembly.GetModules(false);
                    var types   = modules[0].GetTypes();

                    //loop through each class that was defined and look for the first occurrance of the entry point method
                    foreach (var mi in from type in types select type.GetMethods() into mis from mi in mis where mi.Name == "ApplyFormula" select mi)
                    {
                        return((KeyValuePair <Sensor, SensorState>)mi.Invoke(assemblyInstance, new object[] { _sensorVariables, formula.SensorAppliedTo, startTime, endTime, skipMissingValues, reason }));
                    }
                }
            }
            catch (Exception ex)
            {
                Common.ShowMessageBoxWithException("Error", "An exception occurred while executing the script", false, true, ex);
                Debug.WriteLine("Error:  An exception occurred while executing the script: \n" + ex);
            }

            return(new KeyValuePair <Sensor, SensorState>(null, null));
        }
コード例 #22
0
ファイル: SensorState.cs プロジェクト: rwlamont/AllItUp
        /// <summary>
        /// Creates a new sensor state with the specified timestamp representing the date it was last edited, a list of values representing data values recorded in this state, and a reason for the changes stored in this state.
        /// </summary>
        /// <param name="owner">The sensor the sensor state belongs to</param>
        /// <param name="editTimestamp">A DateTime object representing the last edit date and time for this sensor state.</param>
        /// <param name="valueList">A list of data values, representing values recorded in this sensor state.</param>
        /// <param name="reason">A string indicating the reason for the changes made in this state.</param>
        /// <param name="isRaw">Whether or not this represents the sensors raw data.</param>
        /// <param name="changes">The list of changes that have occured for this sensor</param>
        public SensorState(Sensor owner, DateTime editTimestamp, Dictionary<DateTime, float> valueList, ChangeReason reason, bool isRaw, Dictionary<DateTime, LinkedList<int>> changes)
        {
            if (valueList == null)
                throw new ArgumentNullException("valueList");

            _reason = reason;
            _editTimestamp = editTimestamp;
            _valueList = valueList;
            _isRaw = isRaw;
            _changes = changes ?? new Dictionary<DateTime, LinkedList<int>>();
            _owner = owner;
        }
コード例 #23
0
ファイル: SensorState.cs プロジェクト: rwlamont/AllItUp
        /// <summary>
        /// Returns a calibrated state
        /// </summary>
        /// <param name="start">The start timestamp for the calibration</param>
        /// <param name="end">The end timestamp for the calibration</param>
        /// <param name="origA">The original high</param>
        /// <param name="origB">The original low</param>
        /// <param name="newA">The calibrated high</param>
        /// <param name="newB">The calibrated low</param>
        /// <param name="reason">The reason for the calibration</param>
        /// <returns>The calibrated sensor state</returns>
        public SensorState Calibrate(DateTime start, DateTime end, double origA, double origB, double newA, double newB, ChangeReason reason)
        {
            if (start >= end)
                throw new ArgumentException("End time must be greater than start time");

            if (origB > origA)
                throw new ArgumentException("Calibrated B value must be less than the calibrated A value");

            if (newB > newA)
                throw new ArgumentException("Current B value must be less than the current A value");

            //The total minutes in the time span
            double totalMinutes = end.Subtract(start).TotalMinutes;

            //The distance from the median line to the A and B points
            double origMedianDistance = (origA - origB) / 2;
            double newMedianDistance = (newA - newB) / 2;

            //The largest distance the points must move to normalise them with the median line
            double normalisationDistance = newMedianDistance - origMedianDistance;

            //The largest distance the points must move from the normalised position, to the calibrated (correct) position
            double calibrationDistance = (newB + newMedianDistance) - (origB + origMedianDistance);

            //The increment that must be made per minute to normalise the points above and below the median line
            double normalisationIncrement = normalisationDistance / totalMinutes;
            double calibrationIncrement = calibrationDistance / totalMinutes;

            //The gradients of the lines
            double slopeA = (newA - origA) / totalMinutes;
            double slopeMedian = ((newB + newMedianDistance) - (origB + origMedianDistance)) / totalMinutes;

            //The y-intercepts of the lines
            double interceptA = origA;
            double interceptMedian = origB + origMedianDistance;

            //Copy!
            SensorState newState = Clone();

            foreach (var value in Values)
            {
                if (value.Key < start || value.Key > end)
                    continue;

                double timeDiff = value.Key.Subtract(start).TotalMinutes;
                double normalisationScale = GetRelativePositionBetweenLines(interceptA, interceptMedian, slopeA, slopeMedian, timeDiff, value.Value);

                newState.Values[value.Key] = (float)(value.Value - (normalisationScale * normalisationIncrement + calibrationIncrement) * timeDiff);
                newState.AddToChanges(value.Key, reason.ID);
            }

            return newState;
        }
コード例 #24
0
ファイル: SensorState.cs プロジェクト: zhangzheng1205/B3
 public SensorState(Sensor owner, Dictionary <DateTime, float> valueList, ChangeReason reason, Dictionary <DateTime, LinkedList <int> > changes) : this(owner, DateTime.Now, valueList, reason, false, changes)
 {
 }