Exemple #1
0
        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 void InsertFaultDistances(FaultLocationDataSet faultDataSet, SqlCommand command, int cycleIndex, int cycleID)
        {
            IDbDataParameter algorithmParameter = command.CreateParameter();
            IDbDataParameter distanceParameter  = command.CreateParameter();
            double           distance;

            command.CommandText = "INSERT INTO FaultDistance (CycleID, Algorithm, Distance) VALUES (@cycleID, @algorithm, @distance)";
            command.Parameters.AddWithValue("@cycleID", cycleID);
            command.Parameters.Add(algorithmParameter);
            command.Parameters.Add(distanceParameter);

            algorithmParameter.ParameterName = "@algorithm";
            distanceParameter.ParameterName  = "@distance";

            foreach (KeyValuePair <string, double[]> faultDistances in faultDataSet.FaultDistances)
            {
                distance = faultDistances.Value[cycleIndex];

                if (!double.IsNaN(distance))
                {
                    algorithmParameter.Value = faultDistances.Key;
                    distanceParameter.Value  = distance;
                    command.ExecuteNonQuery();
                }
            }

            command.Parameters.Clear();
        }
Exemple #3
0
 // Attempts to execute fault type algorithm and processes errors if they occur.
 private FaultType ExecuteFaultTypeAlgorithm(FaultTypeAlgorithm algorithm, FaultLocationDataSet faultDataSet, string parameters)
 {
     try
     {
         return(algorithm(faultDataSet, parameters));
     }
     catch (Exception ex)
     {
         OnProcessException(new Exception(string.Format("Error executing fault type algorithm: {0}", ex.Message), ex));
         return(FaultType.None);
     }
 }
Exemple #4
0
        public static double[] Novosel(FaultLocationDataSet faultDataSet, string parameters)
        {
            ComplexNumber z;

            ComplexNumber[] voltages;
            ComplexNumber[] currents;
            ComplexNumber   vPre;
            ComplexNumber   iPre;

            ComplexNumber loadImpedance;

            z = GetNominalImpedance(faultDataSet);

            voltages = faultDataSet.Cycles.Select(cycle => GetFaultVoltage(cycle, faultDataSet.FaultType)).ToArray();
            currents = faultDataSet.Cycles.Select(cycle => GetFaultCurrent(cycle, faultDataSet.FaultType)).ToArray();
            vPre     = GetFaultVoltage(faultDataSet.PrefaultCycle, faultDataSet.FaultType);
            iPre     = GetFaultCurrent(faultDataSet.PrefaultCycle, faultDataSet.FaultType);

            loadImpedance = (vPre / iPre) - z;

            return(voltages.Zip(currents, (v, i) =>
            {
                ComplexNumber sourceImpedance = faultDataSet.ZSrc;

                // TODO: Test to determine the effect of using -(v - vPre) / (i - iPre) instead
                if (IsNaN(sourceImpedance))
                {
                    sourceImpedance = (v - vPre) / (i - iPre);
                }

                ComplexNumber ab = (v / (z * i)) + (loadImpedance / z) + 1;
                ComplexNumber cd = (v / (z * i)) * (1 + (loadImpedance / z));
                ComplexNumber ef = ((i - iPre) / (z * i)) * (1 + ((loadImpedance + sourceImpedance) / z));

                double a = ab.Real, b = ab.Imaginary;
                double c = cd.Real, d = cd.Imaginary;
                double e = ef.Real, f = ef.Imaginary;

                double left = (a - ((e * b) / f));
                double right = Math.Sqrt(left * left - 4.0D * (c - ((e * d) / f)));
                double m1 = (left + right) / 2.0D;
                double m2 = (left - right) / 2.0D;

                if (MinDistance(m1, 0.0D, 1.0D) < MinDistance(m2, 0.0D, 1.0D))
                {
                    return m1;
                }

                return m2;
            })
                   .Select(m => m * faultDataSet.LineDistance)
                   .ToArray());
        }
Exemple #5
0
            private bool TryExecute(FaultLocationAlgorithm faultLocationAlgorithm, FaultLocationDataSet faultLocationDataSet, out double[] distances)
            {
                try
                {
                    distances = faultLocationAlgorithm(faultLocationDataSet, null);
                }
                catch
                {
                    distances = null;
                }

                return((object)distances != null);
            }
Exemple #6
0
        /// <summary>
        /// Populate known voltage and current data from PQDIF file.
        /// </summary>
        /// <param name="faultDataSet">Fault data set to be populated.</param>
        /// <param name="settings">Source parameters.</param>
        public static void PopulateDataSet(FaultLocationDataSet faultDataSet, Dictionary <string, string> settings)
        {
            string fileName;

            List <ObservationRecord> observationRecords;
            ObservationRecord        faultObservation;

            ChannelInstance[] anChannels;
            ChannelInstance[] bnChannels;
            ChannelInstance[] cnChannels;

            if (!settings.TryGetValue("fileName", out fileName) || !File.Exists(fileName))
            {
                throw new ArgumentException("Parameters must define a valid \"fileName\" setting.");
            }

            // Parse PQDif File Data
            using (LogicalParser logicalParser = new LogicalParser(fileName))
            {
                observationRecords = new List <ObservationRecord>();
                logicalParser.Open();

                while (logicalParser.HasNextObservationRecord())
                {
                    observationRecords.Add(logicalParser.NextObservationRecord());
                }
            }

            // Get the first observation record that contains six wave forms.
            // Assume that this observation record will has both voltage and
            // current wave forms for each of the three phases
            faultObservation = observationRecords.FirstOrDefault(observation => observation.ChannelInstances.Count(channel => channel.Definition.QuantityTypeID == QuantityType.WaveForm) >= 6);

            if ((object)faultObservation != null)
            {
                // Get the voltage and current wave forms for each of the six phase types
                IEnumerable <ChannelInstance> waveForms = faultObservation.ChannelInstances.Where(channel => channel.Definition.QuantityTypeID == QuantityType.WaveForm).ToList();

                anChannels = waveForms.Where(channel => channel.Definition.Phase == Phase.AN).ToArray();
                bnChannels = waveForms.Where(channel => channel.Definition.Phase == Phase.BN).ToArray();
                cnChannels = waveForms.Where(channel => channel.Definition.Phase == Phase.CN).ToArray();

                // Attempt to fill in fault data for each of the three phase types
                FillFaultData(faultDataSet.Voltages.AN, faultDataSet.Currents.AN, anChannels);
                FillFaultData(faultDataSet.Voltages.BN, faultDataSet.Currents.BN, bnChannels);
                FillFaultData(faultDataSet.Voltages.CN, faultDataSet.Currents.CN, cnChannels);

                // Set the frequency in the data set to the nominal frequency of the system
                faultDataSet.Frequency = faultObservation.Settings.NominalFrequency;
            }
        }
        private void InsertFaultData(Line line, FaultLocationDataSet faultDataSet, SqlCommand command, int fileGroupID)
        {
            int lineID;
            int lineDisturbanceID;

            int    largestCurrentIndex;
            double faultDistance;

            // Get largest current index and median fault distance for that cycle
            largestCurrentIndex = faultDataSet.Cycles.GetLargestCurrentIndex();

            faultDistance = faultDataSet.FaultDistances.Values
                            .Select(distances => distances[largestCurrentIndex])
                            .OrderBy(distance => distance)
                            .ToArray()[faultDataSet.FaultDistances.Count / 2];

            // Get ID of the line associated with this fault data
            command.CommandText = "SELECT ID FROM Line WHERE FLEID = @fleID";
            command.Parameters.AddWithValue("@fleID", line.ID);
            lineID = Convert.ToInt32(command.ExecuteScalar());
            command.Parameters.Clear();

            // Insert a disturbance record for this line
            command.CommandText = "INSERT INTO LineDisturbance (LineID, FileGroupID, FaultType, LargestCurrentIndex, " +
                                  "FaultDistance, IAMax, IBMax, ICMax, VAMin, VBMin, VCMin) VALUES (@lineID, @fileGroupID, " +
                                  "@faultType, @largestCurrentIndex, @faultDistance, @iaMax, @ibMax, @icMax, @vaMin, @vbMin, @vcMin)";

            command.Parameters.AddWithValue("@lineID", lineID);
            command.Parameters.AddWithValue("@fileGroupID", fileGroupID);
            command.Parameters.AddWithValue("@faultType", faultDataSet.FaultType.ToString());
            command.Parameters.AddWithValue("@largestCurrentIndex", largestCurrentIndex);
            command.Parameters.AddWithValue("@faultDistance", faultDistance);
            command.Parameters.AddWithValue("@iaMax", faultDataSet.Cycles.Max(cycle => cycle.AN.I.RMS));
            command.Parameters.AddWithValue("@ibMax", faultDataSet.Cycles.Max(cycle => cycle.BN.I.RMS));
            command.Parameters.AddWithValue("@icMax", faultDataSet.Cycles.Max(cycle => cycle.CN.I.RMS));
            command.Parameters.AddWithValue("@vaMin", faultDataSet.Cycles.Min(cycle => cycle.AN.V.RMS));
            command.Parameters.AddWithValue("@vbMin", faultDataSet.Cycles.Min(cycle => cycle.BN.V.RMS));
            command.Parameters.AddWithValue("@vcMin", faultDataSet.Cycles.Min(cycle => cycle.CN.V.RMS));
            command.ExecuteNonQuery();
            command.Parameters.Clear();

            // Get the ID of the disturbance record
            command.CommandText = "SELECT @@IDENTITY";
            lineDisturbanceID   = Convert.ToInt32(command.ExecuteScalar());

            // Insert data for each cycle into the database
            for (int i = 0; i < faultDataSet.Cycles.Count; i++)
            {
                InsertCycleData(faultDataSet, command, lineDisturbanceID, i);
            }
        }
Exemple #8
0
        public static double[] Eriksson(FaultLocationDataSet faultDataSet, string parameters)
        {
            ComplexNumber z;

            ComplexNumber[] voltages;
            ComplexNumber[] currents;
            ComplexNumber   iPre;

            ComplexNumber sourceImpedance;
            ComplexNumber remoteImpedance;

            sourceImpedance = faultDataSet.ZSrc;
            remoteImpedance = faultDataSet.ZRem;

            if (IsNaN(sourceImpedance) || IsNaN(remoteImpedance))
            {
                return(null);
            }

            z = GetNominalImpedance(faultDataSet);

            voltages = faultDataSet.Cycles.Select(cycle => GetFaultVoltage(cycle, faultDataSet.FaultType)).ToArray();
            currents = faultDataSet.Cycles.Select(cycle => GetFaultCurrent(cycle, faultDataSet.FaultType)).ToArray();
            iPre     = GetFaultCurrent(faultDataSet.PrefaultCycle, faultDataSet.FaultType);

            return(voltages.Zip(currents, (v, i) =>
            {
                ComplexNumber ab = (v / (i * z)) + 1 + (remoteImpedance / z);
                ComplexNumber cd = (v / (i * z)) * ((remoteImpedance / z) + 1);
                ComplexNumber ef = ((i - iPre) / (i * z)) * (((sourceImpedance + remoteImpedance) / z) + 1);

                double a = ab.Real, b = ab.Imaginary;
                double c = cd.Real, d = cd.Imaginary;
                double e = ef.Real, f = ef.Imaginary;

                double left = (a - ((e * b) / f));
                double right = Math.Sqrt(left * left - 4.0D * (c - ((e * d) / f)));
                double m1 = (left + right) / 2.0D;
                double m2 = (left - right) / 2.0D;

                if (MinDistance(m1, 0.0D, 1.0D) < MinDistance(m2, 0.0D, 1.0D))
                {
                    return m1;
                }

                return m2;
            })
                   .Select(m => m * faultDataSet.LineDistance)
                   .ToArray());
        }
Exemple #9
0
        public static double[] Reactance(FaultLocationDataSet faultDataSet, string parameters)
        {
            ComplexNumber nominalImpedance;

            nominalImpedance = GetNominalImpedance(faultDataSet);

            return(faultDataSet.Cycles
                   .Select(cycleData => new
            {
                V = GetFaultVoltage(cycleData, faultDataSet.FaultType),
                I = GetFaultCurrent(cycleData, faultDataSet.FaultType),
                Z = nominalImpedance
            })
                   .Select(cycle => (cycle.V / cycle.I).Imaginary / cycle.Z.Imaginary)
                   .Select(m => m * faultDataSet.LineDistance)
                   .ToArray());
        }
        private void ExecuteFaultLocationAlgorithm(double lineLength, ComplexNumber nominalImpedance, MappingNode local, MappingNode remote)
        {
            FaultLocationDataSet faultLocationDataSet;
            CycleData            remoteCycle;

            ComplexNumber[] curve;

            faultLocationDataSet              = new FaultLocationDataSet();
            faultLocationDataSet.FaultType    = local.FaultType;
            faultLocationDataSet.LineDistance = lineLength;
            faultLocationDataSet.Z1           = nominalImpedance;
            local.CycleDataGroup.PushDataTo(faultLocationDataSet.Cycles);

            remoteCycle = GetCycleAt(remote.CycleDataGroup, remote.Fault.CalculationCycle - remote.StartSample);

            curve = FaultLocationAlgorithms.DoubleEnded(faultLocationDataSet, remoteCycle, string.Empty);
            ExtractDistanceVectors(local, curve);
        }
Exemple #11
0
        public static double[] Takagi(FaultLocationDataSet faultDataSet, string parameters)
        {
            ComplexNumber z;

            ComplexNumber[] voltages;
            ComplexNumber[] currents;
            ComplexNumber   iPre;

            z = GetNominalImpedance(faultDataSet);

            voltages = faultDataSet.Cycles.Select(cycle => GetFaultVoltage(cycle, faultDataSet.FaultType)).ToArray();
            currents = faultDataSet.Cycles.Select(cycle => GetFaultCurrent(cycle, faultDataSet.FaultType)).ToArray();
            iPre     = GetFaultCurrent(faultDataSet.PrefaultCycle, faultDataSet.FaultType);

            return(voltages.Zip(currents, (v, i) =>
            {
                ComplexNumber iSupConjugate = (i - iPre).Conjugate;
                return (v * iSupConjugate).Imaginary / (z * i * iSupConjugate).Imaginary;
            })
                   .Select(m => m * faultDataSet.LineDistance)
                   .ToArray());
        }
Exemple #12
0
        /// <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());
        }
Exemple #13
0
        // Get the nominal impedance value to use in fault calculations, based on the fault type.
        private static ComplexNumber GetNominalImpedance(FaultLocationDataSet faultDataSet)
        {
            switch (faultDataSet.FaultType)
            {
            case FaultType.AN:
            case FaultType.BN:
            case FaultType.CN:
                return(faultDataSet.Zs);

            case FaultType.AB:
            case FaultType.BC:
            case FaultType.CA:
            case FaultType.ABG:
            case FaultType.BCG:
            case FaultType.CAG:
            case FaultType.ABC:
                return(faultDataSet.Z1);

            default:
                throw new ArgumentOutOfRangeException("faultDataSet", string.Format("Unknown fault type: {0}", faultDataSet.FaultType));
            }
        }
Exemple #14
0
        private FaultLocationDataSet GetFaultDataSet(string fileName, Line line)
        {
            string extension = FilePath.GetExtension(fileName).ToLowerInvariant().Trim();

            FaultLocationDataSet faultDataSet = new FaultLocationDataSet()
            {
                PositiveImpedance = new ComplexNumber(line.R1, line.X1),
                ZeroImpedance     = new ComplexNumber(line.R0, line.X0),
                LineDistance      = line.Length
            };

            StringBuilder parameters = new StringBuilder();

            // TODO: Load other needed specific associated parameters based on file / line information once all meta-data is known and defined
            parameters.AppendFormat("fileName={0}; ", fileName);
            parameters.Append("dataSourceType=");

            // Process files based on file extension
            switch (extension)
            {
            case ".pqd":
                parameters.Append("PQDIF");
                break;

            case ".d00":
            case ".dat":
                parameters.Append("Comtrade");
                break;

            default:
                throw new InvalidOperationException(string.Format("Unknown file extension encountered: \"{0}\" - cannot parse file.", extension));
            }

            // Load data sets based on specified parameters
            LoadDataSets(faultDataSet, parameters.ToString(), line);

            return(faultDataSet);
        }
        private void InsertCycleData(FaultLocationDataSet faultDataSet, SqlCommand command, int lineDisturbanceID, int cycleIndex)
        {
            int       cycleID;
            CycleData cycle;

            ComplexNumber[] sequenceVoltages;
            ComplexNumber[] sequenceCurrents;

            // Get the cycle data and sequence
            // components from the fault data set
            cycle            = faultDataSet.Cycles[cycleIndex];
            sequenceVoltages = CycleData.CalculateSequenceComponents(cycle.AN.V, cycle.BN.V, cycle.CN.V);
            sequenceCurrents = CycleData.CalculateSequenceComponents(cycle.AN.I, cycle.BN.I, cycle.CN.I);

            // Insert the cycle data into the database
            command.CommandText = "INSERT INTO Cycle (LineDisturbanceID, TimeStart, CycleIndex," +
                                  "ANVoltagePeak, ANVoltageRMS, ANVoltagePhase, ANCurrentPeak, ANCurrentRMS, ANCurrentPhase, " +
                                  "BNVoltagePeak, BNVoltageRMS, BNVoltagePhase, BNCurrentPeak, BNCurrentRMS, BNCurrentPhase, " +
                                  "CNVoltagePeak, CNVoltageRMS, CNVoltagePhase, CNCurrentPeak, CNCurrentRMS, CNCurrentPhase, " +
                                  "PositiveVoltageMagnitude, PositiveVoltageAngle, PositiveCurrentMagnitude, PositiveCurrentAngle, " +
                                  "NegativeVoltageMagnitude, NegativeVoltageAngle, NegativeCurrentMagnitude, NegativeCurrentAngle, " +
                                  "ZeroVoltageMagnitude, ZeroVoltageAngle, ZeroCurrentMagnitude, ZeroCurrentAngle) " +
                                  "VALUES (@lineDisturbanceID, @timeStart, @cycleIndex, " +
                                  "@anVoltagePeak, @anVoltageRMS, @anVoltagePhase, @anCurrentPeak, @anCurrentRMS, @anCurrentPhase, " +
                                  "@bnVoltagePeak, @bnVoltageRMS, @bnVoltagePhase, @bnCurrentPeak, @bnCurrentRMS, @bnCurrentPhase, " +
                                  "@cnVoltagePeak, @cnVoltageRMS, @cnVoltagePhase, @cnCurrentPeak, @cnCurrentRMS, @cnCurrentPhase, " +
                                  "@positiveVoltageMagnitude, @positiveVoltageAngle, @positiveCurrentMagnitude, @positiveCurrentAngle, " +
                                  "@negativeVoltageMagnitude, @negativeVoltageAngle, @negativeCurrentMagnitude, @negativeCurrentAngle, " +
                                  "@zeroVoltageMagnitude, @zeroVoltageAngle, @zeroCurrentMagnitude, @zeroCurrentAngle)";

            command.Parameters.AddWithValue("@lineDisturbanceID", lineDisturbanceID);
            command.Parameters.AddWithValue("@timeStart", cycle.StartTime);
            command.Parameters.AddWithValue("@cycleIndex", cycleIndex);
            command.Parameters.AddWithValue("@anVoltagePeak", cycle.AN.V.Peak);
            command.Parameters.AddWithValue("@anVoltageRMS", cycle.AN.V.RMS);
            command.Parameters.AddWithValue("@anVoltagePhase", cycle.AN.V.Phase.ToDegrees());
            command.Parameters.AddWithValue("@anCurrentPeak", cycle.AN.I.Peak);
            command.Parameters.AddWithValue("@anCurrentRMS", cycle.AN.I.RMS);
            command.Parameters.AddWithValue("@anCurrentPhase", cycle.AN.I.Phase.ToDegrees());
            command.Parameters.AddWithValue("@bnVoltagePeak", cycle.BN.V.Peak);
            command.Parameters.AddWithValue("@bnVoltageRMS", cycle.BN.V.RMS);
            command.Parameters.AddWithValue("@bnVoltagePhase", cycle.BN.V.Phase.ToDegrees());
            command.Parameters.AddWithValue("@bnCurrentPeak", cycle.BN.I.Peak);
            command.Parameters.AddWithValue("@bnCurrentRMS", cycle.BN.I.RMS);
            command.Parameters.AddWithValue("@bnCurrentPhase", cycle.BN.I.Phase.ToDegrees());
            command.Parameters.AddWithValue("@cnVoltagePeak", cycle.CN.V.Peak);
            command.Parameters.AddWithValue("@cnVoltageRMS", cycle.CN.V.RMS);
            command.Parameters.AddWithValue("@cnVoltagePhase", cycle.CN.V.Phase.ToDegrees());
            command.Parameters.AddWithValue("@cnCurrentPeak", cycle.CN.I.Peak);
            command.Parameters.AddWithValue("@cnCurrentRMS", cycle.CN.I.RMS);
            command.Parameters.AddWithValue("@cnCurrentPhase", cycle.CN.I.Phase.ToDegrees());
            command.Parameters.AddWithValue("@positiveVoltageMagnitude", sequenceVoltages[1].Magnitude);
            command.Parameters.AddWithValue("@positiveVoltageAngle", sequenceVoltages[1].Angle.ToDegrees());
            command.Parameters.AddWithValue("@negativeVoltageMagnitude", sequenceVoltages[2].Magnitude);
            command.Parameters.AddWithValue("@negativeVoltageAngle", sequenceVoltages[2].Angle.ToDegrees());
            command.Parameters.AddWithValue("@zeroVoltageMagnitude", sequenceVoltages[0].Magnitude);
            command.Parameters.AddWithValue("@zeroVoltageAngle", sequenceVoltages[0].Angle.ToDegrees());
            command.Parameters.AddWithValue("@positiveCurrentMagnitude", sequenceCurrents[1].Magnitude);
            command.Parameters.AddWithValue("@positiveCurrentAngle", sequenceCurrents[1].Angle.ToDegrees());
            command.Parameters.AddWithValue("@negativeCurrentMagnitude", sequenceCurrents[2].Magnitude);
            command.Parameters.AddWithValue("@negativeCurrentAngle", sequenceCurrents[2].Angle.ToDegrees());
            command.Parameters.AddWithValue("@zeroCurrentMagnitude", sequenceCurrents[0].Magnitude);
            command.Parameters.AddWithValue("@zeroCurrentAngle", sequenceCurrents[0].Angle.ToDegrees());

            command.ExecuteNonQuery();
            command.Parameters.Clear();

            // Get the ID of the cycle data that was entered
            command.CommandText = "SELECT @@IDENTITY";
            cycleID             = Convert.ToInt32(command.ExecuteScalar());

            // Insert fault distances calculated for this cycle
            InsertFaultDistances(faultDataSet, command, cycleIndex, cycleID);
        }
Exemple #16
0
        /// <summary>
        /// Populate known voltage and current data from PQDIF file.
        /// </summary>
        /// <param name="faultDataSet">Fault data set to be populated.</param>
        /// <param name="settings">Source parameters.</param>
        /// <param name="line">Associated XML event file definition.</param>
        public static void PopulateDataSet(FaultLocationDataSet faultDataSet, Dictionary <string, string> settings, Line line)
        {
            string fileName;

            if ((object)line == null)
            {
                throw new ArgumentNullException("line");
            }

            if (!settings.TryGetValue("fileName", out fileName) || !File.Exists(fileName))
            {
                throw new ArgumentException("Parameters must define a valid \"fileName\" setting.");
            }

            // Comtrade parsing will require a CFG file, make sure this exists...
            string directory             = Path.GetDirectoryName(fileName) ?? string.Empty;
            string rootFileName          = FilePath.GetFileNameWithoutExtension(fileName);
            string configurationFileName = Path.Combine(directory, rootFileName + ".cfg");

            if (!File.Exists(configurationFileName))
            {
                throw new FileNotFoundException(string.Format("Associated CFG file \"{0}\" for COMTRADE data file does not exist - cannot parse COMTRADE file.", configurationFileName));
            }

            // Parse configuration file
            Schema schema = new Schema(configurationFileName);

            // Find <Channels> element in XML line definition
            XElement channels = line.ChannelsElement;

            if ((object)channels == null)
            {
                throw new NullReferenceException("No \"<channels>\" element was found in event file definition - cannot load COMTRADE data file.");
            }

            // Extract COMTRADE channel ID's for desired voltage and current elements
            IEnumerable <Tuple <int, int> > vaIndexes = GetValueIndex(schema, channels, "VA").ToList();
            IEnumerable <Tuple <int, int> > vbIndexes = GetValueIndex(schema, channels, "VB").ToList();
            IEnumerable <Tuple <int, int> > vcIndexes = GetValueIndex(schema, channels, "VC").ToList();
            IEnumerable <Tuple <int, int> > iaIndexes = GetValueIndex(schema, channels, "IA").ToList();
            IEnumerable <Tuple <int, int> > ibIndexes = GetValueIndex(schema, channels, "IB").ToList();
            IEnumerable <Tuple <int, int> > icIndexes = GetValueIndex(schema, channels, "IC").ToList();

            List <long>   times    = new List <long>();
            List <double> vaValues = new List <double>();
            List <double> vbValues = new List <double>();
            List <double> vcValues = new List <double>();
            List <double> iaValues = new List <double>();
            List <double> ibValues = new List <double>();
            List <double> icValues = new List <double>();

            SampleRate sampleRate;

            ValidateIndexes("VA", vaIndexes);
            ValidateIndexes("VB", vbIndexes);
            ValidateIndexes("VC", vcIndexes);
            ValidateIndexes("IA", iaIndexes);
            ValidateIndexes("IB", ibIndexes);
            ValidateIndexes("IC", icIndexes);

            // Create a new COMTRADE file parser
            using (Parser parser = new Parser()
            {
                Schema = schema,
                FileName = fileName,
                InferTimeFromSampleRates = true
            })
            {
                // Open COMTRADE data files
                parser.OpenFiles();

                faultDataSet.Frequency = schema.NominalFrequency;
                sampleRate             = schema.SampleRates.First();

                if (sampleRate.Rate != 0)
                {
                    faultDataSet.SetSampleRates((int)(sampleRate.Rate / faultDataSet.Frequency));
                }

                // Read all COMTRADE records
                while (parser.ReadNext())
                {
                    times.Add(parser.Timestamp.Ticks);
                    vaValues.Add(GetValue(parser, vaIndexes));
                    vbValues.Add(GetValue(parser, vbIndexes));
                    vcValues.Add(GetValue(parser, vcIndexes));
                    iaValues.Add(GetValue(parser, iaIndexes));
                    ibValues.Add(GetValue(parser, ibIndexes));
                    icValues.Add(GetValue(parser, icIndexes));
                }
            }

            // Populate voltage data set
            faultDataSet.Voltages.AN.Times        = times.ToArray();
            faultDataSet.Voltages.AN.Measurements = vaValues.ToArray();
            faultDataSet.Voltages.BN.Times        = times.ToArray();
            faultDataSet.Voltages.BN.Measurements = vbValues.ToArray();
            faultDataSet.Voltages.CN.Times        = times.ToArray();
            faultDataSet.Voltages.CN.Measurements = vcValues.ToArray();

            // Populate current data set
            faultDataSet.Currents.AN.Times        = times.ToArray();
            faultDataSet.Currents.AN.Measurements = iaValues.ToArray();
            faultDataSet.Currents.BN.Times        = times.ToArray();
            faultDataSet.Currents.BN.Measurements = ibValues.ToArray();
            faultDataSet.Currents.CN.Times        = times.ToArray();
            faultDataSet.Currents.CN.Measurements = icValues.ToArray();
        }
Exemple #17
0
        // Static Methods

        // Load voltage and current data set based on connection string parameters
        private static void LoadDataSets(FaultLocationDataSet faultDataSet, string parameters, Line line)
        {
            if (string.IsNullOrEmpty(parameters))
            {
                throw new ArgumentNullException("parameters");
            }

            Dictionary <string, string> settings = parameters.ParseKeyValuePairs();
            string dataSourceType;

            if (!settings.TryGetValue("dataSourceType", out dataSourceType) || string.IsNullOrWhiteSpace(dataSourceType))
            {
                throw new ArgumentException("Parameters must define a \"dataSourceType\" setting.");
            }

            switch (dataSourceType.ToLowerInvariant().Trim())
            {
            case "pqdif":
                PQDIFLoader.PopulateDataSet(faultDataSet, settings);
                break;

            case "comtrade":
                COMTRADELoader.PopulateDataSet(faultDataSet, settings, line);
                break;

            default:
                throw new ArgumentOutOfRangeException("parameters", string.Format("Cannot parse \"{0}\" data source type - format is undefined.", dataSourceType));
            }

            if ((object)faultDataSet.Voltages.AN.Measurements == null || faultDataSet.Voltages.AN.Measurements.Length == 0)
            {
                throw new InvalidOperationException("Missing AN voltage. Cannot calculate fault location without line-to-neutral voltages.");
            }

            if ((object)faultDataSet.Voltages.BN.Measurements == null || faultDataSet.Voltages.BN.Measurements.Length == 0)
            {
                throw new InvalidOperationException("Missing BN voltage. Cannot calculate fault location without line-to-neutral voltages.");
            }

            if ((object)faultDataSet.Voltages.CN.Measurements == null || faultDataSet.Voltages.CN.Measurements.Length == 0)
            {
                throw new InvalidOperationException("Missing CN voltage. Cannot calculate fault location without line-to-neutral voltages.");
            }

            if ((object)faultDataSet.Currents.AN.Measurements == null || faultDataSet.Currents.AN.Measurements.Length == 0)
            {
                throw new InvalidOperationException("Missing AN current. Cannot calculate fault location without line-to-neutral currents.");
            }

            if ((object)faultDataSet.Currents.BN.Measurements == null || faultDataSet.Currents.BN.Measurements.Length == 0)
            {
                throw new InvalidOperationException("Missing BN current. Cannot calculate fault location without line-to-neutral currents.");
            }

            if ((object)faultDataSet.Currents.CN.Measurements == null || faultDataSet.Currents.CN.Measurements.Length == 0)
            {
                throw new InvalidOperationException("Missing CN current. Cannot calculate fault location without line-to-neutral currents.");
            }

            ValidateSampleRates(faultDataSet.Frequency, faultDataSet.Voltages);
            ValidateSampleRates(faultDataSet.Frequency, faultDataSet.Currents);

            faultDataSet.Cycles.Populate(faultDataSet.Frequency, faultDataSet.Voltages, faultDataSet.Currents);
        }
Exemple #18
0
        public override void Initialize(MeterDataSet meterDataSet)
        {
            DataGroup        dataGroup;
            VIDataGroup      viDataGroup;
            VICycleDataGroup viCycleDataGroup;

            List <Fault> faults;

            List <FaultLocationAlgorithm> faultLocationAlgorithms;
            FaultLocationDataSet          faultLocationDataSet;
            ImpedanceExtractor            impedanceExtractor;
            FaultCurveGenerator           faultCurveGenerator;

            CycleDataResource cycleDataResource;

            bool?faultDetectionLogicResult;
            bool defaultFaultDetectionLogicResult;
            bool faultValidationLogicResult;

            Stopwatch stopwatch;

            stopwatch               = new Stopwatch();
            cycleDataResource       = meterDataSet.GetResource <CycleDataResource>();
            faultLocationAlgorithms = GetFaultLocationAlgorithms(m_dbAdapterContainer.GetAdapter <FaultLocationInfoDataContext>());

            Log.Info(string.Format("Executing fault location analysis on {0} events.", cycleDataResource.DataGroups.Count));

            for (int i = 0; i < cycleDataResource.DataGroups.Count; i++)
            {
                dataGroup        = cycleDataResource.DataGroups[i];
                viDataGroup      = cycleDataResource.VIDataGroups[i];
                viCycleDataGroup = cycleDataResource.VICycleDataGroups[i];

                // Engineering reasonableness checks
                Log.Debug("Checking for engineering reasonableness...");

                try
                {
                    stopwatch.Restart();

                    if (!IsReasonable(dataGroup, viCycleDataGroup))
                    {
                        continue;
                    }
                }
                finally
                {
                    Log.Debug(stopwatch.Elapsed);
                }

                // Break into faults and segments
                Log.Debug("Classifying data into faults and segments...");

                try
                {
                    stopwatch.Restart();

                    faults = DetectFaults(viDataGroup, viCycleDataGroup);

                    if (faults.Count > 0)
                    {
                        ClassifyFaults(faults, dataGroup, viCycleDataGroup);
                    }
                }
                finally
                {
                    Log.Debug(stopwatch.Elapsed);
                }

                // Check the fault detection logic and the default fault detection logic
                faultDetectionLogicResult        = CheckFaultDetectionLogic(meterDataSet, dataGroup);
                defaultFaultDetectionLogicResult = CheckDefaultFaultDetectionLogic(faults);

                // If the fault detection logic detects a fault and the default
                // logic does not agree, treat the whole waveform as a fault
                if (faultDetectionLogicResult == true && !defaultFaultDetectionLogicResult)
                {
                    faults.Add(new Fault()
                    {
                        StartSample = 0,
                        EndSample   = dataGroup[0].DataPoints.Count - 1
                    });

                    ClassifyFaults(faults, dataGroup, viCycleDataGroup);
                }

                // Create the fault location data set and begin populating
                // the properties necessary for calculating fault location
                faultLocationDataSet = new FaultLocationDataSet();
                faultLocationDataSet.LineDistance  = dataGroup.Line.Length;
                faultLocationDataSet.PrefaultCycle = FirstCycle(viCycleDataGroup);

                // Extract impedances from the database
                // and into the fault location data set
                impedanceExtractor = new ImpedanceExtractor();
                impedanceExtractor.FaultLocationDataSet = faultLocationDataSet;
                impedanceExtractor.FaultLocationInfo    = m_dbAdapterContainer.GetAdapter <FaultLocationInfoDataContext>();
                impedanceExtractor.Meter = meterDataSet.Meter;
                impedanceExtractor.Line  = dataGroup.Line;

                if (impedanceExtractor.TryExtractImpedances())
                {
                    // Generate fault curves for fault analysis
                    Log.Debug("Generating fault curves...");
                    stopwatch.Restart();

                    faultCurveGenerator = new FaultCurveGenerator();
                    faultCurveGenerator.SamplesPerCycle         = (int)(viDataGroup.VA.SampleRate / m_systemFrequency);
                    faultCurveGenerator.CycleDataGroup          = viCycleDataGroup;
                    faultCurveGenerator.Faults                  = faults;
                    faultCurveGenerator.FaultLocationDataSet    = faultLocationDataSet;
                    faultCurveGenerator.FaultLocationAlgorithms = faultLocationAlgorithms;
                    faultCurveGenerator.GenerateFaultCurves();

                    Log.Debug(stopwatch.Elapsed);

                    // Gather additional info about each fault
                    // based on the results of the above analysis
                    foreach (Fault fault in faults)
                    {
                        PopulateFaultInfo(fault, dataGroup, viCycleDataGroup);
                    }
                }

                // Create a fault group and add it to the lookup table
                faultValidationLogicResult = CheckFaultValidationLogic(faults);
                m_faultLookup.Add(dataGroup, new FaultGroup(faults, faultDetectionLogicResult, defaultFaultDetectionLogicResult, faultValidationLogicResult));
            }
        }