diff --git a/README.md b/README.md
index 67001ae..1650c41 100644
--- a/README.md
+++ b/README.md
@@ -1,72 +1,87 @@
-![Scio Logo](https://d347awuzx0kdse.cloudfront.net/vicomaus/content-image/Tek_Logo_RGB.png){width="50px"}
+
-# tm_data_types
+| | |
+| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| **Testing** | [![Code testing status](https://github.com/tektronix/tm_data_types/actions/workflows/test-code.yml/badge.svg?branch=main)](https://github.com/tektronix/tm_data_types/actions/workflows/test-code.yml) [![Docs testing status](https://github.com/tektronix/tm_data_types/actions/workflows/test-docs.yml/badge.svg?branch=main)](https://github.com/tektronix/tm_data_types/actions/workflows/test-docs.yml) [![Coverage status](https://codecov.io/gh/tektronix/tm_data_types/branch/main/graph/badge.svg)](https://codecov.io/gh/tektronix/tm_data_types) |
+| **Code Quality** | [![CodeQL status](https://github.com/tektronix/tm_data_types/actions/workflows/codeql-analysis.yml/badge.svg?branch=main)](https://github.com/tektronix/tm_data_types/actions/workflows/codeql-analysis.yml) [![CodeFactor grade](https://www.codefactor.io/repository/github/tektronix/tm_data_types/badge)](https://www.codefactor.io/repository/github/tektronix/tm_data_types) [![pre-commit status](https://results.pre-commit.ci/badge/github/tektronix/tm_data_types/main.svg)](https://results.pre-commit.ci/latest/github/tektronix/tm_data_types/main) |
+| **Package** | [![PyPI: Package status](https://img.shields.io/pypi/status/tm_data_types?logo=pypi)](https://pypi.org/project/tm_data_types/) [![PyPI: Latest release version](https://img.shields.io/pypi/v/tm_data_types?logo=pypi)](https://pypi.org/project/tm_data_types/) [![PyPI: Supported Python versions](https://img.shields.io/pypi/pyversions/tm_data_types?logo=python)](https://pypi.org/project/tm_data_types/) [![PyPI: Downloads](https://pepy.tech/badge/tm_data_types)](https://pepy.tech/project/tm_data_types) [![License: Apache 2.0](https://img.shields.io/pypi/l/tm_data_types)](https://github.com/tektronix/tm_data_types/blob/main/LICENSE.md) [![Package build status](https://github.com/tektronix/tm_data_types/actions/workflows/package-build.yml/badge.svg?branch=main)](https://github.com/tektronix/tm_data_types/actions/workflows/package-build.yml) [![PyPI upload status](https://github.com/tektronix/tm_data_types/actions/workflows/package-release.yml/badge.svg?branch=main)](https://github.com/tektronix/tm_data_types/actions/workflows/package-release.yml) |
+| **Documentation** | [![ReadtheDocs Status](https://img.shields.io/readthedocs/tm_data_types/stable?logo=readthedocs)](https://tm_data_types.readthedocs.io/stable) |
+| **Code Style** | [![Test style: pytest](https://img.shields.io/badge/test%20style-pytest-blue)](https://github.com/pytest-dev/pytest) [![Code style: ruff](https://img.shields.io/badge/code%20style-ruff-black)](https://docs.astral.sh/ruff/formatter/) [![Docstring style: google](https://img.shields.io/badge/docstring%20style-google-tan)](https://google.github.io/styleguide/pyguide.html) |
+| **Linting** | [![pre-commit enabled](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://github.com/pre-commit/pre-commit) [![Docstring formatter: docformatter](https://img.shields.io/badge/docstring%20formatter-docformatter-tan)](https://github.com/PyCQA/docformatter)[![Linter: pylint](https://img.shields.io/badge/linter-pylint-purple)](https://github.com/pylint-dev/pylint) |
-## Purpose
+
-Python Instrument IO can be used to:
+---
-- **Convert** CSV, WFM, and BIN format into the waveform object format,
-- **Generate** analog waveforms with NRZ or PAM4 signal processes,
+# tm_data_types: Test & Measurement Data Types
+
+`tm_data_types` provides tools to convert, edit, and write waveform data from Test & Measurement devices.
+It simplifies handling waveform formats like CSV, WFM, and BIN in Python.
+
+`tm_data_types` can be used to:
+
+- **Convert** CSV, WFM, and BIN format into a waveform object,
- **Add or edit** waveform metadata,
- **Write** a valid waveform object to a file.
-This interface assists the client and development team in parsing the format from Tek instrument and construct a
-python object with features. The API is funneled into a single Python file, \[InstrumentIO\]{.title-ref}, which contains
-all the functions required to read, write, and generate various instrument data.
+## Supported File Formats
-For additional documentation, visit our Wiki page.
+
-- Supported files for reader interface function include: '.wfm', '.bin', '.csv', '.awg_wfm'
-- Supported files for writer interface function include: '.wfm', '.csv', '.awg_wfm'
+| Interface | File formats |
+| --------- | -------------------- |
+| Reader | **.bin, .csv, .wfm** |
+| Writer | **.csv, .wfm** |
-## Quick Start
+
-Requirements: [Python 3.0 or above](https://www.python.org/download/releases/3.0/)
+Currently, `tm_data_types` only supports the [Tektronix proprietary](https://download.tek.com/manual/Waveform-File-Format-Manual-077022011.pdf) `.wfm` format.
+Support for other formats is planned for future releases.
-Installed Library: \[datatime\]{.title-ref}, \[struct\]{.title-ref},
-\[numpy\]{.title-ref}, \[scipy\]{.title-ref}, \[pandas\]{.title-ref} (Test waveform plot with \[matplotlib\]{.title-ref})
+## Installation
-```bash
+```shell
pip install tm_data_types
```
-## Waveform Object Attributes
-
-- `._vertical_data` → An array of binary values.
-- `._size` → The size of the vertical data. Read-only, must be an integer.
-- `._spacing` → The horizontal interval between two consecutive vertical data points. Must be an integer or float.
-- `._trigger_index` →
-- `.vertical_data` → vertical data
-- `.horizontal_data` → horizontal data
-- `.time_interval` → time intervals across vertical data
-- `.trigger_position` → trigger position
-
-## Examples
-
-- `read_file_channels(file_path)` → return lists of channels for csv file only
-- `read_file(file_path, channel (opt.))` → return waveform object
-- `write_file(waveform obj, file_path, instrument_type (opt.))` → write file with extension format
-- `initialize_waveform(size (opt.), sample_rate (opt.))` → return simple waveform with size and sample rate.
-- `create_unique_filepath(file_path, file_template)` → return unique file path for converted/created file
-- `random_bits(size)` → returns a random array of values 1 or 0 of user-inputted size.
-- `random_symbols(size)` → returns a random array of values between 0 and 3 of user-inputted size.
-- `nrz(bit_array, symbol_rate=1.0e9, sample_per_ui=10.12345, amplitude=1., offset=0.0, impairment=0.2, noise=0.01, repeats=1)`
- → return NRZ waveform object based on user-inputted bit array. Array could be derived from InstrumentIO's \[random_bits\]{.title-ref} function, or from some other random number generator specified by the user (i.e. PBRS).
-- `pam4(symbol_arr, data_rate=1.0e9, sample_per_ui=10.12345, amplitude=1.0, offset=0.0, impairment=0.2, noise=0.01, repeats=1)`
- → return PAM4 waveform object based on user-inputted symbol array. Array could be derived from InstrumentIO's \[random_symbols\]{.title-ref} function, or from some other random number generator specified by the user (i.e. PBRS).
-- `square(frequency=1000, repeat=5, amplitude=1, rec_length=1000)` → return square waveform object.
-- `sawtooth(frequency=1000, repeat=5, amplitude=1, rec_length=1000)` → return sawtooth waveform object.
-- `triangle(frequency=1000, repeat=5, amplitude=1, rec_length=1000)` → return triangle waveform object.
+## Basic Usage
-## Maintainers
+### Write File
-.. TODO: update email - tmdevicessupport@tektronix.com - For technical support and questions.
+```python
+from tm_data_types import AnalogWaveform, write_file
-- - For open-source policy and license questions.
-- Keith Rule
+waveform = AnalogWaveform()
+file_path = "waveform_1.wfm"
+write_file(file_path, waveform)
+```
+
+### Read File
-For more information about this repository, you can leave a question/comment on the [repository's Discussion board](https://github.com/tektronix/PythonInstrumentIO/discussions).
+```python
+from tm_data_types import read_file
+
+file_path = "waveform_1.wfm"
+waveform = read_file(file_path)
+```
+
+## Documentation
+
+See the full documentation at
+
+## Maintainers
+
+Before reaching out to any maintainers directly, please first check if
+your issue or question is already covered by any [open
+issues](https://github.com/tektronix/tm_data_types/issues). If the issue or
+question you have is not already covered, please [file a new
+issue](https://github.com/tektronix/tm_data_types/issues/new/choose) or
+start a
+[discussion](https://github.com/tektronix/tm_data_types/discussions) and
+the maintainers will review and respond there.
+
+- - For open-source policy and license
+ questions.
## Contributing
@@ -90,10 +105,3 @@ The artifact attestations can also be directly downloaded from the
```shell
gh attestation verify --owner tektronix
```
-
-## Credits
-
-`tm_data_types` was created with
-[cookiecutter](https://cookiecutter.readthedocs.io/en/latest/README.html)
-and the `py-pkgs-cookiecutter`
-[template](https://py-pkgs-cookiecutter.readthedocs.io/en/latest/).
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
new file mode 100644
index 0000000..f78f89d
--- /dev/null
+++ b/docs/CHANGELOG.md
@@ -0,0 +1,6 @@
+{%
+include-markdown "../CHANGELOG.md"
+comments=false
+rewrite-relative-urls=false
+
+%}
diff --git a/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..3a38763
--- /dev/null
+++ b/docs/CODE_OF_CONDUCT.md
@@ -0,0 +1,6 @@
+{%
+include-markdown "../CODE_OF_CONDUCT.md"
+comments=false
+rewrite-relative-urls=false
+
+%}
diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md
new file mode 100644
index 0000000..8e39ea1
--- /dev/null
+++ b/docs/CONTRIBUTING.md
@@ -0,0 +1,6 @@
+{%
+include-markdown "../CONTRIBUTING.md"
+comments=false
+rewrite-relative-urls=false
+
+%}
diff --git a/docs/LICENSE.md b/docs/LICENSE.md
new file mode 100644
index 0000000..ecb14eb
--- /dev/null
+++ b/docs/LICENSE.md
@@ -0,0 +1,8 @@
+# License
+
+{%
+include-markdown "../LICENSE.md"
+comments=false
+rewrite-relative-urls=false
+
+%}
diff --git a/docs/_static/css/theme_overrides.css b/docs/_static/css/theme_overrides.css
index 4d433e4..a4843dc 100644
--- a/docs/_static/css/theme_overrides.css
+++ b/docs/_static/css/theme_overrides.css
@@ -3,7 +3,7 @@
white-space: nowrap !important;
}
-.rst-content table.device-support-table.docutils thead {
+.rst-content table.support-table.docutils thead {
vertical-align: middle;
.line-block {
@@ -11,29 +11,29 @@
}
}
-.device-support-table thead, .device-support-table tbody {
+.support-table thead, .support-table tbody {
border: 2px solid black
}
-.device-support-table table {
+.support-table table {
width: auto !important;
display: table !important;
margin: auto !important;
}
-.device-support-table.docutils tbody tr:has(th p),
-.device-support-table tr:has(td:first-child:not(:empty)) {
+.support-table.docutils tbody tr:has(th p),
+.support-table tr:has(td:first-child:not(:empty)) {
border-top-width: 2px;
border-top-color: black;
border-top-style: solid;
}
-.device-support-table tbody td[rowspan] {
+.support-table tbody td[rowspan] {
background-color: transparent !important;
}
-.device-support-table table td:first-child,
-.device-support-table table th:first-child {
+.support-table table td:first-child,
+.support-table table th:first-child {
font-weight: bolder;
background-color: transparent !important;
}
diff --git a/docs/advanced/writing_to_a_file.md b/docs/advanced/writing_to_a_file.md
deleted file mode 100644
index 900261e..0000000
--- a/docs/advanced/writing_to_a_file.md
+++ /dev/null
@@ -1,29 +0,0 @@
-write_file is a generic method which takes two arguments, the path to write to and the waveform
-to write. The method begins by utilizing a lookup table
-along with the waveform type to determine what type of behavior it will utilize to write.
-Following this, the waveform is formatted and written to the path specified.
-
-Alternatively, write_files_in_parallel can be used instead. This method accepts two separate list for
-lists for file paths and waveforms, where each value in one list index will correspond to the other.
-Multiprocessing is leveraged by partitioning each list and sending them into their own
-distinct process for saving. The write process is identical to the standard write_file.
-
-This writing process is involved, and is distinctly different between each format and waveform type
-No transformations are done when saving to the .wfm format if the data is of the RawSample type.
-This done as the express purpose of this library is to save and load .wfm files as fast as possible.
-However if the data type is Normalized, a transformed is performed, as .wfm files are required to contain
-digitized data with the spacing and offset being separate.
-
-read_file is a generic method which takes one argument, the path in which a waveform file exists that
-should be read. The same lookup table for file extensions is used from write_file, however an additional
-step is used, which is looking through small sections of the files data to determine what the waveform type is.
-Following this, a waveform is provided from the read file, the type of which is dependant on how the data is
-formatted.
-
-read_files_in_parallel handles the same way functionally as write_files_in_parallel, the main difference between
-the two being what arguments are passed in and the queue of waveforms returned.
-
-Reading will reformat the waveform data to match what is required for the oscilloscope to display.
-Waveform files will all return the waveform in the RawSample format. This process takes some time
-as the conversion utilizes mathematical transformations
-on the entire dataset, so the best way to utilize this library is to utilize the .wfm extension.
diff --git a/docs/basic_usage.md b/docs/basic_usage.md
index 6472fa8..fa6b3b5 100644
--- a/docs/basic_usage.md
+++ b/docs/basic_usage.md
@@ -5,7 +5,27 @@ project.
## Write Data
+`tm_data_types` can be used for writing data to a file using [`write_file()`][tm_data_types.write_file].
+
```python
# fmt: off
--8<-- "examples/write_file.py"
```
+
+## Type Conversion and Normalization of Data
+
+`tm_data_types` can be used for type conversion and normalization of analog waveform data.
+
+```python
+# fmt: off
+--8<-- "examples/type_conversion_example.py"
+```
+
+## Write Analog Waveform to CSV file
+
+`tm_data_types` can be used to write an analog waveform to a CSV file using the [`WaveformFileCSVAnalog`][tm_data_types.files_and_formats.csv.data_formats.analog.WaveformFileCSVAnalog] class.
+
+```python
+# fmt: off
+--8<-- "examples/write_csv_example.py"
+```
diff --git a/docs/glossary.md b/docs/glossary.md
new file mode 100644
index 0000000..d781988
--- /dev/null
+++ b/docs/glossary.md
@@ -0,0 +1,15 @@
+# Glossary
+
+A collection of terms and symbols used throughout the documentation and their definitions.
+
+BIN
+: Binary format used for storing waveform data.
+
+CSV
+: Comma-Separated Values
+
+Scope
+: Oscilloscope
+
+WFM
+: Waveform format used by Test & Measurement devices.
diff --git a/docs/macros.py b/docs/macros.py
index c8c53f1..1c7bd6d 100644
--- a/docs/macros.py
+++ b/docs/macros.py
@@ -22,6 +22,41 @@
####################################################################################################
# Helper functions
####################################################################################################
+CONVERSION_PATTERN = re.compile(
+ r"> \[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION|DANGER)]\s*>\s*(.*?)(?=\n[^>]|$)",
+ re.IGNORECASE | re.DOTALL,
+)
+
+
+def convert_gfm_alerts_to_admonitions(content: str) -> str:
+ """Convert GitHub Flavored Markdown (GFM) alerts to MkDocs admonitions.
+
+ Args:
+ content: The content to convert.
+
+ Returns:
+ The updated content with GFM alerts converted to markdown admonitions.
+ """
+
+ def replace_match(match: re.Match[str]) -> str:
+ """Replace the matched GFM alert with an admonition.
+
+ Args:
+ match: The matched GFM alert.
+
+ Returns:
+ The replacement text.
+ """
+ alert_type = match.group(1).lower()
+ text = match.group(2).strip()
+ # Replace initial '>' from subsequent lines
+ text = text.replace("\n>", "\n")
+ # Replace with admonition format
+ return f"!!! {alert_type}\n " + text.replace("\n", "\n ")
+
+ return re.sub(CONVERSION_PATTERN, replace_match, content)
+
+
def import_object(objname: str) -> Any:
"""Import a python object by its qualified name.
@@ -182,6 +217,8 @@ def on_post_page_macros(env: MacrosPlugin) -> None:
# Check if all black format disable comments should be removed from the page
if env.page.file.src_path in FILES_TO_REMOVE_BLACK_FORMATTER_DISABLE_COMMENT: # pyright: ignore[reportUnknownMemberType]
env.markdown = env.markdown.replace("# fmt: off\n", "") # pyright: ignore[reportUnknownMemberType]
+ # Check if there are any admonitions to replace on the page
+ env.markdown = convert_gfm_alerts_to_admonitions(env.markdown) # pyright: ignore[reportUnknownMemberType,reportUnknownArgumentType]
# Check if the title is correct
if actual_title_match := HEADER_ONE_REGEX.search(env.markdown): # pyright: ignore[reportUnknownMemberType,reportUnknownArgumentType]
actual_title = actual_title_match.group(1)
diff --git a/mkdocs.yml b/mkdocs.yml
index 1534b64..4269ca4 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -152,6 +152,10 @@ nav: # The first entry in each section needs a hard-coded title to avoid being
- index.md
- The Basics:
- Basic Usage: basic_usage.md
- - Advanced Topics:
- - Write to file: advanced\writing_to_a_file.md
+ - glossary.md
+ - CHANGELOG.md
+ - Contributing:
+ - Contributing Guidelines: CONTRIBUTING.md
+ - CODE_OF_CONDUCT.md
+ - LICENSE.md
- API Reference: reference/
diff --git a/src/tm_data_types/datum/data_types.py b/src/tm_data_types/datum/data_types.py
index c68fc44..1ca113a 100644
--- a/src/tm_data_types/datum/data_types.py
+++ b/src/tm_data_types/datum/data_types.py
@@ -43,7 +43,7 @@ def _check_type(
def type_ratio(dtype_from: PossibleTypes, dtype_to: PossibleTypes) -> float:
- """Calculate the ratio of ranges between two seperate types.
+ """Calculate the ratio of ranges between two separate types.
Example:
Converting from np.int16 to np.int8 will give you a ratio of 1/256.
@@ -469,7 +469,7 @@ def _raw_sample_format_to_this_format(
class Digitized(MeasuredData):
- """Data that has been converted to seperate data streams along the 2nd axis."""
+ """Data that has been converted to separate data streams along the 2nd axis."""
################################################################################################
# Public Methods
diff --git a/src/tm_data_types/datum/waveforms/analog_waveform.py b/src/tm_data_types/datum/waveforms/analog_waveform.py
index 01c68dd..28ce0b1 100644
--- a/src/tm_data_types/datum/waveforms/analog_waveform.py
+++ b/src/tm_data_types/datum/waveforms/analog_waveform.py
@@ -38,7 +38,7 @@ class AnalogWaveformMetaInfo(WaveformMetaInfo):
class AnalogWaveform(Waveform):
- """Class which represents an analog waveform with a y and x axis."""
+ """Class which represents an analog waveform with a y-axis and x-axis."""
################################################################################################
# Dunder Methods
@@ -72,7 +72,7 @@ def __setattr__(self, key: str, value: Any) -> None:
self.__dict__.pop("normalized_vertical_values", None)
if key == "y_axis_values":
- # y axis values need to be typecase when set.
+ # y-axis values need to be typecase when set.
if not isinstance(value, MeasuredData):
super(Waveform, self).__setattr__("y_axis_values", RawSample(value))
else:
@@ -139,7 +139,7 @@ def normalized_vertical_values(self) -> Normalized: # pyright: ignore [reportIn
@property
def y_axis_extent_magnitude(self) -> float:
- """Get the magnitude extent of values that can be represented in the y axis units.
+ """Get the magnitude extent of values that can be represented in the y-axis units.
Returns:
A float value which represents the magnitude of what values which can be represented
@@ -151,7 +151,7 @@ def y_axis_extent_magnitude(self) -> float:
@y_axis_extent_magnitude.setter
def y_axis_extent_magnitude(self, extent_magnitude: float) -> None:
- """Set the spacing based on values that can be represented in the y axis units.
+ """Set the spacing based on values that can be represented in the y-axis units.
Example:
If the extent magnitude is 1.0 and the numpy type is a long, then it will
diff --git a/src/tm_data_types/datum/waveforms/digital_waveform.py b/src/tm_data_types/datum/waveforms/digital_waveform.py
index bb671e3..fc26580 100644
--- a/src/tm_data_types/datum/waveforms/digital_waveform.py
+++ b/src/tm_data_types/datum/waveforms/digital_waveform.py
@@ -30,7 +30,7 @@ class DigitalWaveformMetaInfo(WaveformMetaInfo): # pylint: disable=too-many-ins
class DigitalWaveform(Waveform):
- """Class which represents an digital waveform with a y and x axis."""
+ """Class which represents a digital waveform with a y-axis and x-axis."""
################################################################################################
# Dunder Methods
diff --git a/src/tm_data_types/datum/waveforms/iq_waveform.py b/src/tm_data_types/datum/waveforms/iq_waveform.py
index 0fe0425..47d7e5e 100644
--- a/src/tm_data_types/datum/waveforms/iq_waveform.py
+++ b/src/tm_data_types/datum/waveforms/iq_waveform.py
@@ -173,7 +173,7 @@ def iq_axis_extent_magnitude(self) -> float:
@iq_axis_extent_magnitude.setter
def iq_axis_extent_magnitude(self, extent_magnitude: float):
- """Set the magnitude extent of values that can be represented in the y axis units.
+ """Set the magnitude extent of values that can be represented in the y-axis units.
Args:
extent_magnitude: A float value which represents the magnitude of what values which
diff --git a/src/tm_data_types/datum/waveforms/waveform.py b/src/tm_data_types/datum/waveforms/waveform.py
index 6af650d..2b2ea18 100644
--- a/src/tm_data_types/datum/waveforms/waveform.py
+++ b/src/tm_data_types/datum/waveforms/waveform.py
@@ -83,7 +83,7 @@ class Waveform(Datum, ABC):
def __init__(
self,
) -> None:
- """Initialize the waveform's meta info and x axis specifications."""
+ """Initialize the waveform's meta info and x-axis specifications."""
self.meta_info: Optional[WaveformMetaInfo] = None
self.trigger_index: float = 0.0
self.source_name: Optional[str] = None
diff --git a/src/tm_data_types/files_and_formats/csv/csv.py b/src/tm_data_types/files_and_formats/csv/csv.py
index d9a3ad2..43468c4 100644
--- a/src/tm_data_types/files_and_formats/csv/csv.py
+++ b/src/tm_data_types/files_and_formats/csv/csv.py
@@ -90,7 +90,7 @@ def read_datum(self) -> WAVEFORM_TYPE: # pylint: disable=too-many-branches
except ValueError:
# otherwise the info is in the header
if len(row) > 1:
- # record length is special as it needs to be stored but it's not relevant
+ # record length is special as it needs to be stored, but it's not relevant
# to the waveform values
if row[0] == "Record Length":
record_length = int(row[1])
@@ -168,7 +168,7 @@ def csv_writer(self) -> csv.writer:
################################################################################################
# Writing
def _setup_generic_csv_header(self, waveform: Waveform) -> str:
- """Setup the generic header values for the csv file during writing.
+ """Set up the generic header values for the csv file during writing.
Args:
waveform: The waveform used to get the generic header values.
diff --git a/src/tm_data_types/files_and_formats/csv/data_formats/analog.py b/src/tm_data_types/files_and_formats/csv/data_formats/analog.py
index a485474..3679d4a 100644
--- a/src/tm_data_types/files_and_formats/csv/data_formats/analog.py
+++ b/src/tm_data_types/files_and_formats/csv/data_formats/analog.py
@@ -63,7 +63,7 @@ def _set_waveform_values( # pyright: ignore [reportIncompatibleMethodOverride]
Args:
waveform: The analog waveform which is being formatted.
- values_matrix: A matrix containing the x and y axis values.
+ values_matrix: A matrix containing the x-axis and y-axis values.
"""
normalized_vertical_values = Normalized(values_matrix[:, 1], as_type=np.float32)
vertical_minimum = normalized_vertical_values.min()
diff --git a/src/tm_data_types/files_and_formats/waveform_file.py b/src/tm_data_types/files_and_formats/waveform_file.py
index d5a2e3b..8f4b80a 100644
--- a/src/tm_data_types/files_and_formats/waveform_file.py
+++ b/src/tm_data_types/files_and_formats/waveform_file.py
@@ -30,7 +30,7 @@ def __init__(
Args:
file_path: The path for the file to read/write from.
- io_type: A file to represent what type of IO transferrence is occuring.
+ io_type: A file to represent what type of IO transference is occurring.
"""
self.file_path = file_path
self.io_type = io_type
@@ -74,7 +74,7 @@ def write(self, to_write_info: str) -> None:
@staticmethod
def update_bidict(original_bidict: bidict, operating_bidict: Dict[str, str]) -> bidict:
- """Update a bi directional dict with new values.
+ """Update a bidirectional dict with new values.
This may need to be a factory helper.
diff --git a/src/tm_data_types/files_and_formats/wfm/wfm.py b/src/tm_data_types/files_and_formats/wfm/wfm.py
index 7da14c9..86b4d59 100644
--- a/src/tm_data_types/files_and_formats/wfm/wfm.py
+++ b/src/tm_data_types/files_and_formats/wfm/wfm.py
@@ -121,7 +121,7 @@ def read_datum(self) -> DATUM_TYPE_VAR:
formatted_data = WfmFormat()
formatted_data.unpack_wfm_file(endian_prefix, version_number, self.fd)
- waveform: DATUM_TYPE_VAR = self.DATUM_TYPE() # pylist: disable=abstract-class-instantiated
+ waveform: DATUM_TYPE_VAR = self.DATUM_TYPE() # pylint: disable=abstract-class-instantiated
meta_data = self.META_DATA_TYPE(
**self.META_DATA_TYPE.remap(self._META_DATA_LOOKUP.inverse, formatted_data.meta_data),
)
@@ -152,10 +152,10 @@ def write_datum(self, waveform: Waveform) -> None:
formatted_data = WfmFormat()
if waveform.meta_info:
- exlusive_meta_data = waveform.meta_info.operable_exclusive_metadata()
+ exclusive_meta_data = waveform.meta_info.operable_exclusive_metadata()
formatted_data.meta_data = self.META_DATA_TYPE.remap(
- self._META_DATA_LOOKUP, exlusive_meta_data
+ self._META_DATA_LOOKUP, exclusive_meta_data
)
else:
formatted_data.meta_data = self.META_DATA_TYPE.remap(self._META_DATA_LOOKUP, {})
@@ -190,7 +190,7 @@ def _check_metadata(self, meta_data: Dict[str, Union[str, Double, Long, Unsigned
)
return True
except TypeError as e:
- # if have too many keywords, this format doesn't work
+ # if you have too many keywords, this format doesn't work
if "unexpected keyword" in str(e):
return False
# if we are missing some keywords, that is fine
diff --git a/src/tm_data_types/io_factory_methods.py b/src/tm_data_types/io_factory_methods.py
index 49476f1..b984ca7 100644
--- a/src/tm_data_types/io_factory_methods.py
+++ b/src/tm_data_types/io_factory_methods.py
@@ -24,36 +24,62 @@
# pylint: disable=unused-argument
def write_file(
- file_path: str,
- datum: Datum,
+ path: str,
+ waveform: Datum,
product: InstrumentSeries = InstrumentSeries.TEKSCOPE,
file_format: Optional[CSVFormats] = None,
) -> None:
"""Write a waveform to a provided file.
+ Process Overview:
+ 1. Lookup Table: The method begins by using a lookup table to determine the behavior based on the
+ waveform type.
+ 2. Formatting: The waveform is formatted according to its type.
+ 3. Writing: Finally, the formatted waveform is written to the specified file path.
+
+ Special Cases:
+ - RawSample Type: No transformations are applied when saving data in the `.wfm`
+ format, if the waveform is of the [`RawSample`][tm_data_types.RawSample] type.
+ This is done to ensure that `.wfm` files are saved and loaded as quickly as possible.
+ - Normalized Type: If the waveform is of the [`Normalized`][tm_data_types.datum.data_types.Normalized] type,
+ a transformation is performed because `.wfm` files must contain digitized data,
+ with spacing and offset stored separately.
+
Args:
- file_path: The path file to write to.
- datum: The datum that is being written.
+ path: The path file to write to.
+ waveform: The waveform that is being written.
product: The product being written to.
file_format: A specialized file format we are writing as.
"""
-
- _, path_extension = os.path.splitext(file_path)
+ _, path_extension = os.path.splitext(path)
try:
file_extension = FileExtensions[path_extension.replace(".", "").upper()]
except KeyError as e:
raise IOError(f"The {path_extension} extension cannot be written to.") from e
# find the format based on the waveform extension
- format_class: AbstractedFile = find_class_format(file_extension, type(datum))
+ format_class: AbstractedFile = find_class_format(file_extension, type(waveform))
# using __init__ for instantiation due to pyright confusion
- format_class = format_class(file_path, access_type(file_extension, write=True), product)
+ format_class = format_class(path, access_type(file_extension, write=True), product)
with format_class as fd:
- fd.write_datum(datum)
+ fd.write_datum(waveform)
def read_file(file_path: str) -> DatumAlias:
"""Read a waveform from a provided file.
+ Process Overview:
+ 1. Lookup Table: Similar to [`write_file()`][tm_data_types.write_file], a lookup table is used to determine
+ the file extension.
+ 2. Type Detection: The method reads small sections of the file to identify the waveform type.
+ 3. Reformatting: The waveform is read and returned in the appropriate format,
+ depending on how the data is structured.
+
+ Special Cases:
+ - All waveforms are returned in the [`RawSample`][tm_data_types.RawSample] format.
+ The data is reformatted for compatibility with the oscilloscope, which involves
+ mathematical transformations on the entire dataset.
+ This can be time-consuming, so using the `.wfm` format is recommended for efficiency.
+
Args:
file_path: The path file to read from.
"""
@@ -117,6 +143,15 @@ def write_files_in_parallel(
) -> None:
"""Write a list of waveforms to a list of provided files in parallel.
+ This method offers a parallelized approach to writing multiple waveform files.
+
+ Process Overview:
+ 1. Multiprocessing: The lists of file paths and waveforms are partitioned and processed in parallel.
+ 2. Writing: Each process uses the same method as [`write_file()`][tm_data_types.write_file]
+ to save its assigned waveforms.
+
+ This method is particularly useful for saving multiple waveform files efficiently.
+
Args:
file_paths: The path file to write to.
datums: The datum that is being written.
@@ -155,7 +190,8 @@ def _read_files(file_paths: str, file_queue: multiprocessing.Queue) -> None:
"""Read a waveform from a provided file.
Args:
- file_path: The file paths to read from.
+ file_paths: The file paths to read from.
+ file_queue: The queue to put the read data into.
"""
for file_path in file_paths:
file_queue.put((file_path, read_file(file_path)))
@@ -164,8 +200,16 @@ def _read_files(file_paths: str, file_queue: multiprocessing.Queue) -> None:
def read_files_in_parallel(file_paths: List[str], force_process_count: int = 4) -> List[Datum]:
"""Read a list of files in parallel.
+ This method allows for the parallel reading of multiple waveform files.
+
+ Process Overview:
+ 1. Multiprocessing: Similar to [`write_files_in_parallel()`][tm_data_types.write_files_in_parallel],
+ the file paths are partitioned and processed in parallel.
+ 2. Reading: The waveforms are read using the same process as [`read_file()`][tm_data_types.read_file],
+ and a queue of waveforms is returned.
+
Args:
- file_paths: The file paths to read from.
+ file_paths: A list of file paths to read from.
force_process_count: The number of processes that should be created for this operation.
"""
process_count = min(force_process_count, len(file_paths))