Process History View (PHV) is the trend and event tool that ships with DeltaV. Every faceplate has a button that opens it, and on most systems the chart it opens is close to useless: auto-scaled or 0 to 100, one pen, the faceplate's name for a title, and none of the related loops. Operators rebuild the same chart by hand every shift.
This is the method I used to fix that on a large DeltaV system (roughly 10,000 modules, controllers and safety devices). A right-click on the PHV glyph of any faceplate now opens a chart built for that module: its own pens in fixed colors, a Y-window padded around the alarm limits or the engineering range, related loops in gray, the tag as title, the description as subtitle, events filtered to the module, and the last 24 hours on screen. Nothing was downloaded to a controller, and the stock button still works.
## How PHV opens from a faceplate today
The stock behaviour is not in the PHV manual. It is mentioned in the batch trending topic and in the maintenance book under "backing up supporting data":
1. The faceplate runs `CHS.exe` (PHV) with a chart file named after the **faceplate**, from `DeltaV\DVData\Charts\Lib`, and the switch `/sub <module tag>`.
2. `/sub` rewrites the module portion of every pen path in the template. One template per faceplate, so every PID loop opens the same chart with the tag swapped in. The chart cannot be saved.
3. A faceplate with no matching `.phve` opens PHV with a file-not-found dialog.
The PHV command line (historian collection book, "Customizing Process History View") takes the file first, then `/new`, `/histnode`, `/eventsnode`, `/sub`, `/prompt`, `/trend` (eight references at most), `/module` (events only), `/starttime`, `/endtime` and `/span`. There is no switch for pen color or Y-range, and `/trend` is ignored when a file is named. Anything per-module therefore has to live in the chart file. That fact decided the design.
See also [[How does PHV Open In DeltaV]].
## Options I rejected
- **`/trend` from the faceplate script.** No colors, no ranges, eight pens, ignored once a file is named.
- **Spare module parameters.** PCSD gives every module ten spare floats and strings for this kind of thing, but on this system they were already in use, and SIS modules have none (any change means a download and re-verification).
- **DeltaV Live scripting alone.** Live scripts can read and write parameters and launch a signed executable, but have no file or HTTP access and keep nothing per tag between sessions.
What worked: generate one chart file per module from the configuration database. The file carries everything PHV needs, and the Live script is one line.
## The method
```mermaid
flowchart LR
A[DeltaV configuration database] -->|Export whole system| B[FHX text export]
B --> C[Scan: faceplates, scales, alarms, links, history, enumerations]
C --> D[Rules: pens, windows, partners, statistics, servers]
D --> E[One .phve file per module]
E --> F[Charts library folder on each console]
G[Faceplate right-click in Live] --> H[CHS.exe opens that module's file]
F --> H
```
### 1. Mine the configuration database
DeltaV Explorer exports the whole system to an FHX file, a text dump of every module, class, node and library item. Here it was about a gigabyte of UTF-16. It is the only input that changes, so the pipeline runs from a fresh export in about a minute.
One streaming pass, counting braces per block, collects:
- per module: faceplate, description, plant area, engineering ranges (instance first, then class default), HIHI and LOLO limits and their enable flags, cascade links (`CAS_IN_REF`, `BKCAL_IN`), enumeration sets behind discrete parameters, and which parameters have history collection turned on;
- per controller, logic solver and I/O node: its type;
- per safety module: its composites, alarm groups, and each voter's trip limit and trip direction.
Two FHX traps. An instance record holds only what differs from its class, so read the class first and apply the instance on top. And class defaults look like real configuration but often are not.
### 2. Decide what every chart shows, as rules
One rule applied 3,000 times beats 3,000 hand-made charts.
**Pens by faceplate.** Analog input: PV. PID: PV, SP, OUT, valve position. Analog output: OUT, position, readback. Discrete input, output and valve: the state, plus position feedback where it is historized. Colors are fixed by position (red, orange, green, blue) so every loop reads the same way.
**A fixed Y-window that keeps the pen on screen.** Auto-scaling hides a pen sitting on its limit. The window is HIHI and LOLO plus 10 % of the distance between them when the alarm limits can be trusted, otherwise the engineering range plus 5 % of span, rounded outward to tidy numbers. Percent pens are -5 to 105.
**Trusting an alarm limit.** PCSD ships HIHI = 95 and LOLO = 5 on every class regardless of scale, so an untouched default on a 0 to 3000 psig transmitter would clip the chart to 5 to 95 psig. A limit counts only when it lies strictly inside the engineering range and either the alarm is enabled or the instance value differs from the class default.
**Discrete windows** run from -1 to the highest visible state plus one: a 0/1 signal plots on -1 to 2, a three-state damper on -1 to 3.
**Related loops in gray.** Cascade masters and slaves, found by following the `CAS_IN_REF` and `BKCAL_IN` links both ways, and A/B/C/D siblings, each on its own axis. A module with more partners than free slots gets none rather than a random subset.
**Axis sharing.** SP shares the PV axis, valve position shares the OUT axis. Everything else gets its own.
**Statistics.** Min, max and time-weighted average on analog pens. A total only on flow-rate PVs, with the multiplier that turns the rate into a quantity and the quantity unit.
**Title, events, servers, time.** Tag for the title, description for the subtitle, events filtered to the module only, historian and event chronicle servers written into the file by plant-area prefix, window = last 24 hours ending now.
**Controllers and I/O nodes** get an events-first chart with the NTP offset and performance indices, keyed on the node's block type.
**Safety devices.** In the PCSD SIS library a transmitter or valve is a composite inside a safety module and carries no faceplate. The faceplate hangs on an *alarm group*, whose name is the tag the operator sees and whose assignments name the composites behind it. The event chronicle logs trips and bypasses against the alarm group, not the module. So: one chart per alarm group, pens from the composites it fronts, window from every voter's trip limit with the side read from the voter's `DETECT_TYPE`, events filtered to the group. My first version guessed the trip side from the pre-trip limit; disabled limits are stored as plus or minus 99999 and inverted the guess on 900-odd charts. Read the parameter that says what you want to know.
### 3. Write the chart files
A `.phve` is an undocumented MFC CArchive binary. Decoding it was the usual exercise: save a chart, change one setting, save again, diff, repeat. Strings are `FF FE FF`, a length byte, then UTF-16. Each pen is a record with a scale mode (engineering limits, auto, defined limits), two doubles for the limits, descriptor, parameter path, color and statistics flags. The chart record holds the trend count, server names, title, subtitle and times. The event filter is a list holding a `MOD` placeholder.
Two decisions made it robust:
- **Clone, don't construct.** Every chart starts as a byte copy of a master chart saved from the site's own PHV, with its legend columns and preferences. The generator resets the twenty pen slots, fills them, and patches title, servers, times and filter. Whatever I never decoded is inherited untouched.
- **Round-trip as the unit test.** Parser output fed back through the serializer must reproduce every stock library template byte for byte. A misread field shows up at once.
One trap: the span is stored in three places and the two that look like a span are not what PHV honours. The window that counts is the pair of absolute start and end seconds in the event date filter. The generator writes start = end minus 86,400 and an end of "*", which PHV reads as now.
Everything site- or library-specific sits in three YAML files: *settings* (paths, padding, rounding, colors, flow units), *library* (faceplate to pen family; each family's pens, scale attributes, alarm block, enumeration set, axis sharing) and *servers* (historian and event server by area prefix). The Python is mechanism only. Another PCSD site edits the faceplate list and the server table; a different control library rewrites the families.
```yaml
families:
PID:
pens:
- {path: PID1/PV.CV, scale: [PID1/PV_SCALE, AI1/OUT_SCALE], alarms: PID1}
- {path: PID1/SP.CV, scale: [PID1/PV_SCALE, AI1/OUT_SCALE], alarms: PID1}
- {path: PID1/OUT.CV, scale: [PID1/OUT_SCALE], default_percent: true}
- {path: AO1/PV.CV, scale: [AO1/PV_SCALE], default_percent: true}
share_axis: [false, true, false, true] # SP on the PV axis, valve on the OUT axis
```
### 4. Launch it from DeltaV Live
Copy the generated folder under `DeltaV\DVData\Charts\Lib\<project>` on each console. The stock button keeps opening the library template with `/sub`.
In Graphics Studio, once: a Private String standard holding `%DeltaVPath%\CHS.exe;NoSignatureCheck`. Then, on a *copy* of each faceplate (a library upgrade overwrites the original), select the PHV glyph and add a Secondary-Click (right-click) action. Double-click was the first choice, but Live does not handle double-click events reliably, so the right-click is the gesture:
```ts
// The last path segment of the display tag is the module tag. An SIS faceplate
// carries "<safety module>/<alarm group>", and the group is the chart's file name.
const tag = Dsp.Tag.split("%").pop().split("/").pop();
const ok = await ENV.RunAsync(GL.MyLibrary.PHVApp, "Lib/MyProject/" + tag + ".phve");
if (!ok) await MessageBoxAsync("Process History View could not be started.", "Trend",
Constants.MessageBoxButtonType.MB_OK, 10);
```
No time or server switches. The file carries them.
### 5. Keep it current
The generator is safe to rerun after every database change:
- a manifest holds the hash of every chart it wrote. A chart whose hash changed was saved by an operator; it is reported as "kept" and left alone (`--force` overrides);
- `--dry-run` writes the change report (new, updated, unchanged, kept, orphaned) and nothing else;
- `--prune` removes charts for modules that have left the database;
- a CSV with one row per pen shows where each range and limit came from. That is what you read when a chart looks wrong.
New modules get a chart on the next run. A right-click that hits the file-not-found dialog is the cue that a run is due.
## Results
| Chart kind | Count |
|---|---|
| Analog modules (AI, PID, cascade, AO) | 3,616 |
| Discrete modules (DI, DO, valves) | 3,008 |
| Controllers and I/O nodes | 119 |
| Safety alarm groups | 2,953 |
| **Total** | **9,696** |
Scan about fifteen seconds, full build about a minute. Reruns are byte-identical where nothing changed, which is how I know a change to the generator did only what it was meant to.
## Lessons
- Read the whole help set. The faceplate-to-chart mechanism was in the batch and maintenance books, not the PHV book.
- Test what the documentation implies but does not say.
- Treat library defaults as noise until an instance proves otherwise.
- Keep mechanism and site knowledge in separate files. That is what makes the tool portable.
- For an undocumented binary format, clone a real file and patch it, and make byte-exact round-tripping the test.
## Want this on your system?
I will generate the chart set for your DeltaV system for a one-day services fee. The work is done remotely from an export. Nothing is installed on your system and nothing is downloaded to a controller.
What I need from you:
- a whole-system FHX export (DeltaV Explorer, File, Export, Whole System);
- a copy of `DeltaV\DVData\Charts\Lib` from one workstation, plus one chart saved from your own PHV with the legend and preferences you like, to use as the master;
- your historian and event chronicle server names, by plant area;
- the list of faceplates to cover.
What you get back:
- the chart folder, one `.phve` per module, ready to copy under `Charts\Lib`;
- the review spreadsheet, one row per pen, showing where every range and limit came from;
- the Graphics Studio steps and the Live script for the right-click;
- the configuration files, so the next database change is a rerun you can do yourself.
A PCSD-based system fits in the day. A different control library needs its pen families written first, and I will tell you up front what that adds.
**Bruce Schaller, PE**
Control System Integrators, Providence, Rhode Island
[
[email protected]](mailto:
[email protected])
+1 401 441 1557
[controlsysint.com](https://controlsysint.com)