Contains data for a single cycle over all three line-to-neutral conductors.
        public static double[] ModifiedTakagi(FaultLocationDataSet faultDataSet, string parameters)
        {
            ComplexNumber z;

            ComplexNumber[] voltages;
            ComplexNumber[] currents;
            ComplexNumber[] zeros;

            z = GetNominalImpedance(faultDataSet);

            voltages = faultDataSet.Cycles.Select(cycle => GetFaultVoltage(cycle, faultDataSet.FaultType)).ToArray();
            currents = faultDataSet.Cycles.Select(cycle => GetFaultCurrent(cycle, faultDataSet.FaultType)).ToArray();
            zeros    = faultDataSet.Cycles.Select(cycle => 3 * CycleData.CalculateSequenceComponents(cycle.AN.I, cycle.BN.I, cycle.CN.I)[0]).ToArray();

            return(voltages.Zip(currents, (v, i) => new
            {
                V = v,
                I = i
            })
                   .Zip(zeros, (vi, zero) =>
            {
                ComplexNumber v = vi.V;
                ComplexNumber i = vi.I;
                Angle t = (i / zero).Angle;

                ComplexNumber ejt = new ComplexNumber(t, 1.0D);

                return (v * zero.Conjugate * ejt).Imaginary / (z * i * zero.Conjugate * ejt).Imaginary;
            })
                   .Select(m => m * faultDataSet.LineDistance)
                   .ToArray());
        }
        private CycleData GetCycleAt(VICycleDataGroup viCycleDataGroup, int index)
        {
            CycleData cycle = new CycleData();

            Cycle[] cycles =
            {
                cycle.AN.V,
                cycle.BN.V,
                cycle.CN.V,
                cycle.AN.I,
                cycle.BN.I,
                cycle.CN.I
            };

            CycleDataGroup[] cycleDataGroups =
            {
                viCycleDataGroup.VA,
                viCycleDataGroup.VB,
                viCycleDataGroup.VC,
                viCycleDataGroup.IA,
                viCycleDataGroup.IB,
                viCycleDataGroup.IC
            };

            for (int i = 0; i < cycles.Length; i++)
            {
                cycles[i].RMS   = cycleDataGroups[i].RMS[index].Value;
                cycles[i].Phase = cycleDataGroups[i].Phase[index].Value;
                cycles[i].Peak  = cycleDataGroups[i].Peak[index].Value;
                cycles[i].Error = cycleDataGroups[i].Error[index].Value;
            }

            return(cycle);
        }
        private static bool RatedCurrentTrigger(FaultLocationDataSet faultDataSet, string parameters)
        {
            Dictionary <string, string> parameterLookup;
            string parameterValue;
            double ratingMultiplier;

            double anFaultLimit;
            double bnFaultLimit;
            double cnFaultLimit;

            List <int> faultedCycles;
            bool       anFaultCycle;
            bool       bnFaultCycle;
            bool       cnFaultCycle;

            // If no cycles exist in the data set, there is no fault
            if (faultDataSet.Cycles.Count <= 0)
            {
                return(false);
            }

            // Get parameters required for determining the existence of the fault
            parameterLookup = parameters.ParseKeyValuePairs();

            if (!parameterLookup.TryGetValue("ratingMultiplier", out parameterValue) || !double.TryParse(parameterValue, out ratingMultiplier))
            {
                ratingMultiplier = 2.0D;
            }

            // Determine the upper limit of the current during normal conditions
            anFaultLimit = faultDataSet.RatedCurrent * ratingMultiplier;
            bnFaultLimit = faultDataSet.RatedCurrent * ratingMultiplier;
            cnFaultLimit = faultDataSet.RatedCurrent * ratingMultiplier;

            // Build a list of faulted cycles
            faultedCycles = new List <int>();

            for (int i = 0; i < faultDataSet.Cycles.Count; i++)
            {
                CycleData cycle = faultDataSet.Cycles[i];

                anFaultCycle = (cycle.AN.I.RMS >= anFaultLimit);
                bnFaultCycle = (cycle.BN.I.RMS >= bnFaultLimit);
                cnFaultCycle = (cycle.CN.I.RMS >= cnFaultLimit);

                if (anFaultCycle || bnFaultCycle || cnFaultCycle)
                {
                    faultedCycles.Add(i);
                }
            }

            // Provide additional information about which
            // cycles were found to contain fault conditions
            faultDataSet.FaultedCycles = faultedCycles;

            return(faultedCycles.Count > 0);
        }
        // Get teh current to use in fault calculations for this cycle, based on the fault type.
        private static ComplexNumber GetDoubleEndedFaultCurrent(CycleData cycle, FaultType faultType)
        {
            ComplexNumber[] sequenceComponents;

            sequenceComponents = CycleData.CalculateSequenceComponents(cycle.AN.I, cycle.BN.I, cycle.CN.I);

            if (faultType == FaultType.ABC || faultType == FaultType.ABCG)
            {
                return(sequenceComponents[1]);
            }

            return(sequenceComponents[2]);
        }
        // True if current spikes upward by 300amps within a cycle while in a range between the
        //rated current and a user defined maximum current.
        private static bool RangeSpikeTrigger(FaultLocationDataSet faultDataSet, string parameters)
        {
            Dictionary <string, string> parameterLookup;
            string parameterValue;
            double ratingMultiplier;

            double anFaultLimit;
            double bnFaultLimit;
            double cnFaultLimit;

            List <int> faultedCycles;
            bool       anFaultCycle;
            bool       bnFaultCycle;
            bool       cnFaultCycle;

            // If no cycles exist in the data set, there is no fault
            if (faultDataSet.Cycles.Count <= 0)
            {
                return(false);
            }

            // Get parameters required for determining the existence of the fault
            parameterLookup = parameters.ParseKeyValuePairs();

            if (!parameterLookup.TryGetValue("ratingMultiplier", out parameterValue) || !double.TryParse(parameterValue, out ratingMultiplier))
            {
                ratingMultiplier = 0.50D;
            }

            // Determine the upper limit of the current range during normal conditions
            anFaultLimit = faultDataSet.RatedCurrent * ratingMultiplier;
            bnFaultLimit = faultDataSet.RatedCurrent * ratingMultiplier;
            cnFaultLimit = faultDataSet.RatedCurrent * ratingMultiplier;

            for (int i = 0; i < faultDataSet.Cycles.Count; i++)
            {
                CycleData cycle = faultDataSet.Cycles[i];

                if ((cycle.AN.I.RMS >= faultDataSet.RatedCurrent && cycle.AN.I.RMS <= anFaultLimit ||
                     cycle.BN.I.RMS >= faultDataSet.RatedCurrent && cycle.BN.I.RMS <= bnFaultLimit ||
                     cycle.CN.I.RMS >= faultDataSet.RatedCurrent && cycle.CN.I.RMS <= cnFaultLimit) &&

                    faultDataSet.Cycles[i + 1].AN.I.RMS > faultDataSet.Cycles[i].AN.I.RMS + 300D ||
                    faultDataSet.Cycles[i + 1].BN.I.RMS > faultDataSet.Cycles[i].BN.I.RMS + 300D ||
                    faultDataSet.Cycles[i + 1].CN.I.RMS > faultDataSet.Cycles[i].CN.I.RMS + 300D)
                {
                    return(true);
                }
            }
            return(false);
        }
        /// <summary>
        /// Get the current to use in fault calculations for this cycle, based on the fault type.
        /// </summary>
        /// <param name="cycle">The cycle of data from which to derive the fault current.</param>
        /// <param name="viFaultType">The fault type used to determine which current to use.</param>
        /// <returns>The current to use in fault calculations.</returns>
        public static ComplexNumber GetFaultCurrent(CycleData cycle, FaultType viFaultType)
        {
            switch (viFaultType)
            {
            case FaultType.AN:
                return(cycle.AN.I.Complex);

            case FaultType.BN:
                return(cycle.BN.I.Complex);

            case FaultType.CN:
                return(cycle.CN.I.Complex);

            case FaultType.AB:
            case FaultType.ABG:
                return(cycle.AN.I.Complex - cycle.BN.I.Complex);

            case FaultType.BC:
            case FaultType.BCG:
                return(cycle.BN.I.Complex - cycle.CN.I.Complex);

            case FaultType.CA:
            case FaultType.CAG:
                return(cycle.CN.I.Complex - cycle.AN.I.Complex);

            case FaultType.ABC:
            case FaultType.ABCG:
                if (cycle.AN.I.Error < cycle.BN.I.Error && cycle.AN.I.Error < cycle.CN.I.Error)
                {
                    return(cycle.AN.I.Complex);
                }

                if (cycle.BN.I.Error < cycle.CN.I.Error)
                {
                    return(cycle.BN.I.Complex);
                }

                return(cycle.CN.I.Complex);

            default:
                throw new ArgumentOutOfRangeException("viFaultType");
            }
        }
        /// <summary>
        /// Double-ended algorithm for calculating the distance to a fault that was found in the <see cref="FaultLocationDataSet"/>.
        /// </summary>
        /// <param name="localFaultDataSet">The data set used to find the distance to the fault.</param>
        /// <param name="remoteFaultCycle">The cycle of data from the remote station used in the double-ended distance algorithm.</param>
        /// <param name="parameters">Extra parameters to the algorithm.</param>
        /// <returns>A set of distance calculations, one for each cycle of data in <paramref name="localFaultDataSet"/>.</returns>
        public static ComplexNumber[] DoubleEnded(FaultLocationDataSet localFaultDataSet, CycleData remoteFaultCycle, string parameters)
        {
            FaultType faultType;
            ComplexNumber vfs;
            ComplexNumber ifs;
            ComplexNumber z;

            faultType = localFaultDataSet.FaultType;
            vfs = GetDoubleEndedFaultVoltage(remoteFaultCycle, faultType);
            ifs = GetDoubleEndedFaultCurrent(remoteFaultCycle, faultType);
            z = localFaultDataSet.Z1;

            return localFaultDataSet.Cycles
                .Select(cycleData => new
                {
                    Vns = GetDoubleEndedFaultVoltage(cycleData, faultType),
                    Ins = GetDoubleEndedFaultCurrent(cycleData, faultType)
                })
                .Select(cycle => (cycle.Vns - vfs + z * ifs) / (z * (cycle.Ins + ifs)))
                .Select(m => m * localFaultDataSet.LineDistance)
                .ToArray();
        }
Beispiel #8
0
        public void PushDataTo(CycleDataSet cycleDataSet)
        {
            FaultAlgorithms.CycleData cycleData;
            Cycle[]          cycles;
            CycleDataGroup[] cycleDataGroups;

            cycleDataGroups = new CycleDataGroup[] { VA, VB, VC, IA, IB, IC };
            cycles          = new Cycle[cycleDataGroups.Length];

            for (int i = 0; i < VA.ToDataGroup().Samples; i++)
            {
                cycleData = new FaultAlgorithms.CycleData();

                cycles[0] = cycleData.AN.V;
                cycles[1] = cycleData.BN.V;
                cycles[2] = cycleData.CN.V;
                cycles[3] = cycleData.AN.I;
                cycles[4] = cycleData.BN.I;
                cycles[5] = cycleData.CN.I;

                for (int j = 0; j < cycles.Length; j++)
                {
                    if (cycleDataGroups[j] == null)
                    {
                        continue;
                    }

                    cycles[j].RMS   = cycleDataGroups[j].RMS[i].Value;
                    cycles[j].Phase = cycleDataGroups[j].Phase[i].Value;
                    cycles[j].Peak  = cycleDataGroups[j].Peak[i].Value;
                    cycles[j].Error = cycleDataGroups[j].Error[i].Value;
                }

                cycleDataSet[i] = cycleData;
            }
        }
        public void PushDataTo(CycleDataSet cycleDataSet)
        {
            CycleData cycleData;
            Cycle[] cycles;
            CycleDataGroup[] cycleDataGroups;

            cycleDataGroups = new CycleDataGroup[] { VA, VB, VC, IA, IB, IC };
            cycles = new Cycle[cycleDataGroups.Length];

            for (int i = 0; i < VA.ToDataGroup().Samples; i++)
            {
                cycleData = new CycleData();

                cycles[0] = cycleData.AN.V;
                cycles[1] = cycleData.BN.V;
                cycles[2] = cycleData.CN.V;
                cycles[3] = cycleData.AN.I;
                cycles[4] = cycleData.BN.I;
                cycles[5] = cycleData.CN.I;

                for (int j = 0; j < cycles.Length; j++)
                {
                    cycles[j].RMS = cycleDataGroups[j].RMS[i].Value;
                    cycles[j].Phase = cycleDataGroups[j].Phase[i].Value;
                    cycles[j].Peak = cycleDataGroups[j].Peak[i].Value;
                    cycles[j].Error = cycleDataGroups[j].Error[i].Value;
                }

                cycleDataSet[i] = cycleData;
            }
        }
        // Get the voltage to use in fault calculations for this cycle, based on the fault type.
        private static ComplexNumber GetFaultVoltage(CycleData cycle, FaultType viFaultType)
        {
            switch (viFaultType)
            {
                case FaultType.AN:
                    return cycle.AN.V.Complex;

                case FaultType.BN:
                    return cycle.BN.V.Complex;

                case FaultType.CN:
                    return cycle.CN.V.Complex;

                case FaultType.AB:
                case FaultType.ABG:
                    return cycle.AN.V.Complex - cycle.BN.V.Complex;

                case FaultType.BC:
                case FaultType.BCG:
                    return cycle.BN.V.Complex - cycle.CN.V.Complex;

                case FaultType.CA:
                case FaultType.CAG:
                    return cycle.CN.V.Complex - cycle.AN.V.Complex;

                case FaultType.ABC:
                    if (cycle.AN.I.Error < cycle.BN.I.Error && cycle.AN.I.Error < cycle.CN.I.Error)
                        return cycle.AN.V.Complex;

                    if (cycle.BN.I.Error < cycle.CN.I.Error)
                        return cycle.BN.V.Complex;

                    return cycle.CN.V.Complex;

                default:
                    throw new ArgumentOutOfRangeException("viFaultType");
            }
        }
        // Get the voltage used in double-ended fault calculations for this cycle, based on the fault type.
        private static ComplexNumber GetDoubleEndedFaultVoltage(CycleData cycle, FaultType faultType)
        {
            ComplexNumber[] sequenceComponents;

            sequenceComponents = CycleData.CalculateSequenceComponents(cycle.AN.V, cycle.BN.V, cycle.CN.V);

            if (faultType == FaultType.ABC)
                return sequenceComponents[1];

            return sequenceComponents[2];
        }
        /// <summary>
        /// Double-ended algorithm for calculating the distance to a fault that was found in the <see cref="FaultLocationDataSet"/>.
        /// </summary>
        /// <param name="localFaultDataSet">The data set used to find the distance to the fault.</param>
        /// <param name="remoteFaultCycle">The cycle of data from the remote station used in the double-ended distance algorithm.</param>
        /// <param name="parameters">Extra parameters to the algorithm.</param>
        /// <returns>A set of distance calculations, one for each cycle of data in <paramref name="localFaultDataSet"/>.</returns>
        public static ComplexNumber[] DoubleEnded(FaultLocationDataSet localFaultDataSet, CycleData remoteFaultCycle, string parameters)
        {
            FaultType     faultType;
            ComplexNumber vfs;
            ComplexNumber ifs;
            ComplexNumber z;

            faultType = localFaultDataSet.FaultType;
            vfs       = GetDoubleEndedFaultVoltage(remoteFaultCycle, faultType);
            ifs       = GetDoubleEndedFaultCurrent(remoteFaultCycle, faultType);
            z         = localFaultDataSet.Z1;

            return(localFaultDataSet.Cycles
                   .Select(cycleData => new
            {
                Vns = GetDoubleEndedFaultVoltage(cycleData, faultType),
                Ins = GetDoubleEndedFaultCurrent(cycleData, faultType)
            })
                   .Select(cycle => (cycle.Vns - vfs + z * ifs) / (z * (cycle.Ins + ifs)))
                   .Select(m => m * localFaultDataSet.LineDistance)
                   .ToArray());
        }