Compare commits
58 Commits
Author | SHA1 | Date | |
---|---|---|---|
1a76c4e7ab | |||
67ddbb0f90 | |||
97497e640e | |||
e78cf5595a | |||
086f348084 | |||
8f61cd85d0 | |||
80fd25e7e4 | |||
30fb1190bb | |||
fa80af8447 | |||
926a6abf1f | |||
2285bb78c1 | |||
894d980a64 | |||
9a922762fa | |||
26682f1741 | |||
f1f6c0d45b | |||
e0c42766bf | |||
0202163f08 | |||
18a1b2faa3 | |||
c034cdcb95 | |||
0c152c337e | |||
22a33c2b84 | |||
3369bb290a | |||
322b5ebc9b | |||
014c742e0a | |||
6d920c6809 | |||
2f7b9fc1eb | |||
134f5b45d7 | |||
f35d9a85a6 | |||
5650e7b03b | |||
76886011bb | |||
528de3b4cc | |||
1256c71fac | |||
d637fb73ee | |||
5c4f7e5c97 | |||
919101b339 | |||
67a1864837 | |||
eca933ccef | |||
a5b391e757 | |||
34a4532a02 | |||
98f40179e1 | |||
5a7bc985b4 | |||
f4c099c1d2 | |||
78d0034e34 | |||
a56b2e30e2 | |||
ec010af947 | |||
7e0df9e643 | |||
a20217967f | |||
958d1f96d1 | |||
48d559f084 | |||
167a0b7aef | |||
2c9e9b0eb2 | |||
c8ace2330d | |||
60ef43e66e | |||
a2044ba7de | |||
1fcebaf119 | |||
bb3d848fd6 | |||
4d4e5558e1 | |||
83d495920a |
2
.github/workflows/python_publish.yml
vendored
2
.github/workflows/python_publish.yml
vendored
@ -55,6 +55,6 @@ jobs:
|
||||
name: python-package-distributions
|
||||
path: dist/
|
||||
- name: Publish distribution 📦 to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
uses: pypa/gh-action-pypi-publish@0ab0b79471669eb3a4d647e625009c62f9f3b241
|
||||
with:
|
||||
password: ${{ secrets.PYPI_API_TOKEN }}
|
3
Pipfile
3
Pipfile
@ -9,6 +9,9 @@ charon-vna = {file = ".", editable = true}
|
||||
[dev-packages]
|
||||
ipykernel = "*"
|
||||
ipywidgets = "*"
|
||||
black = "*"
|
||||
flake8 = "*"
|
||||
isort = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.10"
|
||||
|
633
Pipfile.lock
generated
633
Pipfile.lock
generated
@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "8ca47bc9e64405da418625530ed3861fbf72ff2f615aa4053f0da928dd09a494"
|
||||
"sha256": "470252a74774400955ef60d73f7e697760609be00b7733aa7a51b2f192e37fe5"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
@ -36,74 +36,63 @@
|
||||
},
|
||||
"contourpy": {
|
||||
"hashes": [
|
||||
"sha256:00ccd0dbaad6d804ab259820fa7cb0b8036bda0686ef844d24125d8287178ce0",
|
||||
"sha256:0be4d8425bfa755e0fd76ee1e019636ccc7c29f77a7c86b4328a9eb6a26d0639",
|
||||
"sha256:0dce35502151b6bd35027ac39ba6e5a44be13a68f55735c3612c568cac3805fd",
|
||||
"sha256:0fa4c02abe6c446ba70d96ece336e621efa4aecae43eaa9b030ae5fb92b309ad",
|
||||
"sha256:14e262f67bd7e6eb6880bc564dcda30b15e351a594657e55b7eec94b6ef72843",
|
||||
"sha256:167d6c890815e1dac9536dca00828b445d5d0df4d6a8c6adb4a7ec3166812fa8",
|
||||
"sha256:1ec4dc6bf570f5b22ed0d7efba0dfa9c5b9e0431aeea7581aa217542d9e809a4",
|
||||
"sha256:303c252947ab4b14c08afeb52375b26781ccd6a5ccd81abcdfc1fafd14cf93c1",
|
||||
"sha256:31cd3a85dbdf1fc002280c65caa7e2b5f65e4a973fcdf70dd2fdcb9868069294",
|
||||
"sha256:32b238b3b3b649e09ce9aaf51f0c261d38644bdfa35cbaf7b263457850957a84",
|
||||
"sha256:33c92cdae89ec5135d036e7218e69b0bb2851206077251f04a6c4e0e21f03927",
|
||||
"sha256:345af746d7766821d05d72cb8f3845dfd08dd137101a2cb9b24de277d716def8",
|
||||
"sha256:3634b5385c6716c258d0419c46d05c8aa7dc8cb70326c9a4fb66b69ad2b52e09",
|
||||
"sha256:364174c2a76057feef647c802652f00953b575723062560498dc7930fc9b1cb7",
|
||||
"sha256:36e0cff201bcb17a0a8ecc7f454fe078437fa6bda730e695a92f2d9932bd507f",
|
||||
"sha256:36f965570cff02b874773c49bfe85562b47030805d7d8360748f3eca570f4cab",
|
||||
"sha256:3bb3808858a9dc68f6f03d319acd5f1b8a337e6cdda197f02f4b8ff67ad2057b",
|
||||
"sha256:3e1c7fa44aaae40a2247e2e8e0627f4bea3dd257014764aa644f319a5f8600e3",
|
||||
"sha256:3faeb2998e4fcb256542e8a926d08da08977f7f5e62cf733f3c211c2a5586223",
|
||||
"sha256:420d39daa61aab1221567b42eecb01112908b2cab7f1b4106a52caaec8d36973",
|
||||
"sha256:4553c421929ec95fb07b3aaca0fae668b2eb5a5203d1217ca7c34c063c53d087",
|
||||
"sha256:4865cd1d419e0c7a7bf6de1777b185eebdc51470800a9f42b9e9decf17762081",
|
||||
"sha256:4cfb5c62ce023dfc410d6059c936dcf96442ba40814aefbfa575425a3a7f19dc",
|
||||
"sha256:4d63ee447261e963af02642ffcb864e5a2ee4cbfd78080657a9880b8b1868e18",
|
||||
"sha256:570ef7cf892f0afbe5b2ee410c507ce12e15a5fa91017a0009f79f7d93a1268f",
|
||||
"sha256:637f674226be46f6ba372fd29d9523dd977a291f66ab2a74fbeb5530bb3f445d",
|
||||
"sha256:68a32389b06b82c2fdd68276148d7b9275b5f5cf13e5417e4252f6d1a34f72a2",
|
||||
"sha256:69375194457ad0fad3a839b9e29aa0b0ed53bb54db1bfb6c3ae43d111c31ce41",
|
||||
"sha256:6cb6cc968059db9c62cb35fbf70248f40994dfcd7aa10444bbf8b3faeb7c2d67",
|
||||
"sha256:710a26b3dc80c0e4febf04555de66f5fd17e9cf7170a7b08000601a10570bda6",
|
||||
"sha256:732896af21716b29ab3e988d4ce14bc5133733b85956316fb0c56355f398099b",
|
||||
"sha256:75ee7cb1a14c617f34a51d11fa7524173e56551646828353c4af859c56b766e2",
|
||||
"sha256:76a896b2f195b57db25d6b44e7e03f221d32fe318d03ede41f8b4d9ba1bff53c",
|
||||
"sha256:76c905ef940a4474a6289c71d53122a4f77766eef23c03cd57016ce19d0f7b42",
|
||||
"sha256:7a52040312b1a858b5e31ef28c2e865376a386c60c0e248370bbea2d3f3b760d",
|
||||
"sha256:7ffa0db17717a8ffb127efd0c95a4362d996b892c2904db72428d5b52e1938a4",
|
||||
"sha256:81cb5ed4952aae6014bc9d0421dec7c5835c9c8c31cdf51910b708f548cf58e5",
|
||||
"sha256:834e0cfe17ba12f79963861e0f908556b2cedd52e1f75e6578801febcc6a9f49",
|
||||
"sha256:87ddffef1dbe5e669b5c2440b643d3fdd8622a348fe1983fad7a0f0ccb1cd67b",
|
||||
"sha256:880ea32e5c774634f9fcd46504bf9f080a41ad855f4fef54f5380f5133d343c7",
|
||||
"sha256:8ca947601224119117f7c19c9cdf6b3ab54c5726ef1d906aa4a69dfb6dd58102",
|
||||
"sha256:90f73a5116ad1ba7174341ef3ea5c3150ddf20b024b98fb0c3b29034752c8aeb",
|
||||
"sha256:92f8557cbb07415a4d6fa191f20fd9d2d9eb9c0b61d1b2f52a8926e43c6e9af7",
|
||||
"sha256:94e848a6b83da10898cbf1311a815f770acc9b6a3f2d646f330d57eb4e87592e",
|
||||
"sha256:9c0da700bf58f6e0b65312d0a5e695179a71d0163957fa381bb3c1f72972537c",
|
||||
"sha256:a11077e395f67ffc2c44ec2418cfebed032cd6da3022a94fc227b6faf8e2acb8",
|
||||
"sha256:aea348f053c645100612b333adc5983d87be69acdc6d77d3169c090d3b01dc35",
|
||||
"sha256:b11b39aea6be6764f84360fce6c82211a9db32a7c7de8fa6dd5397cf1d079c3b",
|
||||
"sha256:c6c7c2408b7048082932cf4e641fa3b8ca848259212f51c8c59c45aa7ac18f14",
|
||||
"sha256:c6ec93afeb848a0845a18989da3beca3eec2c0f852322efe21af1931147d12cb",
|
||||
"sha256:cacd81e2d4b6f89c9f8a5b69b86490152ff39afc58a95af002a398273e5ce589",
|
||||
"sha256:d402880b84df3bec6eab53cd0cf802cae6a2ef9537e70cf75e91618a3801c20c",
|
||||
"sha256:d51fca85f9f7ad0b65b4b9fe800406d0d77017d7270d31ec3fb1cc07358fdea0",
|
||||
"sha256:d73f659398a0904e125280836ae6f88ba9b178b2fed6884f3b1f95b989d2c8da",
|
||||
"sha256:d78ab28a03c854a873787a0a42254a0ccb3cb133c672f645c9f9c8f3ae9d0800",
|
||||
"sha256:da84c537cb8b97d153e9fb208c221c45605f73147bd4cadd23bdae915042aad6",
|
||||
"sha256:dbc4c3217eee163fa3984fd1567632b48d6dfd29216da3ded3d7b844a8014a66",
|
||||
"sha256:e12968fdfd5bb45ffdf6192a590bd8ddd3ba9e58360b29683c6bb71a7b41edca",
|
||||
"sha256:e1fd23e9d01591bab45546c089ae89d926917a66dceb3abcf01f6105d927e2cb",
|
||||
"sha256:e8134301d7e204c88ed7ab50028ba06c683000040ede1d617298611f9dc6240c",
|
||||
"sha256:eb8b141bb00fa977d9122636b16aa67d37fd40a3d8b52dd837e536d64b9a4d06",
|
||||
"sha256:eca7e17a65f72a5133bdbec9ecf22401c62bcf4821361ef7811faee695799779",
|
||||
"sha256:f317576606de89da6b7e0861cf6061f6146ead3528acabff9236458a6ba467f8",
|
||||
"sha256:fd2a0fc506eccaaa7595b7e1418951f213cf8255be2600f1ea1b61e46a60c55f",
|
||||
"sha256:fe41b41505a5a33aeaed2a613dccaeaa74e0e3ead6dd6fd3a118fb471644fd6c"
|
||||
"sha256:041b640d4ec01922083645a94bb3b2e777e6b626788f4095cf21abbe266413c1",
|
||||
"sha256:05e806338bfeaa006acbdeba0ad681a10be63b26e1b17317bfac3c5d98f36cda",
|
||||
"sha256:08d9d449a61cf53033612cb368f3a1b26cd7835d9b8cd326647efe43bca7568d",
|
||||
"sha256:0ffa84be8e0bd33410b17189f7164c3589c229ce5db85798076a3fa136d0e509",
|
||||
"sha256:113231fe3825ebf6f15eaa8bc1f5b0ddc19d42b733345eae0934cb291beb88b6",
|
||||
"sha256:14c102b0eab282427b662cb590f2e9340a9d91a1c297f48729431f2dcd16e14f",
|
||||
"sha256:174e758c66bbc1c8576992cec9599ce8b6672b741b5d336b5c74e35ac382b18e",
|
||||
"sha256:19c1555a6801c2f084c7ddc1c6e11f02eb6a6016ca1318dd5452ba3f613a1751",
|
||||
"sha256:19d40d37c1c3a4961b4619dd9d77b12124a453cc3d02bb31a07d58ef684d3d86",
|
||||
"sha256:1bf98051f1045b15c87868dbaea84f92408337d4f81d0e449ee41920ea121d3b",
|
||||
"sha256:20914c8c973f41456337652a6eeca26d2148aa96dd7ac323b74516988bea89fc",
|
||||
"sha256:287ccc248c9e0d0566934e7d606201abd74761b5703d804ff3df8935f523d546",
|
||||
"sha256:2ba94a401342fc0f8b948e57d977557fbf4d515f03c67682dd5c6191cb2d16ec",
|
||||
"sha256:31c1b55c1f34f80557d3830d3dd93ba722ce7e33a0b472cba0ec3b6535684d8f",
|
||||
"sha256:36987a15e8ace5f58d4d5da9dca82d498c2bbb28dff6e5d04fbfcc35a9cb3a82",
|
||||
"sha256:3a04ecd68acbd77fa2d39723ceca4c3197cb2969633836ced1bea14e219d077c",
|
||||
"sha256:3e8b974d8db2c5610fb4e76307e265de0edb655ae8169e8b21f41807ccbeec4b",
|
||||
"sha256:3ea9924d28fc5586bf0b42d15f590b10c224117e74409dd7a0be3b62b74a501c",
|
||||
"sha256:4318af1c925fb9a4fb190559ef3eec206845f63e80fb603d47f2d6d67683901c",
|
||||
"sha256:44a29502ca9c7b5ba389e620d44f2fbe792b1fb5734e8b931ad307071ec58c53",
|
||||
"sha256:47734d7073fb4590b4a40122b35917cd77be5722d80683b249dac1de266aac80",
|
||||
"sha256:4d76d5993a34ef3df5181ba3c92fabb93f1eaa5729504fb03423fcd9f3177242",
|
||||
"sha256:4dbbc03a40f916a8420e420d63e96a1258d3d1b58cbdfd8d1f07b49fcbd38e85",
|
||||
"sha256:500360b77259914f7805af7462e41f9cb7ca92ad38e9f94d6c8641b089338124",
|
||||
"sha256:523a8ee12edfa36f6d2a49407f705a6ef4c5098de4f498619787e272de93f2d5",
|
||||
"sha256:573abb30e0e05bf31ed067d2f82500ecfdaec15627a59d63ea2d95714790f5c2",
|
||||
"sha256:5b75aa69cb4d6f137b36f7eb2ace9280cfb60c55dc5f61c731fdf6f037f958a3",
|
||||
"sha256:61332c87493b00091423e747ea78200659dc09bdf7fd69edd5e98cef5d3e9a8d",
|
||||
"sha256:805617228ba7e2cbbfb6c503858e626ab528ac2a32a04a2fe88ffaf6b02c32bc",
|
||||
"sha256:841ad858cff65c2c04bf93875e384ccb82b654574a6d7f30453a04f04af71342",
|
||||
"sha256:89785bb2a1980c1bd87f0cb1517a71cde374776a5f150936b82580ae6ead44a1",
|
||||
"sha256:8eb96e79b9f3dcadbad2a3891672f81cdcab7f95b27f28f1c67d75f045b6b4f1",
|
||||
"sha256:974d8145f8ca354498005b5b981165b74a195abfae9a8129df3e56771961d595",
|
||||
"sha256:9ddeb796389dadcd884c7eb07bd14ef12408aaae358f0e2ae24114d797eede30",
|
||||
"sha256:a045f341a77b77e1c5de31e74e966537bba9f3c4099b35bf4c2e3939dd54cdab",
|
||||
"sha256:a0cffcbede75c059f535725c1680dfb17b6ba8753f0c74b14e6a9c68c29d7ea3",
|
||||
"sha256:a761d9ccfc5e2ecd1bf05534eda382aa14c3e4f9205ba5b1684ecfe400716ef2",
|
||||
"sha256:a7895f46d47671fa7ceec40f31fae721da51ad34bdca0bee83e38870b1f47ffd",
|
||||
"sha256:a9fa36448e6a3a1a9a2ba23c02012c43ed88905ec80163f2ffe2421c7192a5d7",
|
||||
"sha256:ab29962927945d89d9b293eabd0d59aea28d887d4f3be6c22deaefbb938a7277",
|
||||
"sha256:abbb49fb7dac584e5abc6636b7b2a7227111c4f771005853e7d25176daaf8453",
|
||||
"sha256:ac4578ac281983f63b400f7fe6c101bedc10651650eef012be1ccffcbacf3697",
|
||||
"sha256:adce39d67c0edf383647a3a007de0a45fd1b08dedaa5318404f1a73059c2512b",
|
||||
"sha256:ade08d343436a94e633db932e7e8407fe7de8083967962b46bdfc1b0ced39454",
|
||||
"sha256:b2bdca22a27e35f16794cf585832e542123296b4687f9fd96822db6bae17bfc9",
|
||||
"sha256:b2f926efda994cdf3c8d3fdb40b9962f86edbc4457e739277b961eced3d0b4c1",
|
||||
"sha256:b457d6430833cee8e4b8e9b6f07aa1c161e5e0d52e118dc102c8f9bd7dd060d6",
|
||||
"sha256:c414fc1ed8ee1dbd5da626cf3710c6013d3d27456651d156711fa24f24bd1291",
|
||||
"sha256:cb76c1a154b83991a3cbbf0dfeb26ec2833ad56f95540b442c73950af2013750",
|
||||
"sha256:dfd97abd83335045a913e3bcc4a09c0ceadbe66580cf573fe961f4a825efa699",
|
||||
"sha256:e914a8cb05ce5c809dd0fe350cfbb4e881bde5e2a38dc04e3afe1b3e58bd158e",
|
||||
"sha256:ece6df05e2c41bd46776fbc712e0996f7c94e0d0543af1656956d150c4ca7c81",
|
||||
"sha256:efa874e87e4a647fd2e4f514d5e91c7d493697127beb95e77d2f7561f6905bd9",
|
||||
"sha256:f611e628ef06670df83fce17805c344710ca5cde01edfdc72751311da8585375"
|
||||
],
|
||||
"markers": "python_version >= '3.9'",
|
||||
"version": "==1.3.0"
|
||||
"markers": "python_version >= '3.10'",
|
||||
"version": "==1.3.1"
|
||||
},
|
||||
"cycler": {
|
||||
"hashes": [
|
||||
@ -123,57 +112,59 @@
|
||||
},
|
||||
"fonttools": {
|
||||
"hashes": [
|
||||
"sha256:07e005dc454eee1cc60105d6a29593459a06321c21897f769a281ff2d08939f6",
|
||||
"sha256:0a911591200114969befa7f2cb74ac148bce5a91df5645443371aba6d222e263",
|
||||
"sha256:0d1d353ef198c422515a3e974a1e8d5b304cd54a4c2eebcae708e37cd9eeffb1",
|
||||
"sha256:0e88e3018ac809b9662615072dcd6b84dca4c2d991c6d66e1970a112503bba7e",
|
||||
"sha256:1d152d1be65652fc65e695e5619e0aa0982295a95a9b29b52b85775243c06556",
|
||||
"sha256:262705b1663f18c04250bd1242b0515d3bbae177bee7752be67c979b7d47f43d",
|
||||
"sha256:278913a168f90d53378c20c23b80f4e599dca62fbffae4cc620c8eed476b723e",
|
||||
"sha256:301540e89cf4ce89d462eb23a89464fef50915255ece765d10eee8b2bf9d75b2",
|
||||
"sha256:31c32d7d4b0958600eac75eaf524b7b7cb68d3a8c196635252b7a2c30d80e986",
|
||||
"sha256:357cacb988a18aace66e5e55fe1247f2ee706e01debc4b1a20d77400354cddeb",
|
||||
"sha256:37cddd62d83dc4f72f7c3f3c2bcf2697e89a30efb152079896544a93907733bd",
|
||||
"sha256:41bb0b250c8132b2fcac148e2e9198e62ff06f3cc472065dff839327945c5882",
|
||||
"sha256:4aa4817f0031206e637d1e685251ac61be64d1adef111060df84fdcbc6ab6c44",
|
||||
"sha256:4e10d2e0a12e18f4e2dd031e1bf7c3d7017be5c8dbe524d07706179f355c5dac",
|
||||
"sha256:5419771b64248484299fa77689d4f3aeed643ea6630b2ea750eeab219588ba20",
|
||||
"sha256:54471032f7cb5fca694b5f1a0aaeba4af6e10ae989df408e0216f7fd6cdc405d",
|
||||
"sha256:58974b4987b2a71ee08ade1e7f47f410c367cdfc5a94fabd599c88165f56213a",
|
||||
"sha256:58d29b9a294573d8319f16f2f79e42428ba9b6480442fa1836e4eb89c4d9d61c",
|
||||
"sha256:5eb2474a7c5be8a5331146758debb2669bf5635c021aee00fd7c353558fc659d",
|
||||
"sha256:6e37561751b017cf5c40fce0d90fd9e8274716de327ec4ffb0df957160be3bff",
|
||||
"sha256:76ae5091547e74e7efecc3cbf8e75200bc92daaeb88e5433c5e3e95ea8ce5aa7",
|
||||
"sha256:7965af9b67dd546e52afcf2e38641b5be956d68c425bef2158e95af11d229f10",
|
||||
"sha256:7e3b7d44e18c085fd8c16dcc6f1ad6c61b71ff463636fcb13df7b1b818bd0c02",
|
||||
"sha256:7ed7ee041ff7b34cc62f07545e55e1468808691dddfd315d51dd82a6b37ddef2",
|
||||
"sha256:82834962b3d7c5ca98cb56001c33cf20eb110ecf442725dc5fdf36d16ed1ab07",
|
||||
"sha256:8583e563df41fdecef31b793b4dd3af8a9caa03397be648945ad32717a92885b",
|
||||
"sha256:8fa92cb248e573daab8d032919623cc309c005086d743afb014c836636166f08",
|
||||
"sha256:93d458c8a6a354dc8b48fc78d66d2a8a90b941f7fec30e94c7ad9982b1fa6bab",
|
||||
"sha256:957f669d4922f92c171ba01bef7f29410668db09f6c02111e22b2bce446f3285",
|
||||
"sha256:9dc080e5a1c3b2656caff2ac2633d009b3a9ff7b5e93d0452f40cd76d3da3b3c",
|
||||
"sha256:9ef1b167e22709b46bf8168368b7b5d3efeaaa746c6d39661c1b4405b6352e58",
|
||||
"sha256:a7a310c6e0471602fe3bf8efaf193d396ea561486aeaa7adc1f132e02d30c4b9",
|
||||
"sha256:ab774fa225238986218a463f3fe151e04d8c25d7de09df7f0f5fce27b1243dbc",
|
||||
"sha256:ada215fd079e23e060157aab12eba0d66704316547f334eee9ff26f8c0d7b8ab",
|
||||
"sha256:c39287f5c8f4a0c5a55daf9eaf9ccd223ea59eed3f6d467133cc727d7b943a55",
|
||||
"sha256:c9c563351ddc230725c4bdf7d9e1e92cbe6ae8553942bd1fb2b2ff0884e8b714",
|
||||
"sha256:d26732ae002cc3d2ecab04897bb02ae3f11f06dd7575d1df46acd2f7c012a8d8",
|
||||
"sha256:d3b659d1029946f4ff9b6183984578041b520ce0f8fb7078bb37ec7445806b33",
|
||||
"sha256:dd9cc95b8d6e27d01e1e1f1fae8559ef3c02c76317da650a19047f249acd519d",
|
||||
"sha256:e4564cf40cebcb53f3dc825e85910bf54835e8a8b6880d59e5159f0f325e637e",
|
||||
"sha256:e7d82b9e56716ed32574ee106cabca80992e6bbdcf25a88d97d21f73a0aae664",
|
||||
"sha256:e8a4b261c1ef91e7188a30571be6ad98d1c6d9fa2427244c545e2fa0a2494dd7",
|
||||
"sha256:e96bc94c8cda58f577277d4a71f51c8e2129b8b36fd05adece6320dd3d57de8a",
|
||||
"sha256:ed2f80ca07025551636c555dec2b755dd005e2ea8fbeb99fc5cdff319b70b23b",
|
||||
"sha256:f5b8a096e649768c2f4233f947cf9737f8dbf8728b90e2771e2497c6e3d21d13",
|
||||
"sha256:f8e953cc0bddc2beaf3a3c3b5dd9ab7554677da72dfaf46951e193c9653e515a",
|
||||
"sha256:fda582236fee135d4daeca056c8c88ec5f6f6d88a004a79b84a02547c8f57386",
|
||||
"sha256:fdb062893fd6d47b527d39346e0c5578b7957dcea6d6a3b6794569370013d9ac"
|
||||
"sha256:07f8288aacf0a38d174445fc78377a97fb0b83cfe352a90c9d9c1400571963c7",
|
||||
"sha256:11e5de1ee0d95af4ae23c1a138b184b7f06e0b6abacabf1d0db41c90b03d834b",
|
||||
"sha256:1bc7ad24ff98846282eef1cbeac05d013c2154f977a79886bb943015d2b1b261",
|
||||
"sha256:1dcc07934a2165ccdc3a5a608db56fb3c24b609658a5b340aee4ecf3ba679dc0",
|
||||
"sha256:22f38464daa6cdb7b6aebd14ab06609328fe1e9705bb0fcc7d1e69de7109ee02",
|
||||
"sha256:27e4ae3592e62eba83cd2c4ccd9462dcfa603ff78e09110680a5444c6925d841",
|
||||
"sha256:3983313c2a04d6cc1fe9251f8fc647754cf49a61dac6cb1e7249ae67afaafc45",
|
||||
"sha256:529cef2ce91dc44f8e407cc567fae6e49a1786f2fefefa73a294704c415322a4",
|
||||
"sha256:5323a22eabddf4b24f66d26894f1229261021dacd9d29e89f7872dd8c63f0b8b",
|
||||
"sha256:54153c49913f45065c8d9e6d0c101396725c5621c8aee744719300f79771d75a",
|
||||
"sha256:546565028e244a701f73df6d8dd6be489d01617863ec0c6a42fa25bf45d43048",
|
||||
"sha256:5480673f599ad410695ca2ddef2dfefe9df779a9a5cda89503881e503c9c7d90",
|
||||
"sha256:5e8d657cd7326eeaba27de2740e847c6b39dde2f8d7cd7cc56f6aad404ddf0bd",
|
||||
"sha256:62d65a3022c35e404d19ca14f291c89cc5890032ff04f6c17af0bd1927299674",
|
||||
"sha256:6314bf82c54c53c71805318fcf6786d986461622dd926d92a465199ff54b1b72",
|
||||
"sha256:7a8aa2c5e5b8b3bcb2e4538d929f6589a5c6bdb84fd16e2ed92649fb5454f11c",
|
||||
"sha256:827e95fdbbd3e51f8b459af5ea10ecb4e30af50221ca103bea68218e9615de07",
|
||||
"sha256:859c358ebf41db18fb72342d3080bce67c02b39e86b9fbcf1610cca14984841b",
|
||||
"sha256:86721fbc389ef5cc1e2f477019e5069e8e4421e8d9576e9c26f840dbb04678de",
|
||||
"sha256:89bdc5d88bdeec1b15af790810e267e8332d92561dce4f0748c2b95c9bdf3926",
|
||||
"sha256:8c4491699bad88efe95772543cd49870cf756b019ad56294f6498982408ab03e",
|
||||
"sha256:8c5ec45428edaa7022f1c949a632a6f298edc7b481312fc7dc258921e9399628",
|
||||
"sha256:8e75f12c82127486fac2d8bfbf5bf058202f54bf4f158d367e41647b972342ca",
|
||||
"sha256:a430178ad3e650e695167cb53242dae3477b35c95bef6525b074d87493c4bf29",
|
||||
"sha256:a8c2794ded89399cc2169c4d0bf7941247b8d5932b2659e09834adfbb01589aa",
|
||||
"sha256:aca318b77f23523309eec4475d1fbbb00a6b133eb766a8bdc401faba91261abe",
|
||||
"sha256:ae3b6600565b2d80b7c05acb8e24d2b26ac407b27a3f2e078229721ba5698427",
|
||||
"sha256:aedbeb1db64496d098e6be92b2e63b5fac4e53b1b92032dfc6988e1ea9134a4d",
|
||||
"sha256:aee3b57643827e237ff6ec6d28d9ff9766bd8b21e08cd13bff479e13d4b14765",
|
||||
"sha256:b54baf65c52952db65df39fcd4820668d0ef4766c0ccdf32879b77f7c804d5c5",
|
||||
"sha256:b586ab5b15b6097f2fb71cafa3c98edfd0dba1ad8027229e7b1e204a58b0e09d",
|
||||
"sha256:b8d5e8916c0970fbc0f6f1bece0063363bb5857a7f170121a4493e31c3db3314",
|
||||
"sha256:bc5dbb4685e51235ef487e4bd501ddfc49be5aede5e40f4cefcccabc6e60fb4b",
|
||||
"sha256:bdcc9f04b36c6c20978d3f060e5323a43f6222accc4e7fcbef3f428e216d96af",
|
||||
"sha256:c3ca99e0d460eff46e033cd3992a969658c3169ffcd533e0a39c63a38beb6831",
|
||||
"sha256:caf8230f3e10f8f5d7593eb6d252a37caf58c480b19a17e250a63dad63834cf3",
|
||||
"sha256:cd70de1a52a8ee2d1877b6293af8a2484ac82514f10b1c67c1c5762d38073e56",
|
||||
"sha256:cf4fe7c124aa3f4e4c1940880156e13f2f4d98170d35c749e6b4f119a872551e",
|
||||
"sha256:d342e88764fb201286d185093781bf6628bbe380a913c24adf772d901baa8276",
|
||||
"sha256:da9da6d65cd7aa6b0f806556f4985bcbf603bf0c5c590e61b43aa3e5a0f822d0",
|
||||
"sha256:dc5294a3d5c84226e3dbba1b6f61d7ad813a8c0238fceea4e09aa04848c3d851",
|
||||
"sha256:dd68c87a2bfe37c5b33bcda0fba39b65a353876d3b9006fde3adae31f97b3ef5",
|
||||
"sha256:e6e8766eeeb2de759e862004aa11a9ea3d6f6d5ec710551a88b476192b64fd54",
|
||||
"sha256:e894b5bd60d9f473bed7a8f506515549cc194de08064d829464088d23097331b",
|
||||
"sha256:eb6ca911c4c17eb51853143624d8dc87cdcdf12a711fc38bf5bd21521e79715f",
|
||||
"sha256:ed63959d00b61959b035c7d47f9313c2c1ece090ff63afea702fe86de00dbed4",
|
||||
"sha256:f412604ccbeee81b091b420272841e5ec5ef68967a9790e80bffd0e30b8e2977",
|
||||
"sha256:f7d66c15ba875432a2d2fb419523f5d3d347f91f48f57b8b08a2dfc3c39b8a3f",
|
||||
"sha256:f9e736f60f4911061235603a6119e72053073a12c6d7904011df2d8fad2c0e35",
|
||||
"sha256:fb594b5a99943042c702c550d5494bdd7577f6ef19b0bc73877c948a63184a32"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==4.54.1"
|
||||
"version": "==4.55.3"
|
||||
},
|
||||
"kiwisolver": {
|
||||
"hashes": [
|
||||
@ -297,49 +288,43 @@
|
||||
},
|
||||
"matplotlib": {
|
||||
"hashes": [
|
||||
"sha256:039082812cacd6c6bec8e17a9c1e6baca230d4116d522e81e1f63a74d01d2e21",
|
||||
"sha256:03ba9c1299c920964e8d3857ba27173b4dbb51ca4bab47ffc2c2ba0eb5e2cbc5",
|
||||
"sha256:050598c2b29e0b9832cde72bcf97627bf00262adbc4a54e2b856426bb2ef0697",
|
||||
"sha256:18128cc08f0d3cfff10b76baa2f296fc28c4607368a8402de61bb3f2eb33c7d9",
|
||||
"sha256:1cd93b91ab47a3616b4d3c42b52f8363b88ca021e340804c6ab2536344fad9ca",
|
||||
"sha256:1d94ff717eb2bd0b58fe66380bd8b14ac35f48a98e7c6765117fe67fb7684e64",
|
||||
"sha256:306c8dfc73239f0e72ac50e5a9cf19cc4e8e331dd0c54f5e69ca8758550f1e1e",
|
||||
"sha256:37e51dd1c2db16ede9cfd7b5cabdfc818b2c6397c83f8b10e0e797501c963a03",
|
||||
"sha256:3fd595f34aa8a55b7fc8bf9ebea8aa665a84c82d275190a61118d33fbc82ccae",
|
||||
"sha256:4876d7d40219e8ae8bb70f9263bcbe5714415acfdf781086601211335e24f8aa",
|
||||
"sha256:5413401594cfaff0052f9d8b1aafc6d305b4bd7c4331dccd18f561ff7e1d3bd3",
|
||||
"sha256:5816b1e1fe8c192cbc013f8f3e3368ac56fbecf02fb41b8f8559303f24c5015e",
|
||||
"sha256:65aacf95b62272d568044531e41de26285d54aec8cb859031f511f84bd8b495a",
|
||||
"sha256:6758baae2ed64f2331d4fd19be38b7b4eae3ecec210049a26b6a4f3ae1c85dcc",
|
||||
"sha256:6d1ce5ed2aefcdce11904fc5bbea7d9c21fff3d5f543841edf3dea84451a09ea",
|
||||
"sha256:6d9f07a80deab4bb0b82858a9e9ad53d1382fd122be8cde11080f4e7dfedb38b",
|
||||
"sha256:7741f26a58a240f43bee74965c4882b6c93df3e7eb3de160126d8c8f53a6ae6e",
|
||||
"sha256:8912ef7c2362f7193b5819d17dae8629b34a95c58603d781329712ada83f9447",
|
||||
"sha256:909645cce2dc28b735674ce0931a4ac94e12f5b13f6bb0b5a5e65e7cea2c192b",
|
||||
"sha256:96ab43906269ca64a6366934106fa01534454a69e471b7bf3d79083981aaab92",
|
||||
"sha256:9d78bbc0cbc891ad55b4f39a48c22182e9bdaea7fc0e5dbd364f49f729ca1bbb",
|
||||
"sha256:ab68d50c06938ef28681073327795c5db99bb4666214d2d5f880ed11aeaded66",
|
||||
"sha256:ac43031375a65c3196bee99f6001e7fa5bdfb00ddf43379d3c0609bdca042df9",
|
||||
"sha256:ae82a14dab96fbfad7965403c643cafe6515e386de723e498cf3eeb1e0b70cc7",
|
||||
"sha256:b2696efdc08648536efd4e1601b5fd491fd47f4db97a5fbfd175549a7365c1b2",
|
||||
"sha256:b82c5045cebcecd8496a4d694d43f9cc84aeeb49fe2133e036b207abe73f4d30",
|
||||
"sha256:be0fc24a5e4531ae4d8e858a1a548c1fe33b176bb13eff7f9d0d38ce5112a27d",
|
||||
"sha256:bf81de2926c2db243c9b2cbc3917619a0fc85796c6ba4e58f541df814bbf83c7",
|
||||
"sha256:c375cc72229614632c87355366bdf2570c2dac01ac66b8ad048d2dabadf2d0d4",
|
||||
"sha256:c797dac8bb9c7a3fd3382b16fe8f215b4cf0f22adccea36f1545a6d7be310b41",
|
||||
"sha256:cef2a73d06601437be399908cf13aee74e86932a5ccc6ccdf173408ebc5f6bb2",
|
||||
"sha256:d52a3b618cb1cbb769ce2ee1dcdb333c3ab6e823944e9a2d36e37253815f9556",
|
||||
"sha256:d719465db13267bcef19ea8954a971db03b9f48b4647e3860e4bc8e6ed86610f",
|
||||
"sha256:d8dd059447824eec055e829258ab092b56bb0579fc3164fa09c64f3acd478772",
|
||||
"sha256:dbe196377a8248972f5cede786d4c5508ed5f5ca4a1e09b44bda889958b33f8c",
|
||||
"sha256:e0830e188029c14e891fadd99702fd90d317df294c3298aad682739c5533721a",
|
||||
"sha256:f053c40f94bc51bc03832a41b4f153d83f2062d88c72b5e79997072594e97e51",
|
||||
"sha256:f32c7410c7f246838a77d6d1eff0c0f87f3cb0e7c4247aebea71a6d5a68cab49",
|
||||
"sha256:f6ee45bc4245533111ced13f1f2cace1e7f89d1c793390392a80c139d6cf0e6c",
|
||||
"sha256:f7c0410f181a531ec4e93bbc27692f2c71a15c2da16766f5ba9761e7ae518413"
|
||||
"sha256:01d2b19f13aeec2e759414d3bfe19ddfb16b13a1250add08d46d5ff6f9be83c6",
|
||||
"sha256:12eaf48463b472c3c0f8dbacdbf906e573013df81a0ab82f0616ea4b11281908",
|
||||
"sha256:2c5829a5a1dd5a71f0e31e6e8bb449bc0ee9dbfb05ad28fc0c6b55101b3a4be6",
|
||||
"sha256:2fbbabc82fde51391c4da5006f965e36d86d95f6ee83fb594b279564a4c5d0d2",
|
||||
"sha256:3547d153d70233a8496859097ef0312212e2689cdf8d7ed764441c77604095ae",
|
||||
"sha256:359f87baedb1f836ce307f0e850d12bb5f1936f70d035561f90d41d305fdacea",
|
||||
"sha256:3b427392354d10975c1d0f4ee18aa5844640b512d5311ef32efd4dd7db106ede",
|
||||
"sha256:4659665bc7c9b58f8c00317c3c2a299f7f258eeae5a5d56b4c64226fca2f7c59",
|
||||
"sha256:4673ff67a36152c48ddeaf1135e74ce0d4bce1bbf836ae40ed39c29edf7e2765",
|
||||
"sha256:503feb23bd8c8acc75541548a1d709c059b7184cde26314896e10a9f14df5f12",
|
||||
"sha256:5439f4c5a3e2e8eab18e2f8c3ef929772fd5641876db71f08127eed95ab64683",
|
||||
"sha256:5cdbaf909887373c3e094b0318d7ff230b2ad9dcb64da7ade654182872ab2593",
|
||||
"sha256:5e6c6461e1fc63df30bf6f80f0b93f5b6784299f721bc28530477acd51bfc3d1",
|
||||
"sha256:5fd41b0ec7ee45cd960a8e71aea7c946a28a0b8a4dcee47d2856b2af051f334c",
|
||||
"sha256:607b16c8a73943df110f99ee2e940b8a1cbf9714b65307c040d422558397dac5",
|
||||
"sha256:7e8632baebb058555ac0cde75db885c61f1212e47723d63921879806b40bec6a",
|
||||
"sha256:81713dd0d103b379de4516b861d964b1d789a144103277769238c732229d7f03",
|
||||
"sha256:845d96568ec873be63f25fa80e9e7fae4be854a66a7e2f0c8ccc99e94a8bd4ef",
|
||||
"sha256:95b710fea129c76d30be72c3b38f330269363fbc6e570a5dd43580487380b5ff",
|
||||
"sha256:96f2886f5c1e466f21cc41b70c5a0cd47bfa0015eb2d5793c88ebce658600e25",
|
||||
"sha256:994c07b9d9fe8d25951e3202a68c17900679274dadfc1248738dcfa1bd40d7f3",
|
||||
"sha256:9ade1003376731a971e398cc4ef38bb83ee8caf0aee46ac6daa4b0506db1fd06",
|
||||
"sha256:9b0558bae37f154fffda54d779a592bc97ca8b4701f1c710055b609a3bac44c8",
|
||||
"sha256:a2a43cbefe22d653ab34bb55d42384ed30f611bcbdea1f8d7f431011a2e1c62e",
|
||||
"sha256:a994f29e968ca002b50982b27168addfd65f0105610b6be7fa515ca4b5307c95",
|
||||
"sha256:ad2e15300530c1a94c63cfa546e3b7864bd18ea2901317bae8bbf06a5ade6dcf",
|
||||
"sha256:ae80dc3a4add4665cf2faa90138384a7ffe2a4e37c58d83e115b54287c4f06ef",
|
||||
"sha256:b886d02a581b96704c9d1ffe55709e49b4d2d52709ccebc4be42db856e511278",
|
||||
"sha256:c40ba2eb08b3f5de88152c2333c58cee7edcead0a2a0d60fcafa116b17117adc",
|
||||
"sha256:c55b20591ced744aa04e8c3e4b7543ea4d650b6c3c4b208c08a05b4010e8b442",
|
||||
"sha256:c58a9622d5dbeb668f407f35f4e6bfac34bb9ecdcc81680c04d0258169747997",
|
||||
"sha256:d44cb942af1693cced2604c33a9abcef6205601c445f6d0dc531d813af8a2f5a",
|
||||
"sha256:d907fddb39f923d011875452ff1eca29a9e7f21722b873e90db32e5d8ddff12e",
|
||||
"sha256:fd44fc75522f58612ec4a33958a7e5552562b7705b42ef1b4f8c0818e304a363"
|
||||
],
|
||||
"markers": "python_version >= '3.9'",
|
||||
"version": "==3.9.2"
|
||||
"markers": "python_version >= '3.10'",
|
||||
"version": "==3.10.0"
|
||||
},
|
||||
"numcodecs": {
|
||||
"hashes": [
|
||||
@ -366,11 +351,64 @@
|
||||
},
|
||||
"numpy": {
|
||||
"hashes": [
|
||||
"sha256:78574ac2d1a4a02421f25da9559850d59457bac82f2b8d7a44fe83a64f770098",
|
||||
"sha256:aa08e04e08aaf974d4458def539dece0d28146d866a39da5639596f4921fd761"
|
||||
"sha256:0557eebc699c1c34cccdd8c3778c9294e8196df27d713706895edc6f57d29608",
|
||||
"sha256:0798b138c291d792f8ea40fe3768610f3c7dd2574389e37c3f26573757c8f7ef",
|
||||
"sha256:0da8495970f6b101ddd0c38ace92edea30e7e12b9a926b57f5fabb1ecc25bb90",
|
||||
"sha256:0f0986e917aca18f7a567b812ef7ca9391288e2acb7a4308aa9d265bd724bdae",
|
||||
"sha256:122fd2fcfafdefc889c64ad99c228d5a1f9692c3a83f56c292618a59aa60ae83",
|
||||
"sha256:140dd80ff8981a583a60980be1a655068f8adebf7a45a06a6858c873fcdcd4a0",
|
||||
"sha256:16757cf28621e43e252c560d25b15f18a2f11da94fea344bf26c599b9cf54b73",
|
||||
"sha256:18142b497d70a34b01642b9feabb70156311b326fdddd875a9981f34a369b671",
|
||||
"sha256:1c92113619f7b272838b8d6702a7f8ebe5edea0df48166c47929611d0b4dea69",
|
||||
"sha256:1e25507d85da11ff5066269d0bd25d06e0a0f2e908415534f3e603d2a78e4ffa",
|
||||
"sha256:30bf971c12e4365153afb31fc73f441d4da157153f3400b82db32d04de1e4066",
|
||||
"sha256:3579eaeb5e07f3ded59298ce22b65f877a86ba8e9fe701f5576c99bb17c283da",
|
||||
"sha256:36b2b43146f646642b425dd2027730f99bac962618ec2052932157e213a040e9",
|
||||
"sha256:3905a5fffcc23e597ee4d9fb3fcd209bd658c352657548db7316e810ca80458e",
|
||||
"sha256:3a4199f519e57d517ebd48cb76b36c82da0360781c6a0353e64c0cac30ecaad3",
|
||||
"sha256:3f2f5cddeaa4424a0a118924b988746db6ffa8565e5829b1841a8a3bd73eb59a",
|
||||
"sha256:40deb10198bbaa531509aad0cd2f9fadb26c8b94070831e2208e7df543562b74",
|
||||
"sha256:440cfb3db4c5029775803794f8638fbdbf71ec702caf32735f53b008e1eaece3",
|
||||
"sha256:4723a50e1523e1de4fccd1b9a6dcea750c2102461e9a02b2ac55ffeae09a4410",
|
||||
"sha256:4bddbaa30d78c86329b26bd6aaaea06b1e47444da99eddac7bf1e2fab717bd72",
|
||||
"sha256:4e58666988605e251d42c2818c7d3d8991555381be26399303053b58a5bbf30d",
|
||||
"sha256:54dc1d6d66f8d37843ed281773c7174f03bf7ad826523f73435deb88ba60d2d4",
|
||||
"sha256:57fcc997ffc0bef234b8875a54d4058afa92b0b0c4223fc1f62f24b3b5e86038",
|
||||
"sha256:58b92a5828bd4d9aa0952492b7de803135038de47343b2aa3cc23f3b71a3dc4e",
|
||||
"sha256:5a145e956b374e72ad1dff82779177d4a3c62bc8248f41b80cb5122e68f22d13",
|
||||
"sha256:6ab153263a7c5ccaf6dfe7e53447b74f77789f28ecb278c3b5d49db7ece10d6d",
|
||||
"sha256:7832f9e8eb00be32f15fdfb9a981d6955ea9adc8574c521d48710171b6c55e95",
|
||||
"sha256:7fe4bb0695fe986a9e4deec3b6857003b4cfe5c5e4aac0b95f6a658c14635e31",
|
||||
"sha256:7fe8f3583e0607ad4e43a954e35c1748b553bfe9fdac8635c02058023277d1b3",
|
||||
"sha256:85ad7d11b309bd132d74397fcf2920933c9d1dc865487128f5c03d580f2c3d03",
|
||||
"sha256:9874bc2ff574c40ab7a5cbb7464bf9b045d617e36754a7bc93f933d52bd9ffc6",
|
||||
"sha256:a184288538e6ad699cbe6b24859206e38ce5fba28f3bcfa51c90d0502c1582b2",
|
||||
"sha256:a222d764352c773aa5ebde02dd84dba3279c81c6db2e482d62a3fa54e5ece69b",
|
||||
"sha256:a50aeff71d0f97b6450d33940c7181b08be1441c6c193e678211bff11aa725e7",
|
||||
"sha256:a55dc7a7f0b6198b07ec0cd445fbb98b05234e8b00c5ac4874a63372ba98d4ab",
|
||||
"sha256:a62eb442011776e4036af5c8b1a00b706c5bc02dc15eb5344b0c750428c94219",
|
||||
"sha256:a7d41d1612c1a82b64697e894b75db6758d4f21c3ec069d841e60ebe54b5b571",
|
||||
"sha256:a98f6f20465e7618c83252c02041517bd2f7ea29be5378f09667a8f654a5918d",
|
||||
"sha256:afe8fb968743d40435c3827632fd36c5fbde633b0423da7692e426529b1759b1",
|
||||
"sha256:b0b227dcff8cdc3efbce66d4e50891f04d0a387cce282fe1e66199146a6a8fca",
|
||||
"sha256:b30042fe92dbd79f1ba7f6898fada10bdaad1847c44f2dff9a16147e00a93661",
|
||||
"sha256:b606b1aaf802e6468c2608c65ff7ece53eae1a6874b3765f69b8ceb20c5fa78e",
|
||||
"sha256:b6207dc8fb3c8cb5668e885cef9ec7f70189bec4e276f0ff70d5aa078d32c88e",
|
||||
"sha256:c2aed8fcf8abc3020d6a9ccb31dbc9e7d7819c56a348cc88fd44be269b37427e",
|
||||
"sha256:cb24cca1968b21355cc6f3da1a20cd1cebd8a023e3c5b09b432444617949085a",
|
||||
"sha256:cff210198bb4cae3f3c100444c5eaa573a823f05c253e7188e1362a5555235b3",
|
||||
"sha256:d35717333b39d1b6bb8433fa758a55f1081543de527171543a2b710551d40881",
|
||||
"sha256:df12a1f99b99f569a7c2ae59aa2d31724e8d835fc7f33e14f4792e3071d11221",
|
||||
"sha256:e09d40edfdb4e260cb1567d8ae770ccf3b8b7e9f0d9b5c2a9992696b30ce2742",
|
||||
"sha256:e12c6c1ce84628c52d6367863773f7c8c8241be554e8b79686e91a43f1733773",
|
||||
"sha256:e2b8cd48a9942ed3f85b95ca4105c45758438c7ed28fff1e4ce3e57c3b589d8e",
|
||||
"sha256:e500aba968a48e9019e42c0c199b7ec0696a97fa69037bea163b55398e390529",
|
||||
"sha256:ebe5e59545401fbb1b24da76f006ab19734ae71e703cdb4a8b347e84a0cece67",
|
||||
"sha256:f0dd071b95bbca244f4cb7f70b77d2ff3aaaba7fa16dc41f58d14854a6204e6c",
|
||||
"sha256:f8c8b141ef9699ae777c6278b52c706b653bf15d135d302754f6b2e90eb30367"
|
||||
],
|
||||
"markers": "python_version >= '3.10'",
|
||||
"version": "==2.1.3"
|
||||
"version": "==2.2.0"
|
||||
},
|
||||
"packaging": {
|
||||
"hashes": [
|
||||
@ -532,6 +570,36 @@
|
||||
"markers": "python_version >= '3.9'",
|
||||
"version": "==3.2.0"
|
||||
},
|
||||
"pyside6": {
|
||||
"hashes": [
|
||||
"sha256:6d1fd95651cdbdea741af21e155350986eca31ff015fc4c721ce01c2a110a4cc",
|
||||
"sha256:7d6adc5d53313249bbe02edb673877c1d437e215d71e88da78412520653f5c9f",
|
||||
"sha256:866eeaca3ffead6b9d30fa3ed395d5624da0246d7586c8b8207e77ac65d82458",
|
||||
"sha256:ddeeaeca8ebd0ddb1ded30dd33e9240a40f330cc91832de346ba6c9d0cd1253e"
|
||||
],
|
||||
"markers": "python_version < '3.14' and python_version >= '3.9'",
|
||||
"version": "==6.8.1"
|
||||
},
|
||||
"pyside6-addons": {
|
||||
"hashes": [
|
||||
"sha256:570a25016d80046274f454ed0bb06734f478ce6c21be5dec62b624773fc7504e",
|
||||
"sha256:879c12346b4b76f5d5ee6499d8ca53b5666c0c998b8fdf8780f08f69ea95d6f9",
|
||||
"sha256:d7c8c1e89ee0db84631d5b8fdb9129d9d2a0ffb3b4cb2f5192dc8367dd980db4",
|
||||
"sha256:f80cc03c1ac54132c6f800aa461dced64acd7d1646898db164ccb56fe3c23dd4"
|
||||
],
|
||||
"markers": "python_version < '3.14' and python_version >= '3.9'",
|
||||
"version": "==6.8.1"
|
||||
},
|
||||
"pyside6-essentials": {
|
||||
"hashes": [
|
||||
"sha256:2f600b149e65b57acd6a444edb17615adc42cc2491548ae443ccb574036d86b1",
|
||||
"sha256:bd05155245e3cd1572e68d72772e78fadfd713575bbfdd2c5e060d5278e390e9",
|
||||
"sha256:bf8a3c9ee0b997eb18fb00cb09aacaa28b8a51ce3c295a252cc594c5530aba56",
|
||||
"sha256:d5ed4ddb149f36d65bc49ae4260b2d213ee88b2d9a309012ae27f38158c2d1b6"
|
||||
],
|
||||
"markers": "python_version < '3.14' and python_version >= '3.9'",
|
||||
"version": "==6.8.1"
|
||||
},
|
||||
"python-dateutil": {
|
||||
"hashes": [
|
||||
"sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3",
|
||||
@ -549,11 +617,11 @@
|
||||
},
|
||||
"scikit-rf": {
|
||||
"hashes": [
|
||||
"sha256:722def5442bb7033d608e8d3f717b38a3315846496925e85e8015cf006c36bb7",
|
||||
"sha256:d7e1de31842d8922d1c741de7cc09aecf083a94ddc408ee2fe3f36a284858a09"
|
||||
"sha256:796758dcd79650d8c66585583ac8ef13afde0d65d2da324ec60a4557eae52a9a",
|
||||
"sha256:9864653abf0761049ba95deb37741581fff5cf8d43f4acf6e46576e34e04ad43"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==1.4.1"
|
||||
"version": "==1.5.0"
|
||||
},
|
||||
"scipy": {
|
||||
"hashes": [
|
||||
@ -594,13 +662,23 @@
|
||||
"markers": "python_version >= '3.10'",
|
||||
"version": "==1.14.1"
|
||||
},
|
||||
"shiboken6": {
|
||||
"hashes": [
|
||||
"sha256:1dc4c1976809b0e68872bb98474cccd590455bdcd015f0e0639907e94af27b6a",
|
||||
"sha256:3ea127fd72be113b73cacd70e06687ad6f83c1c888047833c7dcdd5cf8e7f586",
|
||||
"sha256:9a2f51d1ddd3b6d193a0f0fdc09f8d41f2092bc664723c9b9efc1056660d0608",
|
||||
"sha256:ab5b60602ca6227103138aae89c4f5df3b1b8e249cbc8ec9e6e2a57f20ad9a91"
|
||||
],
|
||||
"markers": "python_version < '3.14' and python_version >= '3.9'",
|
||||
"version": "==6.8.1"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
||||
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
||||
"sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274",
|
||||
"sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.16.0"
|
||||
"version": "==1.17.0"
|
||||
},
|
||||
"typing-extensions": {
|
||||
"hashes": [
|
||||
@ -620,11 +698,11 @@
|
||||
},
|
||||
"xarray": {
|
||||
"hashes": [
|
||||
"sha256:ae1d38cb44a0324dfb61e492394158ae22389bf7de9f3c174309c17376df63a0",
|
||||
"sha256:e369e2bac430e418c2448e5b96f07da4635f98c1319aa23cfeb3fbcb9a01d2e0"
|
||||
"sha256:1ccace44573ddb862e210ad3ec204210654d2c750bec11bbe7d842dfc298591f",
|
||||
"sha256:6ee94f63ddcbdd0cf3909d1177f78cdac756640279c0e32ae36819a89cdaba37"
|
||||
],
|
||||
"markers": "python_version >= '3.10'",
|
||||
"version": "==2024.10.0"
|
||||
"version": "==2024.11.0"
|
||||
},
|
||||
"zarr": {
|
||||
"hashes": [
|
||||
@ -638,10 +716,48 @@
|
||||
"develop": {
|
||||
"asttokens": {
|
||||
"hashes": [
|
||||
"sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24",
|
||||
"sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"
|
||||
"sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7",
|
||||
"sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2"
|
||||
],
|
||||
"version": "==2.4.1"
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==3.0.0"
|
||||
},
|
||||
"black": {
|
||||
"hashes": [
|
||||
"sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f",
|
||||
"sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd",
|
||||
"sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea",
|
||||
"sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981",
|
||||
"sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b",
|
||||
"sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7",
|
||||
"sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8",
|
||||
"sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175",
|
||||
"sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d",
|
||||
"sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392",
|
||||
"sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad",
|
||||
"sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f",
|
||||
"sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f",
|
||||
"sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b",
|
||||
"sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875",
|
||||
"sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3",
|
||||
"sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800",
|
||||
"sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65",
|
||||
"sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2",
|
||||
"sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812",
|
||||
"sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50",
|
||||
"sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "python_version >= '3.9'",
|
||||
"version": "==24.10.0"
|
||||
},
|
||||
"click": {
|
||||
"hashes": [
|
||||
"sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28",
|
||||
"sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==8.1.7"
|
||||
},
|
||||
"comm": {
|
||||
"hashes": [
|
||||
@ -653,12 +769,35 @@
|
||||
},
|
||||
"debugpy": {
|
||||
"hashes": [
|
||||
"sha256:a6531d952b565b7cb2fbd1ef5df3d333cf160b44f37547a4e7cf73666aca5d8d",
|
||||
"sha256:e6355385db85cbd666be703a96ab7351bc9e6c61d694893206f8001e22aee091",
|
||||
"sha256:ec684553aba5b4066d4de510859922419febc710df7bba04fe9e7ef3de15d34f"
|
||||
"sha256:0e22f846f4211383e6a416d04b4c13ed174d24cc5d43f5fd52e7821d0ebc8920",
|
||||
"sha256:116bf8342062246ca749013df4f6ea106f23bc159305843491f64672a55af2e5",
|
||||
"sha256:189058d03a40103a57144752652b3ab08ff02b7595d0ce1f651b9acc3a3a35a0",
|
||||
"sha256:23dc34c5e03b0212fa3c49a874df2b8b1b8fda95160bd79c01eb3ab51ea8d851",
|
||||
"sha256:28e45b3f827d3bf2592f3cf7ae63282e859f3259db44ed2b129093ca0ac7940b",
|
||||
"sha256:2b26fefc4e31ff85593d68b9022e35e8925714a10ab4858fb1b577a8a48cb8cd",
|
||||
"sha256:32db46ba45849daed7ccf3f2e26f7a386867b077f39b2a974bb5c4c2c3b0a280",
|
||||
"sha256:40499a9979c55f72f4eb2fc38695419546b62594f8af194b879d2a18439c97a9",
|
||||
"sha256:44b1b8e6253bceada11f714acf4309ffb98bfa9ac55e4fce14f9e5d4484287a1",
|
||||
"sha256:52c3cf9ecda273a19cc092961ee34eb9ba8687d67ba34cc7b79a521c1c64c4c0",
|
||||
"sha256:52d8a3166c9f2815bfae05f386114b0b2d274456980d41f320299a8d9a5615a7",
|
||||
"sha256:61bc8b3b265e6949855300e84dc93d02d7a3a637f2aec6d382afd4ceb9120c9f",
|
||||
"sha256:654130ca6ad5de73d978057eaf9e582244ff72d4574b3e106fb8d3d2a0d32458",
|
||||
"sha256:6ad2688b69235c43b020e04fecccdf6a96c8943ca9c2fb340b8adc103c655e57",
|
||||
"sha256:6c1f6a173d1140e557347419767d2b14ac1c9cd847e0b4c5444c7f3144697e4e",
|
||||
"sha256:84e511a7545d11683d32cdb8f809ef63fc17ea2a00455cc62d0a4dbb4ed1c308",
|
||||
"sha256:85de8474ad53ad546ff1c7c7c89230db215b9b8a02754d41cb5a76f70d0be296",
|
||||
"sha256:8988f7163e4381b0da7696f37eec7aca19deb02e500245df68a7159739bbd0d3",
|
||||
"sha256:8da1db4ca4f22583e834dcabdc7832e56fe16275253ee53ba66627b86e304da1",
|
||||
"sha256:8ffc382e4afa4aee367bf413f55ed17bd91b191dcaf979890af239dda435f2a1",
|
||||
"sha256:987bce16e86efa86f747d5151c54e91b3c1e36acc03ce1ddb50f9d09d16ded0e",
|
||||
"sha256:ad7efe588c8f5cf940f40c3de0cd683cc5b76819446abaa50dc0829a30c094db",
|
||||
"sha256:bb3b15e25891f38da3ca0740271e63ab9db61f41d4d8541745cfc1824252cb28",
|
||||
"sha256:c928bbf47f65288574b78518449edaa46c82572d340e2750889bbf8cd92f3737",
|
||||
"sha256:ce291a5aca4985d82875d6779f61375e959208cdf09fcec40001e65fb0a54768",
|
||||
"sha256:d8768edcbeb34da9e11bcb8b5c2e0958d25218df7a6e56adf415ef262cd7b6d1"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==1.8.8"
|
||||
"version": "==1.8.11"
|
||||
},
|
||||
"decorator": {
|
||||
"hashes": [
|
||||
@ -684,6 +823,15 @@
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==2.1.0"
|
||||
},
|
||||
"flake8": {
|
||||
"hashes": [
|
||||
"sha256:049d058491e228e03e67b390f311bbf88fce2dbaa8fa673e7aea87b7198b8d38",
|
||||
"sha256:597477df7860daa5aa0fdd84bf5208a043ab96b8e96ab708770ae0364dd03213"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "python_full_version >= '3.8.1'",
|
||||
"version": "==7.1.1"
|
||||
},
|
||||
"ipykernel": {
|
||||
"hashes": [
|
||||
"sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5",
|
||||
@ -695,11 +843,11 @@
|
||||
},
|
||||
"ipython": {
|
||||
"hashes": [
|
||||
"sha256:0188a1bd83267192123ccea7f4a8ed0a78910535dbaa3f37671dca76ebd429c8",
|
||||
"sha256:40b60e15b22591450eef73e40a027cf77bd652e757523eebc5bd7c7c498290eb"
|
||||
"sha256:85ec56a7e20f6c38fce7727dcca699ae4ffc85985aa7b23635a8008f918ae321",
|
||||
"sha256:cb0a405a306d2995a5cbb9901894d240784a9f341394c6ba3f4fe8c6eb89ff6e"
|
||||
],
|
||||
"markers": "python_version >= '3.10'",
|
||||
"version": "==8.29.0"
|
||||
"version": "==8.30.0"
|
||||
},
|
||||
"ipywidgets": {
|
||||
"hashes": [
|
||||
@ -710,13 +858,22 @@
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==8.1.5"
|
||||
},
|
||||
"isort": {
|
||||
"hashes": [
|
||||
"sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109",
|
||||
"sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "python_full_version >= '3.8.0'",
|
||||
"version": "==5.13.2"
|
||||
},
|
||||
"jedi": {
|
||||
"hashes": [
|
||||
"sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd",
|
||||
"sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"
|
||||
"sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0",
|
||||
"sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==0.19.1"
|
||||
"version": "==0.19.2"
|
||||
},
|
||||
"jupyter-client": {
|
||||
"hashes": [
|
||||
@ -750,6 +907,22 @@
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==0.1.7"
|
||||
},
|
||||
"mccabe": {
|
||||
"hashes": [
|
||||
"sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325",
|
||||
"sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==0.7.0"
|
||||
},
|
||||
"mypy-extensions": {
|
||||
"hashes": [
|
||||
"sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d",
|
||||
"sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==1.0.0"
|
||||
},
|
||||
"nest-asyncio": {
|
||||
"hashes": [
|
||||
"sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe",
|
||||
@ -774,6 +947,14 @@
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==0.8.4"
|
||||
},
|
||||
"pathspec": {
|
||||
"hashes": [
|
||||
"sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08",
|
||||
"sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==0.12.1"
|
||||
},
|
||||
"pexpect": {
|
||||
"hashes": [
|
||||
"sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523",
|
||||
@ -835,6 +1016,22 @@
|
||||
],
|
||||
"version": "==0.2.3"
|
||||
},
|
||||
"pycodestyle": {
|
||||
"hashes": [
|
||||
"sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3",
|
||||
"sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==2.12.1"
|
||||
},
|
||||
"pyflakes": {
|
||||
"hashes": [
|
||||
"sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f",
|
||||
"sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==3.2.0"
|
||||
},
|
||||
"pygments": {
|
||||
"hashes": [
|
||||
"sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199",
|
||||
@ -968,11 +1165,11 @@
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
||||
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
||||
"sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274",
|
||||
"sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.16.0"
|
||||
"version": "==1.17.0"
|
||||
},
|
||||
"stack-data": {
|
||||
"hashes": [
|
||||
@ -981,22 +1178,60 @@
|
||||
],
|
||||
"version": "==0.6.3"
|
||||
},
|
||||
"tomli": {
|
||||
"hashes": [
|
||||
"sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6",
|
||||
"sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd",
|
||||
"sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c",
|
||||
"sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b",
|
||||
"sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8",
|
||||
"sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6",
|
||||
"sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77",
|
||||
"sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff",
|
||||
"sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea",
|
||||
"sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192",
|
||||
"sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249",
|
||||
"sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee",
|
||||
"sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4",
|
||||
"sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98",
|
||||
"sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8",
|
||||
"sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4",
|
||||
"sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281",
|
||||
"sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744",
|
||||
"sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69",
|
||||
"sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13",
|
||||
"sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140",
|
||||
"sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e",
|
||||
"sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e",
|
||||
"sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc",
|
||||
"sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff",
|
||||
"sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec",
|
||||
"sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2",
|
||||
"sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222",
|
||||
"sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106",
|
||||
"sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272",
|
||||
"sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a",
|
||||
"sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"
|
||||
],
|
||||
"markers": "python_version < '3.11'",
|
||||
"version": "==2.2.1"
|
||||
},
|
||||
"tornado": {
|
||||
"hashes": [
|
||||
"sha256:163b0aafc8e23d8cdc3c9dfb24c5368af84a81e3364745ccb4427669bf84aec8",
|
||||
"sha256:25486eb223babe3eed4b8aecbac33b37e3dd6d776bc730ca14e1bf93888b979f",
|
||||
"sha256:454db8a7ecfcf2ff6042dde58404164d969b6f5d58b926da15e6b23817950fc4",
|
||||
"sha256:613bf4ddf5c7a95509218b149b555621497a6cc0d46ac341b30bd9ec19eac7f3",
|
||||
"sha256:6d5ce3437e18a2b66fbadb183c1d3364fb03f2be71299e7d10dbeeb69f4b2a14",
|
||||
"sha256:8ae50a504a740365267b2a8d1a90c9fbc86b780a39170feca9bcc1787ff80842",
|
||||
"sha256:92d3ab53183d8c50f8204a51e6f91d18a15d5ef261e84d452800d4ff6fc504e9",
|
||||
"sha256:a02a08cc7a9314b006f653ce40483b9b3c12cda222d6a46d4ac63bb6c9057698",
|
||||
"sha256:b24b8982ed444378d7f21d563f4180a2de31ced9d8d84443907a0a64da2072e7",
|
||||
"sha256:d9a566c40b89757c9aa8e6f032bcdb8ca8795d7c1a9762910c722b1635c9de4d",
|
||||
"sha256:e2e20b9113cd7293f164dc46fffb13535266e713cdb87bd2d15ddb336e96cfc4"
|
||||
"sha256:072ce12ada169c5b00b7d92a99ba089447ccc993ea2143c9ede887e0937aa803",
|
||||
"sha256:1a017d239bd1bb0919f72af256a970624241f070496635784d9bf0db640d3fec",
|
||||
"sha256:2876cef82e6c5978fde1e0d5b1f919d756968d5b4282418f3146b79b58556482",
|
||||
"sha256:304463bd0772442ff4d0f5149c6f1c2135a1fae045adf070821c6cdc76980634",
|
||||
"sha256:908b71bf3ff37d81073356a5fadcc660eb10c1476ee6e2725588626ce7e5ca38",
|
||||
"sha256:92bad5b4746e9879fd7bf1eb21dce4e3fc5128d71601f80005afa39237ad620b",
|
||||
"sha256:932d195ca9015956fa502c6b56af9eb06106140d844a335590c1ec7f5277d10c",
|
||||
"sha256:bca9eb02196e789c9cb5c3c7c0f04fb447dc2adffd95265b2c7223a8a615ccbf",
|
||||
"sha256:c36e62ce8f63409301537222faffcef7dfc5284f27eec227389f2ad11b09d946",
|
||||
"sha256:c82c46813ba483a385ab2a99caeaedf92585a1f90defb5693351fa7e4ea0bf73",
|
||||
"sha256:e828cce1123e9e44ae2a50a9de3055497ab1d0aeb440c5ac23064d9e44880da1"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==6.4.1"
|
||||
"version": "==6.4.2"
|
||||
},
|
||||
"traitlets": {
|
||||
"hashes": [
|
||||
|
57
README.md
57
README.md
@ -1,13 +1,43 @@
|
||||
# Charon
|
||||
# Charon VNA
|
||||
|
||||
Named after [Pluto's moon](https://en.wikipedia.org/wiki/Charon_(moon)), Charon is a simple RF switch assembly for using the [ADI Pluto SDR]() as a vector network analyzer.
|
||||
Named after [Pluto's moon](https://en.wikipedia.org/wiki/Charon_(moon)), Charon uses the [ADI Pluto SDR](https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/adalm-pluto.html) as a vector network analyzer. The basic usage is as a 1 port VNA but this can be extended to arbitrarily many ports with the addition of a couple RF switches.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Install LibIIO. This is a dependency of [PyADI-IIO](https://wiki.analog.com/resources/tools-software/linux-software/pyadi-iio).
|
||||
On Ubuntu 22.04 just run `sudo apt-get install -y libiio-dev`
|
||||
|
||||
2. `pip install charon-vna`
|
||||
2. Charon releases are published on [PyPi](https://pypi.org/project/charon-vna/). Install using pip:
|
||||
`pip install charon-vna`
|
||||
|
||||
## Hardware Setup
|
||||
|
||||
You need a few things:
|
||||
- [Analog Devices Pluto SDR](https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/adalm-pluto.html)
|
||||
- Any variant of the Pluto *should* work too such as the [Pluto+](https://github.com/plutoplus/plutoplus?tab=readme-ov-file) however I have only tested with the basic flavor
|
||||
- Note that you _must_ have two receive ports which means revision C or later of the basic Pluto
|
||||
- Directional couplers (1 per port up to 4 ports)
|
||||
- I have been using [AAMCS-UDC-0.5G-18G-10dB-Sf](http://www.aa-mcs.com/wp-content/uploads/documents/AAMCS-UDC-0.5G-18G-10dB-Sf.pdf)
|
||||
- Charon switch board - coming soon.
|
||||
- Optional. Without this you'll be limited to S11 and uncalibrated S21 measurements (with required re-cabling)
|
||||
- There's nothing special about this particular board, if you want more than 4 ports you can make your own pretty easily. You just need 3 SPxT switches. Note that these switches will see tons of cycles so avoid mechanical switches
|
||||
- SMA cables
|
||||
- Calibration standard
|
||||
- Ideally something with s-parameters measured on a better VNA
|
||||
- I have used a basic SMA load and two modified SMA jacks with decent results
|
||||
|
||||
### Pluto Configuration
|
||||
|
||||
Most of my testing is with Pluto firmware [v0.39](https://github.com/analogdevicesinc/plutosdr-fw/releases/tag/v0.39) though this may work with other firmware versions. I had issues with the Pluto sometimes seeing no signal which resolved when I upgraded from v0.35. Instructions for upgrading firmware are on the [Analog Devices wiki](https://wiki.analog.com/university/tools/pluto/users/firmware).
|
||||
|
||||
We need two receive channels on the SDR. If you have a Pluto+ that should already be configured and you can skip this step.
|
||||
|
||||
Analog devices has a [guide](https://wiki.analog.com/university/tools/pluto/users/customizing#updating_to_the_ad9364) for enabling the second channel. Ideally this should be set as `ad9361` to enable a wider band of operation in addition to the second channel, however the critical setting is enabling 2r2t. SSH into the Pluto and run the following:
|
||||
```bash
|
||||
fw_setenv attr_name compatible
|
||||
fw_setenv attr_val ad9361
|
||||
fw_setenv mode 2r2t
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
@ -27,20 +57,9 @@ If you have an RF power meter you can generate your own power calibration.
|
||||
|
||||
Note that unlike the main calibration, power calibration frequencies do not need to match the measurement frequencies. Values are interpolated.
|
||||
|
||||
## Hardware
|
||||
## References
|
||||
|
||||
You need a few things:
|
||||
- [Analog Devices Pluto SDR](https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/adalm-pluto.html).
|
||||
Any variant of the Pluto *should* work too such as the [Pluto+](https://github.com/plutoplus/plutoplus?tab=readme-ov-file)
|
||||
- Directional couplers (1 per port up to 4 ports).
|
||||
I have been using [AAMCS-UDC-0.5G-18G-10dB-Sf](http://www.aa-mcs.com/wp-content/uploads/documents/AAMCS-UDC-0.5G-18G-10dB-Sf.pdf)
|
||||
- Charon switch board - coming soon.
|
||||
Without this, you'll be limited to S11 and uncalibrated S21 measurements (with required re-cabling).
|
||||
There's nothing special about this particular board, if you want more than 4 ports you can make your own pretty easily. You just need 3 SPxT switches. Note that these switches will see tons of cycles so avoid mechanical switches.
|
||||
- SMA cables
|
||||
|
||||
### Pluto Modification
|
||||
|
||||
We need two receive channels on the SDR. If you have a Pluto+ that should already be configured and you can skip this step.
|
||||
|
||||
Analog devices has a [guide](https://wiki.analog.com/university/tools/pluto/users/customizing#updating_to_the_ad9364) for enabling the second channel. Ideally this should be set as `ad9361` to enable a wider band of operation in addition to the second channel, however the critical setting is enabling 2r2t.
|
||||
#### Pluto Default Connection Settings
|
||||
user: `root`
|
||||
password: `analog`
|
||||
ip: `192.168.2.1`
|
26
charon_vna/cli.py
Normal file
26
charon_vna/cli.py
Normal file
@ -0,0 +1,26 @@
|
||||
# %% imports
|
||||
from pathlib import Path
|
||||
|
||||
import click
|
||||
|
||||
# from charon_vna.vna import Charon
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.argument("start", type=float)
|
||||
@click.argument("stop", type=float)
|
||||
@click.argument("pts", type=int)
|
||||
@click.option("--ports", "-n", type=int, default=1, help="Number of ports.")
|
||||
@click.option("--power", "-p", type=float, default=-5, help="Port output power [dBm].")
|
||||
@click.option("--snp", "-o", type=click.Path(), help="Path for output Touchstone file.")
|
||||
def capture(start: float, stop: float, pts: int, power: float, snp: Path, ports: int):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
# %%
|
||||
def main():
|
||||
capture()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
505
charon_vna/config_default.json
Normal file
505
charon_vna/config_default.json
Normal file
@ -0,0 +1,505 @@
|
||||
{
|
||||
"frequency": [
|
||||
80000000.0,
|
||||
80841683.36673346,
|
||||
81683366.73346694,
|
||||
82525050.1002004,
|
||||
83366733.46693386,
|
||||
84208416.83366734,
|
||||
85050100.2004008,
|
||||
85891783.56713426,
|
||||
86733466.93386774,
|
||||
87575150.3006012,
|
||||
88416833.66733468,
|
||||
89258517.03406814,
|
||||
90100200.4008016,
|
||||
90941883.76753508,
|
||||
91783567.13426854,
|
||||
92625250.501002,
|
||||
93466933.86773548,
|
||||
94308617.23446894,
|
||||
95150300.6012024,
|
||||
95991983.96793588,
|
||||
96833667.33466934,
|
||||
97675350.70140281,
|
||||
98517034.06813627,
|
||||
99358717.43486974,
|
||||
100200400.8016032,
|
||||
101042084.16833667,
|
||||
101883767.53507014,
|
||||
102725450.90180361,
|
||||
103567134.26853707,
|
||||
104408817.63527054,
|
||||
105250501.00200401,
|
||||
106092184.36873747,
|
||||
106933867.73547095,
|
||||
107775551.10220441,
|
||||
108617234.46893787,
|
||||
109458917.83567134,
|
||||
110300601.20240481,
|
||||
111142284.56913827,
|
||||
111983967.93587175,
|
||||
112825651.30260521,
|
||||
113667334.66933867,
|
||||
114509018.03607213,
|
||||
115350701.40280561,
|
||||
116192384.76953909,
|
||||
117034068.13627255,
|
||||
117875751.50300601,
|
||||
118717434.86973947,
|
||||
119559118.23647295,
|
||||
120400801.60320641,
|
||||
121242484.96993989,
|
||||
122084168.33667335,
|
||||
122925851.70340681,
|
||||
123767535.07014027,
|
||||
124609218.43687375,
|
||||
125450901.80360723,
|
||||
126292585.17034069,
|
||||
127134268.53707415,
|
||||
127975951.90380761,
|
||||
128817635.27054109,
|
||||
129659318.63727455,
|
||||
130501002.00400802,
|
||||
131342685.37074149,
|
||||
132184368.73747495,
|
||||
133026052.10420841,
|
||||
133867735.47094189,
|
||||
134709418.83767536,
|
||||
135551102.20440882,
|
||||
136392785.5711423,
|
||||
137234468.93787575,
|
||||
138076152.30460924,
|
||||
138917835.67134267,
|
||||
139759519.03807616,
|
||||
140601202.40480962,
|
||||
141442885.7715431,
|
||||
142284569.13827655,
|
||||
143126252.50501,
|
||||
143967935.8717435,
|
||||
144809619.23847696,
|
||||
145651302.60521042,
|
||||
146492985.97194389,
|
||||
147334669.33867735,
|
||||
148176352.70541084,
|
||||
149018036.07214427,
|
||||
149859719.43887776,
|
||||
150701402.80561122,
|
||||
151543086.17234468,
|
||||
152384769.53907818,
|
||||
153226452.9058116,
|
||||
154068136.2725451,
|
||||
154909819.63927856,
|
||||
155751503.00601202,
|
||||
156593186.3727455,
|
||||
157434869.73947895,
|
||||
158276553.10621244,
|
||||
159118236.4729459,
|
||||
159959919.83967936,
|
||||
160801603.20641282,
|
||||
161643286.57314628,
|
||||
162484969.93987978,
|
||||
163326653.30661324,
|
||||
164168336.6733467,
|
||||
165010020.04008016,
|
||||
165851703.40681362,
|
||||
166693386.7735471,
|
||||
167535070.14028054,
|
||||
168376753.50701404,
|
||||
169218436.8737475,
|
||||
170060120.24048096,
|
||||
170901803.60721445,
|
||||
171743486.97394788,
|
||||
172585170.34068137,
|
||||
173426853.70741484,
|
||||
174268537.0741483,
|
||||
175110220.4408818,
|
||||
175951903.80761522,
|
||||
176793587.1743487,
|
||||
177635270.54108217,
|
||||
178476953.90781564,
|
||||
179318637.2745491,
|
||||
180160320.64128256,
|
||||
181002004.00801605,
|
||||
181843687.37474948,
|
||||
182685370.74148297,
|
||||
183527054.10821643,
|
||||
184368737.4749499,
|
||||
185210420.8416834,
|
||||
186052104.20841682,
|
||||
186893787.5751503,
|
||||
187735470.94188377,
|
||||
188577154.30861723,
|
||||
189418837.67535073,
|
||||
190260521.04208416,
|
||||
191102204.40881765,
|
||||
191943887.7755511,
|
||||
192785571.14228457,
|
||||
193627254.50901806,
|
||||
194468937.8757515,
|
||||
195310621.242485,
|
||||
196152304.60921845,
|
||||
196993987.9759519,
|
||||
197835671.34268537,
|
||||
198677354.70941883,
|
||||
199519038.07615232,
|
||||
200360721.44288576,
|
||||
201202404.80961925,
|
||||
202044088.1763527,
|
||||
202885771.54308617,
|
||||
203727454.90981966,
|
||||
204569138.2765531,
|
||||
205410821.6432866,
|
||||
206252505.01002005,
|
||||
207094188.3767535,
|
||||
207935871.743487,
|
||||
208777555.11022043,
|
||||
209619238.47695392,
|
||||
210460921.8436874,
|
||||
211302605.21042085,
|
||||
212144288.5771543,
|
||||
212985971.94388777,
|
||||
213827655.31062126,
|
||||
214669338.67735472,
|
||||
215511022.04408818,
|
||||
216352705.41082165,
|
||||
217194388.7775551,
|
||||
218036072.14428857,
|
||||
218877755.51102206,
|
||||
219719438.87775552,
|
||||
220561122.24448898,
|
||||
221402805.61122245,
|
||||
222244488.9779559,
|
||||
223086172.3446894,
|
||||
223927855.71142286,
|
||||
224769539.07815632,
|
||||
225611222.44488978,
|
||||
226452905.81162325,
|
||||
227294589.1783567,
|
||||
228136272.5450902,
|
||||
228977955.91182366,
|
||||
229819639.27855712,
|
||||
230661322.64529058,
|
||||
231503006.01202404,
|
||||
232344689.37875754,
|
||||
233186372.745491,
|
||||
234028056.11222446,
|
||||
234869739.47895792,
|
||||
235711422.84569138,
|
||||
236553106.21242484,
|
||||
237394789.57915834,
|
||||
238236472.9458918,
|
||||
239078156.31262526,
|
||||
239919839.67935872,
|
||||
240761523.04609218,
|
||||
241603206.41282564,
|
||||
242444889.77955914,
|
||||
243286573.1462926,
|
||||
244128256.51302606,
|
||||
244969939.87975952,
|
||||
245811623.24649298,
|
||||
246653306.61322647,
|
||||
247494989.97995993,
|
||||
248336673.3466934,
|
||||
249178356.71342686,
|
||||
250020040.08016032,
|
||||
250861723.44689378,
|
||||
251703406.81362727,
|
||||
252545090.18036073,
|
||||
253386773.5470942,
|
||||
254228456.91382766,
|
||||
255070140.28056112,
|
||||
255911823.6472946,
|
||||
256753507.01402807,
|
||||
257595190.38076153,
|
||||
258436873.747495,
|
||||
259278557.11422846,
|
||||
260120240.48096192,
|
||||
260961923.8476954,
|
||||
261803607.21442887,
|
||||
262645290.58116233,
|
||||
263486973.9478958,
|
||||
264328657.31462926,
|
||||
265170340.68136275,
|
||||
266012024.0480962,
|
||||
266853707.41482967,
|
||||
267695390.78156313,
|
||||
268537074.1482966,
|
||||
269378757.51503,
|
||||
270220440.8817636,
|
||||
271062124.248497,
|
||||
271903807.61523044,
|
||||
272745490.98196393,
|
||||
273587174.3486974,
|
||||
274428857.71543086,
|
||||
275270541.08216435,
|
||||
276112224.44889784,
|
||||
276953907.8156313,
|
||||
277795591.1823647,
|
||||
278637274.5490982,
|
||||
279478957.9158317,
|
||||
280320641.2825651,
|
||||
281162324.6492986,
|
||||
282004008.0160321,
|
||||
282845691.38276553,
|
||||
283687374.74949896,
|
||||
284529058.1162325,
|
||||
285370741.48296595,
|
||||
286212424.8496994,
|
||||
287054108.21643287,
|
||||
287895791.58316636,
|
||||
288737474.9498998,
|
||||
289579158.3166333,
|
||||
290420841.6833668,
|
||||
291262525.0501002,
|
||||
292104208.41683364,
|
||||
292945891.78356713,
|
||||
293787575.1503006,
|
||||
294629258.51703405,
|
||||
295470941.88376755,
|
||||
296312625.25050104,
|
||||
297154308.61723447,
|
||||
297995991.98396796,
|
||||
298837675.35070145,
|
||||
299679358.7174349,
|
||||
300521042.0841683,
|
||||
301362725.4509018,
|
||||
302204408.8176353,
|
||||
303046092.1843687,
|
||||
303887775.5511022,
|
||||
304729458.9178357,
|
||||
305571142.28456914,
|
||||
306412825.6513026,
|
||||
307254509.0180361,
|
||||
308096192.38476956,
|
||||
308937875.751503,
|
||||
309779559.1182365,
|
||||
310621242.48497,
|
||||
311462925.8517034,
|
||||
312304609.2184369,
|
||||
313146292.5851704,
|
||||
313987975.9519038,
|
||||
314829659.31863725,
|
||||
315671342.68537074,
|
||||
316513026.05210423,
|
||||
317354709.41883767,
|
||||
318196392.78557116,
|
||||
319038076.15230465,
|
||||
319879759.5190381,
|
||||
320721442.8857715,
|
||||
321563126.25250506,
|
||||
322404809.6192385,
|
||||
323246492.9859719,
|
||||
324088176.3527054,
|
||||
324929859.7194389,
|
||||
325771543.08617234,
|
||||
326613226.45290583,
|
||||
327454909.8196393,
|
||||
328296593.18637276,
|
||||
329138276.5531062,
|
||||
329979959.9198397,
|
||||
330821643.2865732,
|
||||
331663326.6533066,
|
||||
332505010.0200401,
|
||||
333346693.3867736,
|
||||
334188376.753507,
|
||||
335030060.12024045,
|
||||
335871743.486974,
|
||||
336713426.85370743,
|
||||
337555110.22044086,
|
||||
338396793.58717436,
|
||||
339238476.95390785,
|
||||
340080160.3206413,
|
||||
340921843.6873748,
|
||||
341763527.05410826,
|
||||
342605210.4208417,
|
||||
343446893.7875751,
|
||||
344288577.1543086,
|
||||
345130260.5210421,
|
||||
345971943.88777554,
|
||||
346813627.25450903,
|
||||
347655310.6212425,
|
||||
348496993.98797596,
|
||||
349338677.35470945,
|
||||
350180360.7214429,
|
||||
351022044.08817637,
|
||||
351863727.45490986,
|
||||
352705410.8216433,
|
||||
353547094.1883768,
|
||||
354388777.5551102,
|
||||
355230460.9218437,
|
||||
356072144.28857714,
|
||||
356913827.65531063,
|
||||
357755511.0220441,
|
||||
358597194.38877755,
|
||||
359438877.75551105,
|
||||
360280561.1222445,
|
||||
361122244.48897797,
|
||||
361963927.85571146,
|
||||
362805611.2224449,
|
||||
363647294.5891784,
|
||||
364488977.9559118,
|
||||
365330661.3226453,
|
||||
366172344.6893788,
|
||||
367014028.05611223,
|
||||
367855711.4228457,
|
||||
368697394.78957915,
|
||||
369539078.15631264,
|
||||
370380761.5230461,
|
||||
371222444.88977957,
|
||||
372064128.25651306,
|
||||
372905811.6232465,
|
||||
373747494.98998,
|
||||
374589178.3567134,
|
||||
375430861.7234469,
|
||||
376272545.0901804,
|
||||
377114228.4569138,
|
||||
377955911.8236473,
|
||||
378797595.19038075,
|
||||
379639278.55711424,
|
||||
380480961.92384773,
|
||||
381322645.29058117,
|
||||
382164328.65731466,
|
||||
383006012.0240481,
|
||||
383847695.3907816,
|
||||
384689378.7575151,
|
||||
385531062.1242485,
|
||||
386372745.490982,
|
||||
387214428.8577154,
|
||||
388056112.2244489,
|
||||
388897795.59118235,
|
||||
389739478.95791584,
|
||||
390581162.32464933,
|
||||
391422845.69138277,
|
||||
392264529.05811626,
|
||||
393106212.4248497,
|
||||
393947895.7915832,
|
||||
394789579.1583167,
|
||||
395631262.5250501,
|
||||
396472945.8917836,
|
||||
397314629.258517,
|
||||
398156312.6252505,
|
||||
398997995.991984,
|
||||
399839679.35871744,
|
||||
400681362.72545093,
|
||||
401523046.09218436,
|
||||
402364729.45891786,
|
||||
403206412.8256513,
|
||||
404048096.1923848,
|
||||
404889779.5591183,
|
||||
405731462.9258517,
|
||||
406573146.2925852,
|
||||
407414829.6593186,
|
||||
408256513.0260521,
|
||||
409098196.3927856,
|
||||
409939879.75951904,
|
||||
410781563.12625253,
|
||||
411623246.49298596,
|
||||
412464929.85971946,
|
||||
413306613.22645295,
|
||||
414148296.5931864,
|
||||
414989979.95991987,
|
||||
415831663.3266533,
|
||||
416673346.6933868,
|
||||
417515030.0601203,
|
||||
418356713.4268537,
|
||||
419198396.7935872,
|
||||
420040080.16032064,
|
||||
420881763.52705413,
|
||||
421723446.89378756,
|
||||
422565130.26052105,
|
||||
423406813.62725455,
|
||||
424248496.993988,
|
||||
425090180.36072147,
|
||||
425931863.7274549,
|
||||
426773547.0941884,
|
||||
427615230.4609219,
|
||||
428456913.8276553,
|
||||
429298597.1943888,
|
||||
430140280.56112224,
|
||||
430981963.92785573,
|
||||
431823647.2945892,
|
||||
432665330.66132265,
|
||||
433507014.02805614,
|
||||
434348697.3947896,
|
||||
435190380.76152307,
|
||||
436032064.12825656,
|
||||
436873747.49499,
|
||||
437715430.8617235,
|
||||
438557114.2284569,
|
||||
439398797.5951904,
|
||||
440240480.96192384,
|
||||
441082164.3286573,
|
||||
441923847.6953908,
|
||||
442765531.06212425,
|
||||
443607214.42885774,
|
||||
444448897.7955912,
|
||||
445290581.16232467,
|
||||
446132264.52905816,
|
||||
446973947.8957916,
|
||||
447815631.2625251,
|
||||
448657314.6292585,
|
||||
449498997.995992,
|
||||
450340681.3627255,
|
||||
451182364.7294589,
|
||||
452024048.0961924,
|
||||
452865731.46292585,
|
||||
453707414.82965934,
|
||||
454549098.1963928,
|
||||
455390781.56312627,
|
||||
456232464.92985976,
|
||||
457074148.2965932,
|
||||
457915831.6633267,
|
||||
458757515.0300601,
|
||||
459599198.3967936,
|
||||
460440881.7635271,
|
||||
461282565.1302605,
|
||||
462124248.496994,
|
||||
462965931.86372745,
|
||||
463807615.23046094,
|
||||
464649298.59719443,
|
||||
465490981.96392787,
|
||||
466332665.33066136,
|
||||
467174348.6973948,
|
||||
468016032.0641283,
|
||||
468857715.4308618,
|
||||
469699398.7975952,
|
||||
470541082.1643287,
|
||||
471382765.5310621,
|
||||
472224448.8977956,
|
||||
473066132.26452905,
|
||||
473907815.63126254,
|
||||
474749498.99799603,
|
||||
475591182.36472946,
|
||||
476432865.73146296,
|
||||
477274549.0981964,
|
||||
478116232.4649299,
|
||||
478957915.83166337,
|
||||
479799599.1983968,
|
||||
480641282.5651303,
|
||||
481482965.9318637,
|
||||
482324649.2985972,
|
||||
483166332.6653307,
|
||||
484008016.03206414,
|
||||
484849699.39879763,
|
||||
485691382.76553106,
|
||||
486533066.13226455,
|
||||
487374749.498998,
|
||||
488216432.8657315,
|
||||
489058116.23246497,
|
||||
489899799.5991984,
|
||||
490741482.9659319,
|
||||
491583166.3326653,
|
||||
492424849.6993988,
|
||||
493266533.0661323,
|
||||
494108216.43286574,
|
||||
494949899.79959923,
|
||||
495791583.16633266,
|
||||
496633266.53306615,
|
||||
497474949.89979964,
|
||||
498316633.2665331,
|
||||
499158316.63326657,
|
||||
500000000.0
|
||||
],
|
||||
"power": -5
|
||||
}
|
25
charon_vna/config_default.py
Normal file
25
charon_vna/config_default.py
Normal file
@ -0,0 +1,25 @@
|
||||
import json
|
||||
import subprocess
|
||||
|
||||
import numpy as np
|
||||
|
||||
from charon_vna.gui import DEFAULT_CONFIG
|
||||
|
||||
config = dict(
|
||||
frequency=np.linspace(80e6, 500e6, 500).tolist(),
|
||||
power=-5,
|
||||
)
|
||||
|
||||
with open(DEFAULT_CONFIG, "w") as f:
|
||||
json.dump(config, f)
|
||||
|
||||
# autoformat
|
||||
subprocess.run(
|
||||
[
|
||||
"python",
|
||||
"-m",
|
||||
"json.tool",
|
||||
DEFAULT_CONFIG.resolve().as_posix(),
|
||||
DEFAULT_CONFIG.resolve().as_posix(),
|
||||
]
|
||||
)
|
268
charon_vna/gui.py
Normal file
268
charon_vna/gui.py
Normal file
@ -0,0 +1,268 @@
|
||||
# %% imports
|
||||
import json
|
||||
import pickle
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
import matplotlib as mpl
|
||||
import numpy as np
|
||||
import skrf as rf
|
||||
import xarray as xr
|
||||
from numpy import typing as npt
|
||||
from PySide6.QtGui import QAction, QKeySequence
|
||||
from PySide6.QtWidgets import (
|
||||
QApplication,
|
||||
QDialogButtonBox,
|
||||
QFileDialog,
|
||||
QInputDialog,
|
||||
QLineEdit,
|
||||
QMainWindow,
|
||||
QMenu,
|
||||
QProgressBar,
|
||||
QTabWidget,
|
||||
QVBoxLayout,
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from charon_vna.plots import PlotWidget
|
||||
from charon_vna.util import net2s, s2net
|
||||
from charon_vna.vna import Charon
|
||||
|
||||
# %%
|
||||
DEFAULT_CONFIG = Path(__file__).parent / "config_default.json"
|
||||
CONFIG_SUFFIX = ".json"
|
||||
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
config_path: Path | None
|
||||
# device: Charon
|
||||
|
||||
plots: List[PlotWidget]
|
||||
|
||||
def __init__(self, ip: str | None = None):
|
||||
super().__init__()
|
||||
|
||||
self.config_path = DEFAULT_CONFIG
|
||||
with open(self.config_path, "r") as f:
|
||||
config = json.load(f)
|
||||
self._frequency = config["frequency"]
|
||||
|
||||
vna_kwargs = dict(
|
||||
frequency=self._frequency,
|
||||
)
|
||||
if ip is not None:
|
||||
vna_kwargs["ip"] = ip
|
||||
self.vna = Charon(**vna_kwargs)
|
||||
|
||||
mpl.use("QtAgg")
|
||||
|
||||
self.setWindowTitle("Charon VNA")
|
||||
|
||||
# Menu
|
||||
menubar = self.menuBar()
|
||||
|
||||
menu_file = QMenu("&File")
|
||||
menubar.addMenu(menu_file)
|
||||
action_open_config = QAction("&Open Configuration", self)
|
||||
menu_file.addAction(action_open_config)
|
||||
action_open_config.triggered.connect(self.open_config)
|
||||
action_open_config.setShortcut(QKeySequence("Ctrl+O"))
|
||||
action_save_config = QAction("&Save Configuration", self)
|
||||
menu_file.addAction(action_save_config)
|
||||
action_save_config.triggered.connect(self.save_config)
|
||||
action_save_config.setShortcut(QKeySequence("Ctrl+S"))
|
||||
action_saveas_config = QAction("Save Configuration &As", self)
|
||||
menu_file.addAction(action_saveas_config)
|
||||
action_saveas_config.triggered.connect(self.saveas_config)
|
||||
action_saveas_config.setShortcut(QKeySequence("Ctrl+Shift+S"))
|
||||
|
||||
menu_stimulus = QMenu("&Stimulus")
|
||||
menubar.addMenu(menu_stimulus)
|
||||
action_set_frequency = QAction("&Frequency", self)
|
||||
menu_stimulus.addAction(action_set_frequency)
|
||||
action_set_frequency.triggered.connect(self.set_frequency)
|
||||
action_set_power = QAction("&Power", self)
|
||||
menu_stimulus.addAction(action_set_power)
|
||||
# action_set_power.triggered.connect(self.set_power)
|
||||
action_trigger = QAction("&Trigger", self)
|
||||
action_trigger.triggered.connect(self.capture)
|
||||
action_trigger.setShortcut("Ctrl+T")
|
||||
menu_stimulus.addAction(action_trigger)
|
||||
|
||||
menu_calibration = QMenu("&Calibration")
|
||||
menubar.addMenu(menu_calibration)
|
||||
action_cal_solt = QAction("&SOLT", self)
|
||||
action_cal_solt.triggered.connect(self.calibrate_solt)
|
||||
menu_calibration.addAction(action_cal_solt)
|
||||
|
||||
# Content
|
||||
window_layout = QVBoxLayout()
|
||||
|
||||
prog_sweep = QProgressBar()
|
||||
prog_sweep.setMinimum(0)
|
||||
prog_sweep.setMaximum(100)
|
||||
prog_sweep.setFormat("%v / %m")
|
||||
# prog_sweep.setTextVisible(False)
|
||||
prog_sweep.setValue(0)
|
||||
window_layout.addWidget(prog_sweep)
|
||||
self.prog_sweep = prog_sweep
|
||||
|
||||
plot_widget = QTabWidget()
|
||||
self.plots = []
|
||||
for type_ in [
|
||||
"logmag",
|
||||
"phase",
|
||||
"vswr",
|
||||
"smith",
|
||||
]:
|
||||
self.plots.append(PlotWidget(type_=type_))
|
||||
plot_widget.addTab(self.plots[-1], type_)
|
||||
window_layout.addWidget(plot_widget)
|
||||
|
||||
# Set the central widget of the Window.
|
||||
widget = QWidget()
|
||||
widget.setLayout(window_layout)
|
||||
self.setCentralWidget(widget)
|
||||
|
||||
def saveas_config(self) -> None:
|
||||
print("Prompting for save path...")
|
||||
dialog = QFileDialog(self)
|
||||
dialog.setDefaultSuffix(CONFIG_SUFFIX)
|
||||
dialog.setAcceptMode(QFileDialog.AcceptMode.AcceptSave)
|
||||
if dialog.exec():
|
||||
config_path = Path(dialog.selectedFiles()[0])
|
||||
if config_path.suffix != CONFIG_SUFFIX:
|
||||
raise ValueError(
|
||||
f"{config_path.name} is not a valid configuration file. Must have extension {CONFIG_SUFFIX}"
|
||||
)
|
||||
if config_path == DEFAULT_CONFIG:
|
||||
raise ValueError(f"Cannot overwrite default configuration file at {DEFAULT_CONFIG}")
|
||||
self.config_path = config_path
|
||||
print(f"Config path is now {self.config_path.resolve()}")
|
||||
|
||||
self.save_config()
|
||||
|
||||
def open_config(self) -> None:
|
||||
print("Prompting for load path...")
|
||||
dialog = QFileDialog(self)
|
||||
dialog.setNameFilter(f"*{CONFIG_SUFFIX}")
|
||||
dialog.setAcceptMode(QFileDialog.AcceptMode.AcceptOpen)
|
||||
if dialog.exec():
|
||||
config_path = Path(dialog.selectedFiles()[0])
|
||||
print(config_path)
|
||||
if config_path.suffix != CONFIG_SUFFIX:
|
||||
raise ValueError(
|
||||
f"{config_path.name} is not a valid configuration file. Must have extension {CONFIG_SUFFIX}"
|
||||
)
|
||||
self.config_path = config_path
|
||||
print(f"Config path is now {self.config_path.resolve()}")
|
||||
|
||||
self.load_config(self.config_path)
|
||||
|
||||
def save_config(self) -> None:
|
||||
if self.config_path == DEFAULT_CONFIG:
|
||||
self.saveas_config()
|
||||
else:
|
||||
print(f"Saving config to {self.config_path.resolve()}")
|
||||
# TODO: save config
|
||||
|
||||
def load_config(self, path: Path) -> None:
|
||||
print(f"Loading config from {path}...")
|
||||
# TODO: load config
|
||||
|
||||
def progress_callback(self, done: int, total: int):
|
||||
self.prog_sweep.setMaximum(total)
|
||||
self.prog_sweep.setValue(done)
|
||||
|
||||
def capture(self) -> None:
|
||||
s = self.vna.vna_capture(self._frequency, self.progress_callback)
|
||||
|
||||
if self.vna.calibration is not None:
|
||||
s_calibrated = self.vna.calibration.apply_cal(s2net(s))
|
||||
data = net2s(s_calibrated)
|
||||
else:
|
||||
data = xr.DataArray(
|
||||
[[s]],
|
||||
dims=["m", "n", "frequency"],
|
||||
coords=dict(
|
||||
frequency=s.coords["frequency"],
|
||||
m=[1],
|
||||
n=[1],
|
||||
),
|
||||
)
|
||||
|
||||
for plot in self.plots:
|
||||
plot.update_plot(data)
|
||||
|
||||
def set_frequency(self, *, frequency: npt.ArrayLike | None = None):
|
||||
print(frequency)
|
||||
if frequency is None:
|
||||
start, ok = QInputDialog.getDouble(
|
||||
self, "Start Frequency", "Start Frequency", minValue=30e6, maxValue=6e9, value=1e9
|
||||
)
|
||||
stop, ok = QInputDialog.getDouble(
|
||||
self, "Stop Frequency", "Stop Frequency", minValue=30e6, maxValue=6e9, value=2e9
|
||||
)
|
||||
points, ok = QInputDialog.getInt(self, "Points", "Points", minValue=2, value=101)
|
||||
frequency = np.linspace(start, stop, points)
|
||||
# Currently does not support zero span
|
||||
self._frequency = frequency
|
||||
|
||||
def calibrate_solt(self):
|
||||
if len(self.vna.ports) > 1:
|
||||
raise NotImplementedError
|
||||
|
||||
calfile = Path(__file__).parent / "cal.pkl"
|
||||
if calfile.exists():
|
||||
# don't re-cal while debugging because that's slooooooow
|
||||
with open(calfile, "rb") as f:
|
||||
calibration = pickle.load(f)
|
||||
else:
|
||||
s = dict()
|
||||
for net in ["short", "open", "load"]:
|
||||
input(f"Connect {net} standard and press ENTER...")
|
||||
s[net] = self.vna.vna_capture(self._frequency, self.progress_callback)
|
||||
|
||||
ideal = rf.media.DefinedGammaZ0(frequency=rf.media.Frequency.from_f(self._frequency, unit="Hz"))
|
||||
calibration = rf.calibration.OnePort(
|
||||
[s2net(s["short"]), s2net(s["open"]), s2net(s["load"])],
|
||||
[ideal.short(), ideal.open(), ideal.load(0)],
|
||||
)
|
||||
# TODO: don't use pickles for calibration. They're fragile
|
||||
with open(calfile, "wb") as f:
|
||||
pickle.dump(calibration, f)
|
||||
self.vna.calibration = calibration
|
||||
|
||||
|
||||
def main() -> None:
|
||||
app = QApplication(sys.argv)
|
||||
|
||||
try:
|
||||
window = MainWindow()
|
||||
except Exception as e:
|
||||
if e.args[0] == "No device found":
|
||||
dialog = QInputDialog()
|
||||
text, ok = dialog.getText(
|
||||
None,
|
||||
"Pluto IP Address",
|
||||
"Enter Pluto IP Address",
|
||||
QLineEdit.Normal,
|
||||
"192.168.2.1",
|
||||
)
|
||||
match = re.match(r"(\d{1,3}\.){3}\d{1,3}", text)
|
||||
if not match:
|
||||
raise ValueError(f"Invalid IP address: {text}")
|
||||
window = MainWindow(ip=text)
|
||||
else:
|
||||
raise e
|
||||
|
||||
window.show()
|
||||
|
||||
app.exec()
|
||||
|
||||
|
||||
# %%
|
||||
if __name__ == "__main__":
|
||||
main()
|
90
charon_vna/gui_helpers.py
Normal file
90
charon_vna/gui_helpers.py
Normal file
@ -0,0 +1,90 @@
|
||||
from PySide6.QtCore import QMargins, QPoint, QRect, QSize, Qt
|
||||
from PySide6.QtWidgets import QLayout, QSizePolicy
|
||||
|
||||
|
||||
class FlowLayout(QLayout):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
if parent is not None:
|
||||
self.setContentsMargins(QMargins(0, 0, 0, 0))
|
||||
|
||||
self._item_list = []
|
||||
|
||||
def __del__(self):
|
||||
item = self.takeAt(0)
|
||||
while item:
|
||||
item = self.takeAt(0)
|
||||
|
||||
def addItem(self, item):
|
||||
self._item_list.append(item)
|
||||
|
||||
def count(self):
|
||||
return len(self._item_list)
|
||||
|
||||
def itemAt(self, index):
|
||||
if 0 <= index < len(self._item_list):
|
||||
return self._item_list[index]
|
||||
|
||||
return None
|
||||
|
||||
def takeAt(self, index):
|
||||
if 0 <= index < len(self._item_list):
|
||||
return self._item_list.pop(index)
|
||||
|
||||
return None
|
||||
|
||||
def expandingDirections(self):
|
||||
return Qt.Orientation(0)
|
||||
|
||||
def hasHeightForWidth(self):
|
||||
return True
|
||||
|
||||
def heightForWidth(self, width):
|
||||
height = self._do_layout(QRect(0, 0, width, 0), True)
|
||||
return height
|
||||
|
||||
def setGeometry(self, rect):
|
||||
super(FlowLayout, self).setGeometry(rect)
|
||||
self._do_layout(rect, False)
|
||||
|
||||
def sizeHint(self):
|
||||
return self.minimumSize()
|
||||
|
||||
def minimumSize(self):
|
||||
size = QSize()
|
||||
|
||||
for item in self._item_list:
|
||||
size = size.expandedTo(item.minimumSize())
|
||||
|
||||
size += QSize(2 * self.contentsMargins().top(), 2 * self.contentsMargins().top())
|
||||
return size
|
||||
|
||||
def _do_layout(self, rect, test_only):
|
||||
x = rect.x()
|
||||
y = rect.y()
|
||||
line_height = 0
|
||||
spacing = self.spacing()
|
||||
|
||||
for item in self._item_list:
|
||||
style = item.widget().style()
|
||||
layout_spacing_x = style.layoutSpacing(
|
||||
QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Orientation.Horizontal
|
||||
)
|
||||
layout_spacing_y = style.layoutSpacing(QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Vertical)
|
||||
space_x = spacing + layout_spacing_x
|
||||
space_y = spacing + layout_spacing_y
|
||||
next_x = x + item.sizeHint().width() + space_x
|
||||
if next_x - space_x > rect.right() and line_height > 0:
|
||||
x = rect.x()
|
||||
y = y + line_height + space_y
|
||||
next_x = x + item.sizeHint().width() + space_x
|
||||
line_height = 0
|
||||
|
||||
if not test_only:
|
||||
item.setGeometry(QRect(QPoint(x, y), item.sizeHint()))
|
||||
|
||||
x = next_x
|
||||
line_height = max(line_height, item.sizeHint().height())
|
||||
|
||||
return y + line_height - rect.y()
|
11
charon_vna/io_.py
Normal file
11
charon_vna/io_.py
Normal file
@ -0,0 +1,11 @@
|
||||
from pathlib import Path
|
||||
|
||||
import skrf as rf
|
||||
from util import net2s
|
||||
|
||||
|
||||
# scikit-rf has no way to save files aside from touchstone and pickle
|
||||
def cal2zarr(cal: rf.calibration.Calibration, outpath: Path):
|
||||
ideals = [net2s(net) for net in cal.ideals]
|
||||
measured = [net2s(net) for net in cal.measured]
|
||||
# s.to_zarr(outpath)
|
129
charon_vna/plots.py
Normal file
129
charon_vna/plots.py
Normal file
@ -0,0 +1,129 @@
|
||||
# %% imports
|
||||
from typing import Callable, List, Literal, Tuple
|
||||
|
||||
import numpy as np
|
||||
import xarray as xr
|
||||
from matplotlib import pyplot as plt
|
||||
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg
|
||||
from matplotlib.lines import Line2D
|
||||
from matplotlib.ticker import EngFormatter
|
||||
from numpy import typing as npt
|
||||
from PySide6.QtWidgets import QVBoxLayout, QWidget
|
||||
from skrf import plotting as rf_plt
|
||||
|
||||
from charon_vna.util import db20, s2vswr
|
||||
|
||||
__all__ = ("PlotWidget",)
|
||||
|
||||
|
||||
# %%
|
||||
class PlotWidget(QWidget):
|
||||
traces: List[Tuple[int | str]]
|
||||
lines: List[Line2D]
|
||||
|
||||
def __init__(self, type_: str = "logmag"):
|
||||
super().__init__()
|
||||
|
||||
self.traces = [(1, 1)]
|
||||
|
||||
layout = QVBoxLayout()
|
||||
self.setLayout(layout)
|
||||
|
||||
self.fig = plt.Figure(figsize=(5, 4), dpi=100, tight_layout=True)
|
||||
self.ax = self.fig.add_subplot(111)
|
||||
self.set_plot_type(type_)
|
||||
self.lines = [
|
||||
self.ax.plot([np.nan], [np.nan], label="$S_{" + str(m) + str(n) + "}$")[0] for m, n in self.traces
|
||||
]
|
||||
self.ax.legend(loc="upper right")
|
||||
|
||||
canvas = FigureCanvasQTAgg(self.fig)
|
||||
layout.addWidget(canvas)
|
||||
|
||||
# toolbar = QToolBar("Toolbar")
|
||||
# toolbar.addAction("blah")
|
||||
# self.addToolBar(toolbar)
|
||||
|
||||
def set_plot_type(
|
||||
self,
|
||||
type_: Literal["logmag", "phase", "vswr", "smith"],
|
||||
sweep_type: Literal["frequency", "time"] = "frequency",
|
||||
) -> None:
|
||||
if sweep_type != "frequency":
|
||||
raise NotImplementedError("Only frequency sweeps are currently supported")
|
||||
|
||||
if type_ == "logmag":
|
||||
self.setup_logmag()
|
||||
elif type_ == "phase":
|
||||
self.setup_phase()
|
||||
elif type_ == "vswr":
|
||||
self.setup_vswr()
|
||||
elif type_ == "smith":
|
||||
self.setup_smith()
|
||||
else:
|
||||
raise ValueError(f"Unknown plot type: {type_}")
|
||||
|
||||
self._plot_type = type_
|
||||
|
||||
def update_plot(self, data: xr.DataArray):
|
||||
if self._plot_type == "logmag":
|
||||
self.update_logmag(data)
|
||||
elif self._plot_type == "phase":
|
||||
self.update_phase(data)
|
||||
elif self._plot_type == "vswr":
|
||||
self.update_vswr(data)
|
||||
elif self._plot_type == "smith":
|
||||
self.update_smith(data)
|
||||
|
||||
def setup_rect(self) -> None:
|
||||
self.ax.grid(True)
|
||||
self.ax.xaxis.set_major_formatter(EngFormatter())
|
||||
self.ax.set_xlabel("Frequency [Hz]")
|
||||
|
||||
def update_rect(self, data: xr.DataArray, func: Callable[[npt.ArrayLike], npt.ArrayLike]) -> None:
|
||||
self.ax.set_xlim(data["frequency"].min().data, data["frequency"].max().data)
|
||||
for ii, (m, n) in enumerate(self.traces):
|
||||
self.lines[ii].set_xdata(data["frequency"])
|
||||
self.lines[ii].set_ydata(func(data.sel(m=m, n=n)))
|
||||
|
||||
self.fig.canvas.draw()
|
||||
|
||||
def setup_logmag(self, ylim: List[float] = [-30, 30]) -> None:
|
||||
self.setup_rect()
|
||||
self.ax.set_ylim(ylim)
|
||||
self.ax.set_ylabel("Amplitude [dB]")
|
||||
|
||||
def update_logmag(self, data: xr.DataArray) -> None:
|
||||
self.update_rect(data, db20)
|
||||
|
||||
def setup_phase(self) -> None:
|
||||
self.setup_rect()
|
||||
self.ax.set_ylim(-200, 200)
|
||||
self.ax.set_ylabel("Phase [deg]")
|
||||
|
||||
def update_phase(self, data: xr.DataArray):
|
||||
self.update_rect(data, lambda s: np.angle(s, deg=True))
|
||||
|
||||
def setup_vswr(self) -> None:
|
||||
self.setup_rect()
|
||||
self.ax.set_yticks(np.arange(1, 11))
|
||||
self.ax.set_ylim(1, 10)
|
||||
self.ax.set_ylabel("VSWR")
|
||||
|
||||
def update_vswr(self, data: xr.DataArray) -> None:
|
||||
self.update_rect(data, s2vswr)
|
||||
|
||||
def setup_smith(self) -> None:
|
||||
self.ax.grid(False)
|
||||
self.ax.set_xlim(-1, 1)
|
||||
self.ax.set_ylim(-1, 1)
|
||||
self.ax.set_aspect("equal")
|
||||
rf_plt.smith(ax=self.ax, smithR=1, chart_type="z", draw_vswr=None)
|
||||
|
||||
def update_smith(self, data: xr.DataArray) -> None:
|
||||
for ii, (m, n) in enumerate(self.traces):
|
||||
sel = data.sel(m=m, n=n)
|
||||
self.lines[ii].set_xdata(sel.real)
|
||||
self.lines[ii].set_ydata(sel.imag)
|
||||
|
||||
self.fig.canvas.draw()
|
63
charon_vna/pluto_example.py
Normal file
63
charon_vna/pluto_example.py
Normal file
@ -0,0 +1,63 @@
|
||||
# Copyright (C) 2019 Analog Devices, Inc.
|
||||
#
|
||||
# SPDX short identifier: ADIBSD
|
||||
|
||||
|
||||
# I'm not sure why but sometimes I need to run this once to make the rest of my scripts work.
|
||||
# Probably just me running things manually out of order or something but I'm throwing this in here until I verify.
|
||||
|
||||
import time
|
||||
|
||||
import adi
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
from scipy import signal
|
||||
|
||||
# Create radio
|
||||
sdr = adi.Pluto(uri="ip:192.168.3.1")
|
||||
|
||||
# Configure properties
|
||||
sdr.rx_rf_bandwidth = 4000000
|
||||
sdr.rx_lo = 2000000000
|
||||
sdr.tx_lo = 2000000000
|
||||
sdr.tx_cyclic_buffer = True
|
||||
sdr.tx_hardwaregain_chan0 = -30
|
||||
sdr.gain_control_mode_chan0 = "slow_attack"
|
||||
|
||||
# Read properties
|
||||
print("RX LO %s" % (sdr.rx_lo))
|
||||
|
||||
# Create a sinewave waveform
|
||||
fs = int(sdr.sample_rate)
|
||||
print(fs)
|
||||
N = 1024
|
||||
fc = int(-3000000 / (fs / N)) * (fs / N)
|
||||
ts = 1 / float(fs)
|
||||
t = np.arange(0, N * ts, ts)
|
||||
i = np.cos(2 * np.pi * t * fc) * 2**14
|
||||
q = np.sin(2 * np.pi * t * fc) * 2**14
|
||||
iq = i + 1j * q
|
||||
|
||||
# Send data
|
||||
sdr.tx(iq)
|
||||
|
||||
# Collect data
|
||||
for r in range(20):
|
||||
x = sdr.rx()
|
||||
f, Pxx_den = signal.periodogram(x, fs, return_onesided=False)
|
||||
plt.clf()
|
||||
plt.semilogy(f, Pxx_den)
|
||||
plt.ylim([1e-7, 1e2])
|
||||
plt.xlabel("frequency [Hz]")
|
||||
plt.ylabel("PSD [V**2/Hz]")
|
||||
plt.grid(True)
|
||||
plt.draw()
|
||||
plt.pause(0.05)
|
||||
time.sleep(0.1)
|
||||
|
||||
plt.show()
|
||||
|
||||
|
||||
plt.plot(np.real(x))
|
||||
plt.plot(np.imag(x))
|
||||
plt.show()
|
84
charon_vna/util.py
Normal file
84
charon_vna/util.py
Normal file
@ -0,0 +1,84 @@
|
||||
import numpy as np
|
||||
import skrf as rf
|
||||
import xarray as xr
|
||||
from numpy import typing as npt
|
||||
|
||||
HAM_BANDS = [
|
||||
[135.7e3, 137.8e3],
|
||||
[472e3, 479e3],
|
||||
[1.8e6, 2e6],
|
||||
[3.5e6, 4e6],
|
||||
[5332e3, 5405e3],
|
||||
[7e6, 7.3e6],
|
||||
[10.1e6, 10.15e6],
|
||||
[14e6, 14.35e6],
|
||||
[18.068e6, 18.168e6],
|
||||
[21e6, 21.45e6],
|
||||
[24.89e6, 24.99e6],
|
||||
[28e6, 29.7e6],
|
||||
[50e6, 54e6],
|
||||
[144e6, 148e6],
|
||||
[219e6, 220e6],
|
||||
[222e6, 225e6],
|
||||
[420e6, 450e6],
|
||||
[902e6, 928e6],
|
||||
[1240e6, 1300e6],
|
||||
[2300e6, 2310e6],
|
||||
[2390e6, 2450e6],
|
||||
[3400e6, 3450e6],
|
||||
[5650e6, 5925e6],
|
||||
[10e9, 10.5e9],
|
||||
[24e9, 24.25e9],
|
||||
[47e9, 47.2e9],
|
||||
[76e9, 81e9],
|
||||
[122.25e9, 123e9],
|
||||
[134e9, 141e9],
|
||||
[241e9, 250e9],
|
||||
[275e9, np.inf],
|
||||
]
|
||||
|
||||
|
||||
def db10(p: npt.ArrayLike) -> npt.ArrayLike:
|
||||
return 10 * np.log10(np.abs(p))
|
||||
|
||||
|
||||
def db20(v: npt.ArrayLike) -> npt.ArrayLike:
|
||||
return 20 * np.log10(np.abs(v))
|
||||
|
||||
|
||||
def s2vswr(s: npt.ArrayLike) -> npt.ArrayLike:
|
||||
return np.abs((1 + np.abs(s)) / (1 - np.abs(s)))
|
||||
|
||||
|
||||
def minmax(x):
|
||||
return (np.min(x), np.max(x))
|
||||
|
||||
|
||||
def s2net(s: xr.DataArray) -> rf.Network:
|
||||
net = rf.Network(frequency=s.frequency, f_unit="Hz", s=s)
|
||||
return net
|
||||
|
||||
|
||||
def net2s(net: rf.Network) -> xr.DataArray:
|
||||
port_tuples = net.port_tuples
|
||||
|
||||
m = list(set(t[0] for t in port_tuples))
|
||||
m.sort()
|
||||
m = np.array(m)
|
||||
m += 1 # skrf uses 0-indexed ports
|
||||
|
||||
n = list(set(t[0] for t in port_tuples))
|
||||
n.sort()
|
||||
n = np.array(n)
|
||||
n += 1 # skrf uses 0-indexed ports
|
||||
|
||||
s = xr.DataArray(
|
||||
net.s,
|
||||
dims=["frequency", "m", "n"],
|
||||
coords=dict(
|
||||
frequency=net.f,
|
||||
m=m,
|
||||
n=n,
|
||||
),
|
||||
)
|
||||
return s
|
466
charon_vna/vna.py
Normal file
466
charon_vna/vna.py
Normal file
@ -0,0 +1,466 @@
|
||||
# %% imports
|
||||
import copy
|
||||
from enum import IntEnum, unique
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, Dict, Literal, Tuple
|
||||
|
||||
import adi
|
||||
import iio
|
||||
import numpy as np
|
||||
import skrf as rf
|
||||
import xarray as xr
|
||||
from matplotlib import pyplot as plt
|
||||
from matplotlib.ticker import EngFormatter
|
||||
from numpy import typing as npt
|
||||
from scipy import signal
|
||||
|
||||
from charon_vna.util import HAM_BANDS, db20, net2s, s2net
|
||||
|
||||
dir_ = Path(__file__).parent
|
||||
|
||||
|
||||
# %% connection
|
||||
|
||||
|
||||
def generate_tone(f: float, fs: float, N: int = 1024, scale: int = 2**14):
|
||||
fs = int(fs)
|
||||
fc = int(f / (fs / N)) * (fs / N)
|
||||
ts = 1 / float(fs)
|
||||
t = np.arange(0, N * ts, ts)
|
||||
i = np.cos(2 * np.pi * t * fc) * scale
|
||||
q = np.sin(2 * np.pi * t * fc) * scale
|
||||
iq = i + 1j * q
|
||||
|
||||
return iq
|
||||
|
||||
|
||||
@unique
|
||||
class AD9361Register(IntEnum):
|
||||
AUXDAC1_WORD = 0x018
|
||||
AUXDAC2_WORD = 0x019
|
||||
AUXDAC1_CONFIG = 0x01A
|
||||
AUXDAC2_CONFIG = 0x01B
|
||||
AUXADC_CLOCK_DIVIDER = 0x01C
|
||||
AUXADC_CONFIG = 0x01D
|
||||
AUXADC_WORD_MSB = 0x01E
|
||||
AUXADC_WORD_LSB = 0x01F
|
||||
AUTO_GPIO = 0x020
|
||||
AGC_GAIN_LOCK_DELAY = 0x021
|
||||
AGC_ATTACK_DELAY = 0x022
|
||||
AUXDAC_ENABLE_CONTROL = 0x023
|
||||
RX_LOAD_SYNTH_DELAY = 0x024
|
||||
TX_LOAD_SYNTH_DELAY = 0x025
|
||||
EXTERNAL_LNA_CONTROL = 0x026
|
||||
GPO_FORCE_AND_INIT = 0x027
|
||||
GPO0_RX_DELAY = 0x028
|
||||
GPO1_RX_DELAY = 0x029
|
||||
GPO2_RX_DELAY = 0x02A
|
||||
GPO3_RX_DELAY = 0x02B
|
||||
GPO0_TX_DELAY = 0x02C
|
||||
GPO1_TX_DELAY = 0x02D
|
||||
GPO2_TX_DELAY = 0x02E
|
||||
GPO3_TX_DELAY = 0x02F
|
||||
AUXDAC1_RX_DELAY = 0x030
|
||||
AUXDAC1_TX_DELAY = 0x031
|
||||
AUXDAC2_RX_DELAY = 0x032
|
||||
AUXDAC2_TX_DELAY = 0x033
|
||||
|
||||
|
||||
class Charon:
|
||||
FREQUENCY_OFFSET = 1e6
|
||||
|
||||
calibration: rf.calibration.Calibration | None = None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
ip: str = "192.168.2.1",
|
||||
frequency: npt.ArrayLike = np.linspace(1e9, 2e9, 3),
|
||||
ports: Tuple[int] = (1,),
|
||||
):
|
||||
self.ports = ports
|
||||
self.frequency = frequency
|
||||
|
||||
# everything RF
|
||||
uri = f"ip:{ip}"
|
||||
self.sdr = adi.ad9361(uri=uri)
|
||||
for attr, expected in [
|
||||
("adi,2rx-2tx-mode-enable", True),
|
||||
# ("adi,gpo-manual-mode-enable", True),
|
||||
]:
|
||||
# available configuration options:
|
||||
# https://wiki.analog.com/resources/tools-software/linux-drivers/iio-transceiver/ad9361-customization
|
||||
if bool(self.sdr._get_iio_debug_attr(attr)) != expected:
|
||||
raise ValueError(
|
||||
f"'{attr}' is not set in pluto. "
|
||||
"See README.md for instructions for one time configuration instructions"
|
||||
)
|
||||
# TODO: it might be possible to change this on the fly.
|
||||
# I think we'll actually just fail in __init__ of ad9361 if 2rx-2tx is wrong
|
||||
|
||||
self.sdr.rx_lo = int(self.frequency[0])
|
||||
self.sdr.tx_lo = int(self.frequency[0])
|
||||
self.sdr.sample_rate = 30e6
|
||||
self.sdr.rx_rf_bandwidth = int(4e6)
|
||||
self.sdr.tx_rf_bandwidth = int(4e6)
|
||||
self.sdr.rx_destroy_buffer()
|
||||
self.sdr.tx_destroy_buffer()
|
||||
self.sdr.rx_enabled_channels = [0, 1]
|
||||
self.sdr.tx_enabled_channels = [0]
|
||||
self.sdr.loopback = 0
|
||||
self.sdr.gain_control_mode_chan0 = "manual"
|
||||
self.sdr.gain_control_mode_chan1 = "manual"
|
||||
self.sdr.rx_hardwaregain_chan0 = 10
|
||||
self.sdr.rx_hardwaregain_chan1 = 10
|
||||
self.sdr.tx_hardwaregain_chan0 = -10
|
||||
|
||||
# # switch control
|
||||
ctx = iio.Context(uri)
|
||||
self.ctrl = ctx.find_device("ad9361-phy")
|
||||
# raw ad9361 register accesss:
|
||||
# https://ez.analog.com/linux-software-drivers/f/q-a/120853/control-fmcomms3-s-gpo-with-python
|
||||
# https://www.analog.com/media/cn/technical-documentation/user-guides/ad9364_register_map_reference_manual_ug-672.pdf # noqa: E501
|
||||
self.ctrl.reg_write(AD9361Register.EXTERNAL_LNA_CONTROL, 0x90) # bit 7: AuxDAC Manual, bit 4: GPO Manual
|
||||
self.ctrl.reg_write(AD9361Register.AUXDAC_ENABLE_CONTROL, 0x3F)
|
||||
self._set_gpo(0b0000)
|
||||
self._set_dac(value=0, channel=1)
|
||||
self._set_dac(value=0, channel=2)
|
||||
|
||||
def get_config(self) -> Dict[str, Any]:
|
||||
config = dict()
|
||||
config["rx_lo"] = self.sdr.rx_lo
|
||||
config["rx_rf_bandwidth"] = self.sdr.rx_rf_bandwidth
|
||||
config["rx_enabled_channels"] = self.sdr.rx_enabled_channels
|
||||
for chan in config["rx_enabled_channels"]:
|
||||
config[f"rx_hardwaregain_chan{chan}"] = getattr(self.sdr, f"rx_hardwaregain_chan{chan}")
|
||||
config[f"gain_control_mode_chan{chan}"] = getattr(self.sdr, f"gain_control_mode_chan{chan}")
|
||||
|
||||
config["tx_lo"] = self.sdr.tx_lo
|
||||
config["tx_rf_bandwidth"] = self.sdr.tx_rf_bandwidth
|
||||
config["tx_cyclic_buffer"] = self.sdr.tx_cyclic_buffer
|
||||
config["tx_enabled_channels"] = self.sdr.tx_enabled_channels
|
||||
for chan in config["tx_enabled_channels"]:
|
||||
config[f"tx_hardwaregain_chan{chan}"] = getattr(self.sdr, f"tx_hardwaregain_chan{chan}")
|
||||
|
||||
config["filter"] = self.sdr.filter
|
||||
config["sample_rate"] = self.sdr.sample_rate
|
||||
config["loopback"] = self.sdr.loopback
|
||||
|
||||
return config
|
||||
|
||||
def _get_gpo(self) -> int:
|
||||
return (self.ctrl.reg_read(AD9361Register.GPO_FORCE_AND_INIT) >> 4) & 0x0F
|
||||
|
||||
def _set_gpo(self, value: int) -> None:
|
||||
self.ctrl.reg_write(AD9361Register.GPO_FORCE_AND_INIT, (value & 0x0F) << 4) # bits 7-4: GPO3-0
|
||||
|
||||
def _set_dac(self, value: int, channel: Literal[1, 2]):
|
||||
if channel not in [1, 2]:
|
||||
raise ValueError(f"Invalid channel {channel}. Must be 1 or 2")
|
||||
|
||||
if value > 0x3FF or value < 0:
|
||||
raise ValueError("Invalid value for 10 bit DAC. Must be between 0 and 0x3FF (inclusive)")
|
||||
|
||||
@unique
|
||||
class Vref(IntEnum):
|
||||
VREF_1V0 = 0b00
|
||||
VREF_1V5 = 0b01
|
||||
VREF_2V0 = 0b10
|
||||
VREF_2V5 = 0b11
|
||||
|
||||
@unique
|
||||
class StepFactor(IntEnum):
|
||||
FACTOR_2 = 0b0
|
||||
FACTOR_1 = 0b1
|
||||
|
||||
# https://www.analog.com/media/cn/technical-documentation/user-guides/ad9364_register_map_reference_manual_ug-672.pdf
|
||||
# page 13
|
||||
# vout = 0.97 * vref + (0.000738 + 9e-6 * (vref * 1.6 - 2)) * auxdac_word[9:0] * step_factor - 0.3572 * step_factor + 0.05
|
||||
# vout ~= (vref - 0.3572 * step_factor) + 0.000738 * auxdac_word[9:0] * step_factor
|
||||
# which gives a 1.5V swing with step_factor == 2 and 0.75V swing with step_factor == 1
|
||||
# vref basically just changes the minimum voltage with negligible impact on output scaling
|
||||
|
||||
self.ctrl.reg_write(
|
||||
AD9361Register.__getitem__(f"AUXDAC{channel}_WORD"),
|
||||
(value >> 2) & 0xFF,
|
||||
)
|
||||
self.ctrl.reg_write(
|
||||
AD9361Register.__getitem__(f"AUXDAC{channel}_CONFIG"),
|
||||
(value & 0x3) | (Vref.VREF_1V0.value << 2) | (StepFactor.FACTOR_2 << 4),
|
||||
)
|
||||
|
||||
def set_output_power(self, power: float):
|
||||
# FIXME: this is a hack because I don't want to go through re-calibration
|
||||
if power == 5:
|
||||
tx_gain = -1
|
||||
elif power == 0:
|
||||
tx_gain = -7
|
||||
elif power == -5:
|
||||
tx_gain = -12
|
||||
elif power == -10:
|
||||
tx_gain = -17
|
||||
elif power == -15:
|
||||
tx_gain = -22
|
||||
else:
|
||||
raise NotImplementedError()
|
||||
# # TODO: correct over frequency
|
||||
# tx_gain_idx = np.abs(pout.sel(tx_channel=0) - power).argmin(dim="tx_gain")
|
||||
# tx_gain = pout.coords["tx_gain"][tx_gain_idx]
|
||||
self.sdr.tx_hardwaregain_chan0 = float(tx_gain)
|
||||
|
||||
def set_output(self, frequency: float, power: float):
|
||||
# TODO: switch to DDS in Pluto
|
||||
|
||||
self.sdr.tx_destroy_buffer()
|
||||
self.set_output_power(power)
|
||||
self.sdr.tx_lo = int(frequency - self.FREQUENCY_OFFSET)
|
||||
self.sdr.tx_cyclic_buffer = True
|
||||
# For some reason the pluto's DDS has truly horrendous phase noise to the point where it looks modulated
|
||||
self.sdr.tx(generate_tone(f=self.FREQUENCY_OFFSET, fs=self.sdr.sample_rate))
|
||||
# self.sdr.dds_single_tone(self.FREQUENCY_OFFSET, scale=0.9, channel=0)
|
||||
|
||||
def _rx(self, count: int = 1, fc: float | None = None) -> npt.ArrayLike:
|
||||
if count < 1:
|
||||
raise ValueError
|
||||
|
||||
self.sdr.rx_destroy_buffer()
|
||||
if fc is not None:
|
||||
self.sdr.rx_lo = int(fc)
|
||||
self.sdr.rx_enabled_channels = [0, 1]
|
||||
self.sdr.gain_control_mode_chan0 = "manual"
|
||||
self.sdr.gain_control_mode_chan1 = "manual"
|
||||
self.sdr.rx_hardwaregain_chan0 = 30
|
||||
self.sdr.rx_hardwaregain_chan1 = 30
|
||||
return np.concatenate([np.array(self.sdr.rx()) for _ in range(count)], axis=-1)
|
||||
|
||||
def get_b_over_a(self, frequency: float):
|
||||
self.set_output(frequency=frequency, power=-5)
|
||||
|
||||
data = self._rx(1, fc=frequency - self.FREQUENCY_OFFSET)
|
||||
ddc_tone = generate_tone(f=-self.FREQUENCY_OFFSET, fs=self.sdr.sample_rate, scale=1)
|
||||
ddc_data = data * ddc_tone
|
||||
|
||||
ddc_rel = ddc_data[1] / ddc_data[0]
|
||||
|
||||
# plt.figure()
|
||||
# plt.plot(
|
||||
# np.fft.fftshift(np.fft.fftfreq(ddc_data.shape[-1], 1 / self.sdr.sample_rate)),
|
||||
# np.abs(np.fft.fftshift(np.fft.fft(ddc_data, axis=-1))).T,
|
||||
# )
|
||||
# plt.show()
|
||||
|
||||
# TODO: calculate sos only once
|
||||
n, wn = signal.buttord(
|
||||
wp=0.3 * sdr.FREQUENCY_OFFSET,
|
||||
ws=0.8 * sdr.FREQUENCY_OFFSET,
|
||||
gpass=1,
|
||||
gstop=40,
|
||||
analog=False,
|
||||
fs=self.sdr.sample_rate,
|
||||
)
|
||||
sos = signal.butter(n, wn, "lowpass", analog=False, output="sos", fs=self.sdr.sample_rate)
|
||||
# TODO: figure out why filt sucks. Introduces SO much phase noise (out to several MHz)
|
||||
filt_data = signal.sosfiltfilt(sos, ddc_data, axis=-1)
|
||||
|
||||
filt_rel = filt_data[1] / filt_data[0]
|
||||
|
||||
return np.mean(data[1] / data[0])
|
||||
|
||||
def sweep_b_over_a(self):
|
||||
s = xr.DataArray(
|
||||
np.zeros(
|
||||
len(self.frequency),
|
||||
dtype=np.complex128,
|
||||
),
|
||||
dims=["frequency"],
|
||||
coords=dict(
|
||||
frequency=self.frequency,
|
||||
),
|
||||
)
|
||||
for frequency in self.frequency:
|
||||
s.loc[dict(frequency=frequency)] = self.get_b_over_a(frequency=frequency)
|
||||
return s
|
||||
|
||||
def vna_capture(self, frequency: npt.ArrayLike, callback: Callable[int, int] | None):
|
||||
s = xr.DataArray(
|
||||
np.empty(len(frequency), dtype=np.complex128),
|
||||
dims=["frequency"],
|
||||
coords=dict(
|
||||
frequency=frequency,
|
||||
),
|
||||
)
|
||||
for ff, freq in enumerate(s.frequency.data):
|
||||
if callback is not None:
|
||||
callback(ff, len(s.frequency))
|
||||
self.set_output(frequency=freq, power=-5)
|
||||
self.sdr.rx_destroy_buffer()
|
||||
self.sdr.rx_lo = int(freq)
|
||||
self.sdr.rx_enabled_channels = [0, 1]
|
||||
self.sdr.gain_control_mode_chan0 = "manual"
|
||||
self.sdr.gain_control_mode_chan1 = "manual"
|
||||
self.sdr.rx_hardwaregain_chan0 = 40
|
||||
self.sdr.rx_hardwaregain_chan1 = 40
|
||||
rx = self.sdr.rx()
|
||||
s.loc[dict(frequency=freq)] = np.mean(rx[1] / rx[0])
|
||||
if callback is not None:
|
||||
callback(len(s.frequency), len(s.frequency))
|
||||
|
||||
return s
|
||||
|
||||
|
||||
# %%
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
|
||||
# %%
|
||||
sdr = Charon("ip:192.168.3.1", frequency=np.linspace(1e9, 1.1e9, 11))
|
||||
|
||||
# %% initialization
|
||||
config = sdr.get_config()
|
||||
# print(sdr.ctrl.debug_attrs["adi,rx-rf-port-input-select"].value)
|
||||
# print(sdr.ctrl.debug_attrs["adi,tx-rf-port-input-select"].value)
|
||||
config
|
||||
|
||||
# %% generate tone
|
||||
fc = 1e9
|
||||
sdr.set_output(frequency=fc + sdr.FREQUENCY_OFFSET, power=-5)
|
||||
|
||||
# %% capture data
|
||||
data = sdr._rx(1, fc=fc)
|
||||
|
||||
# %% Plot in time
|
||||
fig, axs = plt.subplots(2, 1, sharex=True, tight_layout=True)
|
||||
axs[0].plot(np.real(data).T)
|
||||
axs[1].plot(np.imag(data).T)
|
||||
axs[0].set_ylabel("Real")
|
||||
axs[1].set_ylabel("Imag")
|
||||
axs[0].grid(True)
|
||||
axs[1].grid(True)
|
||||
axs[-1].set_xlabel("Sample")
|
||||
axs[-1].set_xlim(0, data.shape[-1])
|
||||
fig.show()
|
||||
|
||||
# %%
|
||||
fig, ax = plt.subplots(1, 1, tight_layout=True)
|
||||
ax.plot(np.real(data).T, np.imag(data).T)
|
||||
ax.grid(True)
|
||||
ax.set_aspect("equal")
|
||||
ax.set_xlabel("Real")
|
||||
ax.set_ylabel("Imag")
|
||||
ax.set_xlim(np.array([-1, 1]) * (2 ** (12 - 1) - 1))
|
||||
ax.set_ylim(ax.get_xlim())
|
||||
fig.show()
|
||||
|
||||
# %% Plot in frequency
|
||||
f = np.fft.fftfreq(data.shape[-1], 1 / sdr.sdr.sample_rate)
|
||||
RX_BITS = 12 # for each of i, q (including sign bit)
|
||||
fft_data = np.fft.fft(data, axis=-1, norm="forward") / (2 ** (RX_BITS - 1))
|
||||
plt.figure()
|
||||
for cc, chan in enumerate(sdr.sdr.rx_enabled_channels):
|
||||
plt.plot(
|
||||
np.fft.fftshift(f),
|
||||
db20(np.fft.fftshift(fft_data[cc])),
|
||||
label=f"Channel {chan}",
|
||||
)
|
||||
plt.legend()
|
||||
plt.ylim(-100, 0)
|
||||
plt.xlabel("Frequency [Hz]")
|
||||
plt.ylabel("Power [dBfs]")
|
||||
plt.title(f"Fc = {sdr.sdr.rx_lo / 1e9} GHz")
|
||||
plt.gca().xaxis.set_major_formatter(EngFormatter())
|
||||
plt.grid(True)
|
||||
plt.show()
|
||||
|
||||
# %%
|
||||
s = sdr.vna_capture(frequency=np.linspace(70e6, 200e6, 101))
|
||||
|
||||
# %% Plot Logmag
|
||||
fig, axs = plt.subplots(2, 1, sharex=True, tight_layout=True)
|
||||
|
||||
axs[0].plot(s.frequency, db20(s), label="Measured")
|
||||
axs[1].plot(s.frequency, np.rad2deg(np.angle((s))), label="Measured")
|
||||
|
||||
axs[0].grid(True)
|
||||
axs[1].grid(True)
|
||||
|
||||
axs[0].set_ylim(-80, 0)
|
||||
axs[1].set_ylim(-200, 200)
|
||||
axs[1].set_xlim(np.min(s.frequency), np.max(s.frequency))
|
||||
axs[1].xaxis.set_major_formatter(EngFormatter(places=1))
|
||||
axs[1].set_xlabel("Frequency")
|
||||
|
||||
axs[0].set_ylabel("|S11| [dB]")
|
||||
axs[1].set_ylabel("∠S11 [deg]")
|
||||
|
||||
reference_sparams = None
|
||||
reference_sparams = dir_ / "RBP-135+_Plus25degC.s2p"
|
||||
if reference_sparams is not None:
|
||||
ref = rf.Network(reference_sparams)
|
||||
rbp135 = net2s(ref)
|
||||
|
||||
axs[0].plot(rbp135.frequency, db20(rbp135.sel(m=1, n=1)), label="Datasheet")
|
||||
axs[1].plot(rbp135.frequency, np.rad2deg(np.angle(rbp135.sel(m=2, n=1))), label="Datasheet")
|
||||
axs[0].legend()
|
||||
axs[1].legend()
|
||||
|
||||
plt.show()
|
||||
|
||||
# %% SOL calibration
|
||||
cal_frequency = np.linspace(70e6, 600e6, 101)
|
||||
ideal_cal_frequency = rf.Frequency(np.min(cal_frequency), np.max(cal_frequency), len(cal_frequency))
|
||||
input("Connect SHORT and press ENTER...")
|
||||
short = sdr.vna_capture(frequency=cal_frequency)
|
||||
input("Connect OPEN and press ENTER...")
|
||||
open = sdr.vna_capture(frequency=cal_frequency)
|
||||
input("Connect LOAD and press ENTER...")
|
||||
load = sdr.vna_capture(frequency=cal_frequency)
|
||||
|
||||
short_net = s2net(short)
|
||||
open_net = s2net(open)
|
||||
load_net = s2net(load)
|
||||
|
||||
cal_ideal = rf.media.DefinedGammaZ0(frequency=ideal_cal_frequency)
|
||||
calibration = rf.calibration.OnePort(
|
||||
[short_net, open_net, load_net],
|
||||
[cal_ideal.short(), cal_ideal.open(), cal_ideal.load(0)],
|
||||
)
|
||||
|
||||
# %%
|
||||
s = sdr.vna_capture(frequency=cal_frequency)
|
||||
|
||||
# %%
|
||||
s_calibrated = calibration.apply_cal(s2net(s))
|
||||
|
||||
plt.figure()
|
||||
s_calibrated.plot_s_smith()
|
||||
# ref.plot_s_smith(m=1, n=1)
|
||||
plt.show()
|
||||
|
||||
plt.figure()
|
||||
for start, stop in HAM_BANDS:
|
||||
plt.axvspan(start, stop, alpha=0.1, color="k")
|
||||
s_calibrated.plot_s_db()
|
||||
# ref.plot_s_db(m=1, n=1)
|
||||
plt.gca().xaxis.set_major_formatter(EngFormatter())
|
||||
plt.grid(True)
|
||||
plt.xlim(s_calibrated.f[0], s_calibrated.f[-1])
|
||||
plt.show()
|
||||
|
||||
plt.figure()
|
||||
for start, stop in HAM_BANDS:
|
||||
plt.axvspan(start, stop, alpha=0.1, color="k")
|
||||
# s_calibrated.plot_s_vswr()
|
||||
# drop invalid points
|
||||
vswr = copy.deepcopy(s_calibrated.s_vswr[:, 0, 0])
|
||||
vswr[vswr < 1] = np.nan
|
||||
plt.plot(s_calibrated.f, vswr)
|
||||
plt.axhline(1, color="k", linestyle="--")
|
||||
plt.ylabel("VSWR")
|
||||
plt.xlabel("Frequency [Hz]")
|
||||
# ref.plot_s_vswr(m=1, n=1)
|
||||
plt.gca().xaxis.set_major_formatter(EngFormatter())
|
||||
plt.grid(True)
|
||||
plt.ylim(0, 10)
|
||||
plt.xlim(s_calibrated.f[0], s_calibrated.f[-1])
|
||||
plt.show()
|
||||
|
||||
# %%
|
@ -3,7 +3,7 @@ requires = ["setuptools", "setuptools-scm"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "charon-vna"
|
||||
name = "charon_vna"
|
||||
authors = [{ name = "Brendan Haines", email = "brendan.haines@gmail.com" }]
|
||||
description = "RF Network Analyzer based on the Pluto SDR"
|
||||
readme = "README.md"
|
||||
@ -21,14 +21,17 @@ dependencies = [
|
||||
"pyadi-iio",
|
||||
"click",
|
||||
"matplotlib",
|
||||
"pyside6",
|
||||
]
|
||||
dynamic = ["version"]
|
||||
|
||||
[project.urls]
|
||||
homepage = "https://git.brendanhaines.com/brendanhaines/charon"
|
||||
homepage = "https://pypi.org/project/charon-vna/"
|
||||
repository = "https://git.brendanhaines.com/brendanhaines/charon_vna"
|
||||
|
||||
[project.scripts]
|
||||
# charon = "charon.charon:main"
|
||||
charon-cli = "charon_vna.cli:main"
|
||||
charon-gui = "charon_vna.gui:main"
|
||||
|
||||
[tool.setuptools_scm]
|
||||
version_file = "charon_vna/_version.py"
|
||||
@ -50,3 +53,6 @@ exclude = '''
|
||||
| dist
|
||||
)/
|
||||
'''
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
||||
|
Loading…
x
Reference in New Issue
Block a user