108 lines
3.4 KiB
Python
108 lines
3.4 KiB
Python
"""
|
|
Parser for OWON oscilloscope CSV files.
|
|
"""
|
|
|
|
import csv
|
|
from typing import Dict, List
|
|
import numpy as np
|
|
|
|
from .base_parser import BaseOscilloscopeParser
|
|
from .data import ScopeData, ChannelData
|
|
|
|
|
|
class OwonParser(BaseOscilloscopeParser):
|
|
"""Parser for OWON oscilloscope CSV files."""
|
|
|
|
def can_parse(self, file_path: str) -> bool:
|
|
"""Check if file is from OWON scope."""
|
|
try:
|
|
with open(file_path, "r") as f:
|
|
first_lines = [f.readline().strip() for _ in range(10)]
|
|
# Look for OWON-specific patterns
|
|
return any("Channel" in line and "CH" in line for line in first_lines)
|
|
except:
|
|
return False
|
|
|
|
def parse(self, file_path: str) -> ScopeData:
|
|
"""Parse OWON oscilloscope CSV file."""
|
|
|
|
with open(file_path, "r") as f:
|
|
# Read header metadata
|
|
metadata_lines = []
|
|
data_start_line = 0
|
|
|
|
for i, line in enumerate(f):
|
|
line = line.strip()
|
|
if not line: # Empty line indicates end of metadata
|
|
data_start_line = i + 1
|
|
break
|
|
metadata_lines.append(line)
|
|
|
|
# Parse metadata
|
|
metadata = self._parse_metadata(metadata_lines)
|
|
|
|
# Reset file pointer to data section
|
|
f.seek(0)
|
|
for _ in range(data_start_line):
|
|
next(f)
|
|
|
|
# Parse CSV data
|
|
reader = csv.DictReader(f)
|
|
|
|
# Extract data columns
|
|
voltage_data = []
|
|
time_data = []
|
|
|
|
for row in reader:
|
|
# Get voltage data (look for CH*_Voltage column)
|
|
voltage_col = None
|
|
for col_name in row.keys():
|
|
if "Voltage" in col_name:
|
|
voltage_col = col_name
|
|
break
|
|
|
|
if voltage_col is None:
|
|
raise ValueError("Could not find voltage column in CSV data")
|
|
|
|
# Convert mV to volts
|
|
voltage_mv = float(row[voltage_col])
|
|
voltage_data.append(voltage_mv / 1000.0)
|
|
|
|
# Calculate time values from index and time interval
|
|
index = int(row["index"])
|
|
time_interval = self._extract_time_interval(metadata)
|
|
time_data.append(index * time_interval)
|
|
|
|
# Create channel data
|
|
channel_name = metadata.get("Channel", "CH1").replace(":", "").strip()
|
|
|
|
channel_data = ChannelData(
|
|
channel_name=channel_name,
|
|
voltage_values=np.array(voltage_data),
|
|
time_values=np.array(time_data),
|
|
metadata=metadata,
|
|
)
|
|
|
|
return ScopeData(channels={channel_name: channel_data}, metadata=metadata)
|
|
|
|
def _parse_metadata(self, metadata_lines: List[str]) -> Dict[str, str]:
|
|
"""
|
|
Parse metadata from header lines.
|
|
|
|
You can access the metadata like this:
|
|
data = parse_owon_data(".CSV")
|
|
print(data.frequency)
|
|
print(data.vpp)
|
|
"""
|
|
metadata = {}
|
|
|
|
for line in metadata_lines:
|
|
if "," in line:
|
|
parts = line.split(",", 1)
|
|
if len(parts) == 2:
|
|
key = parts[0].strip().rstrip(":").strip()
|
|
value = parts[1].strip()
|
|
metadata[key] = value
|
|
|
|
return metadata
|