/// <summary> /// Get <see cref="MeasurementMetadata"/> for specified <see cref="SignalKind"/>. /// </summary> /// <param name="lookup">A lookup table by signal reference.</param> /// <param name="type"><see cref="SignalKind"/> to request signal reference for.</param> /// <returns>The <see cref="MeasurementMetadata"/> for a given <see cref="SignalKind"/>; otherwise <c>null</c> if value does not exist.</returns> public MeasurementMetadata GetMetadata(Dictionary <string, MeasurementMetadata> lookup, SignalKind type) { // Clear the cache if the lookup dictionary has changed. // Since the instance of Lookup is effectively readonly as implemented in PhasorMeasurementMapper // a simple reference check is all that is needed. If it could be modified, this would likely be a // concurrent dictionary instead. if (m_metadataLookupObject != lookup) { Array.Clear(m_generatedMeasurementMetadataCache, 0, m_generatedMeasurementMetadataCache.Length); m_metadataLookupObject = lookup; } // Gets the cache for the supplied SignalKind int typeIndex = (int)type; MeasurementMetadata[] metadataArray = m_generatedMeasurementMetadataCache[typeIndex]; // If this SignalKind is null, create the sub array and generate all item lookups if ((object)metadataArray == null) { metadataArray = new MeasurementMetadata[1]; m_generatedMeasurementMetadataCache[typeIndex] = metadataArray; string signalReference = GetSignalReference(type); MeasurementMetadata metadata; if (lookup.TryGetValue(signalReference, out metadata)) { metadataArray[0] = metadata; } } return(metadataArray[0]); }
public static bool TryGetMeasurementMetdataFromConfigurationFrame(System.Guid signalID, ConfigurationFrame sourceFrame, out MeasurementMetadata measurementMetadata) { guid_t tempsignalID = Common.ParseGuid(signalID.ToByteArray(), true); measurementMetadata = new MeasurementMetadata(); { bool ret = CommonPINVOKE.SubscriberInstanceBase_TryGetMeasurementMetdataFromConfigurationFrame(guid_t.getCPtr(tempsignalID), ConfigurationFrame.getCPtr(sourceFrame), MeasurementMetadata.getCPtr(measurementMetadata)); if (CommonPINVOKE.SWIGPendingException.Pending) { throw CommonPINVOKE.SWIGPendingException.Retrieve(); } return(ret); } }
private static void MapMeasurementAttributes(ICollection <IMeasurement> mappedMeasurements, string signalReference, IMeasurement parsedMeasurement) { // Coming into this function the parsed measurement value will only have a "value" and a "timestamp"; // the measurement will not yet be associated with an actual historian measurement ID as the measurement // will have come directly out of the parsed phasor protocol data frame. We take the generated signal // reference and use that to lookup the actual historian measurement ID, source, adder and multipler. MeasurementMetadata definedMeasurement = m_definedMeasurements.GetOrAdd(signalReference, signal => MeasurementKey.LookUpOrCreate(Guid.NewGuid(), signal, ++measurementID).Metadata); // Assign ID and other relevant attributes to the parsed measurement value parsedMeasurement.Metadata = definedMeasurement; // Add the updated measurement value to the destination measurement collection mappedMeasurements.Add(parsedMeasurement); }
private void PublishRandomValues() { const ulong Interval = 1000; // If metadata can change, the following integer should not be static: int count = m_measurementMetadata.Count; long timestamp = RoundToSubsecondDistribution(DateTime.UtcNow.Ticks, 30); Measurement[] measurements = new Measurement[count]; Random rand = new Random(); // Create new measurement values for publication for (int i = 0; i < count; i++) { MeasurementMetadata metadata = m_measurementMetadata[i]; Measurement measurement = new Measurement(metadata.SignalID, timestamp); double randFraction = rand.NextDouble(); double sign = randFraction > 0.5D ? 1.0D : -1.0D; measurement.Value = metadata.Reference.Kind switch { SignalKind.Frequency => 60.0D + sign * randFraction * 0.1D, SignalKind.DfDt => sign * randFraction * 2.0D, SignalKind.Magnitude => 500.0D + sign * randFraction * 50.0D, SignalKind.Angle => sign * randFraction * 180.0D, _ => sign * randFraction * uint.MaxValue }; measurements[i] = measurement; } // Publish measurements PublishMeasurements(measurements); // Display a processing message every few seconds bool showMessage = m_processCount + (ulong)count >= (m_processCount / Interval + 1) * Interval && GetTotalMeasurementsSent() > 0; m_processCount += (ulong)count; if (showMessage) { StatusMessage($"{GetTotalMeasurementsSent()} measurements published so far...\n"); } }
//Later, a more sophisticated factory method is required public RowReaderWriter CreateRowReaderWriter(MeasurementMetadata metadata) { var valueType = metadata.ColumnsInternal[1].ValueType; if (valueType == typeof(float)) { return(new FloatRowReaderWriter()); } if (valueType == typeof(double)) { return(new DoubleRowReaderWriter()); } if (valueType == typeof(bool)) { return(new BoolRowReaderWriter()); } if (valueType == typeof(byte)) { return(new ByteRowReaderWriter()); } if (valueType == typeof(short)) { return(new ShortRowReaderWriter()); } if (valueType == typeof(int)) { return(new IntRowReaderWriter()); } if (valueType == typeof(long)) { return(new LongRowReaderWriter()); } if (valueType == typeof(decimal)) { return(new DecimalRowReaderWriter()); } if (valueType == typeof(DateTime)) { return(new DateTimeRowReaderWriter()); } throw new NotSupportedException("Invalid column type"); }
/// <summary> /// Get <see cref="MeasurementMetadata"/> for specified <see cref="SignalKind"/>. /// </summary> /// <param name="lookup">A lookup table by signal reference.</param> /// <param name="type"><see cref="SignalKind"/> to request signal reference for.</param> /// <param name="index">Index <see cref="SignalKind"/> to request signal reference for.</param> /// <param name="count">Number of signals defined for this <see cref="SignalKind"/>.</param> /// <returns>The MeasurementMetadata for a given <see cref="SignalKind"/>. Null if it does not exist.</returns> public MeasurementMetadata GetMetadata(Dictionary <string, MeasurementMetadata> lookup, SignalKind type, int index, int count) { // Clear the cache if the lookup dictionary has changed. // Since the instance of Lookup is effectively readonly as implemented in PhasorMeasurementMapper // a simple reference check is all that is needed. If it could be modified, this would likely be a // concurrent dictionary instead. if (m_metadataLookupObject != lookup) { Array.Clear(m_generatedMeasurementMetadataCache, 0, m_generatedMeasurementMetadataCache.Length); m_metadataLookupObject = lookup; } // Gets the cache for the supplied SignalKind int typeIndex = (int)type; MeasurementMetadata[] metadataArray = m_generatedMeasurementMetadataCache[typeIndex]; // If this SignalKind is null, create the sub array and generate all item lookups, also, rebuild // if the count is not the same. This could be because a new config frame was received. if ((object)metadataArray == null || metadataArray.Length != count) { metadataArray = new MeasurementMetadata[count]; m_generatedMeasurementMetadataCache[typeIndex] = metadataArray; for (int x = 0; x < count; x++) { string signalReference = GetSignalReference(type, x, count); MeasurementMetadata metadata; if (lookup.TryGetValue(signalReference, out metadata)) { metadataArray[x] = metadata; } } } return(metadataArray[index]); }
// In this example we use predefined structures to setup synchrophasor style metadata. This is only for setup simplification of // the initial target uses cases that interact with IEEE C37.118. Technically the publisher can create its own metadata sets. private void DefineMetadata() { // This sample just generates random Guid measurement and device identifiers - for a production system, // these Guid values would need to persist between runs defining a permanent association between the // defined metadata and the identifier... DeviceMetadata device1Metadata = new DeviceMetadata(); DateTime timestamp = DateTime.UtcNow; // Add a device device1Metadata.Name = "Test PMU"; device1Metadata.Acronym = device1Metadata.Name.Replace(" ", "").ToUpper(); device1Metadata.UniqueID = Guid.NewGuid(); device1Metadata.Longitude = 300; device1Metadata.Latitude = 200; device1Metadata.FramesPerSecond = 30; device1Metadata.ProtocolName = "STTP"; device1Metadata.UpdatedOn = timestamp; m_deviceMetadata.Add(device1Metadata); string pointTagPrefix = device1Metadata.Acronym + "."; string measurementSource = "PPA:"; int runtimeIndex = 1; // Add a frequency measurement MeasurementMetadata measurement1Metadata = new MeasurementMetadata(); measurement1Metadata.ID = $"{measurementSource}{runtimeIndex++}"; measurement1Metadata.PointTag = pointTagPrefix + "FREQ"; measurement1Metadata.SignalID = Guid.NewGuid(); measurement1Metadata.DeviceAcronym = device1Metadata.Acronym; measurement1Metadata.Reference.Acronym = device1Metadata.Acronym; measurement1Metadata.Reference.Kind = SignalKind.Frequency; measurement1Metadata.Reference.Index = 0; measurement1Metadata.PhasorSourceIndex = 0; measurement1Metadata.UpdatedOn = timestamp; // Add a dF/dt measurement MeasurementMetadata measurement2Metadata = new MeasurementMetadata(); measurement2Metadata.ID = $"{measurementSource}{runtimeIndex++}"; measurement2Metadata.PointTag = pointTagPrefix + "DFDT"; measurement2Metadata.SignalID = Guid.NewGuid(); measurement2Metadata.DeviceAcronym = device1Metadata.Acronym; measurement2Metadata.Reference.Acronym = device1Metadata.Acronym; measurement2Metadata.Reference.Kind = SignalKind.DfDt; measurement2Metadata.Reference.Index = 0; measurement2Metadata.PhasorSourceIndex = 0; measurement2Metadata.UpdatedOn = timestamp; // Add a phase angle measurement MeasurementMetadata measurement3Metadata = new MeasurementMetadata(); measurement3Metadata.ID = $"{measurementSource}{runtimeIndex++}"; measurement3Metadata.PointTag = pointTagPrefix + "VPHA"; measurement3Metadata.SignalID = Guid.NewGuid(); measurement3Metadata.DeviceAcronym = device1Metadata.Acronym; measurement3Metadata.Reference.Acronym = device1Metadata.Acronym; measurement3Metadata.Reference.Kind = SignalKind.Angle; measurement3Metadata.Reference.Index = 1; // First phase angle measurement3Metadata.PhasorSourceIndex = 1; // Match to Phasor.SourceIndex = 1 measurement3Metadata.UpdatedOn = timestamp; // Add a phase magnitude measurement MeasurementMetadata measurement4Metadata = new MeasurementMetadata(); measurement4Metadata.ID = $"{measurementSource}{runtimeIndex++}"; measurement4Metadata.PointTag = pointTagPrefix + "VPHM"; measurement4Metadata.SignalID = Guid.NewGuid(); measurement4Metadata.DeviceAcronym = device1Metadata.Acronym; measurement4Metadata.Reference.Acronym = device1Metadata.Acronym; measurement4Metadata.Reference.Kind = SignalKind.Magnitude; measurement4Metadata.Reference.Index = 1; // First phase magnitude measurement4Metadata.PhasorSourceIndex = 1; // Match to Phasor.SourceIndex = 1 measurement4Metadata.UpdatedOn = timestamp; m_measurementMetadata.Add(measurement1Metadata); m_measurementMetadata.Add(measurement2Metadata); m_measurementMetadata.Add(measurement3Metadata); m_measurementMetadata.Add(measurement4Metadata); // Add a phasor PhasorMetadata phasor1Metadata = new PhasorMetadata(); phasor1Metadata.DeviceAcronym = device1Metadata.Acronym; phasor1Metadata.Label = device1Metadata.Name + " Voltage Phasor"; phasor1Metadata.Type = "V"; // Voltage phasor phasor1Metadata.Phase = "+"; // Positive sequence phasor1Metadata.SourceIndex = 1; // Phasor number 1 phasor1Metadata.UpdatedOn = timestamp; m_phasorMetadata.Add(phasor1Metadata); m_metadataVersion++; // Pass meta-data to publisher instance for proper conditioning base.DefineMetadata(m_deviceMetadata, m_measurementMetadata, m_phasorMetadata, m_metadataVersion); }
public MetadataFormatProvider(MeasurementMetadata metadata, string signalTypeAcronym) { m_metadata = metadata; m_signalTypeAcronym = signalTypeAcronym; }
internal static global::System.Runtime.InteropServices.HandleRef getCPtr(MeasurementMetadata obj) { return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr; }