7 Replies Latest reply on Sep 15, 2011 4:52 PM by matthew.rivett

    Autoscale with limits

    matthew.rivett

      Has anyone written any code that would make a trend autoscale if it is within certain limits but if it is outside of those limits have a min and max?

       

      For example if the values of the traces were all between -1500 and 1500 it would be autoscaled.  If any one of the trends exceeded those limits it would be set to -1500 and 1500.  Sometimes we have bad data outside of the normal range that will throw off the autoscale and make the trend impossible to read.

       

      Thanks!

        • Re: Autoscale with limits
          dtakara

          Hi Matt,

           

          You may want to try this:

           
          Sub UpdateScale()
          Const Min = -1500
          Const Max = 1500
          
          Dim i As Long
          Dim aPIValue As PIValue
          Trend1.CurrentTrace = 1
          
          If Trend1.TraceValuesCount > 0 Then
              For i = 1 To Trend1.TraceValuesCount
                  Set aPIValue = Trend1.GetTracePIValue(i)
                  If aPIValue.Value > Max Or aPIValue.Value < Min Then
                      Trend1.SetTraceScale Min, Max
                      Exit Sub
                  End If
                  Trend1.SetTraceScale "Autorange", "Autorange"
              Next i
          End If
          
          End Sub
          
          Private Sub Trend1_DataUpdate(ByVal ntrace As Integer)
              UpdateScale
          End Sub
          

          In case the quantity of values in your trend is not so large, it should probably have acceptable performance.

            • Re: Autoscale with limits
              matthew.rivett

              Daniel,

               

              I have 7 traces with an hour of data each.  The tags update approx every 2 seconds.  For one trace I saw around 1600 data points for the hour.  Process Book is locking up with this code for me.  Would it be really inefficient to use the PI-SDK to analyze the data and set the scales based on it?

               

              Thanks,

               

              Matt

                • Re: Autoscale with limits
                  dtakara

                  The PI-SDK RecordedValues method with a filter expression might be more efficient. Could you try this on a trend with a single tag?

                   
                  Sub UpdateScale()
                      ' lower limit
                      Const Min = 0
                      ' upper limit
                      Const Max = 100
                      
                      Dim i As Long
                      Dim myServer As Server
                      Dim myPIPoint As PIPoint
                      Dim myPIData As PIData
                      Dim myPIValues As PIValues
                      Dim msg As String
                      Dim TagName As String
                      Dim NodeName As String
                      Dim st As New PITimeFormat
                      Dim et As New PITimeFormat
                      
                      
                      TagName = ParseTagName(Trend1.GetTagName(1))
                      NodeName = ParseNodeName(Trend1.GetTagName(1))
                      st.InputString = Trend1.StartTime
                      et.InputString = Trend1.endtime
                      
                      Set myServer = PISDK.Servers(NodeName)
                      Set myPIPoint = myServer.PIPoints(TagName)
                      Set myPIData = myPIPoint.Data
                      
                      ' checking for the existance of values outside limits in the trend period
                      Set myPIValues = myPIData.RecordedValues(st, et, btInside, "'" & TagName & "' > " & _
                                              CStr(Max) & " or '" & TagName & "' < " & CStr(Min), fvRemoveFiltered)
                      If myPIValues.Count > 0 Then
                          Trend1.SetTraceScale Min, Max
                      Else
                          Trend1.SetTraceScale "Autorange", "Autorange"
                      End If
                  
                  End Sub
                  
                  Function ParseTagName(FullTagPath As String) As String
                  
                      ' This function strips the tag name and backslash chars from the full tag path
                      ' returned by the properties of some ProcessBook objects. For example,
                      ' "\\milkyway\sinusoid" is stripped to "sinusoid".
                      Dim SearchChar As String
                      Dim MyPos As Integer
                      SearchChar = "\"
                      MyPos = InStr(3, FullTagPath, SearchChar, vbTextCompare)
                      ParseTagName = Right$(FullTagPath, Len(FullTagPath) - MyPos)
                      
                  End Function
                  
                  Function ParseNodeName(FullTagPath As String) As String
                  
                      ' This function strips the node name and backslash chars from the full tag path
                      ' returned by the properties of some ProcessBook objects. For example,
                      ' "\\milkyway\sinusoid" is stripped to "milkyway".
                      Dim SearchChar As String
                      Dim MyPos As Integer
                      SearchChar = "\"
                      MyPos = InStr(3, FullTagPath, SearchChar, vbTextCompare)
                      ParseNodeName = Mid(FullTagPath, 3, MyPos - 3)
                      
                  End Function
                  
                  Private Sub Trend1_DataUpdate(ByVal ntrace As Integer)
                  
                      UpdateScale
                      
                  End Sub
                  

                   

                   

                   

                    • Re: Autoscale with limits
                      matthew.rivett

                      Daniel,

                       

                      This code is very fast for a single tag.  I'm going to modify it to loop through all of them and see how it performs.

                       

                      Thanks,

                       

                      Matt

                      • Re: Autoscale with limits
                        matthew.rivett

                         

                         
                        Sub UpdateScale()
                            ' lower limit
                            Const Min = -1500
                            ' upper limit
                            Const Max = 1500
                             
                            Dim i As Long
                            Dim myServer As Server
                            Dim myPIPoint As PIPoint
                            Dim myPIData As PIData
                            Dim myPIValues As PIValues
                            Dim msg As String
                            Dim TagName As String
                            Dim NodeName As String
                            Dim st As New PITimeFormat
                            Dim et As New PITimeFormat
                            Dim bAuto As Boolean
                            bAuto = True
                            Trend1.CurrentTrace = 1
                            
                            If Trend1.TraceCount > 0 Then
                                For i = 1 To Trend1.TraceCount
                                    TagName = ParseTagName(Trend1.GetTagName(i))
                                    NodeName = ParseNodeName(Trend1.GetTagName(i))
                                    st.InputString = Trend1.StartTime
                                    et.InputString = Trend1.EndTime
                                     
                                    Set myServer = PISDK.Servers(NodeName)
                                    Set myPIPoint = myServer.PIPoints(TagName)
                                    Set myPIData = myPIPoint.Data
                                     
                                    ' checking for the existance of values outside limits in the trend period
                                    Set myPIValues = myPIData.RecordedValues(st, et, btInside, "'" & TagName & "' > " & _
                                                            CStr(Max) & " or '" & TagName & "' < " & CStr(Min), fvRemoveFiltered)
                                    If myPIValues.Count > 0 Then
                                        bAuto = False
                                        Exit For
                                    End If
                                Next i
                            End If
                            
                            If bAuto Then
                                Trend1.SetTraceScale "Autorange", "Autorange"
                            Else
                                Trend1.SetTraceScale Min, Max
                            End If
                         
                        End Sub
                         
                        Function ParseTagName(FullTagPath As String) As String
                         
                            ' This function strips the tag name and backslash chars from the full tag path
                            ' returned by the properties of some ProcessBook objects. For example,
                            ' "\\milkyway\sinusoid" is stripped to "sinusoid".
                            Dim SearchChar As String
                            Dim MyPos As Integer
                            SearchChar = "\"
                            MyPos = InStr(3, FullTagPath, SearchChar, vbTextCompare)
                            ParseTagName = Right$(FullTagPath, Len(FullTagPath) - MyPos)
                             
                        End Function
                         
                        Function ParseNodeName(FullTagPath As String) As String
                         
                            ' This function strips the node name and backslash chars from the full tag path
                            ' returned by the properties of some ProcessBook objects. For example,
                            ' "\\milkyway\sinusoid" is stripped to "milkyway".
                            Dim SearchChar As String
                            Dim MyPos As Integer
                            SearchChar = "\"
                            MyPos = InStr(3, FullTagPath, SearchChar, vbTextCompare)
                            ParseNodeName = Mid(FullTagPath, 3, MyPos - 3)
                             
                        End Function
                         
                        Private Sub Trend1_DataUpdate(ByVal ntrace As Integer)
                             If DateDiff("n", dtLastScaleReset, Now) >= 1 Then
                                UpdateScale
                                dtLastScaleReset = Now()
                            End If
                        End Sub
                        

                         

                         

                        Do you see any obvious flaws with this code?  It seems to be working well.

                         

                         

                          • Re: Autoscale with limits
                            dtakara

                            I don't see any obvious flaws, Matt.

                             

                            If I understand your code correctly, you want to have a trend with multiple traces on a single scale and you want this single scale to be within Min and Max whenever any of the traces goes out of the expected scale. If that's so, then you're good.

                             

                            Also, I understand you don't want to run the code to adjust the scale of your trend adjusted more often than once a minute. That sounds fair enough, in order to avoid excessive load on the PI Server from this single ProcessBook trend.

                             

                            By the way, you may want to remove the auxiliary variable msg, which I forgot to remove from my sample code.

                              • Re: Autoscale with limits
                                matthew.rivett

                                That is correct.  I did notice msg wasn't used after I pasted the code.  Here is the complete code for anyone who might need it.  Thank you for your help Daniel.

                                 

                                If your trend isn't named Trend1 you'll need to make some modifications.

                                 

                                 

                                 

                                 

                                 
                                Dim dtLastScaleReset As Date
                                
                                Sub UpdateScale()
                                    ' lower limit
                                    Const Min = -1500
                                    ' upper limit
                                    Const Max = 1500
                                     
                                    Dim i As Long
                                    Dim myServer As Server
                                    Dim myPIPoint As PIPoint
                                    Dim myPIData As PIData
                                    Dim myPIValues As PIValues
                                    Dim TagName As String
                                    Dim NodeName As String
                                    Dim st As New PITimeFormat
                                    Dim et As New PITimeFormat
                                    Dim bAuto As Boolean
                                    bAuto = True
                                    Trend1.CurrentTrace = 1
                                    
                                    If Trend1.TraceCount > 0 Then
                                        For i = 1 To Trend1.TraceCount
                                            TagName = ParseTagName(Trend1.GetTagName(i))
                                            NodeName = ParseNodeName(Trend1.GetTagName(i))
                                            st.InputString = Trend1.StartTime
                                            et.InputString = Trend1.EndTime
                                             
                                            Set myServer = PISDK.Servers(NodeName)
                                            Set myPIPoint = myServer.PIPoints(TagName)
                                            Set myPIData = myPIPoint.Data
                                             
                                            ' checking for the existance of values outside limits in the trend period
                                            Set myPIValues = myPIData.RecordedValues(st, et, btInside, "'" & TagName & "' > " & _
                                                                    CStr(Max) & " or '" & TagName & "' < " & CStr(Min), fvRemoveFiltered)
                                            If myPIValues.Count > 0 Then
                                                bAuto = False
                                                Exit For
                                            End If
                                        Next i
                                    End If
                                    
                                    If bAuto Then
                                        Trend1.SetTraceScale "Autorange", "Autorange"
                                    Else
                                        Trend1.SetTraceScale Min, Max
                                    End If
                                End Sub
                                 
                                Function ParseTagName(FullTagPath As String) As String
                                    ' This function strips the tag name and backslash chars from the full tag path
                                    ' returned by the properties of some ProcessBook objects. For example,
                                    ' "\\milkyway\sinusoid" is stripped to "sinusoid".
                                    Dim SearchChar As String
                                    Dim MyPos As Integer
                                    SearchChar = "\"
                                    MyPos = InStr(3, FullTagPath, SearchChar, vbTextCompare)
                                    ParseTagName = Right$(FullTagPath, Len(FullTagPath) - MyPos)
                                End Function
                                 
                                Function ParseNodeName(FullTagPath As String) As String
                                    ' This function strips the node name and backslash chars from the full tag path
                                    ' returned by the properties of some ProcessBook objects. For example,
                                    ' "\\milkyway\sinusoid" is stripped to "milkyway".
                                    Dim SearchChar As String
                                    Dim MyPos As Integer
                                    SearchChar = "\"
                                    MyPos = InStr(3, FullTagPath, SearchChar, vbTextCompare)
                                    ParseNodeName = Mid(FullTagPath, 3, MyPos - 3)
                                End Function
                                 
                                Private Sub Trend1_DataUpdate(ByVal ntrace As Integer)
                                     If DateDiff("n", dtLastScaleReset, Now) >= 1 Then
                                        UpdateScale
                                        dtLastScaleReset = Now()
                                    End If
                                End Sub
                                
                                Private Sub Display_Open()
                                    dtLastScaleReset = Now()
                                End Sub