PyChOpMarg 3.1.0__tar.gz → 3.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/PKG-INFO +3 -2
  2. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/pyproject.toml +1 -1
  3. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/PyChOpMarg.egg-info/PKG-INFO +3 -2
  4. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/PyChOpMarg.egg-info/SOURCES.txt +2 -0
  5. pychopmarg-3.1.2/src/pychopmarg/cli.py +74 -0
  6. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/pychopmarg/com.py +2 -2
  7. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/pychopmarg/common.py +3 -2
  8. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/pychopmarg/config/ieee_8023by.py +1 -1
  9. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/pychopmarg/config/ieee_8023dj.py +1 -1
  10. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/pychopmarg/config/template.py +26 -3
  11. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/pychopmarg/excel.py +0 -1
  12. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/pychopmarg/noise.py +10 -8
  13. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/pychopmarg/optimize.py +15 -4
  14. pychopmarg-3.1.2/src/pychopmarg/py.typed +0 -0
  15. pychopmarg-3.1.2/src/pychopmarg/utility/jupyter.py +52 -0
  16. pychopmarg-3.1.0/src/pychopmarg/cli.py +0 -51
  17. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/LICENSE +0 -0
  18. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/README.md +0 -0
  19. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/setup.cfg +0 -0
  20. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/PyChOpMarg.egg-info/dependency_links.txt +0 -0
  21. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/PyChOpMarg.egg-info/entry_points.txt +0 -0
  22. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/PyChOpMarg.egg-info/requires.txt +0 -0
  23. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/PyChOpMarg.egg-info/top_level.txt +0 -0
  24. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/pychopmarg/__init__.py +0 -0
  25. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/pychopmarg/__main__.py +0 -0
  26. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/pychopmarg/config/__init__.py +0 -0
  27. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/pychopmarg/matlab.py +0 -0
  28. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/pychopmarg/plot.py +0 -0
  29. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/pychopmarg/utility/__init__.py +0 -0
  30. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/pychopmarg/utility/filter.py +0 -0
  31. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/pychopmarg/utility/general.py +0 -0
  32. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/pychopmarg/utility/probability.py +0 -0
  33. {pychopmarg-3.1.0 → pychopmarg-3.1.2}/src/pychopmarg/utility/sparams.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: PyChOpMarg
3
- Version: 3.1.0
3
+ Version: 3.1.2
4
4
  Summary: Python implementation of COM, as per IEEE 802.3-22 Annex 93A/178A.
5
5
  Author-email: David Banas <capn.freako@gmail.com>
6
6
  License: BSD3
@@ -34,6 +34,7 @@ Requires-Dist: click
34
34
  Requires-Dist: numpy
35
35
  Requires-Dist: scikit-rf>=0.29
36
36
  Requires-Dist: typing_extensions
37
+ Dynamic: license-file
37
38
 
38
39
  # PyChOpMarg
39
40
 
@@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta"
9
9
  [project]
10
10
  name = "PyChOpMarg"
11
11
  description = "Python implementation of COM, as per IEEE 802.3-22 Annex 93A/178A."
12
- version = "3.1.0"
12
+ version = "3.1.2"
13
13
  authors = [{name = "David Banas", email = "capn.freako@gmail.com"}]
14
14
  urls = { documentation = "https://pychopmarg.readthedocs.io/en/latest/"}
15
15
  readme = "README.md"
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: PyChOpMarg
3
- Version: 3.1.0
3
+ Version: 3.1.2
4
4
  Summary: Python implementation of COM, as per IEEE 802.3-22 Annex 93A/178A.
5
5
  Author-email: David Banas <capn.freako@gmail.com>
6
6
  License: BSD3
@@ -34,6 +34,7 @@ Requires-Dist: click
34
34
  Requires-Dist: numpy
35
35
  Requires-Dist: scikit-rf>=0.29
36
36
  Requires-Dist: typing_extensions
37
+ Dynamic: license-file
37
38
 
38
39
  # PyChOpMarg
39
40
 
@@ -17,6 +17,7 @@ src/pychopmarg/matlab.py
17
17
  src/pychopmarg/noise.py
18
18
  src/pychopmarg/optimize.py
19
19
  src/pychopmarg/plot.py
20
+ src/pychopmarg/py.typed
20
21
  src/pychopmarg/config/__init__.py
21
22
  src/pychopmarg/config/ieee_8023by.py
22
23
  src/pychopmarg/config/ieee_8023dj.py
@@ -24,5 +25,6 @@ src/pychopmarg/config/template.py
24
25
  src/pychopmarg/utility/__init__.py
25
26
  src/pychopmarg/utility/filter.py
26
27
  src/pychopmarg/utility/general.py
28
+ src/pychopmarg/utility/jupyter.py
27
29
  src/pychopmarg/utility/probability.py
28
30
  src/pychopmarg/utility/sparams.py
@@ -0,0 +1,74 @@
1
+ """
2
+ Main Entry Point for PyChOpMarg when using the CLI.
3
+
4
+ Original author: David Banas <capn.freako@gmail.com>
5
+
6
+ Original date: March 25, 2024
7
+
8
+ Copyright (c) 2024 David Banas; all rights reserved World wide.
9
+ """
10
+
11
+ from pathlib import Path
12
+ from typing import Optional
13
+
14
+ import click # type: ignore
15
+
16
+ from pychopmarg import __version__
17
+ # from pychopmarg.com import COM
18
+ from pychopmarg.utility.jupyter import execute_notebook, convert_notebook_to_html
19
+
20
+
21
+ # ToDo: Activate when new `PyChOpMargUI` package is ready.
22
+ # @click.group(invoke_without_command=True, context_settings=dict(help_option_names=["-h", "--help"]))
23
+ @click.group(invoke_without_command=False, context_settings=dict(help_option_names=["-h", "--help"]))
24
+ @click.pass_context
25
+ @click.version_option(version=__version__)
26
+ def cli(ctx):
27
+ """
28
+ PyChOpMarg command line interface.
29
+ """
30
+
31
+ if ctx.invoked_subcommand is None: # No sub-command like `sim` given open the GUI like default.
32
+ # theCOM = COM()
33
+
34
+ # # Show the GUI.
35
+ # theCOM.configure_traits(view=traits_view)
36
+ raise RuntimeError("Sorry, the PyChOpMarg GUI is currently non-functional.")
37
+
38
+
39
+ # @cli.command(context_settings=dict(help_option_names=["-h", "--help"]))
40
+ # @click.argument("config-file", type=click.Path(exists=True))
41
+ # @click.option("--results", "-r", type=click.Path(), help="Override the results filename.")
42
+ # def run(config_file, results):
43
+ # """
44
+ # Run a COM calculation without opening the GUI.
45
+
46
+ # Will load the CONFIG_FILE from the given filepath, run the
47
+ # COM calculation and then save the results into a file with the same name
48
+ # but a different extension as the configuration file.
49
+ # """
50
+ # theCOM = COM()
51
+ # theCOM.load_configuration(config_file)
52
+ # theCOM.simulate(initial_run=True, update_plots=True)
53
+ # if not results:
54
+ # results = Path(config_file).with_suffix(".pychopmarg_results")
55
+ # theCOM.save_results(results)
56
+
57
+
58
+ @cli.command(context_settings=dict(help_option_names=["-h", "--help"]))
59
+ @click.argument("notebook-file", type=click.Path(exists=True))
60
+ def run_notebook(notebook_file: Path):
61
+ """
62
+ Run a Jupyter notebook in place w/o opening a browser tab.
63
+ """
64
+ execute_notebook(notebook_file)
65
+
66
+ @cli.command(context_settings=dict(help_option_names=["-h", "--help"]))
67
+ @click.argument("notebook-file", type=click.Path(exists=True))
68
+ @click.option("--out-file", "-o", type=click.Path(), help="Override the output filename.")
69
+ def convert_notebook(notebook_file: Path, out_file: Optional[Path] = None):
70
+ """
71
+ Convert a Jupyter notebook to an HTML report, omitting all code.
72
+ """
73
+ convert_notebook_to_html(Path(notebook_file), results_path=out_file)
74
+
@@ -139,8 +139,8 @@ class COM(): # pylint: disable=too-many-instance-attributes,too-many-public-met
139
139
 
140
140
  # Create the system time & frequency vectors.
141
141
  fb = com_params.fb * 1e9
142
- # fstep = com_params.fstep * 1e9
143
- fstep = 50e6 # Dramatically improves performance.
142
+ fstep = com_params.fstep * 1e9
143
+ # fstep = 50e6 # Dramatically improves performance.
144
144
  # - time
145
145
  tmax = 1 / fstep # Just enough to cover one full cycle of the fundamental.
146
146
  ui = 1 / fb
@@ -27,8 +27,9 @@ COMFiles: TypeAlias = str | list[str]
27
27
  COMNtwk: TypeAlias = tuple[rf.Network, str]
28
28
  COMChnl: TypeAlias = tuple[COMNtwk, Cvec]
29
29
 
30
- PI: float = np.pi
31
- TWOPI: float = 2 * np.pi
30
+ # PI = np.pi # Making autodoc barf.
31
+ PI = 3.14159 #: Value of Pi
32
+ TWOPI = 2.0 * PI #: 2 * Pi
32
33
 
33
34
  ChnlGrpName: TypeAlias = str # channel group name
34
35
  ChnlSetName: TypeAlias = str # channel set name (the stem of the thru channel s4p file name)
@@ -14,7 +14,7 @@ from pychopmarg.config.template import COMParams
14
14
  fB = 25 * 66. / 64.
15
15
 
16
16
  IEEE_8023by = COMParams(
17
- fB, 0.01, 40e9, 2, 32, 1e-5, 0.010, 1.0, 0.4, 0.4, 0.6, 50,
17
+ fB, 0.01, 2, 32, 1e-5, 0.010, 1.0, 0.4, 0.4, 0.6, 50,
18
18
  0.05, 27, 5.2e-8, 0.01,
19
19
  fB / 4, fB / 4, fB, 1.0, [float(-n) for n in range(13)], [0.],
20
20
  [-1.] * 6, [1.] * 6, [0.25] * 6, 0.,
@@ -12,7 +12,7 @@ import numpy as np
12
12
  from pychopmarg.config.template import COMParams
13
13
 
14
14
  IEEE_8023dj = COMParams(
15
- 106.25, 0.01, 40e9, 4, 32, 2e-4, 0.004, 0.95, 0.413, 0.413, 0.45, 50,
15
+ 106.25, 0.01, 4, 32, 2e-4, 0.004, 0.95, 0.413, 0.413, 0.45, 50,
16
16
  0.02, 33, 6.0e-9, 0.01,
17
17
  42.5, 42.5, 106.25, 1.328125, [-n for n in range(16)], [-n / 2 for n in range(11)],
18
18
  [-0.06, 0.0, -0.34, -0.2, 0.0, 0.0], [0.0, 0.12, 0.0, 0.0, 0.0, 0.0], [0.005, 0.005, 0.005, 0.005, 0.0, 0.0], 0.5,
@@ -13,14 +13,37 @@ import numpy as np
13
13
  from pychopmarg.common import Rvec
14
14
 
15
15
 
16
- @dataclass
16
+ # @dataclass(frozen=True) # We take COM parameters to be immutable.
17
+ @dataclass()
17
18
  class COMParams(): # pylint: disable=too-many-instance-attributes
18
- "Template definition for COM parameters."
19
+ """
20
+ Template definition for COM parameters.
21
+
22
+ ToDo:
23
+ 1. Use `metadata` to provide units:
24
+
25
+ .. code-block:: python
26
+
27
+ @dataclass
28
+ class Product:
29
+ name: str
30
+ price: float = field(metadata={"unit": "USD"})
31
+
32
+ 2. Is there a `helptext` field available in `metadata`?
33
+
34
+ 3. If we ever want to exclude some fields from comparison operations:
35
+
36
+ .. code-block:: python
37
+
38
+ @dataclass
39
+ class CustomTask:
40
+ name: str
41
+ priority: int = field(compare=False)
42
+ """
19
43
 
20
44
  # General
21
45
  fb: float # (GBaud)
22
46
  fstep: float # (GHz)
23
- fmax: float # (Hz)
24
47
  L: int # modulation levels
25
48
  M: int # samples per UI
26
49
  DER_0: float # detector error ratio
@@ -261,7 +261,6 @@ def get_com_params(cfg_file: Path) -> COMParams: # noqa=E501 pylint: disable=to
261
261
  rslt = COMParams(
262
262
  com_params_dict["fb"],
263
263
  com_params_dict["fstep"],
264
- com_params_dict["fmax"],
265
264
  com_params_dict["L"],
266
265
  com_params_dict["M"],
267
266
  com_params_dict["DER_0"],
@@ -91,9 +91,7 @@ class NoiseCalc(): # pylint: disable=too-many-instance-attributes
91
91
  ValueError: Unless `f` is uniformly sampled.
92
92
 
93
93
  Notes:
94
- 1. No assumption is made, re: any linkage between `t` and `f`.
95
- 2. The transfer functions are assumed to contain only positive frequency values.
96
- 3. `f` may begin at zero, but is not required to.
94
+ 1. The transfer functions are assumed to contain only positive frequency values.
97
95
 
98
96
  ToDo:
99
97
  1. Consider defining a data class to hold the initialization data.
@@ -122,10 +120,10 @@ class NoiseCalc(): # pylint: disable=too-many-instance-attributes
122
120
  assert f[1] == f0, ValueError(
123
121
  f"The second element of `f` ({f[1]}) must be the fundamental frequency implied by the time vector ({f0})!")
124
122
  fs = 1 / t[1]
125
- assert f[-1] == fs / 2, ValueError(
123
+ assert (f[-1] - fs / 2) < eps, ValueError(
126
124
  f"The last element of `f` ({f[-1]}) must be half the sampling frequency ({fs})!")
127
125
  dfs = diff(f)
128
- assert all(dfs == dfs[0]), ValueError(
126
+ assert all((dfs - dfs[0]) < eps), ValueError(
129
127
  "The frequency vector, `f`, must be uniformly sampled!")
130
128
 
131
129
  super().__init__()
@@ -267,7 +265,7 @@ class NoiseCalc(): # pylint: disable=too-many-instance-attributes
267
265
  nUI = int(len(dV) / nspui)
268
266
  hJ = mean(reshape(concatenate((dV[(ts_ix - 1) % nspui::nspui][:nUI],
269
267
  dV[(ts_ix ) % nspui::nspui][:nUI])), # noqa=E202
270
- shape=(2, nUI)),
268
+ (2, nUI)),
271
269
  axis=0) / t[1]
272
270
 
273
271
  return varX * (self.Add**2 + self.sigma_Rj**2) * abs(rfft(hJ) * Tb)**2 * Tb # i.e. - / fB
@@ -278,7 +276,11 @@ class NoiseCalc(): # pylint: disable=too-many-instance-attributes
278
276
  Sxn = sum(array(list(map(self.Sxn, self.agg_pulse_resps))), axis=0)
279
277
  Stn = self.Stn()
280
278
  Sjn = self.Sjn
281
- min_len = min(len(Srn), len(Sxn), len(Stn), len(Sjn))
282
- Sn = Srn[:min_len] + Sxn[:min_len] + Stn[:min_len] + Sjn[:min_len]
279
+ if self.agg_pulse_resps:
280
+ min_len = min(len(Srn), len(Sxn), len(Stn), len(Sjn))
281
+ Sn = Srn[:min_len] + Sxn[:min_len] + Stn[:min_len] + Sjn[:min_len]
282
+ else:
283
+ min_len = min(len(Srn), len(Stn), len(Sjn))
284
+ Sn = Srn[:min_len] + Stn[:min_len] + Sjn[:min_len]
283
285
  # i.e. - `* fB`, which when combined w/ the implicit `1/N` of `irfft()` yields `* df`.
284
286
  return irfft(Sn) / self.Tb
@@ -13,7 +13,7 @@ from typing import Any, Optional
13
13
  import numpy as np
14
14
  # pylint: disable=redefined-builtin
15
15
  from numpy import (
16
- argmax, array, array_equal, concatenate, dot,
16
+ argmax, array, array_equal, concatenate, dot, identity,
17
17
  log10, maximum, minimum, ones, pad, sqrt, sum, vectorize, where, zeros)
18
18
  from numpy.linalg import lstsq
19
19
  from scipy.linalg import convolution_matrix, solve, toeplitz
@@ -309,9 +309,20 @@ def mmse( # pylint: disable=too-many-arguments,too-many-positional-arguments,to
309
309
  Hb = H[d + 1: d + 1 + Nb]
310
310
  Rn = theNoiseCalc.Rn()[:Nw]
311
311
  R = H.T @ H + toeplitz(Rn) / varX
312
- A = concatenate((concatenate(( R, -Hb.T, -h0.reshape((Nw, 1))), axis=1), # noqa=E201
313
- concatenate((-Hb, ones((Nb, 1)), zeros((Nb, 1))), axis=1),
314
- concatenate(( h0, zeros(2))).reshape((1, Nw + 2)))) # noqa=E201
312
+ Ib = identity(Nb)
313
+ zb = zeros(Nb)
314
+ try: # FixMe: The following breaks when `Nb` /= 1!
315
+ A = concatenate((concatenate(( R, -Hb.T, -h0.reshape((Nw, 1))), axis=1), # noqa=E201
316
+ concatenate((-Hb, Ib, zeros((Nb, 1))), axis=1),
317
+ concatenate(( h0, zb, zeros(1))).reshape((1, Nw + Nb + 1)))) # noqa=E201
318
+ except ValueError as err:
319
+ print(f"R.shape: {R.shape}", flush=True)
320
+ print(f"Hb.shape: {Hb.shape}", flush=True)
321
+ print(f"Nw: {Nw}", flush=True)
322
+ print(f"Nb: {Nb}", flush=True)
323
+ print(f"h0.reshape((Nw, 1)).shape: {h0.reshape((Nw, 1)).shape}", flush=True)
324
+ print(f"concatenate(( h0, zb, zeros(1))).reshape((1, Nw + Nb + 1)).shape: {concatenate(( h0, zb, zeros(1))).reshape((1, Nw + Nb + 1)).shape}", flush=True)
325
+ raise
315
326
  y = concatenate((h0, zeros(Nb), ones(1)))
316
327
  x = solve(A, y)
317
328
  w = x[:Nw]
File without changes
@@ -0,0 +1,52 @@
1
+ """
2
+ Jupyter utilities for PyChOpMarg.
3
+
4
+ Original author: David Banas <capn.freako@gmail.com>
5
+
6
+ Original date: January 23, 2025
7
+
8
+ Copyright (c) 2025 David Banas; all rights reserved World wide.
9
+ """
10
+
11
+ import click # type: ignore
12
+ import os
13
+ from pathlib import Path
14
+ import subprocess
15
+ from typing import Optional
16
+
17
+
18
+ def execute_notebook(notebook_path: Path) -> None:
19
+ """
20
+ Executes a Jupyter notebook.
21
+
22
+ Args:
23
+ notebook_path: Path to the notebook.
24
+ """
25
+
26
+ if not os.path.exists(notebook_path):
27
+ raise FileNotFoundError(f"The notebook {notebook_path} was not found!")
28
+
29
+ subprocess.run([
30
+ 'jupyter', 'nbconvert', '--to', 'notebook', '--execute', '--inplace', notebook_path],
31
+ check=True)
32
+
33
+
34
+ def convert_notebook_to_html(notebook_path: Path, results_path: Optional[Path] = None) -> None:
35
+ """
36
+ Converts a Jupyter notebook to an HTML file, excluding the input cells (code).
37
+
38
+ Args:
39
+ notebook_path: Path to the notebook.
40
+
41
+ Keyword Args:
42
+ results_path: Result file path.
43
+ Default: None (Use stem of ``notebook_path`` with ``.html`` suffix.)
44
+ """
45
+
46
+ if not os.path.exists(notebook_path):
47
+ raise FileNotFoundError(f"The notebook {notebook_path} was not found!")
48
+
49
+ html_path = results_path or Path(notebook_path.name).with_suffix('.html')
50
+ subprocess.run(
51
+ ['jupyter', 'nbconvert', '--to', 'html', '--no-input', '--output', html_path, notebook_path],
52
+ check=True)
@@ -1,51 +0,0 @@
1
- """
2
- Main Entry Point for PyChOpMarg when using the CLI.
3
-
4
- Original author: David Banas <capn.freako@gmail.com>
5
-
6
- Original date: March 25, 2024
7
-
8
- Copyright (c) 2024 David Banas; all rights reserved World wide.
9
- """
10
-
11
- # from pathlib import Path
12
-
13
- # import click # type: ignore
14
-
15
- # from pychopmarg import __version__
16
- # from pychopmarg.com import COM
17
-
18
-
19
- # ToDo: Activate when new `PyChOpMargUI` package is ready.
20
- # @click.group(invoke_without_command=True, context_settings=dict(help_option_names=["-h", "--help"]))
21
- # @click.pass_context
22
- # @click.version_option(version=__version__)
23
- # def cli(ctx):
24
- # """
25
- # PyChOpMargUI GUI.
26
- # """
27
-
28
- # if ctx.invoked_subcommand is None: # No sub-command like `sim` given open the GUI like default.
29
- # theCOM = COM()
30
-
31
- # # Show the GUI.
32
- # theCOM.configure_traits(view=traits_view)
33
-
34
-
35
- # @cli.command(context_settings=dict(help_option_names=["-h", "--help"]))
36
- # @click.argument("config-file", type=click.Path(exists=True))
37
- # @click.option("--results", "-r", type=click.Path(), help="Override the results filename.")
38
- # def run(config_file, results):
39
- # """
40
- # Run a COM calculation without opening the GUI.
41
-
42
- # Will load the CONFIG_FILE from the given filepath, run the
43
- # COM calculation and then save the results into a file with the same name
44
- # but a different extension as the configuration file.
45
- # """
46
- # theCOM = COM()
47
- # theCOM.load_configuration(config_file)
48
- # theCOM.simulate(initial_run=True, update_plots=True)
49
- # if not results:
50
- # results = Path(config_file).with_suffix(".pychopmarg_results")
51
- # theCOM.save_results(results)
File without changes
File without changes
File without changes