paramrf 0.36.4__tar.gz → 0.36.6__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 (262) hide show
  1. {paramrf-0.36.4 → paramrf-0.36.6}/CONTEXT.md +105 -1
  2. {paramrf-0.36.4/paramrf.egg-info → paramrf-0.36.6}/PKG-INFO +2 -2
  3. {paramrf-0.36.4 → paramrf-0.36.6}/docs/adr/0002-parameter-api.md +13 -0
  4. {paramrf-0.36.4 → paramrf-0.36.6}/docs/adr/0005-priors-by-name.md +54 -3
  5. {paramrf-0.36.4 → paramrf-0.36.6}/docs/adr/0007-edge-values.md +61 -1
  6. paramrf-0.36.6/docs/examples/discrepancy_prediction.rst +77 -0
  7. {paramrf-0.36.4 → paramrf-0.36.6}/docs/examples/index.rst +2 -0
  8. paramrf-0.36.6/docs/examples/port_discrepancy.py +409 -0
  9. paramrf-0.36.6/docs/examples/port_discrepancy.rst +53 -0
  10. {paramrf-0.36.4 → paramrf-0.36.6/paramrf.egg-info}/PKG-INFO +2 -2
  11. {paramrf-0.36.4 → paramrf-0.36.6}/paramrf.egg-info/SOURCES.txt +9 -0
  12. {paramrf-0.36.4 → paramrf-0.36.6}/paramrf.egg-info/requires.txt +1 -1
  13. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/_solver_view.py +48 -13
  14. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/covariance_kernels.py +52 -19
  15. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/discrepancy_models.py +136 -21
  16. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/evaluators.py +255 -9
  17. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/fitting/minimize.py +7 -0
  18. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/infer/base.py +15 -4
  19. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/likelihoods.py +34 -40
  20. paramrf-0.36.6/pmrf/linearization.py +198 -0
  21. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/__init__.py +5 -0
  22. paramrf-0.36.6/pmrf/models/port_discrepancy.py +175 -0
  23. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/modules/wrapped.py +14 -0
  24. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/optimize/base.py +6 -2
  25. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/optimize/minimize.py +6 -0
  26. paramrf-0.36.6/pmrf/optimize/solvers/scipy.py +236 -0
  27. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/parameters.py +320 -82
  28. {paramrf-0.36.4 → paramrf-0.36.6}/pyproject.toml +2 -2
  29. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_box_space_solving.py +6 -4
  30. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_covariance_kernels.py +20 -0
  31. paramrf-0.36.6/tests/test_discrepancy_models.py +248 -0
  32. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_evaluators.py +230 -14
  33. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_fitting_minimize.py +115 -2
  34. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_infer_base.py +42 -1
  35. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_infer_sample.py +38 -3
  36. paramrf-0.36.6/tests/test_linearization.py +417 -0
  37. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_models/test_derived.py +12 -2
  38. paramrf-0.36.6/tests/test_models/test_port_discrepancy.py +144 -0
  39. paramrf-0.36.6/tests/test_optimize_minimize.py +374 -0
  40. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_parameters.py +94 -0
  41. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_parameters_joint_prior.py +529 -9
  42. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_parameters_validity.py +11 -0
  43. paramrf-0.36.6/tests/test_port_discrepancy_example.py +70 -0
  44. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_raw_space_solving.py +93 -1
  45. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_structural_updates.py +10 -0
  46. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_terms.py +3 -1
  47. paramrf-0.36.4/pmrf/optimize/solvers/scipy.py +0 -172
  48. paramrf-0.36.4/tests/test_optimize_minimize.py +0 -118
  49. {paramrf-0.36.4 → paramrf-0.36.6}/.github/workflows/docs.yml +0 -0
  50. {paramrf-0.36.4 → paramrf-0.36.6}/.github/workflows/draft-pdf.yml +0 -0
  51. {paramrf-0.36.4 → paramrf-0.36.6}/.github/workflows/publish.yml +0 -0
  52. {paramrf-0.36.4 → paramrf-0.36.6}/.github/workflows/tests.yml +0 -0
  53. {paramrf-0.36.4 → paramrf-0.36.6}/.gitignore +0 -0
  54. {paramrf-0.36.4 → paramrf-0.36.6}/AGENTS.md +0 -0
  55. {paramrf-0.36.4 → paramrf-0.36.6}/CHANGELOG.md +0 -0
  56. {paramrf-0.36.4 → paramrf-0.36.6}/CITATION.cff +0 -0
  57. {paramrf-0.36.4 → paramrf-0.36.6}/CLAUDE.md +0 -0
  58. {paramrf-0.36.4 → paramrf-0.36.6}/CONTRIBUTING.md +0 -0
  59. {paramrf-0.36.4 → paramrf-0.36.6}/LICENSE +0 -0
  60. {paramrf-0.36.4 → paramrf-0.36.6}/NOTICE +0 -0
  61. {paramrf-0.36.4 → paramrf-0.36.6}/README.rst +0 -0
  62. {paramrf-0.36.4 → paramrf-0.36.6}/assets/logo.png +0 -0
  63. {paramrf-0.36.4 → paramrf-0.36.6}/docs/Makefile +0 -0
  64. {paramrf-0.36.4 → paramrf-0.36.6}/docs/_static/custom.css +0 -0
  65. {paramrf-0.36.4 → paramrf-0.36.6}/docs/_templates/autosummary/class.rst +0 -0
  66. {paramrf-0.36.4 → paramrf-0.36.6}/docs/_templates/autosummary/function.rst +0 -0
  67. {paramrf-0.36.4 → paramrf-0.36.6}/docs/_templates/autosummary/module.rst +0 -0
  68. {paramrf-0.36.4 → paramrf-0.36.6}/docs/adr/0001-line-modelling-architecture.md +0 -0
  69. {paramrf-0.36.4 → paramrf-0.36.6}/docs/adr/0003-derived-models.md +0 -0
  70. {paramrf-0.36.4 → paramrf-0.36.6}/docs/adr/0004-profiled-lines.md +0 -0
  71. {paramrf-0.36.4 → paramrf-0.36.6}/docs/adr/0006-reference-impedance.md +0 -0
  72. {paramrf-0.36.4 → paramrf-0.36.6}/docs/agents/domain.md +0 -0
  73. {paramrf-0.36.4 → paramrf-0.36.6}/docs/agents/issue-tracker.md +0 -0
  74. {paramrf-0.36.4 → paramrf-0.36.6}/docs/agents/triage-labels.md +0 -0
  75. {paramrf-0.36.4 → paramrf-0.36.6}/docs/api/index.rst +0 -0
  76. {paramrf-0.36.4 → paramrf-0.36.6}/docs/conf.py +0 -0
  77. {paramrf-0.36.4 → paramrf-0.36.6}/docs/core_concepts/core_primitives.rst +0 -0
  78. {paramrf-0.36.4 → paramrf-0.36.6}/docs/core_concepts/index.rst +0 -0
  79. {paramrf-0.36.4 → paramrf-0.36.6}/docs/core_concepts/jax_overview.rst +0 -0
  80. {paramrf-0.36.4 → paramrf-0.36.6}/docs/core_concepts/optimization_and_inference.rst +0 -0
  81. {paramrf-0.36.4 → paramrf-0.36.6}/docs/core_concepts/parameter_names.rst +0 -0
  82. {paramrf-0.36.4 → paramrf-0.36.6}/docs/examples/cascading_and_terminating.rst +0 -0
  83. {paramrf-0.36.4 → paramrf-0.36.6}/docs/examples/circuit_clc.png +0 -0
  84. {paramrf-0.36.4 → paramrf-0.36.6}/docs/examples/circuit_models.rst +0 -0
  85. {paramrf-0.36.4 → paramrf-0.36.6}/docs/examples/custom_models.rst +0 -0
  86. {paramrf-0.36.4 → paramrf-0.36.6}/docs/examples/derivatives_and_sweeps.rst +0 -0
  87. {paramrf-0.36.4 → paramrf-0.36.6}/docs/examples/model_optimization.rst +0 -0
  88. {paramrf-0.36.4 → paramrf-0.36.6}/docs/examples/multiple_models_one_parameter_set.rst +0 -0
  89. {paramrf-0.36.4 → paramrf-0.36.6}/docs/examples/parameter_naming_and_model_manipulation.rst +0 -0
  90. {paramrf-0.36.4 → paramrf-0.36.6}/docs/examples/shared_substrates.rst +0 -0
  91. {paramrf-0.36.4 → paramrf-0.36.6}/docs/index.rst +0 -0
  92. {paramrf-0.36.4 → paramrf-0.36.6}/docs/license.rst +0 -0
  93. {paramrf-0.36.4 → paramrf-0.36.6}/docs/make.bat +0 -0
  94. {paramrf-0.36.4 → paramrf-0.36.6}/docs/research/conductor-loss-alternatives.md +0 -0
  95. {paramrf-0.36.4 → paramrf-0.36.6}/docs/research/holloway1994.pdf +0 -0
  96. {paramrf-0.36.4 → paramrf-0.36.6}/docs/research/microstrip-loss-conventions.md +0 -0
  97. {paramrf-0.36.4 → paramrf-0.36.6}/docs/research/precision-coax-microstrip-10-500mhz.md +0 -0
  98. {paramrf-0.36.4 → paramrf-0.36.6}/docs/skrf_comparison/index.rst +0 -0
  99. {paramrf-0.36.4 → paramrf-0.36.6}/docs/skrf_comparison/overview.rst +0 -0
  100. {paramrf-0.36.4 → paramrf-0.36.6}/docs/skrf_comparison/performance.rst +0 -0
  101. {paramrf-0.36.4 → paramrf-0.36.6}/docs/tutorials/1_cable_fitting.ipynb +0 -0
  102. {paramrf-0.36.4 → paramrf-0.36.6}/docs/tutorials/2_chip_inductor_fitting.ipynb +0 -0
  103. {paramrf-0.36.4 → paramrf-0.36.6}/docs/tutorials/data/CBN-1.5FT-SMSM.s2p +0 -0
  104. {paramrf-0.36.4 → paramrf-0.36.6}/docs/tutorials/data/on-chip-inductor.s2p +0 -0
  105. {paramrf-0.36.4 → paramrf-0.36.6}/docs/tutorials/index.rst +0 -0
  106. {paramrf-0.36.4 → paramrf-0.36.6}/paper/paper.bib +0 -0
  107. {paramrf-0.36.4 → paramrf-0.36.6}/paper/paper.md +0 -0
  108. {paramrf-0.36.4 → paramrf-0.36.6}/paper/rlc.png +0 -0
  109. {paramrf-0.36.4 → paramrf-0.36.6}/paramrf.egg-info/dependency_links.txt +0 -0
  110. {paramrf-0.36.4 → paramrf-0.36.6}/paramrf.egg-info/top_level.txt +0 -0
  111. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/__init__.py +0 -0
  112. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/bijectors.py +0 -0
  113. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/constraints.py +0 -0
  114. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/distributions.py +0 -0
  115. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/fitting/__init__.py +0 -0
  116. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/fitting/result.py +0 -0
  117. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/fitting/routers.py +0 -0
  118. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/fitting/sample.py +0 -0
  119. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/fitting/targets.py +0 -0
  120. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/frequency.py +0 -0
  121. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/infer/__init__.py +0 -0
  122. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/infer/result.py +0 -0
  123. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/infer/sample.py +0 -0
  124. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/infer/solvers/__init__.py +0 -0
  125. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/infer/solvers/blackjax.py +0 -0
  126. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/infer/solvers/polychord.py +0 -0
  127. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/losses.py +0 -0
  128. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/materials/__init__.py +0 -0
  129. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/materials/conductor.py +0 -0
  130. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/materials/dielectric.py +0 -0
  131. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/materials/properties.py +0 -0
  132. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/materials/roughness.py +0 -0
  133. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/materials/substrate.py +0 -0
  134. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/materials/surface_impedance.py +0 -0
  135. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/math/__init__.py +0 -0
  136. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/math/aggregations.py +0 -0
  137. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/math/bessel.py +0 -0
  138. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/math/conversions.py +0 -0
  139. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/math/losses.py +0 -0
  140. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/math/misc.py +0 -0
  141. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/adapters/__init__.py +0 -0
  142. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/adapters/base.py +0 -0
  143. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/adapters/bridge.py +0 -0
  144. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/adapters/callable.py +0 -0
  145. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/adapters/delegated.py +0 -0
  146. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/adapters/derived.py +0 -0
  147. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/adapters/static.py +0 -0
  148. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/adapters/wrapped.py +0 -0
  149. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/base.py +0 -0
  150. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/components/__init__.py +0 -0
  151. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/components/ideal.py +0 -0
  152. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/components/lines/__init__.py +0 -0
  153. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/components/lines/base.py +0 -0
  154. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/components/lines/coaxial.py +0 -0
  155. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/components/lines/empirical.py +0 -0
  156. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/components/lines/ideal.py +0 -0
  157. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/components/lines/microstrip.py +0 -0
  158. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/components/lines/nodal.py +0 -0
  159. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/components/lines/nonuniform.py +0 -0
  160. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/components/lines/planar.py +0 -0
  161. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/components/lines/profiles.py +0 -0
  162. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/components/lines/stripline.py +0 -0
  163. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/components/lumped.py +0 -0
  164. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/components/sections.py +0 -0
  165. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/composite/__init__.py +0 -0
  166. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/composite/interconnected/__init__.py +0 -0
  167. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/composite/interconnected/cascade.py +0 -0
  168. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/composite/interconnected/circuit/__init__.py +0 -0
  169. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/composite/interconnected/circuit/base.py +0 -0
  170. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/composite/interconnected/circuit/circuit.py +0 -0
  171. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/composite/interconnected/circuit/solvers/__init__.py +0 -0
  172. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/composite/interconnected/circuit/solvers/nodal.py +0 -0
  173. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/composite/interconnected/circuit/solvers/scattering.py +0 -0
  174. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/composite/interconnected/terminated.py +0 -0
  175. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/composite/nodal.py +0 -0
  176. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/composite/topological.py +0 -0
  177. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/composite/transformed.py +0 -0
  178. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/surrogates/__init__.py +0 -0
  179. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/surrogates/expansion.py +0 -0
  180. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/models/surrogates/rational.py +0 -0
  181. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/modules/__init__.py +0 -0
  182. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/modules/base.py +0 -0
  183. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/network_collection.py +0 -0
  184. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/noise_models.py +0 -0
  185. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/optimize/__init__.py +0 -0
  186. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/optimize/result.py +0 -0
  187. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/optimize/solvers/__init__.py +0 -0
  188. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/optimize/solvers/jaxopt.py +0 -0
  189. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/optimize/solvers/optimistix.py +0 -0
  190. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/problems.py +0 -0
  191. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/rf/__init__.py +0 -0
  192. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/rf/cascade.py +0 -0
  193. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/rf/conversions.py +0 -0
  194. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/rf/mna.py +0 -0
  195. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/serialization.py +0 -0
  196. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/terms.py +0 -0
  197. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/types.py +0 -0
  198. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/utils/__init__.py +0 -0
  199. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/utils/array.py +0 -0
  200. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/utils/debug.py +0 -0
  201. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/utils/network.py +0 -0
  202. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/utils/random.py +0 -0
  203. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/utils/rf.py +0 -0
  204. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/utils/transforms.py +0 -0
  205. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/utils/tree.py +0 -0
  206. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/utils/type.py +0 -0
  207. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/viz/__init__.py +0 -0
  208. {paramrf-0.36.4 → paramrf-0.36.6}/pmrf/viz/plots.py +0 -0
  209. {paramrf-0.36.4 → paramrf-0.36.6}/scripts/benchmark_gp_marginal_likelihood.py +0 -0
  210. {paramrf-0.36.4 → paramrf-0.36.6}/scripts/install-test-deps.sh +0 -0
  211. {paramrf-0.36.4 → paramrf-0.36.6}/setup.cfg +0 -0
  212. {paramrf-0.36.4 → paramrf-0.36.6}/tests/__init__.py +0 -0
  213. {paramrf-0.36.4 → paramrf-0.36.6}/tests/_jit.py +0 -0
  214. {paramrf-0.36.4 → paramrf-0.36.6}/tests/conftest.py +0 -0
  215. {paramrf-0.36.4 → paramrf-0.36.6}/tests/data/10m_cable.s2p +0 -0
  216. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_autodiff.py +0 -0
  217. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_conversions.py +0 -0
  218. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_dc_limits.py +0 -0
  219. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_fitting_routers.py +0 -0
  220. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_fitting_sample.py +0 -0
  221. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_fitting_targets.py +0 -0
  222. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_frequency.py +0 -0
  223. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_map_priors.py +0 -0
  224. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_materials/test_conductor.py +0 -0
  225. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_materials/test_dielectric.py +0 -0
  226. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_materials/test_serialization.py +0 -0
  227. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_materials/test_substrate.py +0 -0
  228. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_materials/test_surface_impedance.py +0 -0
  229. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_math/test_bessel.py +0 -0
  230. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_model.py +0 -0
  231. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_models/test_adapters.py +0 -0
  232. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_models/test_cascade.py +0 -0
  233. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_models/test_circuit_native_z0.py +0 -0
  234. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_models/test_circuit_nodal.py +0 -0
  235. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_models/test_circuit_port_order.py +0 -0
  236. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_models/test_circuit_scattering.py +0 -0
  237. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_models/test_circuit_shorted_ports.py +0 -0
  238. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_models/test_circuit_skrf_port_names.py +0 -0
  239. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_models/test_circuit_z0.py +0 -0
  240. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_models/test_current_distribution.py +0 -0
  241. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_models/test_edge_values.py +0 -0
  242. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_models/test_interconnected.py +0 -0
  243. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_models/test_lines.py +0 -0
  244. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_models/test_lines_skrf_matrix.py +0 -0
  245. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_models/test_lumped.py +0 -0
  246. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_models/test_nodal.py +0 -0
  247. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_models/test_profiles.py +0 -0
  248. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_models/test_rational.py +0 -0
  249. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_models/test_repeated_cascade.py +0 -0
  250. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_models/test_sections.py +0 -0
  251. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_models/test_transformed.py +0 -0
  252. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_models/test_transformers.py +0 -0
  253. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_module.py +0 -0
  254. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_naming.py +0 -0
  255. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_optimize_base.py +0 -0
  256. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_parameters_by_name.py +0 -0
  257. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_parameters_prior.py +0 -0
  258. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_serialization.py +0 -0
  259. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_transforms.py +0 -0
  260. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_utils/test_compress.py +0 -0
  261. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_utils/test_debug.py +0 -0
  262. {paramrf-0.36.4 → paramrf-0.36.6}/tests/test_utils/test_tree.py +0 -0
@@ -98,7 +98,9 @@ is derived, so it has no prior of its own.
98
98
 
99
99
  `prf.prior` attaches a prior to the parameters a selector picks (ADR-0005). A
100
100
  scalar distribution gives each of them its own prior. A distribution whose
101
- event size equals the number of parameters is a **joint prior** over them: a
101
+ event size equals the parameters' total size (their number, when they are
102
+ scalars; an array parameter counts each of its values) is a **joint prior** over
103
+ them: a
102
104
  wrapper (`prf.modules.Probabilistic`) around the unchanged tree, so every
103
105
  parameter keeps its name. A joint prior replaces its parameters' own priors,
104
106
  and its `space` says which space its distribution is over. Raw space for its
@@ -170,6 +172,108 @@ Modifies conductor behaviour rather than line state — it scales a surface
170
172
  impedance — so it belongs to the material, not the geometry: it is a field of
171
173
  `RoughConductor` in `pmrf.materials.conductor`.
172
174
 
175
+ ## Discrepancy modelling
176
+
177
+ A fit in Kennedy–O'Hagan form treats an observation as $\tilde h = h(\theta) +
178
+ \delta + \varepsilon$: the model prediction, a **discrepancy** and measurement
179
+ noise. `MarginalLogLikelihood` scores it; see `pmrf.discrepancy_models` and
180
+ `pmrf.likelihoods`.
181
+
182
+ ### Event space and event block
183
+
184
+ The space in which probability is defined: the prediction after the event
185
+ transform, with frequency as the last (event) axis. Every other axis is a batch
186
+ axis. One entry of that batch, for example the real part of S21, is an **event
187
+ block**. Blocks are independent: a kernel chooses the covariance *within* each
188
+ block (`AutoCrossKernel` routes by block, `SharedIndependentKernel` shares
189
+ hyperparameters across blocks) and never couples two blocks.
190
+
191
+ *Avoid:* "output" or "task" for a block; "cross-covariance" for the kernel an
192
+ `AutoCrossKernel` gives a transmission block.
193
+
194
+ ### Discrepancy
195
+
196
+ $\delta$, the systematic misfit between model and reality, as opposed to noise
197
+ $\varepsilon$. Either deterministic or a `GaussianProcess` over each event block.
198
+ It is on the observable unless it is a port or internal discrepancy.
199
+
200
+ ### Residual
201
+
202
+ The observation minus the model prediction, in event space: $r = \tilde h -
203
+ h(\theta)$. It contains both discrepancy and noise.
204
+
205
+ ### Discrepancy prediction
206
+
207
+ The distribution of $\delta$ at new frequencies $x_B$, conditioned on residuals
208
+ at the fit frequencies $x_A$, per event block:
209
+ $\mu = K_{BA}(K_{AA}+\Sigma_n)^{-1} r$ and
210
+ $\Sigma = K_{BB} - K_{BA}(K_{AA}+\Sigma_n)^{-1}K_{AB}$. It excludes noise: it is
211
+ the discrepancy, not a predicted observation.
212
+
213
+ *Avoid:* "posterior predictive" (that includes noise); "discrepancy posterior"
214
+ (ambiguous with a posterior over hyperparameters).
215
+
216
+ ### Linearisation
217
+
218
+ A Gauss–Newton approximation of a fit at its MAP, with the discrepancy's
219
+ hyperparameters held fixed: the Jacobian $J = -\partial r / \partial \theta$ of the
220
+ residual with respect to the model's free parameters, and the Fisher matrix
221
+ $F = J^\top \Sigma_D^{-1} J$ with $\Sigma_D = K + \Sigma_n$ per event block. With
222
+ the prior precision $\Sigma_0^{-1}$ it gives the linearised posterior covariance
223
+ $\Sigma_\text{post} = (F + \Sigma_0^{-1})^{-1}$, over parameter values in one space
224
+ (declared by default). Fisher matrices of independent fits add.
225
+
226
+ ### Joint prediction
227
+
228
+ The Gaussian over the free parameters and the discrepancy at new frequencies
229
+ together, from a linearisation: unlike a discrepancy prediction, it carries the
230
+ parameters' uncertainty into $\delta$ and the cross-covariance between them. It is
231
+ the form in which one fit's posterior becomes the next fit's joint prior.
232
+
233
+ ### Port discrepancy
234
+
235
+ A discrepancy embedded at a component's ports, on its S-parameters rather than on
236
+ an observable: $\check S_{ii} = S_{ii} + \delta_{ii}$ for reflection and
237
+ $\check S_{ij} = S_{ij} e^{\delta_{ij}}$ for transmission. A circuit containing
238
+ the corrected component carries $\delta$ to any observable or quantity of
239
+ interest, so it transfers between fits that observe the component differently.
240
+ Transmission is split into a symmetric and an antisymmetric block,
241
+ $\delta_{ij} = \delta^s_{ij} \pm \delta^a_{ij}$; a reciprocal component has no
242
+ antisymmetric block. $\delta$ is defined at a reference impedance and is learnt
243
+ at that impedance.
244
+
245
+ When the component is observed directly, in an event space of the same form
246
+ (additive for reflection, logarithmic for transmission), the port discrepancy *is*
247
+ the event-space discrepancy, and is marginalised there: this is the **reference
248
+ fit**. A later fit with the component inside a larger circuit holds $\delta$ as
249
+ explicit parameters, under the reference fit's joint prediction as their prior:
250
+ this is a **transfer fit**.
251
+
252
+ *Avoid:* "embedded discrepancy" or "embedded model error" (in the literature
253
+ these embed the error in the parameters); "stage 1" and "stage 2" (say reference
254
+ fit and transfer fit).
255
+
256
+ ### Internal discrepancy
257
+
258
+ A discrepancy on a quantity inside a model rather than on its ports: for a
259
+ uniform line, its characteristic impedance, attenuation and phase constant,
260
+ $\check Z_c = Z_c e^{z}$, $\check\alpha = \alpha e^{a}$, $\check\beta = \beta e^{b}$.
261
+ The correction is log-relative and per unit length, so it is independent of the
262
+ line's length. A port discrepancy carries the whole instance's error and does
263
+ not transfer to another length; an internal discrepancy does, provided the
264
+ line's $\gamma L$ scales with its length. Choose the internal quantity by what
265
+ stays the same between the instances it must transfer across.
266
+
267
+ $\alpha$ and $\beta$ are corrected separately rather than by one complex factor
268
+ on $\gamma$, which would mix phase into loss because $\beta \gg \alpha$.
269
+
270
+ It is learnt in a reference fit either from reference internal quantities, in
271
+ an event space of the same log form, or from port observables alone, and is
272
+ carried into transfer fits as a port discrepancy is.
273
+
274
+ *Avoid:* "internal hook" (no general method interception exists; each
275
+ internal discrepancy corrects one typed quantity).
276
+
173
277
  ## Records at the boundaries
174
278
 
175
279
  These frozen records are the seams that keep `Param`s and `Module`s out of the
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: paramrf
3
- Version: 0.36.4
3
+ Version: 0.36.6
4
4
  Summary: Parametric radio frequency modeling
5
5
  Author-email: Gary Allen <gvcallen@gmail.com>
6
6
  Project-URL: homepage, https://github.com/gvcallen/paramrf
7
7
  Description-Content-Type: text/x-rst
8
8
  License-File: LICENSE
9
9
  License-File: NOTICE
10
- Requires-Dist: parax>=0.11.5
10
+ Requires-Dist: parax>=0.11.6
11
11
  Requires-Dist: threadpoolctl
12
12
  Requires-Dist: eqxpress
13
13
  Requires-Dist: jax
@@ -124,6 +124,19 @@ It replaces `with_values`, `with_free`, `with_fixed`, `Module.map`,
124
124
  - **Not an optimiser step.** In fitting, "updates" also means Optax gradient
125
125
  steps; the docstring says `update` is neither.
126
126
 
127
+ - **Numerical trials can opt out of raising on invalid parameter values.**
128
+ `update(..., on_invalid='raise')` remains strict by default. Numerical value
129
+ updates may opt into `on_invalid='nan'`, which marks the entire updated
130
+ parameter leaf NaN when its candidate is outside the effective constraint,
131
+ lies on an excluded open edge, or contains a nonfinite value. This gives
132
+ line searches and other numerical objectives a non-raising way to reject a
133
+ trial while keeping the parameter pytree structure and the other requested
134
+ values intact. The policy applies only to numerical value updates; structural
135
+ replacements and fixed-state changes remain outside it. Only parameter
136
+ validity failures become NaN: independent model errors keep their existing
137
+ behavior. NaN trials require a floating or complex leaf and do not promote
138
+ integer leaves.
139
+
127
140
  `prf.replace` stays as the plain `dataclasses.replace`: fields of one object,
128
141
  unvalidated, able to break a type. Its docstring points to `update` for
129
142
  anything name-based.
@@ -1,6 +1,7 @@
1
1
  # ADR-0005: Priors are attached by name, and a joint prior keeps its parameters
2
2
 
3
- Status: accepted (2026-09)
3
+ Status: accepted (2026-09); amended (2026-10) to allow array-valued parameters
4
+ under a joint prior, and to compute a constant whitening log-determinant once.
4
5
 
5
6
  ## Context
6
7
 
@@ -43,8 +44,8 @@ The distribution's event size decides which:
43
44
  `prf.Random`. Its raw space becomes the new prior's whitening, as for
44
45
  `prf.Random`, and the prior is truncated to the parameter's existing bounds so
45
46
  the bounds still hold.
46
- - **Event size equal to the number of selected parameters**: a **joint prior**
47
- over them.
47
+ - **Event size equal to the total size of the selected parameters**: a **joint
48
+ prior** over them. For scalar parameters the total size is their number.
48
49
  - Anything else raises.
49
50
 
50
51
  ### A joint prior keeps its parameters
@@ -63,6 +64,22 @@ transparent to the name resolver, as `Tied` is. So:
63
64
  would count the earlier fit's priors twice, since its posterior already
64
65
  includes them.
65
66
 
67
+ ### Array-valued parameters
68
+
69
+ A parameter under a joint prior may be an array, such as a port discrepancy's
70
+ values on a frequency grid. The distribution's vector is the selected parameters'
71
+ values, each flattened in C order, concatenated in name order. A parameter's own
72
+ shape is its declared shape: leading batch axes of a batched model stay batch
73
+ axes. Its raw value under the joint prior is its slice of the whitened vector,
74
+ reshaped to its shape, so it keeps one name however many values it holds.
75
+ Bounds are checked element by element, and fixing or tying the parameter raises,
76
+ as for a scalar.
77
+
78
+ The driving case is a port discrepancy (`CONTEXT.md`), whose values number
79
+ about $6 N_f$ for a reciprocal two-port, a few thousand. One parameter per value
80
+ would give it thousands of names and makes attaching and compiling the prior
81
+ slow (7 s and 52 s at 6000 scalars).
82
+
66
83
  ### Space
67
84
 
68
85
  `space` states the space the distribution is over: `'raw'`, `'declared'` or
@@ -109,6 +126,28 @@ whether a bound is the model's (validity, such as a positive width) or the
109
126
  user's (a range, such as `prf.Bounded`), so the check treats every bound as
110
127
  validity.
111
128
 
129
+ ### Explicit unnormalised truncation for inference
130
+
131
+ Declared- and physical-space joint priors may opt into `prior(...,
132
+ truncate='unnormalised')` when their support leaves a selected parameter's
133
+ validity. The distribution keeps its supplied density at every interior
134
+ validity point, and the attached prior contributes `-inf` outside validity;
135
+ ParamRF does not estimate or apply a truncation normaliser. The wrapper stores
136
+ this choice as static `normalised=False` metadata, which survives resolution,
137
+ updates, enclosing trees and supported serialization. The default remains
138
+ `truncate='normalised'` and retains the support-inside-validity check. Scalar
139
+ events and raw-space joint priors do not support unnormalised truncation.
140
+
141
+ This opt-in is for MAP, scoring, differentiation and posterior covariance.
142
+ Keeping the declared Gaussian density unchanged in the interior preserves its
143
+ gradient and precision, which are needed when transferring a local Gaussian
144
+ fit into a later linearised inference problem. It is not a probability
145
+ normalised over the valid region and cannot be used for sampling or evidence:
146
+ every public sampling path rejects an active unnormalised joint prior before
147
+ calling the sampler, with the affected parameter names in the error. This
148
+ includes direct sampling, `fit_sample`, joint samplers, split samplers and
149
+ hypercube samplers.
150
+
112
151
  ### Hypercube samplers
113
152
 
114
153
  A hypercube sampler maps the unit cube through a joint prior's block as
@@ -130,6 +169,14 @@ CDF.
130
169
  - `prf.resolve` keeps a joint prior, since it is not a tie and does not change
131
170
  what the parameters are. `prf.unwrap` drops it, as it drops every prior.
132
171
 
172
+ ### A constant whitening log-determinant
173
+
174
+ Scoring in raw space adds the log-determinant of the whitening. When the
175
+ whitening's Jacobian is constant, as for a multivariate normal, that term is a
176
+ constant: it is computed once, when the prior is attached, and held by the joint
177
+ prior. Recomputing it as a dense Jacobian and its determinant on every call cost
178
+ 15.7 s per evaluation at 6000 values.
179
+
133
180
  ## Rejected options
134
181
 
135
182
  - **Polishing the collapsing `Probabilistic`** (keeping the names of the
@@ -148,6 +195,10 @@ CDF.
148
195
  - **`Transformed.icdf` in distreqx.** It would not be an inverse CDF, and it would
149
196
  put ParamRF's sampler logic in another repository.
150
197
 
198
+ - **A separate Gaussian-prior node for large arrays** (for a port discrepancy).
199
+ It would be a second way to attach a joint prior, which this ADR removed, and a
200
+ flow or Gaussian posterior over any array parameter needs the same thing.
201
+
151
202
  ## Consequences
152
203
 
153
204
  - The old `Probabilistic` constructor (`target=`, `static=`, tuple targets) and
@@ -85,7 +85,9 @@ wrong for complex $Z_r$.
85
85
  - **Box space** is a fourth space: the box a bounded minimiser searches. It is
86
86
  built from a parameter's bounds, not its prior: the unit box when both bounds
87
87
  are finite, declared space otherwise. A closed edge of the box is the bound
88
- itself; an open edge is inset by δ = 1e-6.
88
+ itself. A finite open edge is inset by a dtype-aware relative distance based
89
+ on machine epsilon, the bound and the original start; infinite edges stay
90
+ infinite. The exact algorithm is recorded below.
89
91
  - **Minimisers say whether they honour bounds**, through the minimiser
90
92
  interface. `SolverView` hands box space to one that does and raw space to one
91
93
  that does not. Nothing in `SolverView` knows about a specific backend.
@@ -95,6 +97,64 @@ wrong for complex $Z_r$.
95
97
  is silent: it is the kind of difference engineers expect between optimisers.
96
98
  - **Raw space is unchanged.** It stays whitened by the prior (ADR-0005).
97
99
 
100
+ ### Open box edges preserve valid starts
101
+
102
+ For each finite open edge `b`, let `x0` be the original box-space start, `eps`
103
+ the dtype's machine epsilon and `tiny` its smallest positive normal value. The
104
+ inward distance is
105
+
106
+ `max(tiny, eps * max(abs(b), abs(x0 - b), tiny))`.
107
+
108
+ Add this distance at a lower edge and subtract it at an upper edge. If rounding
109
+ leaves the result on the excluded edge, move one representable value inward.
110
+ If the proposed inset would exclude an already valid interior start, use that
111
+ start as the search edge. A start exactly on an open edge is moved to the
112
+ resulting interior edge; construction still rejects a deliberately declared
113
+ invalid start. Keep infinite edges infinite. This preserves tiny positive
114
+ starts, avoids a fixed absolute inset and ensures `Positive` has a positive
115
+ normal-number search edge. Closed edges and raw-space closed-start nudging keep
116
+ their existing behavior.
117
+
118
+ ### Trust-constr uses fixed affine search coordinates
119
+
120
+ When bounds are supplied to SciPy `trust-constr` (case-insensitively), pass
121
+ feasible `Bounds` and use fixed affine coordinates. For flattened original box
122
+ start `x0`, choose each scale `s` as `upper - lower` for two finite bounds,
123
+ `abs(x0 - lower)` for lower-only, `abs(upper - x0)` for upper-only, and
124
+ `abs(x0)` for unbounded coordinates. Replace a zero or nonfinite scale by 1.
125
+ SciPy starts at `z0 = 0`, sees bounds `(lower - x0) / s` and
126
+ `(upper - x0) / s`, and evaluates the original objective at `x = x0 + s * z`.
127
+ Apply the affine chain rule to supplied gradients and convert the returned
128
+ coordinates to box space before rebuilding parameters. Scales stay fixed for
129
+ the solve.
130
+
131
+ Metrics retain SciPy's actual internal coordinates. Add `box_origin=x0` and
132
+ `box_scale=s` so callers can recover box coordinates from `metrics.x`; do not
133
+ partially rewrite derivative or multiplier fields. Other methods and calls
134
+ without supplied bounds keep their existing representations and coordinates.
135
+ This is private solver scaling, not a new public value space, and `SolverView`
136
+ continues to expose box space.
137
+
138
+ ### Nonfinite SciPy evaluations fail immediately
139
+
140
+ Before returning an objective value to SciPy, check the loss and each requested
141
+ gradient entry for finiteness; check a Hessian only when a callback is actually
142
+ passed. A nonfinite value raises `FloatingPointError` on that evaluation.
143
+ Include the method, one-based evaluation number, failing quantity and affected
144
+ free parameter names for a nonfinite gradient. A nonfinite loss may list the
145
+ available free names as context without attributing cause. Identify a
146
+ nonfinite attempted parameter vector separately. Diagnostics use the original
147
+ box or raw coordinates before private affine scaling, never the internal vector
148
+ as if it were box space. Direct low-level calls may identify positional
149
+ coordinates when names are unavailable.
150
+
151
+ Do not include parameter values, full model representations or distributions
152
+ in errors or logs. Synchronize deferred JAX results before checking. Public
153
+ minimize and Bayesian fit APIs propagate the exception rather than returning a
154
+ failed start point; close any progress bar on failure. Finite nonconvergence
155
+ still returns `success=False` with its existing warning, and unrelated user
156
+ exceptions retain their type and message.
157
+
98
158
  ## Rejected options
99
159
 
100
160
  - **Keep Y from the MNA solver and detect ill-conditioning.** Wrong answers get
@@ -0,0 +1,77 @@
1
+ Discrepancy Prediction
2
+ ======================
3
+
4
+ A fit with a Gaussian-process discrepancy learns how the model differs from the data, not just the model parameters. That discrepancy can be predicted at frequencies the fit never saw, with its uncertainty. In this example we fit the S11 of a 10 m coaxial line with a GP discrepancy, then predict the discrepancy off the fit grid.
5
+
6
+ Fitting with a Discrepancy
7
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
8
+
9
+ The measured S11 is a coaxial line plus a slow ripple that the model cannot produce, and a little measurement noise. We fit the dielectric constant, with a :class:`~pmrf.discrepancy_models.GaussianProcess` to absorb the ripple. Its kernel's length scale is in the fit frequency's unit, here MHz:
10
+
11
+ .. plot::
12
+ :context: reset
13
+ :include-source:
14
+ :nofigs:
15
+
16
+ import numpy as np
17
+ import pmrf as prf
18
+ from pmrf.models import CoaxialLine
19
+ from pmrf.materials import BulkConductor, ConstantDielectric
20
+ from pmrf.fitting import fit
21
+ from pmrf.likelihoods import GaussianLikelihood
22
+ from pmrf.discrepancy_models import GaussianProcess
23
+ from pmrf.covariance_kernels import Matern52Kernel
24
+
25
+ def coax(ep_r):
26
+ return CoaxialLine(
27
+ d_in=1.05e-3, d_out=3.2e-3,
28
+ dielectric=ConstantDielectric(ep_r=ep_r, tand=1e-3),
29
+ conductor=BulkConductor(sigma=1 / 1.7e-8),
30
+ length=10.0,
31
+ )
32
+
33
+ freq = prf.Frequency(10, 500, 100, 'MHz')
34
+ ripple = 0.01 * np.exp(2j * np.pi * freq.f_scaled / 150.0)
35
+ rng = np.random.default_rng(0)
36
+ noise = 1e-3 * (rng.normal(size=freq.npoints) + 1j * rng.normal(size=freq.npoints))
37
+ s11 = np.asarray(coax(1.40).s(freq)[:, 0, 0]) + ripple + noise
38
+
39
+ gp = GaussianProcess(
40
+ Matern52Kernel(prf.Bounded(10.0, 200.0, value=50.0)) * prf.Bounded(1e-5, 1e-3, value=1e-4)
41
+ )
42
+ result = fit(
43
+ coax(prf.Bounded(1.38, 1.42, value=1.39)), s11, frequency=freq, features='s11',
44
+ likelihood=GaussianLikelihood(prf.Bounded(1e-7, 1e-4, value=1e-6)),
45
+ discrepancy=gp,
46
+ )
47
+
48
+ Predicting the Discrepancy
49
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
50
+
51
+ The fitted :class:`~pmrf.evaluators.MarginalLogLikelihood`, with its optimized GP hyperparameters and noise, is the one term of the fit's objective. :meth:`~pmrf.evaluators.MarginalLogLikelihood.predict_discrepancy` conditions the GP on the fit's residuals and returns the distribution of the discrepancy at new frequencies. Here they extend past the fit band and are given in GHz; they are converted to the fit's unit first.
52
+
53
+ .. plot::
54
+ :context:
55
+ :include-source:
56
+
57
+ import matplotlib.pyplot as plt
58
+
59
+ (term,) = result.solution.objective
60
+ mll = term.evaluator.evaluator
61
+
62
+ new_freq = prf.Frequency(0.005, 0.6, 300, 'GHz')
63
+ delta = mll.predict_discrepancy(result.model, freq, new_freq)
64
+
65
+ mean = delta.mean()
66
+ std = np.sqrt(np.diagonal(delta.covariance(), axis1=-2, axis2=-1))
67
+
68
+ fig, axes = plt.subplots(2, 1, sharex=True)
69
+ for ax, m, s, r, part in zip(axes, mean, std, (ripple.real, ripple.imag), ('Re', 'Im')):
70
+ ax.fill_between(new_freq.f_scaled * 1e3, m - s, m + s, alpha=0.3, label=r'$\pm 1\sigma$')
71
+ ax.plot(new_freq.f_scaled * 1e3, m, label='predicted mean')
72
+ ax.plot(freq.f_scaled, r, 'k.', markersize=3, label='true ripple')
73
+ ax.set_ylabel(rf'{part} $\delta$')
74
+ axes[0].legend()
75
+ axes[1].set_xlabel('Frequency (MHz)')
76
+
77
+ The prediction is in event space: one block for the real part of S11 and one for the imaginary part, with frequency last. It is of the discrepancy alone, and excludes measurement noise. Inside the fit band it follows the ripple closely; beyond it, the mean relaxes towards zero and the uncertainty grows back to the GP's prior.
@@ -9,6 +9,8 @@ This chapter includes some basic examples to demonstrate ParamRF's core features
9
9
  cascading_and_terminating
10
10
  circuit_models
11
11
  model_optimization
12
+ discrepancy_prediction
13
+ port_discrepancy
12
14
  derivatives_and_sweeps
13
15
  parameter_naming_and_model_manipulation
14
16
  custom_models