Skip to content

Commit a247342

Browse files
authored
Merge pull request #12 from ps-wiki/pdf
Add a def. in AGC
2 parents 162d316 + 6c5b32c commit a247342

File tree

7 files changed

+146
-7
lines changed

7 files changed

+146
-7
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ Convert a single JSON file to a Markdown file:
6262
python database/pyscripts/json2md.py --input database/json/stability.json --output _wiki/stability.md
6363
```
6464

65+
Format a single MD file:
66+
67+
```bash
68+
python database/pyscripts/md_format.py -i _wiki/automatic-generation-control.md
69+
```
70+
6571
## License
6672

6773
This project is licensed under the [CC-BY-NC 4.0](./LICENSE).

_pages/add-new.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ There are two ways to add a new term to the wiki: using a Markdown file or a JSO
1313

1414
Use [stability.md](https://github.com/ps-wiki/ps-wiki.github.io/blob/main/_wiki/stability.md) as a reference for creating new term entries.
1515

16+
It is good to format the Markdown file using the provided script:
17+
18+
```bash
19+
python database/pyscripts/md_format.py -i _wiki/stability.md
20+
```
21+
1622
After creating the Markdown file, convert it back to JSON format using the provided script:
1723

1824
```bash

_wiki/automatic-generation-control.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ related:
1515
authors:
1616
- name: Jinning Wang
1717
url: https://jinningwang.github.io
18-
version: 1.0.0
18+
version: 1.0.1
1919
date: 2025-03-15
20-
lastmod: 2025-06-22
21-
generated: 2025-11-03
20+
lastmod: 2025-11-19
21+
generated: 2025-11-19
2222
---
2323

2424
### Definition by NERC
@@ -32,3 +32,19 @@ Source: <d-cite key="nerc2024glossary"></d-cite>
3232
Source: <d-cite key="ferc2020glossary"></d-cite>
3333

3434
> The automatic regulation of the power output of electric generators within a prescribed range in response to a change in system frequency, or tie-line loading, to maintain system frequency or scheduled interchange with other areas within predetermined limits.
35+
36+
### Definition in a Course
37+
38+
Source: <d-cite key="sun2021frequency"></d-cite> p32
39+
40+
> Adding supplementary control on load reference set-points of selected generators:
41+
> − Controlling prime-mover power to match load variations
42+
> − As system load is continually changing, it is necessary to change the output of generators automatically
43+
44+
> Primary objective: LFC
45+
> – Regulating frequency to the specified nominal value, e.g. 60Hz, and maintaining the interchange power between control areas at the scheduled values by adjusting the output of selected generators
46+
47+
> Secondary objective: Generation Dispatch
48+
> – Distributing the required change in generation among generators to minimize operation costs.
49+
50+
> During large disturbances and emergencies, AGC is bypassed and other emergency controls are applied.

assets/bibliography/papers.bib

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1728,5 +1728,15 @@ @online{nyiso2025interconnectionprocess
17281728
author = {New York Independent System Operator (NYISO)},
17291729
url = {https://www.nyiso.com/interconnections},
17301730
html = {https://www.nyiso.com/interconnections},
1731+
bibtex_show = {true},
17311732
year = {2025},
17321733
}
1734+
1735+
@online{sun2021frequency,
1736+
author = {Kai Sun},
1737+
title = {ECE 522 - Power Systems Analysis II: Frequency Regulation and Control},
1738+
year = {2021},
1739+
url = {https://web.eecs.utk.edu/~kaisun/ECE522/ECE522_4-Frequency.pdf},
1740+
pdf = {https://web.eecs.utk.edu/~kaisun/ECE522/ECE522_4-Frequency.pdf},
1741+
bibtex_show = {true},
1742+
}

database/json/automatic-generation-control.json

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
{
2-
"$schema": "https://ps-wiki.github.io/schema/v1/term.schema.json",
32
"id": "automatic-generation-control",
43
"title": "Automatic Generation Control",
54
"description": "AGC. Automatic regulation of the power output of generators.",
65
"language": "en",
76
"tags": ["frequency-control", "ferc", "nerc"],
87
"related": ["fast-frequency-response", "primary-control", "secondary-control", "tertiary-control", "frequency-regulation", "frequency-stability"],
9-
"version": "1.0.0",
8+
"version": "1.0.1",
109
"breaking": false,
1110
"dates": {
1211
"created": "2025-03-15",
13-
"last_modified": "2025-06-22"
12+
"last_modified": "2025-11-19"
1413
},
1514
"authors": [
1615
{
@@ -37,6 +36,15 @@
3736
"source_keys": ["ferc2020glossary"],
3837
"page": null,
3938
"body_md": "> The automatic regulation of the power output of electric generators within a prescribed range in response to a change in system frequency, or tie-line loading, to maintain system frequency or scheduled interchange with other areas within predetermined limits.\n"
39+
},
40+
{
41+
"order": 3,
42+
"id": "definition-in-a-course",
43+
"title": "Definition in a Course",
44+
"type": "definition",
45+
"source_keys": ["sun2021frequency"],
46+
"page": "p32",
47+
"body_md": "> Adding supplementary control on load reference set-points of selected generators:\n> − Controlling prime-mover power to match load variations\n> − As system load is continually changing, it is necessary to change the output of generators automatically\n\n> Primary objective: LFC\n> – Regulating frequency to the specified nominal value, e.g. 60Hz, and maintaining the interchange power between control areas at the scheduled values by adjusting the output of selected generators\n\n> Secondary objective: Generation Dispatch\n> – Distributing the required change in generation among generators to minimize operation costs.\n\n> During large disturbances and emergencies, AGC is bypassed and other emergency controls are applied.\n"
4048
}
4149
]
4250
}

database/pyscripts/md2json.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ def build_json_from_md(md_path: Path, override_id: Optional[str] = None) -> Dict
282282
front, body = split_front_matter(text)
283283
title = (front.get("title") or "").strip()
284284
description = (front.get("description") or "").strip()
285+
version = (front.get("version") or "1.0.0").strip()
285286
tags = ensure_list(front.get("tags"))
286287
related = ensure_list(front.get("related"))
287288
authors = ensure_list(front.get("authors"))
@@ -306,7 +307,7 @@ def build_json_from_md(md_path: Path, override_id: Optional[str] = None) -> Dict
306307
"language": "en",
307308
"tags": tags,
308309
"related": related,
309-
"version": "1.0.0",
310+
"version": version,
310311
"breaking": False,
311312
"dates": {"created": created_str, "last_modified": lastmod_str},
312313
"authors": authors,

database/pyscripts/md_format.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
4+
"""
5+
Format a Jekyll term Markdown file by performing a full MD -> JSON -> MD roundtrip
6+
conversion, which normalizes the file's structure and front matter.
7+
8+
Requires:
9+
- md2json.py (must be in the same directory or accessible on the Python path)
10+
- json2md.py (must be in the same directory or accessible on the Python path)
11+
12+
Usage:
13+
python database/pyscripts/md_format.py -i _wiki/automatic-generation-control.md
14+
"""
15+
16+
import argparse
17+
import sys
18+
from pathlib import Path
19+
20+
# Assuming md2json.py and json2md.py are in the same directory
21+
# We import the main conversion functions directly.
22+
try:
23+
from md2json import build_json_from_md
24+
from json2md import convert_term_to_md
25+
except ImportError:
26+
print("ERROR: Could not import 'build_json_from_md' from md2json.py or 'convert_term_to_md' from json2md.py.", file=sys.stderr)
27+
print("Ensure these files are in the same directory as md_format.py.", file=sys.stderr)
28+
sys.exit(1)
29+
30+
31+
def format_markdown_file(md_path: Path):
32+
"""Performs the MD -> JSON -> MD roundtrip formatting."""
33+
print(f"--- Processing {md_path.name} ---")
34+
35+
# 1. MD -> JSON (in memory)
36+
try:
37+
# Note: We pass None for override_id to use the default title-derived ID
38+
term_json = build_json_from_md(md_path, override_id=None)
39+
print("✅ MD converted to internal JSON structure.")
40+
except Exception as e:
41+
print(f"❌ ERROR: Failed MD -> JSON conversion for {md_path.name}: {e}", file=sys.stderr)
42+
return
43+
44+
# 2. Normalize fields for json2md's expectations
45+
# This block ensures fields like 'tags', 'related', 'authors', and 'dates'
46+
# are present and correctly structured, even if they were missing or None in the MD.
47+
term_json.setdefault("tags", [])
48+
term_json.setdefault("related", [])
49+
term_json.setdefault("authors", [])
50+
# Dates are already derived in build_json_from_md, but we ensure the structure exists
51+
if not term_json.get("dates"):
52+
# This is unlikely to happen with the current md2json logic, but safe to include
53+
term_json["dates"] = {}
54+
55+
# 3. JSON -> MD (formatted string)
56+
try:
57+
# We need a temporary structure to simulate derive_file_dates,
58+
# but since we are writing back to the *same* file, we use the original path.
59+
# json2md's convert_term_to_md doesn't rely on file system stats, only the CLI does.
60+
formatted_md = convert_term_to_md(term_json)
61+
print("✅ JSON structure converted back to formatted MD string.")
62+
except Exception as e:
63+
print(f"❌ ERROR: Failed JSON -> MD conversion for {md_path.name}: {e}", file=sys.stderr)
64+
return
65+
66+
# 4. Overwrite original MD file
67+
try:
68+
md_path.write_text(formatted_md, encoding="utf-8")
69+
print(f"🎉 Successfully wrote standardized format to: {md_path}")
70+
except Exception as e:
71+
print(f"❌ ERROR: Failed to write output file {md_path.name}: {e}", file=sys.stderr)
72+
return
73+
74+
75+
def main():
76+
ap = argparse.ArgumentParser(
77+
description="Format a Jekyll term Markdown file via MD -> JSON -> MD roundtrip."
78+
)
79+
ap.add_argument("-i", "--input", required=True, help="Path to the term Markdown file to format.")
80+
args = ap.parse_args()
81+
82+
md_path = Path(args.input)
83+
84+
if not md_path.exists():
85+
print(f"ERROR: Markdown file not found: {md_path}", file=sys.stderr)
86+
sys.exit(1)
87+
88+
format_markdown_file(md_path)
89+
90+
91+
if __name__ == "__main__":
92+
main()

0 commit comments

Comments
 (0)