2008-11-20 42 views

Respuesta

13

Existen varios modos de muestreo diferentes con los que puede experimentar.

  • Raw
  • interpolada
  • Lab
  • tendencia
  • Calculado

Estos modos están disponibles usando todas las siguientes APIs.

  • API de usuario (ihuapi.dll)
  • SDK (ihsdk.dll)
  • OLEDB (iholedb.dll)
  • Acess cliente de API (Proficy.Historian.ClientAccess.API)

De estos, el modo de muestreo de tendencias es probablemente lo que desea, ya que está diseñado específicamente para gráficos/tendencias. Sin embargo, el laboratorio y la interpolación también pueden ser útiles.

Lea el libro electrónico para obtener más información sobre cada modo de muestreo. En mi máquina está almacenado como C:\Program Files\GE Fanuc\Proficy Historian\Docs\iHistorian.chm y tengo la versión 3.5 instalada. Presta especial atención a las siguientes secciones.

  • Uso del Historiador OLE DB
  • Temas avanzados | Recuperación

Así es como puede construir un OLEDB para hacer un muestreo de tendencia.

set 
    SamplingMode = 'Trend', 
    StartTime = '2010-07-01 00:00:00', 
    EndTime = '2010-07-02 00:00:00', 
    IntervalMilliseconds = 1h 
select 
    timestamp, 
    value, 
    quality 
from 
    ihRawData 
where 
    tagname = 'YOUR_TAG' 

Mostrando los métodos equivalentes que utilizan la API de usuario y el SDK son complejos (más aún con la API de usuario), ya que requieren una gran cantidad de fontanería en el código para obtener la configuración. La API de acceso de cliente es más nueva y usa WCF detrás de escena.

Por cierto, hay algunas limitaciones con el método OLEDB.

  • pesar de lo que la documentación dice que tengo Nunca sido capaz de obtener los parámetros de consulta nativos para trabajar. Eso es sorprendente si quiere usarlo con SQL Server Reporting Services, por ejemplo.
  • No puede escribir muestras en el archivo ni realizar cambios en la configuración de Historian, como agregar/cambiar etiquetas, escribir mensajes, etc.
  • En algunos casos puede ser un poco lento.
  • No tiene ninguna provisión para cruzar múltiples nombres de etiquetas en las columnas y luego llevar adelante muestras para que exista un valor para cada combinación de marca de tiempo y etiqueta. El modo de muestreo de tendencias te lleva a la mitad, pero todavía no cruza y no carga muestras crudas. Por otra parte, la API de usuario y el SDK tampoco pueden hacer esto.
+0

Un poco tarde lo sé, pero es mejor tarde que nunca. Además, responder viejas preguntas sobre SO es como mi estilo de todos modos. –

+0

No tengo tiempo para probar esto ahora, pero es exactamente lo que estaba buscando cuando comencé. ¡Gracias! ¿Puede por casualidad agregar una nota sobre dónde se encuentra normalmente el ebook? –

+0

¿Alguna idea sobre cómo usar las funciones del historiador incorporado como PreviousValue de esta manera? ¿Puede el oledb hacer esto? algo en la línea de seleccionar "indicación de fecha y hora, PreviousValue (Time, tagname) from ..." – xdumaine

4

Un compañero de trabajo mío puso esta juntos:

En web.config:

<add name="HistorianConnectionString" 
    providerName="ihOLEDB.iHistorian.1" 
    connectionString=" 
     Provider=ihOLEDB.iHistorian; 
     User Id=; 
     Password=; 
     Data Source=localhost;" 
/> 

En la capa de datos:

public DataTable GetProficyData(string tagName, DateTime startDate, DateTime endDate) 
{ 
    using (System.Data.OleDb.OleDbConnection cn = new System.Data.OleDb.OleDbConnection()) 
    { 
     cn.ConnectionString = webConfig.ConnectionStrings.ConnectionStrings["HistorianConnectionString"]; 
     cn.Open(); 

     string queryString = string.Format(
       "set samplingmode = rawbytime\n select value as theValue,Timestamp from ihrawdata where tagname = '{0}' AND timestamp between '{1}' and '{2}' and value > 0 order by timestamp", 
       tagName.Replace("'", "\""), startDate, endDate); 

     System.Data.OleDb.OleDbDataAdapter adp = new System.Data.OleDb.OleDbDataAdapter(queryString, cn); 
     DataSet ds = new DataSet(); 

     adp.Fill(ds); 
     return ds.Tables[0]; 
    } 
} 

Actualización:

Esto funcionó bien, pero nos encontramos con un problema con las etiquetas que no se actualizan con mucha frecuencia. Si la etiqueta no se actualizó cerca del inicio o el final de los startDate y endDate solicitados, las tendencias se verán mal. Peor aún, todavía había casos en los que no había puntos explícitos durante la ventana solicitada; no obtendríamos datos.

resolví esto haciendo tres consultas:

  1. el valor anterior antes la fecha de inicio
  2. Los puntos entre startDate y endDate
  3. El valor próximo después la endDate

Esta es una forma potencialmente ineficiente de hacerlo pero funciona:

public DataTable GetProficyData(string tagName, DateTime startDate, DateTime endDate) 
{ 
    DataSet ds = new DataSet(); 
    string queryString; 
    System.Data.OleDb.OleDbDataAdapter adp; 

    using (System.Data.OleDb.OleDbConnection cn = new System.Data.OleDb.OleDbConnection()) 
    { 
     cn.ConnectionString = proficyConn.ConnectionString; 
     cn.Open(); 

     // always get a start value 
     queryString = string.Format(
      "set samplingmode = lab\nselect value as theValue,Timestamp from ihrawdata where tagname = '{0}' AND timestamp between '{1}' and '{2}' order by timestamp", 
      tagName.Replace("'", "\""), startDate.AddMinutes(-1), startDate); 
     adp = new System.Data.OleDb.OleDbDataAdapter(queryString, cn); 
     adp.Fill(ds); 

     // get the range 
     queryString = string.Format(
      "set samplingmode = rawbytime\nselect value as theValue,Timestamp from ihrawdata where tagname = '{0}' AND timestamp between '{1}' and '{2}' order by timestamp", 
      tagName.Replace("'", "\""), startDate, endDate); 
     adp = new System.Data.OleDb.OleDbDataAdapter(queryString, cn); 
     adp.Fill(ds); 

     // always get an end value 
     queryString = string.Format(
      "set samplingmode = lab\nselect value as theValue,Timestamp from ihrawdata where tagname = '{0}' AND timestamp between '{1}' and '{2}' order by timestamp", 
     tagName.Replace("'", "\""), endDate.AddMinutes(-1), endDate); 
     adp = new System.Data.OleDb.OleDbDataAdapter(queryString, cn); 
     adp.Fill(ds); 

     return ds.Tables[0]; 
    } 
} 

Y sí, lo sé, esas consultas se deben parametrizar.

+0

OLE es muy lento. El uso de la API tiene un rendimiento mucho mejor, también puede escribir métodos de extensión que le permiten hacer mucho más de lo que OLE brindará de inmediato. – rolls

+0

En cuanto a la obtención de muestras no puede hacer "ReadSamplesByCount" en lugar de tiempo, de esa manera se obtiene al menos 1 muestra de nuevo. Si no hay muchas muestras, la muestra puede tardar años después del período de tiempo que desea mostrar. – rolls

0

Michael - en IP21 hay una tabla "Interpolada", así como la tabla de puntos de datos "reales". ¿Tiene Proficy eso también?

+0

@reallyJim Creo que sí, sin embargo, en mi caso necesitaba datos sin procesar –

+0

Me encontré con lo mismo hace unos años con un sistema PI, así que siento su dolor! – reallyJim

0

escribimos un contenedor DLL que se veía así de esta manera:

[DllImport("IHUAPI.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "[email protected]")] 
public static extern int ihuReadRawDataByTime(int serverhandle, string tagname, ref IHU_TIMESTAMP startTime, ref IHU_TIMESTAMP endTime, ref int noOfSamples, ref IHU_DATA_SAMPLE* dataValues); 
... 
private int _handle; 

public HistorianTypes.ErrorCode ReadRawByTime(string tagName, DateTime startTime, DateTime endTime, 
               out double[] timeStamps, out double[] values, out IhuComment [] comments) 
{ 
    var startTimeStruct = new IhuApi.IHU_TIMESTAMP(); //Custom datetime to epoch extension method 
    var endTimeStruct = new IhuApi.IHU_TIMESTAMP(); 

    int lRet = 0; 
    int noOfSamples = 0; 
    startTimeStruct = DateTimeToTimeStruct(dstZone.ToUniversalTime(startTime)); 
    endTimeStruct = DateTimeToTimeStruct(dstZone.ToUniversalTime(endTime)); 
    IhuApi.IHU_DATA_SAMPLE* dataSample = (IhuApi.IHU_DATA_SAMPLE*)new IntPtr(0); 

    try { 
     lRet = IhuApi.ihuReadRawDataByTime 
      (
       _handle, // the handle returned from the connect 
       tagName, // the single tagname to retrieve 
       ref startTimeStruct, // start time for query 
       ref endTimeStruct, // end time for query 
       ref noOfSamples, // will be set by API 
       ref dataSample // will be allocated and populated in the user API 
      ); 
      .... 

Algunas notas son que iFIX comprobará si el archivo DLL se carga en el arranque por lo que necesita para hacer cosas como cargar dinámicamente/descarga la DLL para que otras aplicaciones no se cuelguen. Lo hicimos eliminando/agregando claves de registro sobre la marcha.

Otra es que si sondea 10.000 muestras y una de las muestras está dañada, se eliminarán todas las 10.000 muestras. Debe implementar un manejador de datos incorrecto que se iniciará en ambos lados de los datos incorrectos e incremente en pasos para obtener todos los datos a cada lado de la muestra incorrecta.

Hay varios archivos de encabezado C que contienen todos los códigos de error y el encabezado de función para la DLL.

Cuestiones relacionadas