This project has moved and is read-only. For the latest updates, please go here.

how to do exchange between two action adapters in realtime

Nov 13, 2013 at 4:34 PM
I have been writing action adapters for realtime FNET measurement data. The action adapters work fine individually. Then I encounter one problem. For one action adapter, I detect whether the device is "islanding" from the rest of the grid(on backup generator etc). The other action adapter is oscillation detector. However, once a device is islanding, it keeps triggering the oscillation detector as well. What would be the best way to disable certain measurement for oscillation detector once it is considered to be islanding? Is there a way I can pass something between action adapters in realtime?

Thank you very much for the help in advance!

Zoe
Nov 13, 2013 at 8:36 PM
If you only have one instance of your adapters, you can use something like the following.

Islanding Detector:
    public class IslandingDeviceDetector : ActionAdapterBase
    {
        // ...

        private ISet<int> m_islandingDevices = new HashSet<int>();

        protected override void PublishFrame(IFrame frame, int index)
        {
            // Return islanded device IDs
            ISet<int> islandingDeviceIDs = GetIslandingDevices(frame);

            // Begin signaling process
            List<IMeasurement> islandingDeviceSignals = new List<IMeasurement>();

            // Determine which devices have just started islanding
            foreach (int deviceID in islandingDeviceIDs.Except(m_islandingDevices))
            {
                islandingDeviceSignals.Add(new Measurement()
                {
                    ID = IslandingDeviceSignal,
                    StateFlags = IslandingStateFlags, // This flag indicates islanding for this device
                    Value = deviceID,                 // This value identifies the islanding device
                    Timestamp = frame.Timestamp
                });
            }

            // Determine which devices have just stopped islanding
            foreach (int deviceID in m_islandingDevices.Except(islandingDeviceIDs))
            {
                islandingDeviceSignals.Add(new Measurement()
                {
                    ID = IslandingDeviceSignal,
                    StateFlags = MeasurementStateFlags.Normal, // This flag indicates device is no longer islanding
                    Value = deviceID,                          // This value identifies the previously islanding device
                    Timestamp = frame.Timestamp
                });
            }

            m_islandingDevices = islandingDeviceIDs;
            OnNewMeasurements(islandingDeviceSignals);
        }

        private ISet<int> GetIslandingDevices(IFrame frame)
        {
            // Add your custom logic here...
            
            return new HashSet<int>();
        }

        public static readonly MeasurementStateFlags IslandingStateFlags = MeasurementStateFlags.UserDefinedFlag1;
        public static readonly Guid IslandingDeviceSignal = Guid.NewGuid();

        // ...
    }
Oscillation Detector:
    public class OscillationDetector : ActionAdapterBase
    {
        // ...

        public override void Initialize()
        {
            base.Initialize();

            // ...

            // Dynamically add the islanding signal to the list of measurements to be received
            InputMeasurementKeys = InputMeasurementKeys
                .Concat(new MeasurementKey[] { new MeasurementKey(IslandingDeviceDetector.IslandingDeviceSignal, 0, "ISLAND") })
                .ToArray();
        }

        public override void QueueMeasurementsForProcessing(IEnumerable<IMeasurement> measurements)
        {
            foreach (IMeasurement signal in measurements.Where(m => m.ID == IslandingDeviceDetector.IslandingDeviceSignal))
            {
                int deviceID = (int)signal.Value;

                // Track which devices are islanded at any given time
                if (signal.StateFlags == IslandingDeviceDetector.IslandingStateFlags)
                    AddIslandingDevice(deviceID);
                else
                    RemoveIslandingDevice(deviceID);
            }

            // Remove signals from processing where the device is islanded.
            base.QueueMeasurementsForProcessing(measurements.Where(m => m.ID != IslandingDeviceDetector.IslandingDeviceSignal && !BelongsToIslandingDevice(m)));
        }

        private void AddIslandingDevice(int deviceID)
        {
            // Add your custom logic here...
        }

        private void RemoveIslandingDevice(int deviceID)
        {
            // Add your custom logic here...
        }

        private bool BelongsToIslandingDevice(IMeasurement measurement)
        {
            // Add your custom logic here...
        }

        // ...
    }
Stephen
Marked as answer by ritchiecarroll on 11/13/2013 at 1:46 PM
Nov 13, 2013 at 9:07 PM
Stephen,

Thank you so much for such detailed code! I need one instance of islanding detector and oscillation detector per interconnection. But your code is most inspiring. I will try to see what I can do.
Thanks again!

Zoe
Nov 14, 2013 at 7:17 PM
Stephen,
I wrote something as you suggested and also based on some instructions of the wiki. In the oscillation detector, I can get the accurate islanding device name from a global variable(FNETIslandingTrigger.g_IslandingDeviceDictionary), but I still cannot filter that measurement out in PublishFrame. For QueueMeasurementsForProcessing in oscillation detector (the code as below), I tried "base.QueueMeasurementsForProcessing(measurements.Where(m => !BelongToIslandingDevice(m)));", but it also didn't work. I would really appreciate if you could help me with what I do wrong here!

        public override void QueueMeasurementForProcessing(IMeasurement measurement)
        {
            QueueMeasurementsForProcessing(new IMeasurement[] { measurement });
        }

        //filter measurement to exclude the devices that are islanding
        public override void QueueMeasurementsForProcessing(IEnumerable<IMeasurement> measurements)
        {
            
             // Remove signals from processing where the device is islanded.
            //base.QueueMeasurementsForProcessing(measurements.Where(m => !BelongToIslandingDevice(m)));


            List<IMeasurement> inputMeasurements = new List<IMeasurement>();
            foreach (IMeasurement measurement in measurements)
            {
                bool islanding = BelongToIslandingDevice(measurement);
                if (!islanding)
                    inputMeasurements.Add(measurement);
            }

            if (inputMeasurements.Count > 0)
                SortMeasurements(inputMeasurements);

        }

        private bool BelongToIslandingDevice(IMeasurement m)
        {
           
            uint measurementID = m.Key.ID;

            List<string> islandingDeviceList;
            if (FNETIslandingTrigger.g_IslandingDeviceDictionary.TryGetValue(m_monitoredPowerGrid, out islandingDeviceList))
            {
                string strDeviceName;
                m_measurementDeviceDictionary.TryGetValue(measurementID, out strDeviceName);

                if (islandingDeviceList.Contains(strDeviceName))
                {
                    //added by Zoe to debug - start->succcessfully get to this point
                    
                    m_csvStream.Write("\n remove device={0} from  measurement\n", strDeviceName);
                    //added by Zoe to debug - end

                    return true;
                }
                else
                {
                    return false;
                }
            }
            else //if there is no record of islandingDevice list per this interconnection
            {
                return false;
            }
         
        }