FX AI-Based PRPD Classifier Overview
Overview
Starting with BATCAM FX firmware v1.0.3c, our in-house AI-based partial discharge classification feature is integrated into the firmware. Built on CUDA and ONNX Runtime, it is designed to classify partial discharge types in real time on the device.
PRPD (Phase-Resolved Partial Discharge) is a partial discharge diagnostic technique that analyzes discharge signals with respect to the power phase. The AI classifier in BATCAM FX takes this PRPD data as input and determines the partial discharge type.
This document explains how to receive and use the AI-based classification results. The firmware supports a total of four classification results (Corona, Floating, Surface, Noise), and an individual result is provided for each LPoint Audio channel (CH0~CH2).
| Class | Description |
|---|---|
corona | Corona discharge type |
floating | Floating electrode discharge type |
surface | Surface (creeping) discharge type |
noise | Background noise or signals that are not partial discharge |
Classification results are delivered over two channels: ROS 2 and WebSocket. For each LPoint Audio channel, a logit score is provided for every supported partial discharge type, and you can infer the classification result from these scores.
💡 Note: This document applies to BATCAM FX. For the AI features of BATCAM FX2, see the Device Manager — AI document.
Prerequisites
-
Firmware version: BATCAM FX firmware v1.0.3c or later. ROS 2 output was first added in v1.0.3b, and the full feature set including WebSocket output is available from v1.0.3c. For the detailed change history, see the Firmware Release Notes.
-
How to check the version: Open the
{CAMERA_IP}/setting/statuspage in a browser, or check the REST APIGET /setting/statusresponse for thefirmware_versionvalue. (See the FX API Playground.) -
Receiver-side ROS 2 environment: The ROS 2 features of BATCAM FX are based on ROS 2 Humble Hawksbill. The fx-stream-msgs message package is intended for use with Humble and was built and verified on Python 3.10.16 with ROS 2 Jazzy (Ubuntu 24.04). (See the ROS Overview.)
-
Matching ROS_DOMAIN_ID: The camera’s default ROS_DOMAIN_ID is
123. The receiving environment must use the same value for the topics to be visible. (See ROS Domain ID Configuration.)
Receiving Data
ROS 2 Topics
BATCAM FX creates the PRPD classification result topic based on the camera’s hardware ID.
| Item | Value |
|---|---|
| Topic name | /fx_{hardware_id}/prpd |
| Message type | fx_stream_msgs/msg/Prpd |
| Message size | 52 B/message |
| Average bandwidth | About 220 B/s |
Prpd messages provide, for each of the four classes, a length-3 array of per-channel (CH0~CH2) logit values.
| Field | Type | Description |
|---|---|---|
noise | float32[3] | noise class logit for channels CH0~CH2 (dimensionless score) |
corona | float32[3] | corona class logit for channels CH0~CH2 (dimensionless score) |
floating | float32[3] | floating class logit for channels CH0~CH2 (dimensionless score) |
surface | float32[3] | surface class logit for channels CH0~CH2 (dimensionless score) |
Logit values are unnormalized scores that can be positive or negative, so interpret them based on their relative magnitudes.
The full ROS 2 topic list and message definitions are summarized in the message definitions section of the ROS Overview document, and the original message format definitions are available in the SMI OSS - fx-stream-msgs repository.
WebSocket (Protobuf) Stream
From firmware v1.0.3c, the same classification results are also provided as a WebSocket-based Protobuf stream. On the subscription channel, subscribe with Subscribe ID 3 to receive Prpd events, which are sent at about 4 Hz on BATCAM FX.
For a complete Python example covering WebSocket connection, subscription, and parsing, see the Python Protobuf Example document. It also summarizes the differences between FX and FX2.
Classification Method
For each channel, select the class with the highest of the four per-class logit values (argmax). To also compute a probability for each result, take the channel’s per-class values and apply softmax.
| Channel | noise (logit) | corona (logit) | floating (logit) | surface (logit) | Classification result (argmax) | Probability (softmax) |
|---|---|---|---|---|---|---|
| ch0 | -0.96 | 2.98 | -3.55 | 0.30 | corona | 0.918 ( 91.8 % ) |
| ch1 | 4.48 | 5.88 | -5.45 | -1.51 | corona | 0.802 ( 80.2 % ) |
| ch2 | -6.54 | -1.39 | 0.73 | 0.45 | floating | 0.533 ( 53.3 % ) |
💡 Interpretation note: The softmax probability is a relative confidence among the four classes. A low top probability, as with ch2 in the example (53.3 %), means the logit gap between floating (0.73) and surface (0.45) is small and the two classes are competing. The threshold for accepting a classification result depends on the application and site conditions, so define and apply one that fits your system’s requirements.
Softmax
The softmax function converts a logit vector into a probability distribution. The general form is:
However, if logit values are very large or very small, overflow or underflow can occur, so the following normalized form is typically used:
Translated into Python, the formula looks like this:
Python Implementation
import numpy as np
def softmax(logits): logits = np.array(logits) exps = np.exp(logits - np.max(logits)) # numerically stable softmax return exps / np.sum(exps) # return probabilitiesCommon Lisp Implementation
(defun softmax (logits) "Take a list or vector LOGITS and return a softmax probability vector" (let* ((vec (coerce logits 'vector)) (maxval (reduce #'max vec)) (exps (map 'vector (lambda (x) (exp (- x maxval))) vec)) (sum (reduce #'+ exps))) (map 'vector (lambda (x) (/ x sum)) exps)))Complete Example: rclpy Subscriber Node
Below is a complete Python (rclpy) node that subscribes to the PRPD topic and logs the per-channel classification result and probability. Save it as a single file (prpd_subscriber.py) and run it as is.
💡 Note: The topic name
/fx_276730383020104/prpdin the code is an example; change it to match your camera’s hardware ID. You can check the actual topic name with theros2 topic listcommand.
import numpy as npimport rclpyfrom rclpy.node import Node
from fx_stream_msgs.msg import Prpd
# Labels in the same order as the Prpd.msg fieldsLABELS = ['noise', 'corona', 'floating', 'surface']
def softmax(logits): logits = np.array(logits) exps = np.exp(logits - np.max(logits)) # numerically stable softmax return exps / np.sum(exps)
class PrpdSubscriber(Node): def __init__(self): super().__init__('prpd_subscriber') # Change the topic name to match your camera's hardware ID. self.subscription = self.create_subscription( Prpd, '/fx_276730383020104/prpd', self.listener_callback, 10)
def listener_callback(self, msg: Prpd): results = []
# For 3 channels (CH0 ~ CH2) for ch in range(3): logits = [ msg.noise[ch], msg.corona[ch], msg.floating[ch], msg.surface[ch], ] probs = softmax(logits) idx = int(np.argmax(probs)) results.append({ 'channel': f'CH{ch}', 'label': LABELS[idx], 'probability': round(float(probs[idx]), 3), })
# Log the results for result in results: self.get_logger().info( f"{result['channel']}: {result['label']} " f"({result['probability'] * 100:.1f}%)" )
def main(args=None): rclpy.init(args=args) node = PrpdSubscriber() try: rclpy.spin(node) except KeyboardInterrupt: pass finally: node.destroy_node() rclpy.shutdown()
if __name__ == '__main__': main()How to Run
Source your ROS 2 environment and the workspace where the fx-stream-msgs message package was built, then run the script. Use the same ROS_DOMAIN_ID as the camera (default 123).
source /opt/ros/humble/setup.bash# Also source the workspace where the fx-stream-msgs message package was built.export ROS_DOMAIN_ID=123python3 prpd_subscriber.pyExpected Output
Assuming the example logit values from “Classification Method” above are received, the log output looks like this:
[INFO] [1748324429.123456789] [prpd_subscriber]: CH0: corona (91.8%)[INFO] [1748324429.123512345] [prpd_subscriber]: CH1: corona (80.2%)[INFO] [1748324429.123556789] [prpd_subscriber]: CH2: floating (53.3%)Common Lisp Reference Implementation
A Common Lisp reference implementation of the same classification logic (softmax + argmax). Wire up message reception to fit your environment; the code below assumes msg holds (noise corona floating surface) vectors of length 3 each.
; Define labels for the discharge types(defparameter *labels* #("noise" "corona" "floating" "surface"))
; Softmax function(defun softmax (logits) "Take a list or vector LOGITS and return a softmax probability vector" (let* ((vec (coerce logits 'vector)) (maxval (reduce #'max vec)) (exps (map 'vector (lambda (x) (exp (- x maxval))) vec)) (sum (reduce #'+ exps))) (map 'vector (lambda (x) (/ x sum)) exps)))
(defun classify-channel (noise corona floating surface) "Take one channel's logit values and return the label/probability" (let* ((logits (vector noise corona floating surface)) (probs (softmax logits)) (idx (position (reduce #'max probs) probs))) (list :label (aref *labels* idx) :probability (aref probs idx))))
(defun listener-callback (msg) "Assume msg holds (noise corona floating surface) vectors of length 3 each" (loop for ch from 0 below 3 for result = (classify-channel (aref (getf msg :noise) ch) (aref (getf msg :corona) ch) (aref (getf msg :floating) ch) (aref (getf msg :surface) ch)) do (format t "CH~A: ~A (~,1F%)~%" ch (getf result :label) (* (getf result :probability) 100))))Troubleshooting
-
prpdtopic is not visible:-
Check that the firmware version is v1.0.3c or later. Open
{CAMERA_IP}/setting/statusin a browser or check theGET /setting/statusresponse’sfirmware_versionvalue; if the firmware is older, update it via Web Update or Shell Update. -
Check that the receiver’s
ROS_DOMAIN_IDmatches the camera’s. The camera default is123; on firmware 1.0.3 and later, you can read and change it via the REST API (/ros/domain). (See FX API Playground, ROS Domain ID Configuration.) -
ros2 topic listshould show the/fx_{hardware_id}/prpdtopic; run it again to confirm.
-
-
ModuleNotFoundError: No module named 'fx_stream_msgs'error occurs:- fx-stream-msgs message package workspace has not been sourced. Source the workspace’s
setup.bashand run the script again.
- fx-stream-msgs message package workspace has not been sourced. Source the workspace’s
-
Overflow/underflow warnings occur during softmax computation:
- Do not exponentiate raw logit values; use the normalized form from the “Softmax” section above (exponentiate after subtracting
np.max).
- Do not exponentiate raw logit values; use the normalized form from the “Softmax” section above (exponentiate after subtracting
-
The top probability comes out low:
- This is not an error; it means that two or more class logits are close and competing. See the interpretation note under “Classification Method” above.
Related Documents
-
ROS Overview — full topic list, message definitions, and caveats
-
ROS Domain ID Configuration — how to change the domain ID
-
Listening Point Coordinates — LPoint channel concept and configuration limits
-
Firmware Release Notes — PRPD feature change history by version
-
Python Protobuf Example — WebSocket stream subscription example (common to FX/FX2)
-
FX API Playground —
/setting/status,/ros/domainand other REST API references