PyChOpMarg 2.1.1__tar.gz → 2.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 (23) hide show
  1. {pychopmarg-2.1.1 → pychopmarg-2.1.2}/PKG-INFO +1 -1
  2. {pychopmarg-2.1.1 → pychopmarg-2.1.2}/pyproject.toml +1 -1
  3. {pychopmarg-2.1.1 → pychopmarg-2.1.2}/src/PyChOpMarg.egg-info/PKG-INFO +1 -1
  4. {pychopmarg-2.1.1 → pychopmarg-2.1.2}/src/pychopmarg/com.py +75 -61
  5. {pychopmarg-2.1.1 → pychopmarg-2.1.2}/src/pychopmarg/common.py +3 -0
  6. {pychopmarg-2.1.1 → pychopmarg-2.1.2}/src/pychopmarg/noise.py +20 -15
  7. {pychopmarg-2.1.1 → pychopmarg-2.1.2}/src/pychopmarg/optimize.py +44 -32
  8. {pychopmarg-2.1.1 → pychopmarg-2.1.2}/src/pychopmarg/utility/filter.py +10 -16
  9. {pychopmarg-2.1.1 → pychopmarg-2.1.2}/src/pychopmarg/utility/general.py +18 -16
  10. {pychopmarg-2.1.1 → pychopmarg-2.1.2}/src/pychopmarg/utility/probability.py +11 -10
  11. {pychopmarg-2.1.1 → pychopmarg-2.1.2}/src/pychopmarg/utility/sparams.py +25 -16
  12. {pychopmarg-2.1.1 → pychopmarg-2.1.2}/LICENSE +0 -0
  13. {pychopmarg-2.1.1 → pychopmarg-2.1.2}/README.md +0 -0
  14. {pychopmarg-2.1.1 → pychopmarg-2.1.2}/setup.cfg +0 -0
  15. {pychopmarg-2.1.1 → pychopmarg-2.1.2}/src/PyChOpMarg.egg-info/SOURCES.txt +0 -0
  16. {pychopmarg-2.1.1 → pychopmarg-2.1.2}/src/PyChOpMarg.egg-info/dependency_links.txt +0 -0
  17. {pychopmarg-2.1.1 → pychopmarg-2.1.2}/src/PyChOpMarg.egg-info/entry_points.txt +0 -0
  18. {pychopmarg-2.1.1 → pychopmarg-2.1.2}/src/PyChOpMarg.egg-info/requires.txt +0 -0
  19. {pychopmarg-2.1.1 → pychopmarg-2.1.2}/src/PyChOpMarg.egg-info/top_level.txt +0 -0
  20. {pychopmarg-2.1.1 → pychopmarg-2.1.2}/src/pychopmarg/__init__.py +0 -0
  21. {pychopmarg-2.1.1 → pychopmarg-2.1.2}/src/pychopmarg/__main__.py +0 -0
  22. {pychopmarg-2.1.1 → pychopmarg-2.1.2}/src/pychopmarg/cli.py +0 -0
  23. {pychopmarg-2.1.1 → pychopmarg-2.1.2}/src/pychopmarg/utility/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyChOpMarg
3
- Version: 2.1.1
3
+ Version: 2.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
@@ -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 = "2.1.1"
12
+ version = "2.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
1
  Metadata-Version: 2.1
2
2
  Name: PyChOpMarg
3
- Version: 2.1.1
3
+ Version: 2.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
@@ -48,7 +48,12 @@ class OptMode(Enum):
48
48
 
49
49
 
50
50
  class COM(): # pylint: disable=too-many-instance-attributes,too-many-public-methods
51
- "Encoding of the IEEE 802.3-22 Annex 93A/178A 'Channel Operating Margin' (COM) specification."
51
+ """
52
+ Encoding of the IEEE 802.3-22 Annex 93A/178A 'Channel Operating Margin' (COM) specification.
53
+
54
+ ToDo:
55
+ 1. Clean up unused attributes.
56
+ """
52
57
 
53
58
  status_str = str("Ready")
54
59
  debug = bool(False)
@@ -149,7 +154,6 @@ class COM(): # pylint: disable=too-many-instance-attributes,too-many-public-met
149
154
 
150
155
  # - Results
151
156
  # -- COM
152
- # ToDo: Clean up unused attributes.
153
157
  com = float(0.0)
154
158
  com_As = float(0.0)
155
159
  com_cursor_ix = int(0)
@@ -250,8 +254,8 @@ class COM(): # pylint: disable=too-many-instance-attributes,too-many-public-met
250
254
  Default: None
251
255
 
252
256
  Notes:
253
- 1. The instance's current value(s) for `gDC` and `gDC2` are used if not provided.
254
- (Necessary, to accommodate sweeping when optimizing EQ.)
257
+ 1. The instance's current value(s) for ``gDC`` and ``gDC2`` are used if not provided.
258
+ (Necessary, to accommodate sweeping when optimizing EQ.)
255
259
  """
256
260
  gDC = gDC or self.gDC
257
261
  gDC2 = gDC2 or self.gDC2
@@ -672,9 +676,9 @@ class COM(): # pylint: disable=too-many-instance-attributes,too-many-public-met
672
676
 
673
677
  Notes:
674
678
  1. It is at this point in the analysis that the "raw" Touchstone data
675
- gets interpolated to our system frequency vector.
676
- 2. After this step, the package and R0/Rd mismatch have been accounted for,
677
- but not the EQ.
679
+ gets interpolated to our system frequency vector.
680
+
681
+ 2. After this step, the package and R0/Rd mismatch have been accounted for, but not the EQ.
678
682
  """
679
683
 
680
684
  assert s2p.s[0].shape == (2, 2), ValueError("I can only convert 2-port networks.")
@@ -704,15 +708,15 @@ class COM(): # pylint: disable=too-many-instance-attributes,too-many-public-met
704
708
 
705
709
  Keyword Args:
706
710
  tx_taps: Tx FFE tap weights.
707
- Default: None (i.e. - Use `self.tx_taps`.)
711
+ Default: None (i.e. - Use ``self.tx_taps``.)
708
712
  gDC: CTLE first stage d.c. gain (dB).
709
- Default: None (i.e. - Use `self.gDC`.)
713
+ Default: None (i.e. - Use ``self.gDC``.)
710
714
  gDC2: CTLE second stage d.c. gain (dB).
711
- Default: None (i.e. - Use `self.gDC2`.)
715
+ Default: None (i.e. - Use ``self.gDC2``.)
712
716
  rx_taps: Rx FFE tap weights.
713
- Default: None (i.e. - Use `self.rx_taps`.)
717
+ Default: None (i.e. - Use ``self.rx_taps``.)
714
718
  dfe_taps: Rx DFE tap weights.
715
- Default: None (i.e. - Use `self.dfe_taps`.)
719
+ Default: None (i.e. - Use ``self.dfe_taps``.)
716
720
  passive_RxFFE: Enforce passivity of Rx FFE when True.
717
721
  Default: True
718
722
 
@@ -724,11 +728,13 @@ class COM(): # pylint: disable=too-many-instance-attributes,too-many-public-met
724
728
 
725
729
  Notes:
726
730
  1. It is in this processing step that linear EQ is first applied.
727
- 2. Any unprovided EQ values are taken from the `COM` instance.
728
- If you really want to omit a particular EQ component then call with:
729
731
 
730
- - `tx_taps`/`rx_taps`: []
731
- - `gDC`/`gDC2`: 0
732
+ 2. Any unprovided EQ values are taken from the ``COM`` instance.
733
+ If you really want to omit a particular EQ component then call with:
734
+
735
+ - ``tx_taps``: []
736
+ - ``rx_taps``: [1.0]
737
+ - ``gDC``/``gDC2``: 0
732
738
  """
733
739
 
734
740
  assert s2p.s[0, :, :].shape == (2, 2), ValueError(
@@ -777,7 +783,7 @@ class COM(): # pylint: disable=too-many-instance-attributes,too-many-public-met
777
783
 
778
784
  Notes:
779
785
  1. It is at this point in the signal processing chain that we change
780
- time domains.
786
+ time domains.
781
787
  """
782
788
 
783
789
  assert len(H) == len(self.freqs), ValueError(
@@ -799,17 +805,17 @@ class COM(): # pylint: disable=too-many-instance-attributes,too-many-public-met
799
805
 
800
806
  Keyword Args:
801
807
  ntwks: The list of networks to generate pulse responses for.
802
- Default: None (i.e. - Use `self.chnls`.)
808
+ Default: None (i.e. - Use ``self.chnls``.)
803
809
  gDC: Rx CTLE first stage d.c. gain.
804
- Default: None (i.e. - Use `self.gDC`.)
810
+ Default: None (i.e. - Use ``self.gDC``.)
805
811
  gDC2: Rx CTLE second stage d.c. gain.
806
- Default: None (i.e. - Use `self.gDC2`.)
812
+ Default: None (i.e. - Use ``self.gDC2``.)
807
813
  tx_taps: Desired Tx tap weights.
808
- Default: None (i.e. - Use `self.tx_taps`.)
814
+ Default: None (i.e. - Use ``self.tx_taps``.)
809
815
  rx_taps: Desired Rx FFE tap weights.
810
- Default: None (i.e. - Use `self.rx_taps`.)
816
+ Default: None (i.e. - Use ``self.rx_taps``.)
811
817
  dfe_taps: Desired Rx DFE tap weights.
812
- Default: None (i.e. - Use `self.dfe_taps`.)
818
+ Default: None (i.e. - Use ``self.dfe_taps``.)
813
819
  apply_eq: Include linear EQ when True; otherwise, exclude it.
814
820
  (Allows for pulse response generation of terminated, but unequalized, channel.)
815
821
  Default: True
@@ -817,16 +823,14 @@ class COM(): # pylint: disable=too-many-instance-attributes,too-many-public-met
817
823
  Returns:
818
824
  list of pulse responses.
819
825
 
820
- Raises:
821
- None
822
-
823
826
  Notes:
824
- 1. Assumes `self.gDC`, `self.gDC2`, `self.tx_taps`, `self.rx_taps`, and `self.dfe_taps`
825
- have been set correctly, if the equivalent function parameters have not been provided.
827
+ 1. Assumes ``self.gDC``, ``self.gDC2``, ``self.tx_taps``, ``self.rx_taps``, and ``self.dfe_taps``
828
+ have been set correctly, if the equivalent function parameters have not been provided.
829
+
826
830
  2. To generate pulse responses that include all linear EQ except the Rx FFE/DFE
827
- (i.e. - pulse responses suitable for Rx FFE/DFE tap weight optimization,
828
- via either `optimize.przf()` or `optimize.mmse()`),
829
- set `rx_taps` equal to: [1.0] and `dfe_taps` equal to: [].
831
+ (i.e. - pulse responses suitable for Rx FFE/DFE tap weight optimization,
832
+ via either ``optimize.przf()`` or ``optimize.mmse()``),
833
+ set ``rx_taps`` equal to: ``[1.0]`` and ``dfe_taps`` equal to: ``[]``.
830
834
  """
831
835
 
832
836
  gDC = gDC or self.gDC # The more Pythonic way, but doesn't work for lists in newer versions of Python.
@@ -880,7 +884,7 @@ class COM(): # pylint: disable=too-many-instance-attributes,too-many-public-met
880
884
  Default: 0.001 (i.e. - 0.1%, as per Note 2 of 93A.1.7.1)
881
885
 
882
886
  Returns:
883
- The subset of `pr_samps` passing filtration.
887
+ The subset of ``pr_samps`` passing filtration.
884
888
  """
885
889
 
886
890
  thresh = As * rel_thresh
@@ -930,8 +934,8 @@ class COM(): # pylint: disable=too-many-instance-attributes,too-many-public-met
930
934
 
931
935
  Notes:
932
936
  1. As per v3.70 of the COM MATLAB code, we only minimize the
933
- residual of (93A-25); we don't require solving it exactly.
934
- (We do, however, give priority to exact solutions.)
937
+ residual of (93A-25); we don't require solving it exactly.
938
+ (We do, however, give priority to exact solutions.)
935
939
  """
936
940
 
937
941
  M = self.nspui
@@ -993,20 +997,19 @@ class COM(): # pylint: disable=too-many-instance-attributes,too-many-public-met
993
997
  norm_mode: The tap weight normalization mode to use.
994
998
  Default: None (i.e. - Use ``self.norm_mode``.)
995
999
  unit_amp: Enforce unit pulse response amplitude when True.
996
- (For comparing `optimize.przf()` results to `optimize.mmse()` results.)
1000
+ (For comparing ``optimize.przf()`` results to ``optimize.mmse()`` results.)
997
1001
  Default: None (i.e. - Use ``self.unit_amp``.)
998
1002
 
999
1003
  Returns:
1000
1004
  The resultant figure of merit.
1001
1005
 
1002
- Raises:
1003
- None
1004
-
1005
1006
  Notes:
1006
1007
  1. See: IEEE 802.3-2022 93A.1.6.
1007
- 2. When not provided, the values for ``gDC`` and ``gDC2`` are taken from the `COM` instance.
1008
- 3. Unlike other member functions of the `COM` class,
1009
- this function **optimizes** the Rx FFE tap weights when they are not provided.
1008
+
1009
+ 2. When not provided, the values for ``gDC`` and ``gDC2`` are taken from the ``COM`` instance.
1010
+
1011
+ 3. Unlike other member functions of the ``COM`` class,
1012
+ this function *optimizes* the Rx FFE tap weights when they are not provided.
1010
1013
  """
1011
1014
 
1012
1015
  # Honor any mode overrides.
@@ -1146,25 +1149,28 @@ class COM(): # pylint: disable=too-many-instance-attributes,too-many-public-met
1146
1149
  unit_amp: Optional[bool] = None
1147
1150
  ) -> bool:
1148
1151
  """
1149
- Find the optimum values for the linear equalization parameters:
1150
- c[n], gDC, gDC2, and w[n] as per IEEE 802.3-22 93A.1.6
1152
+ Find and set the optimum values for the linear equalization parameters:
1153
+ ``c[n]``, ``gDC``, ``gDC2``, and ``w[n]`` as per IEEE 802.3-22 93A.1.6
1151
1154
  (or, [1] slide 11 if MMSE has been chosen).
1152
1155
 
1153
1156
  Keyword Args:
1154
1157
  do_opt_eq: Perform optimization of linear EQ when True.
1155
1158
  Default: True
1156
- tx_taps: Used when `do_opt_eq` = False.
1159
+ tx_taps: Used when ``do_opt_eq`` = False.
1157
1160
  Default: None
1158
1161
  opt_mode: Optimization mode.
1159
- Default: None (i.e. - Use `self.opt_mode`.)
1162
+ Default: None (i.e. - Use ``self.opt_mode``.)
1160
1163
  norm_mode: The tap weight normalization mode to use.
1161
- Default: None (i.e. - Use `self.norm_mode`.)
1164
+ Default: None (i.e. - Use ``self.norm_mode``.)
1162
1165
  unit_amp: Enforce unit pulse response amplitude when True.
1163
- (For comparing `przf()` results to `mmse()` results.)
1164
- Default: None (i.e. - Use `self.unit_amp`.)
1166
+ (For comparing ``przf()`` results to ``mmse()`` results.)
1167
+ Default: None (i.e. - Use ``self.unit_amp``.)
1165
1168
 
1166
1169
  Returns:
1167
1170
  True if no errors encountered; False otherwise.
1171
+
1172
+ Notes:
1173
+ 1. The found optimum equalization values are set for the instance.
1168
1174
  """
1169
1175
 
1170
1176
  if do_opt_eq:
@@ -1267,29 +1273,37 @@ class COM(): # pylint: disable=too-many-instance-attributes,too-many-public-met
1267
1273
  (In support of MMSE.)
1268
1274
  Default: None
1269
1275
  opt_mode: Optimization mode.
1270
- Default: None (i.e. - Use `self.opt_mode`.)
1276
+ Default: None (i.e. - Use ``self.opt_mode``.)
1271
1277
  norm_mode: The tap weight normalization mode to use.
1272
- Default: None (i.e. - Use `self.norm_mode`.)
1278
+ Default: None (i.e. - Use ``self.norm_mode``.)
1273
1279
  unit_amp: Enforce unit pulse response amplitude when True.
1274
- (For comparing `przf()` results to `mmse()` results.)
1275
- Default: None (i.e. - Use `self.unit_amp`.)
1280
+ (For comparing ``przf()`` results to ``mmse()`` results.)
1281
+ Default: None (i.e. - Use ``self.unit_amp``.)
1276
1282
  dbg_dict: Optional dictionary into which debugging values may be stashed,
1277
1283
  for later analysis.
1278
1284
  Default: None
1279
1285
 
1280
1286
  Returns:
1281
- - signal amplitude
1282
- - noise + interference amplitude (V)
1283
- - cursor location within victim pulse response vector
1287
+ A triplet containing
1288
+
1289
+ - signal amplitude (V)
1290
+ - noise + interference amplitude (V)
1291
+ - cursor location within victim pulse response vector
1284
1292
 
1285
1293
  Notes:
1286
1294
  1. Assumes the following instance variables have been set optimally:
1287
- - gDC
1288
- - gDC2
1289
- - tx_taps
1290
- - rx_taps
1291
- (This assumption is embedded into the `gen_pulse_resps()` function.)
1292
- 2. Fills in the `com_results` dictionary w/ various useful values for debugging.
1295
+
1296
+ - ``gDC``
1297
+ - ``gDC2``
1298
+ - ``tx_taps``
1299
+ - ``rx_taps``
1300
+
1301
+ (This assumption is embedded into the ``gen_pulse_resps()`` function.)
1302
+
1303
+ 2. Fills in the ``com_results`` dictionary w/ various useful values for debugging.
1304
+
1305
+ ToDo:
1306
+ 1. ``DER0 / 2`` in ``Ani`` calculation?
1293
1307
  """
1294
1308
 
1295
1309
  # Honor any mode overrides.
@@ -6,6 +6,9 @@ Original author: David Banas <capn.freako@gmail.com>
6
6
  Original date: March 3, 2024 (Copied from `pybert.utility`.)
7
7
 
8
8
  Copyright (c) 2024 David Banas; all rights reserved World wide.
9
+
10
+ ToDo:
11
+ 1. Specify ``COMParams`` concretely.
9
12
  """
10
13
 
11
14
  from typing import TypeVar, TypeAlias, Any
@@ -147,25 +147,28 @@ class NoiseCalc(): # pylint: disable=too-many-instance-attributes
147
147
 
148
148
  def from_irfft(self, x: Rvec) -> Rvec:
149
149
  """
150
- Interpolate `irfft()` output to `t` and subsample at fBaud.
150
+ Interpolate ``irfft()`` output to ``t`` and subsample at fBaud.
151
151
 
152
152
  Args:
153
- x: `irfft()` results to be interpolated and subsampled.
153
+ x: ``irfft()`` results to be interpolated and subsampled.
154
154
 
155
155
  Returns:
156
- y: interpolated and subsampled vector.
156
+ Interpolated and subsampled vector.
157
157
 
158
158
  Raises:
159
- IndexError: If length of input doesn't match length of `t_irfft` vector.
159
+ IndexError: If length of input doesn't match length of ``t_irfft`` vector.
160
160
 
161
161
  Notes:
162
- 1. Input vector is shifted, such that its peak occurs at `0.1 * max(t)`, before interpolating.
163
- This is done to:
164
- - ensure that we don't omit any non-causal behavior,
165
- which ends up at the end of an IFFT output vector
166
- when the peak is very near the beginning, and
167
- - to ensure that the majority of our available time span
168
- is available for capturing reflections.
162
+ 1. Input vector is shifted, such that its peak occurs at ``0.1 * max(t)``, before interpolating.
163
+ This is done to:
164
+
165
+ * ensure that we don't omit any non-causal behavior,
166
+ which ends up at the end of an IFFT output vector
167
+ when the peak is very near the beginning, and
168
+
169
+ * to ensure that the majority of our available time span
170
+ is available for capturing reflections.
171
+
169
172
  2. The sub-sampling phase is adjusted, so as to ensure that we catch the peak.
170
173
  """
171
174
 
@@ -193,8 +196,8 @@ class NoiseCalc(): # pylint: disable=too-many-instance-attributes
193
196
  uniformly sampled over [0, PI] (rads./s norm.).
194
197
 
195
198
  Notes:
196
- 1. Re: the scaling term: `2 * self.f[-1]`, when combined w/
197
- the implicit `1/N` of the `irfft()` function, this gives `df`.
199
+ 1. Re: the scaling term: ``2 * self.f[-1]``, when combined w/
200
+ the implicit ``1/N`` of the ``irfft()`` function, this gives ``df``.
198
201
  """
199
202
  # "/ 2" in [1] omitted, since we're only considering: m >= 0.
200
203
  rslt = self.eta0 * 1e-9 * abs(self.Hr * self.Hctf) ** 2
@@ -209,8 +212,7 @@ class NoiseCalc(): # pylint: disable=too-many-instance-attributes
209
212
  agg_pulse_resp: Aggressor pulse response (V).
210
213
 
211
214
  Returns:
212
- Sxn: One-sided crosstalk PSD at Rx FFE input,
213
- uniformly sampled over [0, PI] (rads./s norm.).
215
+ One-sided crosstalk PSD at Rx FFE input, uniformly sampled over [0, PI] (rads./s norm.).
214
216
  """
215
217
 
216
218
  nspui = self.nspui
@@ -224,6 +226,9 @@ class NoiseCalc(): # pylint: disable=too-many-instance-attributes
224
226
  """
225
227
  One-sided Tx noise PSD at Rx FFE input,
226
228
  uniformly sampled over [0, PI] (rads./s norm.).
229
+
230
+ ToDo:
231
+ 1. Do I need to honor ``ts_ix``?
227
232
  """
228
233
 
229
234
  Tb = self.Tb
@@ -25,10 +25,18 @@ from pychopmarg.noise import NoiseCalc
25
25
 
26
26
  class NormMode(Enum):
27
27
  "Tap weight normalization mode."
28
- P8023dj = 1 # As per standard (i.e. - clip then renormalize for unit amplitude pulse response.)
29
- Scaled = 2 # Uniformly and minimally scaled to bring tap weights just within their limits.
30
- Unaltered = 3 # Use constrained optimization solution, unchanged.
31
- UnitDcGain = 4 # Tap weights are uniformly scaled, to yield unity gain at d.c.
28
+
29
+ P8023dj = 1
30
+ "As per standard (i.e. - clip then renormalize for unit amplitude pulse response.)"
31
+
32
+ Scaled = 2
33
+ "Uniformly and minimally scaled to bring tap weights just within their limits."
34
+
35
+ Unaltered = 3
36
+ "Use constrained optimization solution, unchanged."
37
+
38
+ UnitDcGain = 4
39
+ "Tap weights are uniformly scaled, to yield unity gain at d.c."
32
40
 
33
41
 
34
42
  def scale_taps(w: Rvec, w_min: Optional[Rvec] = None, w_max: Optional[Rvec] = None) -> Rvec:
@@ -40,12 +48,12 @@ def scale_taps(w: Rvec, w_min: Optional[Rvec] = None, w_max: Optional[Rvec] = No
40
48
 
41
49
  Keyword Args:
42
50
  w_min: Minimum tap weights.
43
- Default: None (Use `-ones(len(w))`.)
51
+ Default: None (Use ``-ones(len(w))``.)
44
52
  w_max: Maximum tap weights.
45
- Default: None (Use `ones(len(w))`.)
53
+ Default: None (Use ``ones(len(w))``.)
46
54
 
47
55
  Returns:
48
- w_lim: Tap weights, scaled proportionally, to just fit inside min/max limits.
56
+ Tap weights, scaled proportionally to just fit inside min/max limits.
49
57
  """
50
58
 
51
59
  if w_min is None:
@@ -82,18 +90,18 @@ def clip_taps(
82
90
 
83
91
  Args:
84
92
  w: The tap weights to clip.
85
- curs_ix: The index, in `w`, of the cursor tap.
93
+ curs_ix: The index, in ``w``, of the cursor tap.
86
94
 
87
95
  Keyword Args:
88
96
  w_min: Minimum tap weights.
89
- Default: None (Use `-ones(len(w))`.)
97
+ Default: None (Use ``-ones(len(w))``.)
90
98
  w_max: Maximum tap weights.
91
- Default: None (Use `ones(len(w))`.)
99
+ Default: None (Use ``ones(len(w))``.)
92
100
  obey_spec: Allow cursor tap weight to grow w/o bound, as per D1.2, when True.
93
101
  Default: True
94
102
 
95
103
  Returns:
96
- w_lim: Tap weights, clipped accordingly.
104
+ Tap weights, clipped accordingly.
97
105
  """
98
106
 
99
107
  if w_min is None:
@@ -136,7 +144,7 @@ def przf( # pylint: disable=too-many-arguments,too-many-positional-arguments,to
136
144
  norm_mode: NormMode = NormMode.P8023dj, unit_amp: bool = False
137
145
  ) -> tuple[Rvec, Rvec, Rvec]:
138
146
  """
139
- Optimize FFE tap weights, via _Pulse Response Zero Forcing_ (PRZF).
147
+ Optimize FFE tap weights, via *Pulse Response Zero Forcing* (PRZF).
140
148
 
141
149
  Args:
142
150
  pulse_resp: The pulse response to be filtered.
@@ -151,20 +159,22 @@ def przf( # pylint: disable=too-many-arguments,too-many-positional-arguments,to
151
159
 
152
160
  Keyword Args:
153
161
  norm_mode: The tap weight normalization mode to use.
154
- Default: Unaltered
162
+ Default: ``P8023dj``
155
163
  unit_amp: Enforce unit pulse response amplitude when True.
156
- (For comparing results to `mmse()`.)
164
+ (For comparing results to ``mmse()``.)
157
165
  Default: False
158
166
 
159
167
  Returns:
160
- A triple consisting of:
161
- - FFE tap weights: The optimum FFE tap weights.
162
- - DFE tap weights: The optimum DFE tap weights.
163
- - pr_samps: The pulse response samples used in optimization.
168
+ A triple consisting of
169
+
170
+ - The optimum FFE tap weights.
171
+ - The optimum DFE tap weights.
172
+ - The pulse response samples used in optimization.
164
173
 
165
174
  Notes:
166
175
  1. The algorithm implemented below is a slightly modified version of:
167
- Mellitz, R., Lusted, K., "RX FFE Implementation Algorithm for COM 4.1",
176
+
177
+ Mellitz, R., Lusted, K., *RX FFE Implementation Algorithm for COM 4.1*,
168
178
  IEEE P802.3dj Task Force, August 31, 2023.
169
179
 
170
180
  ToDo:
@@ -241,7 +251,7 @@ def mmse( # pylint: disable=too-many-arguments,too-many-positional-arguments,to
241
251
  ts_sweep: float = 0.5, norm_mode: NormMode = NormMode.P8023dj
242
252
  ) -> dict[str, Any]:
243
253
  """
244
- Optimize Rx FFE tap weights, via **Minimum Mean Squared Error** (MMSE).
254
+ Optimize Rx FFE tap weights, via *Minimum Mean Squared Error* (MMSE).
245
255
 
246
256
  Args:
247
257
  theNoiseCalc: Initialized instance of ``NoiseCalc`` class.
@@ -257,25 +267,27 @@ def mmse( # pylint: disable=too-many-arguments,too-many-positional-arguments,to
257
267
 
258
268
  Keyword Args:
259
269
  ts_sweep: The cursor sampling time "search radius" around the peak pulse response amplitude (UI).
260
- Default: 0.5 (i.e. - `ts` within [-UI/2, +UI/2] of peak location)
270
+ Default: 0.5 (i.e. - ``ts`` within [-UI/2, +UI/2] of peak location)
261
271
  norm_mode: The tap weight normalization mode to use.
262
- Default: Unaltered
272
+ Default: ``P8023dj``
263
273
 
264
274
  Returns:
265
- A dictionary containing:
266
- - the optimized FFE tap weights, in the "rx_taps" key,
267
- - the optimized DFE tap weights, in the "dfe_tap_weights" key, and
268
- - several other values of general utility for plotting/analysis/debugging.
275
+ A dictionary containing
276
+
277
+ * the optimized FFE tap weights, in the "rx_taps" key,
278
+ * the optimized DFE tap weights, in the "dfe_tap_weights" key, and
279
+ * several other values of general utility for plotting/analysis/debugging.
269
280
 
270
281
  Raises:
271
- ValueError if:
272
- - `dw` > `Nw`, or
273
- - there is insufficient room at the beginning/end of the pulse response vector, for `ts` sweeping.
282
+ ValueError: If ``dw`` > ``Nw``, or there is insufficient room at the beginning/end \
283
+ of the pulse response vector for ``ts`` sweeping.
274
284
 
275
285
  Notes:
276
- 1. The optimization technique encoded here is taken from the following references:
277
- [1] Healey, A., Hegde, R., **Reference receiver framework for 200G/lane electrical interfaces and PHYs**,
278
- IEEE P802.3dj Task Force, Jan. 2024
286
+ 1. The optimization technique encoded here is taken from the following references
287
+
288
+ [1] Healey, A., Hegde, R., *Reference receiver framework for 200G/lane electrical interfaces and PHYs*,
289
+ IEEE P802.3dj Task Force, Jan. 2024
290
+
279
291
  [2] D1.2 of P802.3dj, IEEE P802.3dj Task Force, Aug. 2024
280
292
  """
281
293
 
@@ -3,7 +3,7 @@ Filtering utilities for PyChOpMarg.
3
3
 
4
4
  Original author: David Banas <capn.freako@gmail.com>
5
5
 
6
- Original date: March 3, 2024 (Copied from `pybert.utility`.)
6
+ Original date: March 3, 2024
7
7
 
8
8
  Copyright (c) 2024 David Banas; all rights reserved World wide.
9
9
  """
@@ -26,19 +26,16 @@ def calc_Hctle( # pylint: disable=too-many-arguments,too-many-positional-argume
26
26
  according to (93A-22).
27
27
 
28
28
  Args:
29
- f: Frequencies at which to calculate `Hctle(f)` (Hz).
29
+ f: Frequencies at which to calculate ``Hctle`` (Hz).
30
30
  fz: First stage zero frequency (Hz).
31
31
  fp1: First stage lower pole frequency (Hz).
32
32
  fp2: First stage upper pole frequency (Hz).
33
33
  fLF: Second stage pole/zero frequency (Hz).
34
- gDC: CTLE first stage d.c. gain (dB).
35
- gDC2: CTLE second stage d.c. gain (dB).
34
+ gDC: First stage d.c. gain (dB).
35
+ gDC2: Second stage d.c. gain (dB).
36
36
 
37
37
  Returns:
38
38
  The complex voltage transfer function, H(f), for the CTLE.
39
-
40
- Raises:
41
- None
42
39
  """
43
40
  g1 = from_dB(gDC)
44
41
  g2 = from_dB(gDC2)
@@ -56,20 +53,17 @@ def calc_Hffe(
56
53
  Calculate the voltage transfer function, H(f), for a digital FFE, according to (93A-21).
57
54
 
58
55
  Args:
59
- freqs: Frequencies at which to calculate `Hffe` (Hz).
56
+ freqs: Frequencies at which to calculate ``Hffe`` (Hz).
60
57
  td: Tap delay time (s).
61
58
  tap_weights: The filter tap weights.
62
59
  n_post: The number of post-cursor taps.
63
60
 
64
61
  Keyword Args:
65
- hasCurs: `tap_weights` includes the cursor tap weight when True.
62
+ hasCurs: ``tap_weights`` includes the cursor tap weight when True.
66
63
  Default: False (Cursor tap weight will be calculated.)
67
64
 
68
65
  Returns:
69
66
  The complex voltage transfer function, H(f), for the FFE.
70
-
71
- Raises:
72
- None
73
67
  """
74
68
 
75
69
  bs = list(np.array(tap_weights).flatten())
@@ -82,10 +76,10 @@ def calc_Hffe(
82
76
 
83
77
  def calc_Hdfe(freqs: Rvec, td: float, tap_weights: Rvec) -> Cvec:
84
78
  """
85
- Calculate the voltage transfer function, H(f), for a _Decision Feedback Equalizer_ (DFE).
79
+ Calculate the voltage transfer function, H(f), for a *Decision Feedback Equalizer* (DFE).
86
80
 
87
81
  Args:
88
- freqs: Frequencies at which to calculate `Hdfe` (Hz).
82
+ freqs: Frequencies at which to calculate ``Hdfe`` (Hz).
89
83
  td: Tap delay time (s).
90
84
  tap_weights: The vector of filter tap weights.
91
85
 
@@ -100,7 +94,7 @@ def calc_Hdfe(freqs: Rvec, td: float, tap_weights: Rvec) -> Cvec:
100
94
 
101
95
  def null_filter(nTaps: int, nPreTaps: int = 0) -> Rvec:
102
96
  """
103
- Construct a null filter w/ `nTaps` taps and (optionally) `nPreTaps` pre-cursor taps.
97
+ Construct a null filter w/ ``nTaps`` taps and (optionally) ``nPreTaps`` pre-cursor taps.
104
98
 
105
99
  Args:
106
100
  nTaps: Total number of taps, including the cursor tap.
@@ -110,7 +104,7 @@ def null_filter(nTaps: int, nPreTaps: int = 0) -> Rvec:
110
104
  Default: 0
111
105
 
112
106
  Returns:
113
- taps: The filter tap weight vector, including the cursor tap weight.
107
+ The filter tap weight vector, including the cursor tap weight.
114
108
  """
115
109
 
116
110
  assert nTaps > 0, ValueError(
@@ -3,7 +3,7 @@ General purpose utilities for PyChOpMarg.
3
3
 
4
4
  Original author: David Banas <capn.freako@gmail.com>
5
5
 
6
- Original date: March 3, 2024 (Copied from `pybert.utility`.)
6
+ Original date: March 3, 2024
7
7
 
8
8
  Copyright (c) 2024 David Banas; all rights reserved World wide.
9
9
  """
@@ -43,7 +43,7 @@ def mk_combs(trips: list[tuple[float, float, float]]) -> list[list[float]]:
43
43
  trips: A list of "(min, max, step)" triples, one per weight.
44
44
 
45
45
  Returns:
46
- combs: A list of lists of tap weights, including all possible combinations.
46
+ A list of lists of tap weights, including all possible combinations.
47
47
  """
48
48
  ranges = []
49
49
  for trip in trips:
@@ -56,28 +56,30 @@ def mk_combs(trips: list[tuple[float, float, float]]) -> list[list[float]]:
56
56
 
57
57
  def from_irfft(x: Rvec, t_irfft: Rvec, t: Rvec, nspui: int) -> Rvec:
58
58
  """
59
- Interpolate `irfft()` output to `t` and subsample at fBaud.
59
+ Interpolate ``irfft()`` output to ``t`` and subsample at fBaud.
60
60
 
61
61
  Args:
62
- x: `irfft()` results to be interpolated and subsampled.
63
- t_irfft: Time index vector for `x`.
64
- t: Desired new time index vector (same units as `t_irfft`).
65
- nspui: Number of samples per unit interval.
62
+ x: ``irfft()`` results to be interpolated and subsampled.
63
+ t_irfft: Time index vector for ``x``.
64
+ t: Desired new time index vector (same units as ``t_irfft``).
65
+ nspui: Number of samples per unit interval in ``t``.
66
66
 
67
67
  Returns:
68
- y: interpolated and subsampled vector.
68
+ Interpolated and subsampled vector.
69
69
 
70
70
  Raises:
71
- IndexError: If length of input doesn't match length of `t_irfft` vector.
71
+ IndexError: If length of input doesn't match length of ``t_irfft`` vector.
72
72
 
73
73
  Notes:
74
- 1. Input vector is shifted, such that its peak occurs at `0.1 * max(t)`, before interpolating.
75
- This is done to:
76
- - ensure that we don't omit any non-causal behavior,
77
- which ends up at the end of an IFFT output vector
78
- when the peak is very near the beginning, and
79
- - to ensure that the majority of our available time span
80
- is available for capturing reflections.
74
+ 1. Input vector is shifted, such that its peak occurs at ``0.1 * max(t)``, before interpolating.
75
+ This is done to:
76
+
77
+ - ensure that we don't omit any non-causal behavior,
78
+ which ends up at the end of an IFFT output vector
79
+ when the peak is very near the beginning, and
80
+ - to ensure that the majority of our available time span
81
+ is available for capturing reflections.
82
+
81
83
  2. The sub-sampling phase is adjusted, so as to ensure that we catch the peak.
82
84
  """
83
85
 
@@ -3,7 +3,7 @@ Statistical utilities for PyChOpMarg.
3
3
 
4
4
  Original author: David Banas <capn.freako@gmail.com>
5
5
 
6
- Original date: March 3, 2024 (Copied from `pybert.utility`.)
6
+ Original date: March 3, 2024
7
7
 
8
8
  Copyright (c) 2024 David Banas; all rights reserved World wide.
9
9
  """
@@ -28,7 +28,7 @@ def filt_pr_samps(pr_samps: Rvec, As: float, rel_thresh: float = 0.001) -> Rvec:
28
28
  Default: 0.001 (i.e. - 0.1%, as per Note 2 of 93A.1.7.1)
29
29
 
30
30
  Returns:
31
- The subset of `pr_samps` passing filtration.
31
+ The subset of ``pr_samps`` passing filtration.
32
32
  """
33
33
  thresh = As * rel_thresh
34
34
  return np.array(list(filter(lambda x: abs(x) >= thresh, pr_samps)))
@@ -58,19 +58,20 @@ def delta_pmf( # pylint: disable=too-many-arguments,too-many-positional-argumen
58
58
  Default: None
59
59
 
60
60
  Returns:
61
- A pair consisting of:
62
- - the voltages corresponding to the bins, and
63
- - their probabilities.
61
+ A pair consisting of
62
+
63
+ - the voltages corresponding to the bins, and
64
+ - their probabilities.
64
65
 
65
66
  Raises:
66
- `ValueError` if the given pulse response contains any NaNs.
67
- `ValueError` if a needed shift exceeds half the result vector length.
67
+ ValueError: If the given pulse response contains any NaNs.
68
+ ValueError: If a needed shift exceeds half the result vector length.
68
69
 
69
70
  Notes:
70
71
  1. The input set of pulse response samples is filtered,
71
- as per Note 2 of 93A.1.7.1, unless a y-values override
72
- vector is provided, in which case it is assumed that
73
- the caller has already done the filtering.
72
+ as per Note 2 of 93A.1.7.1, unless a y-values override
73
+ vector is provided, in which case it is assumed that
74
+ the caller has already done the filtering.
74
75
  """
75
76
 
76
77
  assert not any(np.isnan(h_samps)), ValueError(
@@ -3,7 +3,7 @@ S-parameter utilities for PyChOpMarg.
3
3
 
4
4
  Original author: David Banas <capn.freako@gmail.com>
5
5
 
6
- Original date: March 3, 2024 (Copied from `pybert.utility`.)
6
+ Original date: March 3, 2024
7
7
 
8
8
  Copyright (c) 2024 David Banas; all rights reserved World wide.
9
9
  """
@@ -27,7 +27,7 @@ def sdd_21(ntwk: rf.Network, norm: float = 0.5, renumber: bool = False) -> rf.Ne
27
27
 
28
28
  Keyword Args:
29
29
  norm: Normalization factor. (Default = 0.5)
30
- renumber: Automatically detect correct through path when True.
30
+ renumber: Automatically detect and correct through path when True.
31
31
  Default: False
32
32
 
33
33
  Returns:
@@ -43,22 +43,27 @@ def sdd_21(ntwk: rf.Network, norm: float = 0.5, renumber: bool = False) -> rf.Ne
43
43
 
44
44
  def se2mm(ntwk: rf.Network, norm: float = 0.5, renumber: bool = False) -> rf.Network:
45
45
  """
46
- Given a 4-port single-ended network, return its mixed mode equivalent.
46
+ Given a 4-port single-ended network,
47
+ return its mixed mode equivalent in the following format:
48
+
49
+ .. math::
50
+ \\begin{bmatrix}
51
+ Sdd11 & Sdd12 & Sdc11 & Sdc12 \\\\
52
+ Sdd21 & Sdd22 & Sdc21 & Sdc22 \\\\
53
+ Scd11 & Scd12 & Scc11 & Scc12 \\\\
54
+ Scd21 & Scd22 & Scc21 & Scc22
55
+ \\end{bmatrix}
47
56
 
48
57
  Args:
49
58
  ntwk: 4-port single ended network.
50
59
 
51
60
  Keyword Args:
52
61
  norm: Normalization factor. (Default = 0.5)
53
- renumber: Automatically detect correct through path when True.
62
+ renumber: Automatically detect and correct through path when True.
54
63
  Default: False
55
64
 
56
65
  Returns:
57
- Mixed mode equivalent network, in the following format:
58
- Sdd11 Sdd12 Sdc11 Sdc12
59
- Sdd21 Sdd22 Sdc21 Sdc22
60
- Scd11 Scd12 Scc11 Scc12
61
- Scd21 Scd22 Scc21 Scc22
66
+ Mixed mode equivalent network.
62
67
 
63
68
  Notes:
64
69
  1. A "1->2/3->4" port ordering convention is assumed when `renumber` is False.
@@ -121,9 +126,10 @@ def import_s32p( # pylint: disable=too-many-locals
121
126
 
122
127
  Returns:
123
128
  List of 8 pairs, each consisting of:
129
+
124
130
  - a 2-port network representing a *differential* channel, and
125
131
  - the type of that channel, one of: 'THRU', 'NEXT', or 'FEXT.
126
- (First element is the victim and the only one of type 'THRU'.)
132
+ (First element is the victim and the only one of type 'THRU'.)
127
133
 
128
134
  Raises:
129
135
  ValueError: If Touchstone file is not 32-port.
@@ -132,7 +138,7 @@ def import_s32p( # pylint: disable=too-many-locals
132
138
  1. Input Touchstone file is assumed single-ended.
133
139
  2. The differential through and xtalk channels are returned.
134
140
  3. Port 2 of all returned channels correspond to the same physical circuit node,
135
- typically, the Rx input node.
141
+ typically, the Rx input node.
136
142
  """
137
143
 
138
144
  # Import and sanity check the Touchstone file.
@@ -197,8 +203,8 @@ def sCshunt(freqs: Rvec, c: float, r0: float = 50.0) -> rf.Network:
197
203
  Default: 50 Ohms.
198
204
 
199
205
  Returns:
200
- s2p: The network corresponding to a shunt capacitance, `c`,
201
- calculated at the given frequencies, `freqs`.
206
+ The network corresponding to a shunt capacitance, ``c``,
207
+ calculated at the given frequencies, ``freqs``.
202
208
  """
203
209
  w = TWOPI * np.array(freqs)
204
210
  s = 1j * w
@@ -221,8 +227,8 @@ def sLseries(freqs: Rvec, inductance: float, r0: float = 50.0) -> rf.Network:
221
227
  Default: 50 Ohms.
222
228
 
223
229
  Returns:
224
- s2p: The network corresponding to a series inductance, `inductance`,
225
- calculated at the given frequencies, `freqs`.
230
+ The network corresponding to a series inductance, ``inductance``,
231
+ calculated at the given frequencies, ``freqs``.
226
232
  """
227
233
  w = TWOPI * np.array(freqs)
228
234
  s = 1j * w
@@ -242,12 +248,13 @@ def sDieLadderSegment(freqs: Rvec, trip: tuple[float, float, float]) -> rf.Netwo
242
248
  Args:
243
249
  f: List of frequencies to use for network creation (Hz).
244
250
  trip: Triple containing:
251
+
245
252
  - R0: Reference impedance for network (Ohms).
246
253
  - Cd: Shunt capacitance (F).
247
254
  - Ls: Series inductance (H).
248
255
 
249
256
  Returns:
250
- s2p: Two port network for segment.
257
+ Two port network for segment.
251
258
  """
252
259
  R0, Cd, Ls = trip
253
260
  return sCshunt(freqs, Cd, r0=R0) ** sLseries(freqs, Ls, r0=R0)
@@ -269,6 +276,7 @@ def sPkgTline( # pylint: disable=too-many-arguments,too-many-positional-argumen
269
276
  tau: Propagation delay (ns/mm).
270
277
  gamma0: Propagation loss constant (1/mm).
271
278
  z_pairs: List of pairs defining the T-line segments, each containing:
279
+
272
280
  - zc: Characteristic impedance of segment (Ohms).
273
281
  - zp: Length of segment (mm).
274
282
 
@@ -297,6 +305,7 @@ def sPkgTline( # pylint: disable=too-many-arguments,too-many-positional-argumen
297
305
 
298
306
  Args:
299
307
  z_pair: Pair consisting of:
308
+
300
309
  - zc: Characteristic impedance of leg (Ohms).
301
310
  - zp: Length of leg (mm).
302
311
 
File without changes
File without changes
File without changes