| # Copyright 2024 The Pigweed Authors |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| # use this file except in compliance with the License. You may obtain a copy of |
| # the License at |
| # |
| # https://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| # License for the specific language governing permissions and limitations under |
| # the License. |
| """Plot ADC updates as an SVG from a device logfile.""" |
| |
| import argparse |
| from datetime import datetime |
| from datetime import timedelta |
| import logging |
| from pathlib import Path |
| import sys |
| from typing import Optional |
| |
| import matplotlib.pyplot as plt |
| import numpy as np |
| |
| |
| _LOG = logging.getLogger(__package__) |
| ADC_COUNT = 5 |
| |
| |
| def _parse_args(): |
| parser = argparse.ArgumentParser(description=__doc__) |
| parser.add_argument( |
| '-i', |
| '--input-text', |
| type=Path, |
| default=Path('gonk-device-logs.txt'), |
| help='Input log text file.', |
| ) |
| parser.add_argument( |
| '-o', |
| '--output-svg', |
| type=Path, |
| default=Path('plot.svg'), |
| help='Output svg file.', |
| ) |
| return parser.parse_args() |
| |
| |
| def main( |
| input_text: Path, |
| output_svg: Path, |
| ) -> int: |
| """Plot ADC values.""" |
| # pylint: disable=too-many-locals |
| |
| start_time: Optional[datetime] = None |
| time_values = [] |
| vbus_values: list[list[int]] = [] |
| vshunt_values: list[list[int]] = [] |
| for i in range(ADC_COUNT): |
| vbus_values.append([]) |
| vshunt_values.append([]) |
| |
| with input_text.open() as f: |
| current_time = datetime.now() |
| |
| for line in f.readlines(): |
| # Skip lines that are not ADC updates. |
| if 'delta_microseconds' not in line: |
| continue |
| |
| parts = line.split() |
| |
| # Extract the host timestamp |
| dtstr = parts[5] + ' ' + parts[6] |
| dt = datetime.strptime(dtstr, '%Y%m%d %H:%M:%S.%f') |
| # Extract delta_micros |
| delta_micros = int(parts[10]) |
| |
| # Set start timestamp if not found already. |
| if not start_time: |
| start_time = dt |
| current_time = start_time - timedelta(microseconds=delta_micros) |
| |
| # Increment delta_micros |
| current_time += timedelta(microseconds=delta_micros) |
| |
| # Save the timestamp and vbus vshunt values for plotting. |
| time_values.append((current_time - start_time).total_seconds()) |
| vbus = list(int(i) for i in parts[12].split(',')) |
| vshunt = list(int(i) for i in parts[14].split(',')) |
| |
| for i in range(ADC_COUNT): |
| vbus_values[i].append(vbus[i]) |
| vshunt_values[i].append(vshunt[i]) |
| |
| # Plot vbus and vshunt values. |
| _fig, (ax1, ax2) = plt.subplots( |
| 2, 1, layout='constrained', figsize=[11.67, 8.27] |
| ) |
| |
| times = np.asarray(time_values) |
| ax1.set_xlabel('Time (s)') |
| ax2.set_xlabel('Time (s)') |
| |
| linewidth = 0.7 |
| ax1.set_ylabel('vbus') |
| for i in range(ADC_COUNT): |
| ax1.plot( |
| times, |
| np.asarray(vbus_values[i]), |
| label=f'vbus-{i}', |
| linestyle='dotted', |
| linewidth=linewidth, |
| ) |
| |
| ax2.set_ylabel('vshunt') |
| for i in range(ADC_COUNT): |
| ax2.plot( |
| times, |
| np.asarray(vshunt_values[i]), |
| label=f'vshunt-{i}', |
| linestyle='dotted', |
| linewidth=linewidth, |
| ) |
| |
| ax1.legend() |
| ax1.grid(True) |
| ax2.legend() |
| ax2.grid(True) |
| |
| plt.savefig(output_svg) |
| return 0 |
| |
| |
| if __name__ == '__main__': |
| sys.exit(main(**vars(_parse_args()))) |