Table of Contents
Finding the Source of a Grid Oscillation
An MIStudio demonstration on public synchrophasor data
The problem
A generator's governor starts to misbehave. It doesn't trip, it doesn't alarm, it just pushes a small, steady oscillation into the grid. Within seconds every bus on the interconnection is swinging at exactly the same frequency, hundreds of miles from the cause.
This is a forced oscillation, and it is one of the harder faults to chase.
Frequency tells you nothing about location: the whole system rings in unison. The plant that is causing it looks, on a frequency plot, identical to a plant a thousand miles away that is merely responding. Operators have the data. Every PMU on the system is reporting thirty times a secondand no obvious way to turn hundreds of simultaneous channels into an answer.
This demonstration turns 294 channels of synchrophasor data into one name, in under two seconds, using a configured MIStudio application.
The data
The 2021 IEEE-PES Oscillation Source Location Contest published a set of test cases on a WECC 179-bus model. This demonstration uses the contest's sample case:
| Item | Value |
|---|---|
| Duration | 90 seconds at 30 Hz — 2,701 samples per channel |
| Channels | 58 bus voltages and 89 line currents, magnitude and angle — 294 signals |
| Event | A 0.54 Hz forced oscillation between t=30 s and t=83 s |
| Cause | The governor of generator 7031 COLOEAST, in the NORTH area |
The cause is published with the data. It is used here only to check the answer. The application is told nothing about it.
The data is also realistically imperfect. Roughly one frame in 2,000 on the voltage channels, and one in 125 on the current channels, arrives as a dropped sample. A dropped frame is a far larger excursion than the oscillation it sits in, so left alone it does not merely add noise, it decides the ranking.
Run against the raw data, the top five buses are simply the five that caught a dropped frame, and the true source falls to 36th of 58.
Handling it is one clause of configuration, and the answer returns to the top of the list.
What the application does
One button. The extractor reads every bus over the event window, computes a statistical and spectral profile for each, ranks all 58, and labels the winner — in a single database query and a single pass.
Figure 1 — The whole application. Six components, five connections.
The chart then draws the located bus against the four quietest buses on the system, so the contrast is immediate.
Figure 2 — The answer. The legend names the bus the ranking chose.
The result
The application ranks all 58 buses by how far each one's voltage moves during the event:
| Rank | Bus | Std. deviation | Peak-to-peak | Dominant freq. | Inter-area band |
|---|---|---|---|---|---|
| 1 | 7031 COLOEAST 20.0 | 3.65e-03 | 2.41e-02 | 0.547 Hz | 96.9% |
| 2 | 6203 COLSTRP 230 | 3.15e-03 | 2.13e-02 | 0.547 Hz | 95.9% |
| 3 | 7032 CRAIG 20.0 | 3.09e-03 | 1.98e-02 | 0.547 Hz | 97.5% |
| 4 | 2634 INTERM1G 20.0 | 2.84e-03 | 1.03e-01 | 0.547 Hz | 50.0% |
| 5 | 2619 SYLMARLA 230 | 2.14e-03 | 6.90e-02 | 0.547 Hz | 29.9% |
Rank 1 is the documented source.
Ranks 2 and 3 are its electrical neighbors, that's exactly what the physics predicts. The located bus swings 22 times harder than the quietest bus on the system.
Note the Dominant freq. column: 0.547 Hz on every row, source and bystander alike. This is the heart of why forced oscillations are hard, and why frequency analysis alone does not locate them. The amplitude column is what carries the answer.
The Inter-area band column is a second, independent line of evidence, the share of each bus's movement that falls in the 0.1–0.8 Hz inter-area band. At the source it is 96.9%: essentially everything that bus is doing is this oscillation. At SYLMARLA, ranked 5th, it is 29.9%. That bus is mostly moving for other reasons, and a ranking built on this column instead would push it down where it belongs.
How it was built
The application contains no code.
It is six components on a diagram, connected and configured through the MIStudio property sheet:
| Component | Role |
|---|---|
Button | Fires the extraction |
BroadcastServer | Distributes the trigger |
DatabaseConnectionManager | The historian connection |
OscillationSource (FeatureExtractor) | Query, metrics, ranking, selection |
FeatureSampleSeries | Turns the result into chart traces |
CustomEChart | Draws it |
The analysis is a JSON request on one property of one component. It names the window, the dropped-frame filter, the metrics, the ranking, and the selection:
"filters": [ { "column": "VMAG", "operator": ">", "value": 0.5 } ],
"groupBy": [ { "name": "bus", "type": "COLUMN", "column": "BUS" } ],
"order": [ { "by": "metric", "metric": "stddev", "direction": "DESC" } ],
"select": [ { "label": "source", "from": "HEAD", "count": 1 },
{ "label": "comparison", "from": "TAIL", "count": 4 } ]
That select block is worth a second look. It returns two roles from one query — the bus that won the ranking, and the buses to compare it against, each tagged with its role.
The alternative, and the way this is usually done, is to run one query to find the winner and a second query that excludes it by name. That second query hardcodes an answer, and goes quietly stale the moment the data changes.
Why this generalises
A semiconductor version of this application ranks wafer lots by process stability and charts the golden lot against the rest. It is the same components, the same ranking mechanism, the same chart.
What changed between the two is the connection string and the contents of one JSON property.
The domain vocabulary is configuration, not code:
| Semiconductor | Grid |
|---|---|
lot_id | BUS |
| chamber pressure | voltage magnitude |
| process stability | oscillation amplitude |
| the reference lot | the located source |
This is what a general-purpose analysis layer buys: the engineer who knows substations does not have to become a programmer, and the tool does not have to be rewritten for each industry it enters.
Beyond this demonstration
- Event classification across a library of recorded disturbances — voltage sags, frequency events, oscillations — rather than a single known event.
- Continuous monitoring, with the ranking running on a schedule against a live historian and alarming when a bus rises to the top.
- Sub-synchronous oscillations and torsional interaction, the growing concern around inverter-based resources. These live at 10–46 Hz, above what a 30 Hz PMU feed can resolve, and need point-on-wave data — but the metrics that find them are the ones already used here, pointed at different frequency bands.
- COMTRADE fault records, the standard format for that higher-rate data.
Notes on this demonstration
Timings are from a local HSQLDB instance.
The reported dominant frequency of 0.547 Hz differs from the documented 0.54 Hz by about 1%, because the historian's timestamps are stored to the millisecond and 1/30 of a second cannot be represented exactly at that resolution.
Data: 2021 IEEE-PES Oscillation Source Location Contest.


