{ "info": { "author": "Harrison Caudill", "author_email": "harrison@hypersphere.org", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "Intended Audience :: Science/Research", "Intended Audience :: Telecommunications Industry", "License :: OSI Approved :: BSD License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Topic :: Communications :: Ham Radio", "Topic :: Scientific/Engineering :: Atmospheric Science", "Topic :: Scientific/Engineering :: Physics" ], "description": "Note to Anyone Reading This\n===========================\n\nI just closed down business operations at BStar and switched over to\nconsulting. I have some time on my hands right now, so feel free to file an\nissue if you have a feature request.\n\n\nPyPi Naming\n===========\n\nPlease note that there is already a `pylink` package on PyPi, so it is\ncurrently registered as `pylink-satcom`. I'll repeat this warning in\nthe `Installation` section below.\n\n\nPython Link Budget Calculation/Management and General Modelling\n===============================================================\n\nThis software package is meant to replace the manual-intensive\nspreadsheet method. This package is intended to permit the following\nmajor changes in common methodology:\n\n * Use of configuration files on a per (satellite, ground-station,\n radio) basis.\n\n * Ability to export consistently-formatted PDF link budgets for\n communcation with external agencies.\n\n * Ability to easily produce graphs, such as pfd/4kHz for regulatory\n compliance.\n\n * Ability to easily solve for required values within a link budget.\n\n * Ability to tag components with arbitrary values, such as datasheet\n links, descriptions, and part numbers.\n\n * Creation of more generalized models for calculating whatever you\n want (see the [Midlife Crisis Example](examples/midlife_crisis.py)\n or the [HyperSpectral Imaging SNR\n Budget](examples/hyperspectral.py))\n\n * Ease the building of monte-carlo simulations (FIXME: need example).\n\n\nThe nature of this package is best described as three things:\n\n1) A caching DAG (Directed Acyclic Graph) Solver.\n\n2) A set of utilities common to link-budgets.\n\n3) A set of pre-defined computational nodes common to link budgets.\n\nIf you're looking for a quick-start and/or just want to go with some\nboilerplate examples, take a look at the [Examples](examples/)\ndirectory.\n\n\nDAG Solver\n----------\n\nSpreadsheets are, for the most part, DAGs. If you define `C46 = C87 -\n$B$34` then you are, essentially, saying that 3 nodes exist: `C46`,\n`C87`, and `$B$34`. You are also stating that to solve for node `C46`\nyou take the value of node `C87` and subtract the value of node\n`$B$34`.\n\nThis system works the same way, except that instead of saying `C46`,\nwe might instead say `link_margin_db`. And instead of coupling our\npresentation and data layers, as in a spreadsheet, we might define it\nas follows:\n\n```python\ndef _link_margin_db(model):\n # Note how we're just referencing things like required_ebn0_db as\n # instance vars. No they aren't instance vars, that's just how\n # you reference nodes in the DAG.\n return model.received_ebn0_db - model.required_ebn0_db\n\nmy_example = pylink.DAGModel(received_ebn0_db=8.0,\n required_ebn0_db=6.0,\n link_margin_db=_link_margin_db)\nprint('My Example Link Margin: ', my_example.link_margin_db)\n```\n\nThe DAGModel class overrides python's `__getattr__` method so that you\ncan reference nodes directly, without the added syntactic sugar of\nextra parens, brakcets, and tick-marks.\n\nIf you're curious what this all looks like in a context other than\nlink budgets, take a look at the [Midlife Crisis\nExample](examples/midlife_crisis.py). There we create a DAGModel that\nhas nothing at all to do with RF, satellites, etc. There's really\nnothing that restricts us to link budgets, or even RF. Feel free to\nwrite the nodes and use the framework for whatever you want.\n\nPlease note that there are two types of nodes:\n * Static Nodes\n * Calculated Nodes\n\nSimply put, static nodes are just plain old values that you pass in,\nwhereas calculated nodes are functions/methods/... You'll see an enum\nreferenced all over the place. That's because it uses node numbers\ninternally, and an enum is convenient way to reference node numbers\nwithout having to use a bunch of single-ticks and brackets. For example:\n\n```python\ndef _link_margin_db(model):\n return model.received_ebn0_db - model.required_ebn0_db\n\nmy_example = pylink.DAGModel(received_ebn0_db=8.0,\n required_ebn0_db=6.0,\n link_margin_db=_link_margin_db)\nm = my_example # m as in model\ne = m.enum # e as in enum\n\nprint(e.link_margin_db)\nprint(m.node_name(e.link_margin_db))\nprint(m.node_num('link_margin_db')) # the alternative to using the enum\n```\n\nIt also includes a multi-round linear solver for convenience. See the\n[Solver Example](examples/solver.py).\n\n\nUtilities\n---------\n\nThere are some utilities that are handy for working with RF. For\nexample, there's a function that fakes an antenna gain pattern for\nyou: `pylink.pattern_generator`, and another one that calculates the\nattenuation of PFD from spreading over a distance:\n`pylink.spreading_loss_db`.\n\n\nPre-Defined Nodes\n-----------------\n\nAs shown above, new nodes can be registered with the DAG Model directly:\n\n```python\nmy_example = pylink.DAGModel(received_ebn0_db=8.0,\n required_ebn0_db=6.0,\n link_margin_db=_link_margin_db)\n```\n\nHere we've added 3 nodes:\n * received_ebn0_db\n * required_ebn0_db\n * link_margin_db\n\nIt frequently makes sense to group nodes before registration. That's\nwhere Tributaries come into play. If you look in the [Basic\nExample](examples/basic.py), you see that it uses a whole list of\ntributaries. [Geometry](pylink/tributaries/geometry.py) is probably\nthe simplest and most straight-forward tributary if you're looking for\na production example, otherwise please see the [Examples](examples/).\n\nAside from logical grouping, it also makes sense to reuse code.\n[Antennas](pylink/tributaries/antenna.py), for example, have patterns\nthat can be plotted to PNG files irrespective of whether they're a\ntransmit or receive antenna. Instead of duplicating that code, we\nsimply have a single Antenna class that remembers whether it is meant\nfor tx or rx. When it contributes nodes to the DAG, those nodes\n(instance methods) will be able to refer to their object and know\nwhether to use the tx or rx path.\n\n\nInstallation\n=============\n\nPlease note that there is a name collision with another `pylink`\npackage in PyPi. As such, we have registered this package there under\na different name: `pylink-satcom`.\n\nWe recommend using Anaconda with Python 3.7. This package can be\ninstalled by executing: `pip install pylink-satcom`\n\nIf you want to install it from source: `pip install .` works as well.\n\n\nLegacy Support\n==============\n\nMigration instructions from previous versions can be found in the\n[Changelog](CHANGELOG.md).\n\n\nExtending and Understanding\n===========================\n\nSubmodules\n----------\n\n * `model.py`: Contains the actual DAG Model class that houses the core\n logic of the calculations.\n\n * `utils.py`: Standalone utility functions (such as `to_db`)\n\n * `report.py`: Satellite link budget latex report generator.\n\n * `tagged_attribute.py`: The TaggedAttribute class for adding\n metadata tags to individual components.\n\n * `element.py`: RF Element container.\n\n * `tributaries/*.py`: These each provide boilerplate inputs and\n calculators that are common to link budgets.\n For example, you're likely to need a\n transmitter and a receiver. There will be a\n channel to carry the signal, etc.\n\nCreating Tributaries\n--------------------\n\nIf you just want to add one more computation, or modify one, you can\ndo so by including it in the model itself -- you don't need to create\nyour own tributary. If, however, you do want to create a new one, use\nthe pre-existing source as a guide (it should be pretty clear). Note\nthat you'll need to define the `tribute` instance variable. This\nshould be a dict of node-names to values. That works both for\nconstants (like `apoapsis_altitude_km` or `speed_of_light_m_per_s`),\nand for functions that calculate values (like `slant_range_km` or\n`link_margin_db`). The DAG Model will expect this value to exist and\nraise an exception otherwise.\n\nTagging Architecture\n--------------------\n\nIndividual components include a facility for tagging with metadata\nsuch as test report links, datasheets, part numbers, etc. The tagging\nis key/value based, and not restricted or controlled. There are two\nprimary mechanisms by which tagging occurs:\n\n * Through pre-defined objects, such as `Antenna` or `Element`, whcih\n permit arbitrary keyword arguments that will be automatically added\n to their metadata.\n\n * Throug the use of `TaggedAttribute` objects, which permit adding\n arbitrary tags to individual values (such as the\n `rx_antenna_noise_temperature`).\n\nYou'll find examples of both of these usages in the `examples`\ndirectory.\n\nCycles\n------\n\nIn some circumstances, cycles do exist, breaking the DAG nature of\nthis system. Under very special circumstances, we can deal with\nthose. If one of the items in the loop exists within a finite set,\nthen you can do an O(N) search across all of those options, to\ndetermine the most appropriate value. A real-life example can be\nfound in `modulation.py`:\n\n```\nbest_modulation_code\n -> additional_rx_losses_db\n -> excess_noise_bandwidth_loss_db\n -> required_rx_bw_dbhz\n -> required_rx_bw_hz\n -> rx_spectral_efficiency_bps_per_hz\n -> best_modulation_code\n```\n\nThe way we get around this issue, is to recognize that\n`best_modulation_code` exists within a finite set (specifically all\navailable modulation options). That allows us to, essentially, fake\nthe return value of our own function, observe a figure of merit, and\nreturn the appropriate value at the end. To introduce a cycle, you'll\nneed to do the following:\n\n 1. Loop through all possible options\n\n 2. In your loop, start by overriding the value you are attempting to\n compute to the current option\n\n 3. Compute the value that induces a cycle with `clear_stack=True`\n\n 4. Revert the value you are attempting to calculate\n\n 5. Select the appropriate option by comparing the figure of merit.\n\n 6. Return the result from your calculator.\n\nFor example:\n```python\ndef _cycle_inducement(model):\n e = model.enum\n\n best_cycle = -1\n best_option = None\n\n for option in model.cycle_inducement_options: # Step 1\n model.override(e.cycle_inducement, option) # Step 2\n cycle = model.cached_calculate(e.cycle, clear_stack=True) # Step 3\n model.revert(e.cycle_inducement) # Step 4\n\n # Step 5\n if cycle > best_cycle:\n best_cycle = cycle\n best_option = option\n\n return best_option # Step 6\n```\n\nYou can also find a unit-test of this behavior in `model_test.py`.\n\n\nHyperSpectral Imaging\n=====================\n\nBStar pivoted to HyperSpectral in an attempt to address the disparity\nbetween customer/partner/regulator interest in our success and\ninvestor interest. HyperSpectral Imaging was the selected target (due\nto the close association with comms and the simplicity of the business\nmodel). For expediency, the HSI SNR budget was computed using pylink,\nand I'm adding it to the repo to avoid having yet-another-repo. If it\ngathers enough steam, I'll break it out into a separate repo.\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/harrison-caudill/pylink", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "pylink-satcom", "package_url": "https://pypi.org/project/pylink-satcom/", "platform": "", "project_url": "https://pypi.org/project/pylink-satcom/", "project_urls": { "Homepage": "https://github.com/harrison-caudill/pylink" }, "release_url": "https://pypi.org/project/pylink-satcom/0.7/", "requires_dist": [ "matplotlib", "jinja2", "scipy", "numpy" ], "requires_python": "", "summary": "Python Link Budget System", "version": "0.7" }, "last_serial": 4799681, "releases": { "0.5": [ { "comment_text": "", "digests": { "md5": "890ae153871b0044bc2581df9d3cc707", "sha256": "e21b32c39f986ea421973775e79c976966b5aef603817230299111110a60826c" }, "downloads": -1, "filename": "pylink_satcom-0.5-py3-none-any.whl", "has_sig": false, "md5_digest": "890ae153871b0044bc2581df9d3cc707", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 34802, "upload_time": "2019-02-08T19:06:03", "url": "https://files.pythonhosted.org/packages/fc/42/e576fe3b4e45fdf39b3b7c4f4949d242dd931dd4ad2b8358c48eaeef8d99/pylink_satcom-0.5-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1f0b83038dad1bc335d7721be149c620", "sha256": "0caa164148ee91fb1ff77f8298dbb734eddb15e978888c352c8308a4bfab0b2a" }, "downloads": -1, "filename": "pylink-satcom-0.5.tar.gz", "has_sig": false, "md5_digest": "1f0b83038dad1bc335d7721be149c620", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 34144, "upload_time": "2019-02-08T19:06:07", "url": "https://files.pythonhosted.org/packages/b9/35/b4ec013f73c355ea14a600bf4e393eb4ce9b08a3cf634f7131b5bdd4f96e/pylink-satcom-0.5.tar.gz" } ], "0.6": [ { "comment_text": "", "digests": { "md5": "99d8f487d56a1f8d63d2daf65baffcdf", "sha256": "639eef1e69eb8a7c8d38f63e7b40021a3a50a38629a39c3b9753ad1ae71a3e12" }, "downloads": -1, "filename": "pylink_satcom-0.6-py3-none-any.whl", "has_sig": false, "md5_digest": "99d8f487d56a1f8d63d2daf65baffcdf", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 37404, "upload_time": "2019-02-08T20:31:56", "url": "https://files.pythonhosted.org/packages/16/3b/5bdef399599b9ccd0310a07a7b702ce47bb0cf889e64ec49e32c1b8c7340/pylink_satcom-0.6-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b6cb8475b87bc3a2d167f77ead76032f", "sha256": "66aa328ad5e92357bbb4bdc73b108b33b8684e1b53c15a18d2db1fad4ea7db84" }, "downloads": -1, "filename": "pylink-satcom-0.6.tar.gz", "has_sig": false, "md5_digest": "b6cb8475b87bc3a2d167f77ead76032f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 36762, "upload_time": "2019-02-08T20:31:58", "url": "https://files.pythonhosted.org/packages/91/8f/4cb38dc373fd70d9a1916b0e0c27b24117b75bde05322f457bd38aa4fbcb/pylink-satcom-0.6.tar.gz" } ], "0.7": [ { "comment_text": "", "digests": { "md5": "999bb586ff76f724fe88fe05f0bbc02f", "sha256": "cf14924359ab8625af531cf07b4e004d52d896945c452eca0820cb9026e304b2" }, "downloads": -1, "filename": "pylink_satcom-0.7-py3-none-any.whl", "has_sig": false, "md5_digest": "999bb586ff76f724fe88fe05f0bbc02f", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 37478, "upload_time": "2019-02-09T16:17:47", "url": "https://files.pythonhosted.org/packages/5e/a7/1fd2e26933fd0039cfbeca64b52f780d1006d18253263b5ee869c9fb2968/pylink_satcom-0.7-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "6cc340a25b2d7631ac09abc7126b4586", "sha256": "49780bd735eaa317215af5b8592d492a285a04f7864801086f8f78f73e921cb4" }, "downloads": -1, "filename": "pylink-satcom-0.7.tar.gz", "has_sig": false, "md5_digest": "6cc340a25b2d7631ac09abc7126b4586", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 36846, "upload_time": "2019-02-09T16:17:49", "url": "https://files.pythonhosted.org/packages/fb/8f/ec7e7f96b911435fba56d836493c51410ec16bec1dbc81f3968a23a1fbcc/pylink-satcom-0.7.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "999bb586ff76f724fe88fe05f0bbc02f", "sha256": "cf14924359ab8625af531cf07b4e004d52d896945c452eca0820cb9026e304b2" }, "downloads": -1, "filename": "pylink_satcom-0.7-py3-none-any.whl", "has_sig": false, "md5_digest": "999bb586ff76f724fe88fe05f0bbc02f", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 37478, "upload_time": "2019-02-09T16:17:47", "url": "https://files.pythonhosted.org/packages/5e/a7/1fd2e26933fd0039cfbeca64b52f780d1006d18253263b5ee869c9fb2968/pylink_satcom-0.7-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "6cc340a25b2d7631ac09abc7126b4586", "sha256": "49780bd735eaa317215af5b8592d492a285a04f7864801086f8f78f73e921cb4" }, "downloads": -1, "filename": "pylink-satcom-0.7.tar.gz", "has_sig": false, "md5_digest": "6cc340a25b2d7631ac09abc7126b4586", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 36846, "upload_time": "2019-02-09T16:17:49", "url": "https://files.pythonhosted.org/packages/fb/8f/ec7e7f96b911435fba56d836493c51410ec16bec1dbc81f3968a23a1fbcc/pylink-satcom-0.7.tar.gz" } ] }