Quick Start
Load CPOW waveform data
CPOW (Continuous Point-on-Wave) files contain high-resolution waveform captures at 32 kHz across 7 channels.
from equser.data import load_cpow_scaled
result = load_cpow_scaled('20250623_075056.parquet')
# Scaled voltage and current arrays (numpy float64)
print(f"Voltage A peak: {result['VA'].max():.1f} V")
print(f"Current A peak: {result['IA'].max():.3f} A")
print(f"Start time: {result['start_time']}")
print(f"Sample rate: {result['sample_rate']} Hz")
The function handles both data formats automatically:
- int32 (current format): raw ADC counts scaled by
vscale/iscalefrom Parquet metadata. - float (legacy format): values already in volts/amps.
Load PMon summary data
PMon (Power Monitor) files contain 10/12-cycle RMS measurements (~200 ms intervals).
from equser.data import load_pmon
table = load_pmon('20250623_0750.parquet')
print(table.column_names)
# ['time_us', 'FREQ', 'AVRMS', 'BVRMS', 'CVRMS', 'AIRMS', ...]
Analyze zero crossings
Zero-crossing detection is useful for frequency estimation, cycle extraction, and identifying waveform distortions.
import numpy as np
from equser.data import load_cpow_scaled, SAMPLE_RATE_HZ
from equser.analysis import find_zero_crossings
result = load_cpow_scaled('cpow_data.parquet')
time = np.arange(len(result['VA'])) / SAMPLE_RATE_HZ
crossings, indices = find_zero_crossings(result['VA'], time)
print(f"Found {len(crossings)} zero crossings")
# Estimate frequency from crossing intervals
periods = np.diff(crossings)
freq = 1.0 / np.mean(periods)
print(f"Estimated frequency: {freq:.2f} Hz")
Extract complete cycles
from equser.analysis import extract_complete_cycles
cycles = extract_complete_cycles(result['VA'], time, [0.0, 0.05], num_cycles=1)
for cycle_time, cycle_signal, start, end in cycles:
duration_ms = (end - start) * 1000
print(f"Cycle at {start:.6f}s, duration: {duration_ms:.2f} ms")
Plot data (requires [analysis])
from equser.plotting import PowerMonitorPlotter, WaveformPlotter
# PMon data
plotter = PowerMonitorPlotter()
plotter.plot_file('pmon_data.parquet')
# CPOW waveforms
wf_plotter = WaveformPlotter()
wf_plotter.plot_file('cpow_data.parquet')
Query a gateway (requires [analysis])
from equser.api import SynapseClient
client = SynapseClient('http://gateway:8080')
devices = client.list_devices()
table = client.get_pmon_data(devices[0]['id'])
# SQL queries
rows = client.query_sql("SELECT * FROM pmon ORDER BY time_us DESC", limit=10)
Stream real-time data (requires [analysis])
from equser.api import connect_cpow_stream
for batch_or_gap in connect_cpow_stream('http://gateway:8080'):
if isinstance(batch_or_gap, dict):
print(f"Gap: {batch_or_gap['skipped_samples']} samples")
else:
print(f"Batch: {batch_or_gap.num_rows} rows")
CLI tools
# Start power monitoring (requires [daq] + EQ Wave hardware)
equser pmon acquire -c config.yaml
# Convert Avro files to Parquet (requires [daq])
equser pmon convert data/*.avro --remove
# Plot data file (requires [analysis])
equser plot data.parquet