Compare commits
32 Commits
a5b391e757
...
v0.2.0
Author | SHA1 | Date | |
---|---|---|---|
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 |
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"
|
||||
|
370
Pipfile.lock
generated
370
Pipfile.lock
generated
@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "8ca47bc9e64405da418625530ed3861fbf72ff2f615aa4053f0da928dd09a494"
|
||||
"sha256": "470252a74774400955ef60d73f7e697760609be00b7733aa7a51b2f192e37fe5"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
@ -112,59 +112,59 @@
|
||||
},
|
||||
"fonttools": {
|
||||
"hashes": [
|
||||
"sha256:09fe922a3eff181fd07dd724cdb441fb6b9fc355fd1c0f1aa79aca60faf1fbdd",
|
||||
"sha256:0ecd1c2b1c2ec46bb73685bc5473c72e16ed0930ef79bc2919ccadc43a99fb16",
|
||||
"sha256:10aff204e2edee1d312fa595c06f201adf8d528a3b659cfb34cd47eceaaa6a26",
|
||||
"sha256:131591ac8d7a47043aaf29581aba755ae151d46e49d2bf49608601efd71e8b4d",
|
||||
"sha256:18f082445b8fe5e91c53e6184f4c1c73f3f965c8bcc614c6cd6effd573ce6c1a",
|
||||
"sha256:22ef222740eb89d189bf0612eb98fbae592c61d7efeac51bfbc2a1592d469557",
|
||||
"sha256:25062b6ca03464dd5179fc2040fb19e03391b7cc49b9cc4f879312e638605c5c",
|
||||
"sha256:27c0f91adbbd706e8acd1db73e3e510118e62d0ffb651864567dccc5b2339f90",
|
||||
"sha256:2df61d9fc15199cc86dad29f64dd686874a3a52dda0c2d8597d21f509f95c332",
|
||||
"sha256:3d8ccce035320d63dba0c35f52499322f5531dbe85bba1514c7cea26297e4c54",
|
||||
"sha256:3d9bbc1e380fdaf04ad9eabd8e3e6a4301eaf3487940893e9fd98537ea2e283b",
|
||||
"sha256:42a9afedff07b6f75aa0f39b5e49922ac764580ef3efce035ca30284b2ee65c8",
|
||||
"sha256:42aca564b575252fd9954ed0d91d97a24de24289a16ce8ff74ed0bdf5ecebf11",
|
||||
"sha256:44cf2a98aa661dbdeb8c03f5e405b074e2935196780bb729888639f5276067d9",
|
||||
"sha256:45947e7b3f9673f91df125d375eb57b9a23f2a603f438a1aebf3171bffa7a205",
|
||||
"sha256:487e1e8b524143a799bda0169c48b44a23a6027c1bb1957d5a172a7d3a1dd704",
|
||||
"sha256:4c83381c3e3e3d9caa25527c4300543578341f21aae89e4fbbb4debdda8d82a2",
|
||||
"sha256:508ebb42956a7a931c4092dfa2d9b4ffd4f94cea09b8211199090d2bd082506b",
|
||||
"sha256:5b1a6e576db0c83c1b91925bf1363478c4bb968dbe8433147332fb5782ce6190",
|
||||
"sha256:5cfa67414d7414442a5635ff634384101c54f53bb7b0e04aa6a61b013fcce194",
|
||||
"sha256:616368b15716781bc84df5c2191dc0540137aaef56c2771eb4b89b90933f347a",
|
||||
"sha256:627cf10d6f5af5bec6324c18a2670f134c29e1b7dce3fb62e8ef88baa6cba7a9",
|
||||
"sha256:663eba5615d6abaaf616432354eb7ce951d518e43404371bcc2b0694ef21e8d6",
|
||||
"sha256:6b5917ef79cac8300b88fd6113003fd01bbbbea2ea060a27b95d8f77cb4c65c2",
|
||||
"sha256:6fc88cfb58b0cd7b48718c3e61dd0d0a3ee8e2c86b973342967ce09fbf1db6d4",
|
||||
"sha256:7bbae4f3915225c2c37670da68e2bf18a21206060ad31dfb95fec91ef641caa7",
|
||||
"sha256:803d5cef5fc47f44f5084d154aa3d6f069bb1b60e32390c225f897fa19b0f939",
|
||||
"sha256:81ccd2b3a420b8050c7d9db3be0555d71662973b3ef2a1d921a2880b58957db8",
|
||||
"sha256:8b02b10648d69d67a7eb055f4d3eedf4a85deb22fb7a19fbd9acbae7c7538199",
|
||||
"sha256:8bc5f100de0173cc39102c0399bd6c3bd544bbdf224957933f10ee442d43cddd",
|
||||
"sha256:8e2d89fbe9b08d96e22c7a81ec04a4e8d8439c31223e2dc6f2f9fc8ff14bdf9f",
|
||||
"sha256:9008438ad59e5a8e403a62fbefef2b2ff377eb3857d90a3f2a5f4d674ff441b2",
|
||||
"sha256:93f439ca27e55f585e7aaa04a74990acd983b5f2245e41d6b79f0a8b44e684d8",
|
||||
"sha256:944228b86d472612d3b48bcc83b31c25c2271e63fdc74539adfcfa7a96d487fb",
|
||||
"sha256:96e126df9615df214ec7f04bebcf60076297fbc10b75c777ce58b702d7708ffb",
|
||||
"sha256:9b1726872e09268bbedb14dc02e58b7ea31ecdd1204c6073eda4911746b44797",
|
||||
"sha256:9f0e55f5da594b85f269cfbecd2f6bd3e07d0abba68870bc3f34854de4fa4678",
|
||||
"sha256:bbea0ab841113ac8e8edde067e099b7288ffc6ac2dded538b131c2c0595d5f77",
|
||||
"sha256:bef0f8603834643b1a6419d57902f18e7d950ec1a998fb70410635c598dc1a1e",
|
||||
"sha256:c1b9de46ef7b683d50400abf9f1578eaceee271ff51c36bf4b7366f2be29f498",
|
||||
"sha256:c6457f650ebe15baa17fc06e256227f0a47f46f80f27ec5a0b00160de8dc2c13",
|
||||
"sha256:d0bf24d2b02dbc9376d795a63062632ff73e3e9e60c0229373f500aed7e86dd7",
|
||||
"sha256:d1100d8e665fe386a79cab59446992de881ea74d0d6c191bb988642692aa2421",
|
||||
"sha256:d337ec087da8216a828574aa0525d869df0a2ac217a2efc1890974ddd1fbc5b9",
|
||||
"sha256:d34525e8141286fa976e14806639d32294bfb38d28bbdb5f6be9f46a1cd695a6",
|
||||
"sha256:d4ff250ed4ff05015dfd9cf2adf7570c7a383ca80f4d9732ac484a5ed0d8453c",
|
||||
"sha256:d559eb1744c7dcfa90ae60cb1a4b3595e898e48f4198738c321468c01180cd83",
|
||||
"sha256:dbdc251c5e472e5ae6bc816f9b82718b8e93ff7992e7331d6cf3562b96aa268e",
|
||||
"sha256:e857fe1859901ad8c5cab32e0eebc920adb09f413d2d73b74b677cf47b28590c",
|
||||
"sha256:f1c76f423f1a241df08f87614364dff6e0b7ce23c962c1b74bd995ec7c0dad13"
|
||||
"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.55.2"
|
||||
"version": "==4.55.3"
|
||||
},
|
||||
"kiwisolver": {
|
||||
"hashes": [
|
||||
@ -288,50 +288,43 @@
|
||||
},
|
||||
"matplotlib": {
|
||||
"hashes": [
|
||||
"sha256:026bdf3137ab6022c866efa4813b6bbeddc2ed4c9e7e02f0e323a7bca380dfa0",
|
||||
"sha256:031b7f5b8e595cc07def77ec5b58464e9bb67dc5760be5d6f26d9da24892481d",
|
||||
"sha256:0a0a63cb8404d1d1f94968ef35738900038137dab8af836b6c21bb6f03d75465",
|
||||
"sha256:0a361bd5583bf0bcc08841df3c10269617ee2a36b99ac39d455a767da908bbbc",
|
||||
"sha256:10d3e5c7a99bd28afb957e1ae661323b0800d75b419f24d041ed1cc5d844a764",
|
||||
"sha256:1c40c244221a1adbb1256692b1133c6fb89418df27bf759a31a333e7912a4010",
|
||||
"sha256:203d18df84f5288973b2d56de63d4678cc748250026ca9e1ad8f8a0fd8a75d83",
|
||||
"sha256:213d6dc25ce686516208d8a3e91120c6a4fdae4a3e06b8505ced5b716b50cc04",
|
||||
"sha256:3119b2f16de7f7b9212ba76d8fe6a0e9f90b27a1e04683cd89833a991682f639",
|
||||
"sha256:3fb0b37c896172899a4a93d9442ffdc6f870165f59e05ce2e07c6fded1c15749",
|
||||
"sha256:41b016e3be4e740b66c79a031a0a6e145728dbc248142e751e8dab4f3188ca1d",
|
||||
"sha256:4a8d279f78844aad213c4935c18f8292a9432d51af2d88bca99072c903948045",
|
||||
"sha256:4e6eefae6effa0c35bbbc18c25ee6e0b1da44d2359c3cd526eb0c9e703cf055d",
|
||||
"sha256:5f2a4ea08e6876206d511365b0bc234edc813d90b930be72c3011bbd7898796f",
|
||||
"sha256:66d7b171fecf96940ce069923a08ba3df33ef542de82c2ff4fe8caa8346fa95a",
|
||||
"sha256:687df7ceff57b8f070d02b4db66f75566370e7ae182a0782b6d3d21b0d6917dc",
|
||||
"sha256:6be0ba61f6ff2e6b68e4270fb63b6813c9e7dec3d15fc3a93f47480444fd72f0",
|
||||
"sha256:6e9de2b390d253a508dd497e9b5579f3a851f208763ed67fdca5dc0c3ea6849c",
|
||||
"sha256:760a5e89ebbb172989e8273024a1024b0f084510b9105261b3b00c15e9c9f006",
|
||||
"sha256:816a966d5d376bf24c92af8f379e78e67278833e4c7cbc9fa41872eec629a060",
|
||||
"sha256:87ad73763d93add1b6c1f9fcd33af662fd62ed70e620c52fcb79f3ac427cf3a6",
|
||||
"sha256:896774766fd6be4571a43bc2fcbcb1dcca0807e53cab4a5bf88c4aa861a08e12",
|
||||
"sha256:8e0143975fc2a6d7136c97e19c637321288371e8f09cff2564ecd73e865ea0b9",
|
||||
"sha256:90a85a004fefed9e583597478420bf904bb1a065b0b0ee5b9d8d31b04b0f3f70",
|
||||
"sha256:9b081dac96ab19c54fd8558fac17c9d2c9cb5cc4656e7ed3261ddc927ba3e2c5",
|
||||
"sha256:9d6b2e8856dec3a6db1ae51aec85c82223e834b228c1d3228aede87eee2b34f9",
|
||||
"sha256:9f459c8ee2c086455744723628264e43c884be0c7d7b45d84b8cd981310b4815",
|
||||
"sha256:9fa6e193c14d6944e0685cdb527cb6b38b0e4a518043e7212f214113af7391da",
|
||||
"sha256:a42b9dc42de2cfe357efa27d9c50c7833fc5ab9b2eb7252ccd5d5f836a84e1e4",
|
||||
"sha256:b651b0d3642991259109dc0351fc33ad44c624801367bb8307be9bfc35e427ad",
|
||||
"sha256:b6c12514329ac0d03128cf1dcceb335f4fbf7c11da98bca68dca8dcb983153a9",
|
||||
"sha256:c52f48eb75fcc119a4fdb68ba83eb5f71656999420375df7c94cc68e0e14686e",
|
||||
"sha256:c96eeeb8c68b662c7747f91a385688d4b449687d29b691eff7068a4602fe6dc4",
|
||||
"sha256:cd1077b9a09b16d8c3c7075a8add5ffbfe6a69156a57e290c800ed4d435bef1d",
|
||||
"sha256:cd5dbbc8e25cad5f706845c4d100e2c8b34691b412b93717ce38d8ae803bcfa5",
|
||||
"sha256:cf2a60daf6cecff6828bc608df00dbc794380e7234d2411c0ec612811f01969d",
|
||||
"sha256:d3c93796b44fa111049b88a24105e947f03c01966b5c0cc782e2ee3887b790a3",
|
||||
"sha256:d796272408f8567ff7eaa00eb2856b3a00524490e47ad505b0b4ca6bb8a7411f",
|
||||
"sha256:e0fcb7da73fbf67b5f4bdaa57d85bb585a4e913d4a10f3e15b32baea56a67f0a",
|
||||
"sha256:e14485bb1b83eeb3d55b6878f9560240981e7bbc7a8d4e1e8c38b9bd6ec8d2de",
|
||||
"sha256:edd14cf733fdc4f6e6fe3f705af97676a7e52859bf0044aa2c84e55be739241c"
|
||||
"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.3"
|
||||
"markers": "python_version >= '3.10'",
|
||||
"version": "==3.10.0"
|
||||
},
|
||||
"numcodecs": {
|
||||
"hashes": [
|
||||
@ -729,6 +722,43 @@
|
||||
"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": [
|
||||
"sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e",
|
||||
@ -739,35 +769,35 @@
|
||||
},
|
||||
"debugpy": {
|
||||
"hashes": [
|
||||
"sha256:1339e14c7d980407248f09824d1b25ff5c5616651689f1e0f0e51bdead3ea13e",
|
||||
"sha256:17c5e0297678442511cf00a745c9709e928ea4ca263d764e90d233208889a19e",
|
||||
"sha256:1efbb3ff61487e2c16b3e033bc8595aea578222c08aaf3c4bf0f93fadbd662ee",
|
||||
"sha256:365e556a4772d7d0d151d7eb0e77ec4db03bcd95f26b67b15742b88cacff88e9",
|
||||
"sha256:3d9755e77a2d680ce3d2c5394a444cf42be4a592caaf246dbfbdd100ffcf7ae5",
|
||||
"sha256:3e59842d6c4569c65ceb3751075ff8d7e6a6ada209ceca6308c9bde932bcef11",
|
||||
"sha256:472a3994999fe6c0756945ffa359e9e7e2d690fb55d251639d07208dbc37caea",
|
||||
"sha256:54a7e6d3014c408eb37b0b06021366ee985f1539e12fe49ca2ee0d392d9ceca5",
|
||||
"sha256:5e565fc54b680292b418bb809f1386f17081d1346dca9a871bf69a8ac4071afe",
|
||||
"sha256:62d22dacdb0e296966d7d74a7141aaab4bec123fa43d1a35ddcb39bf9fd29d70",
|
||||
"sha256:66eeae42f3137eb428ea3a86d4a55f28da9bd5a4a3d369ba95ecc3a92c1bba53",
|
||||
"sha256:6953b335b804a41f16a192fa2e7851bdcfd92173cbb2f9f777bb934f49baab65",
|
||||
"sha256:7c4d65d03bee875bcb211c76c1d8f10f600c305dbd734beaed4077e902606fee",
|
||||
"sha256:7e646e62d4602bb8956db88b1e72fe63172148c1e25c041e03b103a25f36673c",
|
||||
"sha256:7e8b079323a56f719977fde9d8115590cb5e7a1cba2fcee0986ef8817116e7c1",
|
||||
"sha256:8138efff315cd09b8dcd14226a21afda4ca582284bf4215126d87342bba1cc66",
|
||||
"sha256:8e99c0b1cc7bf86d83fb95d5ccdc4ad0586d4432d489d1f54e4055bcc795f693",
|
||||
"sha256:957363d9a7a6612a37458d9a15e72d03a635047f946e5fceee74b50d52a9c8e2",
|
||||
"sha256:957ecffff80d47cafa9b6545de9e016ae8c9547c98a538ee96ab5947115fb3dd",
|
||||
"sha256:ada7fb65102a4d2c9ab62e8908e9e9f12aed9d76ef44880367bc9308ebe49a0f",
|
||||
"sha256:b74a49753e21e33e7cf030883a92fa607bddc4ede1aa4145172debc637780040",
|
||||
"sha256:c36856343cbaa448171cba62a721531e10e7ffb0abff838004701454149bc037",
|
||||
"sha256:cc37a6c9987ad743d9c3a14fa1b1a14b7e4e6041f9dd0c8abf8895fe7a97b899",
|
||||
"sha256:cfe1e6c6ad7178265f74981edf1154ffce97b69005212fbc90ca22ddfe3d017e",
|
||||
"sha256:e46b420dc1bea64e5bbedd678148be512442bc589b0111bd799367cde051e71a",
|
||||
"sha256:ff54ef77ad9f5c425398efb150239f6fe8e20c53ae2f68367eba7ece1e96226d"
|
||||
"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.9"
|
||||
"version": "==1.8.11"
|
||||
},
|
||||
"decorator": {
|
||||
"hashes": [
|
||||
@ -793,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",
|
||||
@ -819,6 +858,15 @@
|
||||
"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:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0",
|
||||
@ -859,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",
|
||||
@ -883,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",
|
||||
@ -944,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",
|
||||
@ -1090,6 +1178,44 @@
|
||||
],
|
||||
"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:072ce12ada169c5b00b7d92a99ba089447ccc993ea2143c9ede887e0937aa803",
|
||||
|
50
README.md
50
README.md
@ -9,6 +9,35 @@ On Ubuntu 22.04 just run `sudo apt-get install -y libiio-dev`
|
||||
|
||||
2. `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
|
||||
|
||||
There will be some sort of GUI because that sounds useful.
|
||||
@ -27,20 +56,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(),
|
||||
]
|
||||
)
|
@ -1,127 +1,59 @@
|
||||
# %% imports
|
||||
import json
|
||||
import pickle
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Callable, List, Tuple
|
||||
from typing import List
|
||||
|
||||
import matplotlib as mpl
|
||||
import numpy as np
|
||||
import skrf as rf
|
||||
import xarray as xr
|
||||
from gui_helpers import FlowLayout
|
||||
from matplotlib import pyplot as plt
|
||||
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg
|
||||
from matplotlib.ticker import EngFormatter
|
||||
from numpy import typing as npt
|
||||
from PySide6.QtCore import QSize, Qt
|
||||
from PySide6.QtGui import QAction, QKeySequence, QShortcut
|
||||
from PySide6.QtGui import QAction, QKeySequence
|
||||
from PySide6.QtWidgets import (
|
||||
QApplication,
|
||||
QDialogButtonBox,
|
||||
QFileDialog,
|
||||
QInputDialog,
|
||||
QLineEdit,
|
||||
QMainWindow,
|
||||
QMenu,
|
||||
QProgressBar,
|
||||
QPushButton,
|
||||
QToolBar,
|
||||
QVBoxLayout,
|
||||
QWidget,
|
||||
)
|
||||
from skrf import plotting as rf_plt
|
||||
from vna import Charon
|
||||
|
||||
DEFAULT_CONFIG = dict(
|
||||
frequency=np.arange(1e9, 2e9, 11), # Hz
|
||||
power=-5, # dB
|
||||
)
|
||||
from charon_vna.plots import PlotWidget
|
||||
from charon_vna.util import net2s, s2net
|
||||
|
||||
# %%
|
||||
DEFAULT_CONFIG = Path(__file__).parent / "config_default.json"
|
||||
CONFIG_SUFFIX = ".json"
|
||||
|
||||
|
||||
class PlotWidget(QWidget):
|
||||
enabled_ports: List[Tuple[int | str]]
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self.enabled_ports = [(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.setup_logmag()
|
||||
# self.setup_smith()
|
||||
self.ax.legend(loc="upper right")
|
||||
|
||||
canvas = FigureCanvasQTAgg(self.fig)
|
||||
layout.addWidget(canvas)
|
||||
|
||||
# toolbar = QToolBar("Toolbar")
|
||||
# toolbar.addAction("blah")
|
||||
# self.addToolBar(toolbar)
|
||||
|
||||
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[np.complex128]], npt.ArrayLike[float]]
|
||||
) -> None:
|
||||
self.ax.set_xlim(data["frequency"].min().data, data["frequency"].max().data)
|
||||
# remove old lines
|
||||
for line in self.ax.lines:
|
||||
line.remove()
|
||||
for m, n in self.enabled_ports:
|
||||
self.ax.plot(data["frequency"], func(data.sel(m=m, n=n)))
|
||||
|
||||
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, lambda s: 20 * np.log10(np.abs(s)))
|
||||
|
||||
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, lambda s: (1 + np.abs(s)) / (1 - np.abs(s)))
|
||||
|
||||
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:
|
||||
# remove old lines
|
||||
for line in self.ax.lines:
|
||||
line.remove()
|
||||
for m, n in self.enabled_ports:
|
||||
sel = data.sel(m=m, n=n)
|
||||
self.ax.plot(sel.real, sel.imag)
|
||||
|
||||
|
||||
# Subclass QMainWindow to customize your application's main window
|
||||
class MainWindow(QMainWindow):
|
||||
config_path: Path | None
|
||||
device: Charon
|
||||
# device: Charon
|
||||
|
||||
def __init__(self):
|
||||
plots: List[PlotWidget]
|
||||
|
||||
def __init__(self, ip: str | None = None):
|
||||
super().__init__()
|
||||
|
||||
self.config_path = None
|
||||
self.config_path = DEFAULT_CONFIG
|
||||
with open(self.config_path, "r") as f:
|
||||
config = json.load(f)
|
||||
self._frequency = config["frequency"]
|
||||
|
||||
self.device = Charon("ip:192.168.3.1", frequency=DEFAULT_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")
|
||||
|
||||
@ -132,24 +64,37 @@ class MainWindow(QMainWindow):
|
||||
|
||||
menu_file = QMenu("&File")
|
||||
menubar.addMenu(menu_file)
|
||||
action_load_config = QAction("&Open Configuration", self)
|
||||
menu_file.addAction(action_load_config)
|
||||
action_load_config.triggered.connect(self.load_config)
|
||||
QShortcut(QKeySequence("Ctrl+O"), self).activated.connect(self.load_config)
|
||||
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)
|
||||
QShortcut(QKeySequence("Ctrl+S"), self).activated.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)
|
||||
QShortcut(QKeySequence("Ctrl+Shift+S"), self).activated.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()
|
||||
@ -157,16 +102,19 @@ class MainWindow(QMainWindow):
|
||||
prog_sweep = QProgressBar()
|
||||
prog_sweep.setMinimum(0)
|
||||
prog_sweep.setMaximum(100)
|
||||
prog_sweep.setTextVisible(False)
|
||||
prog_sweep.setFormat("%v / %m")
|
||||
# prog_sweep.setTextVisible(False)
|
||||
prog_sweep.setValue(50)
|
||||
window_layout.addWidget(prog_sweep)
|
||||
self.prog_sweep = prog_sweep
|
||||
|
||||
# window_widget.se
|
||||
plot_layout = QVBoxLayout()
|
||||
# TODO: handle plots properly
|
||||
for i in range(2):
|
||||
plot0 = PlotWidget()
|
||||
plot_layout.addWidget(plot0)
|
||||
self.plots = []
|
||||
for type_ in ["logmag", "phase", "vswr", "smith"]:
|
||||
self.plots.append(PlotWidget(type_=type_))
|
||||
plot_layout.addWidget(self.plots[-1])
|
||||
plot_widget = QWidget()
|
||||
plot_widget.setLayout(plot_layout)
|
||||
window_layout.addWidget(plot_widget)
|
||||
@ -178,26 +126,141 @@ class MainWindow(QMainWindow):
|
||||
|
||||
def saveas_config(self) -> None:
|
||||
print("Prompting for save path...")
|
||||
# TODO: prompt for config path
|
||||
self.config_path = Path(__file__).parent / "config.json"
|
||||
print(f"Config path is now {self.config_path.resolve()}")
|
||||
self.save_config()
|
||||
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 is None:
|
||||
if self.config_path == DEFAULT_CONFIG:
|
||||
self.saveas_config()
|
||||
else:
|
||||
print(f"saving config to {self.config_path.resolve()}")
|
||||
print(f"Saving config to {self.config_path.resolve()}")
|
||||
# TODO: save config
|
||||
|
||||
def load_config(self) -> None:
|
||||
print("loading 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)
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
def capture(self) -> None:
|
||||
s = self.vna.vna_capture(self._frequency, self.progress_callback)
|
||||
|
||||
window = MainWindow()
|
||||
window.show()
|
||||
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],
|
||||
),
|
||||
)
|
||||
|
||||
app.exec()
|
||||
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()
|
||||
|
@ -1,7 +1,6 @@
|
||||
from pathlib import Path
|
||||
|
||||
import skrf as rf
|
||||
import xarray as xr
|
||||
from util import net2s
|
||||
|
||||
|
||||
|
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()
|
@ -1,6 +1,7 @@
|
||||
import numpy as np
|
||||
import skrf as rf
|
||||
import xarray as xr
|
||||
from numpy import typing as npt
|
||||
|
||||
HAM_BANDS = [
|
||||
[135.7e3, 137.8e3],
|
||||
@ -37,12 +38,16 @@ HAM_BANDS = [
|
||||
]
|
||||
|
||||
|
||||
def db10(p):
|
||||
def db10(p: npt.ArrayLike) -> npt.ArrayLike:
|
||||
return 10 * np.log10(np.abs(p))
|
||||
|
||||
|
||||
def db20(p):
|
||||
return 20 * 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):
|
||||
|
@ -1,10 +1,11 @@
|
||||
# %% imports
|
||||
import copy
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Tuple
|
||||
from typing import Any, Callable, Dict, Tuple
|
||||
|
||||
import adi
|
||||
import iio
|
||||
|
||||
# import iio
|
||||
import numpy as np
|
||||
import skrf as rf
|
||||
import xarray as xr
|
||||
@ -12,7 +13,8 @@ from matplotlib import pyplot as plt
|
||||
from matplotlib.ticker import EngFormatter
|
||||
from numpy import typing as npt
|
||||
from scipy import signal
|
||||
from util import HAM_BANDS, db20, net2s, s2net
|
||||
|
||||
from charon_vna.util import HAM_BANDS, db20, net2s, s2net
|
||||
|
||||
dir_ = Path(__file__).parent
|
||||
|
||||
@ -35,9 +37,11 @@ def generate_tone(f: float, fs: float, N: int = 1024, scale: int = 2**14):
|
||||
class Charon:
|
||||
FREQUENCY_OFFSET = 1e6
|
||||
|
||||
calibration: rf.calibration.Calibration | None = None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
uri: str,
|
||||
ip: str = "192.168.2.1",
|
||||
frequency: npt.ArrayLike = np.linspace(1e9, 2e9, 3),
|
||||
ports: Tuple[int] = (1,),
|
||||
):
|
||||
@ -45,7 +49,7 @@ class Charon:
|
||||
self.frequency = frequency
|
||||
|
||||
# everything RF
|
||||
self.sdr = adi.ad9361(uri=uri)
|
||||
self.sdr = adi.ad9361(uri=f"ip:{ip}")
|
||||
for attr, expected in [
|
||||
("adi,2rx-2tx-mode-enable", True),
|
||||
# ("adi,gpo-manual-mode-enable", True),
|
||||
@ -81,7 +85,7 @@ class Charon:
|
||||
# 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
|
||||
# # https://www.analog.com/media/cn/technical-documentation/user-guides/ad9364_register_map_reference_manual_ug-672.pdf # noqa: E501
|
||||
# self.ctrl.reg_write(0x26, 0x90) # bit 7: AuxDAC Manual, bit 4: GPO Manual
|
||||
# self._set_gpo(self.ports[0] - 1)
|
||||
# # TODO: init AuxDAC
|
||||
@ -140,8 +144,9 @@ class Charon:
|
||||
self.set_output_power(power)
|
||||
self.sdr.tx_lo = int(frequency - self.FREQUENCY_OFFSET)
|
||||
self.sdr.tx_cyclic_buffer = True
|
||||
# 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)
|
||||
# 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:
|
||||
@ -205,7 +210,7 @@ class Charon:
|
||||
s.loc[dict(frequency=frequency)] = self.get_b_over_a(frequency=frequency)
|
||||
return s
|
||||
|
||||
def vna_capture(self, frequency: npt.ArrayLike):
|
||||
def vna_capture(self, frequency: npt.ArrayLike, callback: Callable[int, int] | None):
|
||||
s = xr.DataArray(
|
||||
np.empty(len(frequency), dtype=np.complex128),
|
||||
dims=["frequency"],
|
||||
@ -213,7 +218,9 @@ class Charon:
|
||||
frequency=frequency,
|
||||
),
|
||||
)
|
||||
for freq in s.frequency.data:
|
||||
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)
|
||||
@ -224,163 +231,166 @@ class Charon:
|
||||
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
|
||||
|
||||
|
||||
# %%
|
||||
sdr = Charon("ip:192.168.3.1", frequency=np.linspace(1e9, 1.1e9, 11))
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
|
||||
# %% 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
|
||||
# %%
|
||||
sdr = Charon("ip:192.168.3.1", frequency=np.linspace(1e9, 1.1e9, 11))
|
||||
|
||||
# %% generate tone
|
||||
fc = 1e9
|
||||
sdr.set_output(frequency=fc + sdr.FREQUENCY_OFFSET, power=-5)
|
||||
# %% 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
|
||||
|
||||
# %% capture data
|
||||
data = sdr._rx(1, fc=fc)
|
||||
# %% generate tone
|
||||
fc = 1e9
|
||||
sdr.set_output(frequency=fc + sdr.FREQUENCY_OFFSET, power=-5)
|
||||
|
||||
# %% 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()
|
||||
# %% capture data
|
||||
data = sdr._rx(1, fc=fc)
|
||||
|
||||
# %%
|
||||
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 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()
|
||||
|
||||
# %% 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}",
|
||||
# %%
|
||||
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)],
|
||||
)
|
||||
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=cal_frequency)
|
||||
|
||||
# %%
|
||||
s = sdr.vna_capture(frequency=np.linspace(70e6, 200e6, 101))
|
||||
# %%
|
||||
s_calibrated = calibration.apply_cal(s2net(s))
|
||||
|
||||
# %% Plot Logmag
|
||||
fig, axs = plt.subplots(2, 1, sharex=True, tight_layout=True)
|
||||
plt.figure()
|
||||
s_calibrated.plot_s_smith()
|
||||
# ref.plot_s_smith(m=1, n=1)
|
||||
plt.show()
|
||||
|
||||
axs[0].plot(s.frequency, db20(s), label="Measured")
|
||||
axs[1].plot(s.frequency, np.rad2deg(np.angle((s))), label="Measured")
|
||||
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()
|
||||
|
||||
axs[0].grid(True)
|
||||
axs[1].grid(True)
|
||||
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()
|
||||
|
||||
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()
|
||||
|
||||
# %%
|
||||
# %%
|
||||
|
@ -26,10 +26,12 @@ dependencies = [
|
||||
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"
|
||||
|
Reference in New Issue
Block a user