From 60beb68aae620797f2659533e57b047a636259de Mon Sep 17 00:00:00 2001 From: Katie Zaback Date: Thu, 19 Oct 2023 14:16:16 -0400 Subject: [PATCH] updating docs --- site/404.html | 241 ++++++++++------- .../assets/javascripts/bundle.220ee61c.min.js | 29 -- .../javascripts/bundle.220ee61c.min.js.map | 8 - .../assets/javascripts/bundle.aecac24b.min.js | 29 ++ .../javascripts/bundle.aecac24b.min.js.map | 7 + .../javascripts/lunr/min/lunr.el.min.js | 1 + .../javascripts/lunr/min/lunr.he.min.js | 1 + ...74e28a9f.min.js => search.f886a092.min.js} | 18 +- ....min.js.map => search.f886a092.min.js.map} | 9 +- site/assets/stylesheets/main.26e3688c.min.css | 1 - .../stylesheets/main.26e3688c.min.css.map | 1 - site/assets/stylesheets/main.35e1ed30.min.css | 1 + .../stylesheets/main.35e1ed30.min.css.map | 1 + .../stylesheets/palette.356b1318.min.css | 1 + .../stylesheets/palette.356b1318.min.css.map | 1 + .../stylesheets/palette.ecc896b0.min.css | 1 - .../stylesheets/palette.ecc896b0.min.css.map | 1 - .../1__pulsar_querying/pq_overview/index.html | 241 +++++++++++------ .../mp_overview/index.html | 241 +++++++++++------ .../ceg_overview/index.html | 241 +++++++++++------ .../sdr_demo/index.html | 241 ++++++++++------- site/getting_started/index.html | 243 ++++++++++------- site/index.html | 249 +++++++++++------- site/search/search_index.json | 2 +- site/sitemap.xml.gz | Bin 127 -> 127 bytes 25 files changed, 1133 insertions(+), 676 deletions(-) delete mode 100644 site/assets/javascripts/bundle.220ee61c.min.js delete mode 100644 site/assets/javascripts/bundle.220ee61c.min.js.map create mode 100644 site/assets/javascripts/bundle.aecac24b.min.js create mode 100644 site/assets/javascripts/bundle.aecac24b.min.js.map create mode 100644 site/assets/javascripts/lunr/min/lunr.el.min.js create mode 100644 site/assets/javascripts/lunr/min/lunr.he.min.js rename site/assets/javascripts/workers/{search.74e28a9f.min.js => search.f886a092.min.js} (66%) rename site/assets/javascripts/workers/{search.74e28a9f.min.js.map => search.f886a092.min.js.map} (80%) delete mode 100644 site/assets/stylesheets/main.26e3688c.min.css delete mode 100644 site/assets/stylesheets/main.26e3688c.min.css.map create mode 100644 site/assets/stylesheets/main.35e1ed30.min.css create mode 100644 site/assets/stylesheets/main.35e1ed30.min.css.map create mode 100644 site/assets/stylesheets/palette.356b1318.min.css create mode 100644 site/assets/stylesheets/palette.356b1318.min.css.map delete mode 100644 site/assets/stylesheets/palette.ecc896b0.min.css delete mode 100644 site/assets/stylesheets/palette.ecc896b0.min.css.map diff --git a/site/404.html b/site/404.html index 4065369..40610ea 100644 --- a/site/404.html +++ b/site/404.html @@ -10,8 +10,9 @@ + - + @@ -19,10 +20,10 @@ - + - + @@ -64,8 +65,11 @@ + + + @@ -124,6 +128,7 @@
@@ -145,33 +150,34 @@
- - - - - - - - - - - - - - - - - -
+ + + + + + + + + + + + + + + + + + @@ -275,6 +296,7 @@
+ @@ -294,14 +316,18 @@ - -
  • - Overview + + + + Overview + + +
  • @@ -309,14 +335,18 @@ - -
  • - Getting Started + + + + Getting Started + + +
  • @@ -324,79 +354,108 @@ - - -
  • - + + + + + +
  • - - - - - - - - +
  • @@ -422,9 +481,10 @@
    + + + Back to top + @@ -451,10 +511,11 @@
    - + + - + diff --git a/site/assets/javascripts/bundle.220ee61c.min.js b/site/assets/javascripts/bundle.220ee61c.min.js deleted file mode 100644 index 116072a..0000000 --- a/site/assets/javascripts/bundle.220ee61c.min.js +++ /dev/null @@ -1,29 +0,0 @@ -"use strict";(()=>{var Ci=Object.create;var gr=Object.defineProperty;var Ri=Object.getOwnPropertyDescriptor;var ki=Object.getOwnPropertyNames,Ht=Object.getOwnPropertySymbols,Hi=Object.getPrototypeOf,yr=Object.prototype.hasOwnProperty,nn=Object.prototype.propertyIsEnumerable;var rn=(e,t,r)=>t in e?gr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,P=(e,t)=>{for(var r in t||(t={}))yr.call(t,r)&&rn(e,r,t[r]);if(Ht)for(var r of Ht(t))nn.call(t,r)&&rn(e,r,t[r]);return e};var on=(e,t)=>{var r={};for(var n in e)yr.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&Ht)for(var n of Ht(e))t.indexOf(n)<0&&nn.call(e,n)&&(r[n]=e[n]);return r};var Pt=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Pi=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of ki(t))!yr.call(e,o)&&o!==r&&gr(e,o,{get:()=>t[o],enumerable:!(n=Ri(t,o))||n.enumerable});return e};var yt=(e,t,r)=>(r=e!=null?Ci(Hi(e)):{},Pi(t||!e||!e.__esModule?gr(r,"default",{value:e,enumerable:!0}):r,e));var sn=Pt((xr,an)=>{(function(e,t){typeof xr=="object"&&typeof an!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(xr,function(){"use strict";function e(r){var n=!0,o=!1,i=null,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function a(O){return!!(O&&O!==document&&O.nodeName!=="HTML"&&O.nodeName!=="BODY"&&"classList"in O&&"contains"in O.classList)}function f(O){var Qe=O.type,De=O.tagName;return!!(De==="INPUT"&&s[Qe]&&!O.readOnly||De==="TEXTAREA"&&!O.readOnly||O.isContentEditable)}function c(O){O.classList.contains("focus-visible")||(O.classList.add("focus-visible"),O.setAttribute("data-focus-visible-added",""))}function u(O){O.hasAttribute("data-focus-visible-added")&&(O.classList.remove("focus-visible"),O.removeAttribute("data-focus-visible-added"))}function p(O){O.metaKey||O.altKey||O.ctrlKey||(a(r.activeElement)&&c(r.activeElement),n=!0)}function m(O){n=!1}function d(O){a(O.target)&&(n||f(O.target))&&c(O.target)}function h(O){a(O.target)&&(O.target.classList.contains("focus-visible")||O.target.hasAttribute("data-focus-visible-added"))&&(o=!0,window.clearTimeout(i),i=window.setTimeout(function(){o=!1},100),u(O.target))}function v(O){document.visibilityState==="hidden"&&(o&&(n=!0),Y())}function Y(){document.addEventListener("mousemove",N),document.addEventListener("mousedown",N),document.addEventListener("mouseup",N),document.addEventListener("pointermove",N),document.addEventListener("pointerdown",N),document.addEventListener("pointerup",N),document.addEventListener("touchmove",N),document.addEventListener("touchstart",N),document.addEventListener("touchend",N)}function B(){document.removeEventListener("mousemove",N),document.removeEventListener("mousedown",N),document.removeEventListener("mouseup",N),document.removeEventListener("pointermove",N),document.removeEventListener("pointerdown",N),document.removeEventListener("pointerup",N),document.removeEventListener("touchmove",N),document.removeEventListener("touchstart",N),document.removeEventListener("touchend",N)}function N(O){O.target.nodeName&&O.target.nodeName.toLowerCase()==="html"||(n=!1,B())}document.addEventListener("keydown",p,!0),document.addEventListener("mousedown",m,!0),document.addEventListener("pointerdown",m,!0),document.addEventListener("touchstart",m,!0),document.addEventListener("visibilitychange",v,!0),Y(),r.addEventListener("focus",d,!0),r.addEventListener("blur",h,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var cn=Pt(Er=>{(function(e){var t=function(){try{return!!Symbol.iterator}catch(c){return!1}},r=t(),n=function(c){var u={next:function(){var p=c.shift();return{done:p===void 0,value:p}}};return r&&(u[Symbol.iterator]=function(){return u}),u},o=function(c){return encodeURIComponent(c).replace(/%20/g,"+")},i=function(c){return decodeURIComponent(String(c).replace(/\+/g," "))},s=function(){var c=function(p){Object.defineProperty(this,"_entries",{writable:!0,value:{}});var m=typeof p;if(m!=="undefined")if(m==="string")p!==""&&this._fromString(p);else if(p instanceof c){var d=this;p.forEach(function(B,N){d.append(N,B)})}else if(p!==null&&m==="object")if(Object.prototype.toString.call(p)==="[object Array]")for(var h=0;hd[0]?1:0}),c._entries&&(c._entries={});for(var p=0;p1?i(d[1]):"")}})})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er);(function(e){var t=function(){try{var o=new e.URL("b","http://a");return o.pathname="c d",o.href==="http://a/c%20d"&&o.searchParams}catch(i){return!1}},r=function(){var o=e.URL,i=function(f,c){typeof f!="string"&&(f=String(f)),c&&typeof c!="string"&&(c=String(c));var u=document,p;if(c&&(e.location===void 0||c!==e.location.href)){c=c.toLowerCase(),u=document.implementation.createHTMLDocument(""),p=u.createElement("base"),p.href=c,u.head.appendChild(p);try{if(p.href.indexOf(c)!==0)throw new Error(p.href)}catch(O){throw new Error("URL unable to set base "+c+" due to "+O)}}var m=u.createElement("a");m.href=f,p&&(u.body.appendChild(m),m.href=m.href);var d=u.createElement("input");if(d.type="url",d.value=f,m.protocol===":"||!/:/.test(m.href)||!d.checkValidity()&&!c)throw new TypeError("Invalid URL");Object.defineProperty(this,"_anchorElement",{value:m});var h=new e.URLSearchParams(this.search),v=!0,Y=!0,B=this;["append","delete","set"].forEach(function(O){var Qe=h[O];h[O]=function(){Qe.apply(h,arguments),v&&(Y=!1,B.search=h.toString(),Y=!0)}}),Object.defineProperty(this,"searchParams",{value:h,enumerable:!0});var N=void 0;Object.defineProperty(this,"_updateSearchParams",{enumerable:!1,configurable:!1,writable:!1,value:function(){this.search!==N&&(N=this.search,Y&&(v=!1,this.searchParams._fromString(this.search),v=!0))}})},s=i.prototype,a=function(f){Object.defineProperty(s,f,{get:function(){return this._anchorElement[f]},set:function(c){this._anchorElement[f]=c},enumerable:!0})};["hash","host","hostname","port","protocol"].forEach(function(f){a(f)}),Object.defineProperty(s,"search",{get:function(){return this._anchorElement.search},set:function(f){this._anchorElement.search=f,this._updateSearchParams()},enumerable:!0}),Object.defineProperties(s,{toString:{get:function(){var f=this;return function(){return f.href}}},href:{get:function(){return this._anchorElement.href.replace(/\?$/,"")},set:function(f){this._anchorElement.href=f,this._updateSearchParams()},enumerable:!0},pathname:{get:function(){return this._anchorElement.pathname.replace(/(^\/?)/,"/")},set:function(f){this._anchorElement.pathname=f},enumerable:!0},origin:{get:function(){var f={"http:":80,"https:":443,"ftp:":21}[this._anchorElement.protocol],c=this._anchorElement.port!=f&&this._anchorElement.port!=="";return this._anchorElement.protocol+"//"+this._anchorElement.hostname+(c?":"+this._anchorElement.port:"")},enumerable:!0},password:{get:function(){return""},set:function(f){},enumerable:!0},username:{get:function(){return""},set:function(f){},enumerable:!0}}),i.createObjectURL=function(f){return o.createObjectURL.apply(o,arguments)},i.revokeObjectURL=function(f){return o.revokeObjectURL.apply(o,arguments)},e.URL=i};if(t()||r(),e.location!==void 0&&!("origin"in e.location)){var n=function(){return e.location.protocol+"//"+e.location.hostname+(e.location.port?":"+e.location.port:"")};try{Object.defineProperty(e.location,"origin",{get:n,enumerable:!0})}catch(o){setInterval(function(){e.location.origin=n()},100)}}})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er)});var qr=Pt((Mt,Nr)=>{/*! - * clipboard.js v2.0.11 - * https://clipboardjs.com/ - * - * Licensed MIT © Zeno Rocha - */(function(t,r){typeof Mt=="object"&&typeof Nr=="object"?Nr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Mt=="object"?Mt.ClipboardJS=r():t.ClipboardJS=r()})(Mt,function(){return function(){var e={686:function(n,o,i){"use strict";i.d(o,{default:function(){return Ai}});var s=i(279),a=i.n(s),f=i(370),c=i.n(f),u=i(817),p=i.n(u);function m(j){try{return document.execCommand(j)}catch(T){return!1}}var d=function(T){var E=p()(T);return m("cut"),E},h=d;function v(j){var T=document.documentElement.getAttribute("dir")==="rtl",E=document.createElement("textarea");E.style.fontSize="12pt",E.style.border="0",E.style.padding="0",E.style.margin="0",E.style.position="absolute",E.style[T?"right":"left"]="-9999px";var H=window.pageYOffset||document.documentElement.scrollTop;return E.style.top="".concat(H,"px"),E.setAttribute("readonly",""),E.value=j,E}var Y=function(T,E){var H=v(T);E.container.appendChild(H);var I=p()(H);return m("copy"),H.remove(),I},B=function(T){var E=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},H="";return typeof T=="string"?H=Y(T,E):T instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(T==null?void 0:T.type)?H=Y(T.value,E):(H=p()(T),m("copy")),H},N=B;function O(j){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?O=function(E){return typeof E}:O=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},O(j)}var Qe=function(){var T=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},E=T.action,H=E===void 0?"copy":E,I=T.container,q=T.target,Me=T.text;if(H!=="copy"&&H!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(q!==void 0)if(q&&O(q)==="object"&&q.nodeType===1){if(H==="copy"&&q.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(H==="cut"&&(q.hasAttribute("readonly")||q.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Me)return N(Me,{container:I});if(q)return H==="cut"?h(q):N(q,{container:I})},De=Qe;function $e(j){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?$e=function(E){return typeof E}:$e=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},$e(j)}function Ei(j,T){if(!(j instanceof T))throw new TypeError("Cannot call a class as a function")}function tn(j,T){for(var E=0;E0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof I.action=="function"?I.action:this.defaultAction,this.target=typeof I.target=="function"?I.target:this.defaultTarget,this.text=typeof I.text=="function"?I.text:this.defaultText,this.container=$e(I.container)==="object"?I.container:document.body}},{key:"listenClick",value:function(I){var q=this;this.listener=c()(I,"click",function(Me){return q.onClick(Me)})}},{key:"onClick",value:function(I){var q=I.delegateTarget||I.currentTarget,Me=this.action(q)||"copy",kt=De({action:Me,container:this.container,target:this.target(q),text:this.text(q)});this.emit(kt?"success":"error",{action:Me,text:kt,trigger:q,clearSelection:function(){q&&q.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(I){return vr("action",I)}},{key:"defaultTarget",value:function(I){var q=vr("target",I);if(q)return document.querySelector(q)}},{key:"defaultText",value:function(I){return vr("text",I)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(I){var q=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return N(I,q)}},{key:"cut",value:function(I){return h(I)}},{key:"isSupported",value:function(){var I=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],q=typeof I=="string"?[I]:I,Me=!!document.queryCommandSupported;return q.forEach(function(kt){Me=Me&&!!document.queryCommandSupported(kt)}),Me}}]),E}(a()),Ai=Li},828:function(n){var o=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function s(a,f){for(;a&&a.nodeType!==o;){if(typeof a.matches=="function"&&a.matches(f))return a;a=a.parentNode}}n.exports=s},438:function(n,o,i){var s=i(828);function a(u,p,m,d,h){var v=c.apply(this,arguments);return u.addEventListener(m,v,h),{destroy:function(){u.removeEventListener(m,v,h)}}}function f(u,p,m,d,h){return typeof u.addEventListener=="function"?a.apply(null,arguments):typeof m=="function"?a.bind(null,document).apply(null,arguments):(typeof u=="string"&&(u=document.querySelectorAll(u)),Array.prototype.map.call(u,function(v){return a(v,p,m,d,h)}))}function c(u,p,m,d){return function(h){h.delegateTarget=s(h.target,p),h.delegateTarget&&d.call(u,h)}}n.exports=f},879:function(n,o){o.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},o.nodeList=function(i){var s=Object.prototype.toString.call(i);return i!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in i&&(i.length===0||o.node(i[0]))},o.string=function(i){return typeof i=="string"||i instanceof String},o.fn=function(i){var s=Object.prototype.toString.call(i);return s==="[object Function]"}},370:function(n,o,i){var s=i(879),a=i(438);function f(m,d,h){if(!m&&!d&&!h)throw new Error("Missing required arguments");if(!s.string(d))throw new TypeError("Second argument must be a String");if(!s.fn(h))throw new TypeError("Third argument must be a Function");if(s.node(m))return c(m,d,h);if(s.nodeList(m))return u(m,d,h);if(s.string(m))return p(m,d,h);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function c(m,d,h){return m.addEventListener(d,h),{destroy:function(){m.removeEventListener(d,h)}}}function u(m,d,h){return Array.prototype.forEach.call(m,function(v){v.addEventListener(d,h)}),{destroy:function(){Array.prototype.forEach.call(m,function(v){v.removeEventListener(d,h)})}}}function p(m,d,h){return a(document.body,m,d,h)}n.exports=f},817:function(n){function o(i){var s;if(i.nodeName==="SELECT")i.focus(),s=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var a=i.hasAttribute("readonly");a||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),a||i.removeAttribute("readonly"),s=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var f=window.getSelection(),c=document.createRange();c.selectNodeContents(i),f.removeAllRanges(),f.addRange(c),s=f.toString()}return s}n.exports=o},279:function(n){function o(){}o.prototype={on:function(i,s,a){var f=this.e||(this.e={});return(f[i]||(f[i]=[])).push({fn:s,ctx:a}),this},once:function(i,s,a){var f=this;function c(){f.off(i,c),s.apply(a,arguments)}return c._=s,this.on(i,c,a)},emit:function(i){var s=[].slice.call(arguments,1),a=((this.e||(this.e={}))[i]||[]).slice(),f=0,c=a.length;for(f;f{"use strict";/*! - * escape-html - * Copyright(c) 2012-2013 TJ Holowaychuk - * Copyright(c) 2015 Andreas Lubbe - * Copyright(c) 2015 Tiancheng "Timothy" Gu - * MIT Licensed - */var rs=/["'&<>]/;Yo.exports=ns;function ns(e){var t=""+e,r=rs.exec(t);if(!r)return t;var n,o="",i=0,s=0;for(i=r.index;i0&&i[i.length-1])&&(c[0]===6||c[0]===2)){r=0;continue}if(c[0]===3&&(!i||c[1]>i[0]&&c[1]=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function W(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var n=r.call(e),o,i=[],s;try{for(;(t===void 0||t-- >0)&&!(o=n.next()).done;)i.push(o.value)}catch(a){s={error:a}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(s)throw s.error}}return i}function D(e,t,r){if(r||arguments.length===2)for(var n=0,o=t.length,i;n1||a(m,d)})})}function a(m,d){try{f(n[m](d))}catch(h){p(i[0][3],h)}}function f(m){m.value instanceof et?Promise.resolve(m.value.v).then(c,u):p(i[0][2],m)}function c(m){a("next",m)}function u(m){a("throw",m)}function p(m,d){m(d),i.shift(),i.length&&a(i[0][0],i[0][1])}}function pn(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof Ee=="function"?Ee(e):e[Symbol.iterator](),r={},n("next"),n("throw"),n("return"),r[Symbol.asyncIterator]=function(){return this},r);function n(i){r[i]=e[i]&&function(s){return new Promise(function(a,f){s=e[i](s),o(a,f,s.done,s.value)})}}function o(i,s,a,f){Promise.resolve(f).then(function(c){i({value:c,done:a})},s)}}function C(e){return typeof e=="function"}function at(e){var t=function(n){Error.call(n),n.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var It=at(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: -`+r.map(function(n,o){return o+1+") "+n.toString()}).join(` - `):"",this.name="UnsubscriptionError",this.errors=r}});function Ve(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Ie=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,n,o,i;if(!this.closed){this.closed=!0;var s=this._parentage;if(s)if(this._parentage=null,Array.isArray(s))try{for(var a=Ee(s),f=a.next();!f.done;f=a.next()){var c=f.value;c.remove(this)}}catch(v){t={error:v}}finally{try{f&&!f.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}else s.remove(this);var u=this.initialTeardown;if(C(u))try{u()}catch(v){i=v instanceof It?v.errors:[v]}var p=this._finalizers;if(p){this._finalizers=null;try{for(var m=Ee(p),d=m.next();!d.done;d=m.next()){var h=d.value;try{ln(h)}catch(v){i=i!=null?i:[],v instanceof It?i=D(D([],W(i)),W(v.errors)):i.push(v)}}}catch(v){n={error:v}}finally{try{d&&!d.done&&(o=m.return)&&o.call(m)}finally{if(n)throw n.error}}}if(i)throw new It(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)ln(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Ve(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Ve(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Sr=Ie.EMPTY;function jt(e){return e instanceof Ie||e&&"closed"in e&&C(e.remove)&&C(e.add)&&C(e.unsubscribe)}function ln(e){C(e)?e():e.unsubscribe()}var Le={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var st={setTimeout:function(e,t){for(var r=[],n=2;n0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var n=this,o=this,i=o.hasError,s=o.isStopped,a=o.observers;return i||s?Sr:(this.currentObservers=null,a.push(r),new Ie(function(){n.currentObservers=null,Ve(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var n=this,o=n.hasError,i=n.thrownError,s=n.isStopped;o?r.error(i):s&&r.complete()},t.prototype.asObservable=function(){var r=new F;return r.source=this,r},t.create=function(r,n){return new xn(r,n)},t}(F);var xn=function(e){ie(t,e);function t(r,n){var o=e.call(this)||this;return o.destination=r,o.source=n,o}return t.prototype.next=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,r)},t.prototype.error=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,r)},t.prototype.complete=function(){var r,n;(n=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||n===void 0||n.call(r)},t.prototype._subscribe=function(r){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(r))!==null&&o!==void 0?o:Sr},t}(x);var Et={now:function(){return(Et.delegate||Date).now()},delegate:void 0};var wt=function(e){ie(t,e);function t(r,n,o){r===void 0&&(r=1/0),n===void 0&&(n=1/0),o===void 0&&(o=Et);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=n,i._timestampProvider=o,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=n===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,n),i}return t.prototype.next=function(r){var n=this,o=n.isStopped,i=n._buffer,s=n._infiniteTimeWindow,a=n._timestampProvider,f=n._windowTime;o||(i.push(r),!s&&i.push(a.now()+f)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var n=this._innerSubscribe(r),o=this,i=o._infiniteTimeWindow,s=o._buffer,a=s.slice(),f=0;f0?e.prototype.requestAsyncId.call(this,r,n,o):(r.actions.push(this),r._scheduled||(r._scheduled=ut.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,n,o){var i;if(o===void 0&&(o=0),o!=null?o>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,n,o);var s=r.actions;n!=null&&((i=s[s.length-1])===null||i===void 0?void 0:i.id)!==n&&(ut.cancelAnimationFrame(n),r._scheduled=void 0)},t}(Wt);var Sn=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var n=this._scheduled;this._scheduled=void 0;var o=this.actions,i;r=r||o.shift();do if(i=r.execute(r.state,r.delay))break;while((r=o[0])&&r.id===n&&o.shift());if(this._active=!1,i){for(;(r=o[0])&&r.id===n&&o.shift();)r.unsubscribe();throw i}},t}(Dt);var Oe=new Sn(wn);var M=new F(function(e){return e.complete()});function Vt(e){return e&&C(e.schedule)}function Cr(e){return e[e.length-1]}function Ye(e){return C(Cr(e))?e.pop():void 0}function Te(e){return Vt(Cr(e))?e.pop():void 0}function zt(e,t){return typeof Cr(e)=="number"?e.pop():t}var pt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Nt(e){return C(e==null?void 0:e.then)}function qt(e){return C(e[ft])}function Kt(e){return Symbol.asyncIterator&&C(e==null?void 0:e[Symbol.asyncIterator])}function Qt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function zi(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Yt=zi();function Gt(e){return C(e==null?void 0:e[Yt])}function Bt(e){return un(this,arguments,function(){var r,n,o,i;return $t(this,function(s){switch(s.label){case 0:r=e.getReader(),s.label=1;case 1:s.trys.push([1,,9,10]),s.label=2;case 2:return[4,et(r.read())];case 3:return n=s.sent(),o=n.value,i=n.done,i?[4,et(void 0)]:[3,5];case 4:return[2,s.sent()];case 5:return[4,et(o)];case 6:return[4,s.sent()];case 7:return s.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function Jt(e){return C(e==null?void 0:e.getReader)}function U(e){if(e instanceof F)return e;if(e!=null){if(qt(e))return Ni(e);if(pt(e))return qi(e);if(Nt(e))return Ki(e);if(Kt(e))return On(e);if(Gt(e))return Qi(e);if(Jt(e))return Yi(e)}throw Qt(e)}function Ni(e){return new F(function(t){var r=e[ft]();if(C(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function qi(e){return new F(function(t){for(var r=0;r=2;return function(n){return n.pipe(e?A(function(o,i){return e(o,i,n)}):de,ge(1),r?He(t):Dn(function(){return new Zt}))}}function Vn(){for(var e=[],t=0;t=2,!0))}function pe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new x}:t,n=e.resetOnError,o=n===void 0?!0:n,i=e.resetOnComplete,s=i===void 0?!0:i,a=e.resetOnRefCountZero,f=a===void 0?!0:a;return function(c){var u,p,m,d=0,h=!1,v=!1,Y=function(){p==null||p.unsubscribe(),p=void 0},B=function(){Y(),u=m=void 0,h=v=!1},N=function(){var O=u;B(),O==null||O.unsubscribe()};return y(function(O,Qe){d++,!v&&!h&&Y();var De=m=m!=null?m:r();Qe.add(function(){d--,d===0&&!v&&!h&&(p=$r(N,f))}),De.subscribe(Qe),!u&&d>0&&(u=new rt({next:function($e){return De.next($e)},error:function($e){v=!0,Y(),p=$r(B,o,$e),De.error($e)},complete:function(){h=!0,Y(),p=$r(B,s),De.complete()}}),U(O).subscribe(u))})(c)}}function $r(e,t){for(var r=[],n=2;ne.next(document)),e}function K(e,t=document){return Array.from(t.querySelectorAll(e))}function z(e,t=document){let r=ce(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ce(e,t=document){return t.querySelector(e)||void 0}function _e(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}function tr(e){return L(b(document.body,"focusin"),b(document.body,"focusout")).pipe(ke(1),l(()=>{let t=_e();return typeof t!="undefined"?e.contains(t):!1}),V(e===_e()),J())}function Xe(e){return{x:e.offsetLeft,y:e.offsetTop}}function Kn(e){return L(b(window,"load"),b(window,"resize")).pipe(Ce(0,Oe),l(()=>Xe(e)),V(Xe(e)))}function rr(e){return{x:e.scrollLeft,y:e.scrollTop}}function dt(e){return L(b(e,"scroll"),b(window,"resize")).pipe(Ce(0,Oe),l(()=>rr(e)),V(rr(e)))}var Yn=function(){if(typeof Map!="undefined")return Map;function e(t,r){var n=-1;return t.some(function(o,i){return o[0]===r?(n=i,!0):!1}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(r){var n=e(this.__entries__,r),o=this.__entries__[n];return o&&o[1]},t.prototype.set=function(r,n){var o=e(this.__entries__,r);~o?this.__entries__[o][1]=n:this.__entries__.push([r,n])},t.prototype.delete=function(r){var n=this.__entries__,o=e(n,r);~o&&n.splice(o,1)},t.prototype.has=function(r){return!!~e(this.__entries__,r)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(r,n){n===void 0&&(n=null);for(var o=0,i=this.__entries__;o0},e.prototype.connect_=function(){!Wr||this.connected_||(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),va?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){!Wr||!this.connected_||(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(t){var r=t.propertyName,n=r===void 0?"":r,o=ba.some(function(i){return!!~n.indexOf(i)});o&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),Gn=function(e,t){for(var r=0,n=Object.keys(t);r0},e}(),Jn=typeof WeakMap!="undefined"?new WeakMap:new Yn,Xn=function(){function e(t){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var r=ga.getInstance(),n=new La(t,r,this);Jn.set(this,n)}return e}();["observe","unobserve","disconnect"].forEach(function(e){Xn.prototype[e]=function(){var t;return(t=Jn.get(this))[e].apply(t,arguments)}});var Aa=function(){return typeof nr.ResizeObserver!="undefined"?nr.ResizeObserver:Xn}(),Zn=Aa;var eo=new x,Ca=$(()=>k(new Zn(e=>{for(let t of e)eo.next(t)}))).pipe(g(e=>L(ze,k(e)).pipe(R(()=>e.disconnect()))),X(1));function he(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ye(e){return Ca.pipe(S(t=>t.observe(e)),g(t=>eo.pipe(A(({target:r})=>r===e),R(()=>t.unobserve(e)),l(()=>he(e)))),V(he(e)))}function bt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function ar(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}var to=new x,Ra=$(()=>k(new IntersectionObserver(e=>{for(let t of e)to.next(t)},{threshold:0}))).pipe(g(e=>L(ze,k(e)).pipe(R(()=>e.disconnect()))),X(1));function sr(e){return Ra.pipe(S(t=>t.observe(e)),g(t=>to.pipe(A(({target:r})=>r===e),R(()=>t.unobserve(e)),l(({isIntersecting:r})=>r))))}function ro(e,t=16){return dt(e).pipe(l(({y:r})=>{let n=he(e),o=bt(e);return r>=o.height-n.height-t}),J())}var cr={drawer:z("[data-md-toggle=drawer]"),search:z("[data-md-toggle=search]")};function no(e){return cr[e].checked}function Ke(e,t){cr[e].checked!==t&&cr[e].click()}function Ue(e){let t=cr[e];return b(t,"change").pipe(l(()=>t.checked),V(t.checked))}function ka(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Ha(){return L(b(window,"compositionstart").pipe(l(()=>!0)),b(window,"compositionend").pipe(l(()=>!1))).pipe(V(!1))}function oo(){let e=b(window,"keydown").pipe(A(t=>!(t.metaKey||t.ctrlKey)),l(t=>({mode:no("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),A(({mode:t,type:r})=>{if(t==="global"){let n=_e();if(typeof n!="undefined")return!ka(n,r)}return!0}),pe());return Ha().pipe(g(t=>t?M:e))}function le(){return new URL(location.href)}function ot(e){location.href=e.href}function io(){return new x}function ao(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)ao(e,r)}function _(e,t,...r){let n=document.createElement(e);if(t)for(let o of Object.keys(t))typeof t[o]!="undefined"&&(typeof t[o]!="boolean"?n.setAttribute(o,t[o]):n.setAttribute(o,""));for(let o of r)ao(n,o);return n}function fr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function so(){return location.hash.substring(1)}function Dr(e){let t=_("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Pa(e){return L(b(window,"hashchange"),e).pipe(l(so),V(so()),A(t=>t.length>0),X(1))}function co(e){return Pa(e).pipe(l(t=>ce(`[id="${t}"]`)),A(t=>typeof t!="undefined"))}function Vr(e){let t=matchMedia(e);return er(r=>t.addListener(()=>r(t.matches))).pipe(V(t.matches))}function fo(){let e=matchMedia("print");return L(b(window,"beforeprint").pipe(l(()=>!0)),b(window,"afterprint").pipe(l(()=>!1))).pipe(V(e.matches))}function zr(e,t){return e.pipe(g(r=>r?t():M))}function ur(e,t={credentials:"same-origin"}){return ue(fetch(`${e}`,t)).pipe(fe(()=>M),g(r=>r.status!==200?Ot(()=>new Error(r.statusText)):k(r)))}function We(e,t){return ur(e,t).pipe(g(r=>r.json()),X(1))}function uo(e,t){let r=new DOMParser;return ur(e,t).pipe(g(n=>n.text()),l(n=>r.parseFromString(n,"text/xml")),X(1))}function pr(e){let t=_("script",{src:e});return $(()=>(document.head.appendChild(t),L(b(t,"load"),b(t,"error").pipe(g(()=>Ot(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(l(()=>{}),R(()=>document.head.removeChild(t)),ge(1))))}function po(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function lo(){return L(b(window,"scroll",{passive:!0}),b(window,"resize",{passive:!0})).pipe(l(po),V(po()))}function mo(){return{width:innerWidth,height:innerHeight}}function ho(){return b(window,"resize",{passive:!0}).pipe(l(mo),V(mo()))}function bo(){return G([lo(),ho()]).pipe(l(([e,t])=>({offset:e,size:t})),X(1))}function lr(e,{viewport$:t,header$:r}){let n=t.pipe(ee("size")),o=G([n,r]).pipe(l(()=>Xe(e)));return G([r,t,o]).pipe(l(([{height:i},{offset:s,size:a},{x:f,y:c}])=>({offset:{x:s.x-f,y:s.y-c+i},size:a})))}(()=>{function e(n,o){parent.postMessage(n,o||"*")}function t(...n){return n.reduce((o,i)=>o.then(()=>new Promise(s=>{let a=document.createElement("script");a.src=i,a.onload=s,document.body.appendChild(a)})),Promise.resolve())}var r=class extends EventTarget{constructor(n){super(),this.url=n,this.m=i=>{i.source===this.w&&(this.dispatchEvent(new MessageEvent("message",{data:i.data})),this.onmessage&&this.onmessage(i))},this.e=(i,s,a,f,c)=>{if(s===`${this.url}`){let u=new ErrorEvent("error",{message:i,filename:s,lineno:a,colno:f,error:c});this.dispatchEvent(u),this.onerror&&this.onerror(u)}};let o=document.createElement("iframe");o.hidden=!0,document.body.appendChild(this.iframe=o),this.w.document.open(),this.w.document.write(` + + - + diff --git a/site/components/2__mission_planning/mp_overview/index.html b/site/components/2__mission_planning/mp_overview/index.html index 51264b5..889b8e6 100644 --- a/site/components/2__mission_planning/mp_overview/index.html +++ b/site/components/2__mission_planning/mp_overview/index.html @@ -14,8 +14,9 @@ + - + @@ -23,10 +24,10 @@ - + - + @@ -68,8 +69,11 @@ + + + @@ -133,6 +137,7 @@
    @@ -154,33 +159,34 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - + + - + diff --git a/site/components/3__custom_event_generation/ceg_overview/index.html b/site/components/3__custom_event_generation/ceg_overview/index.html index ceb41c7..2d45c9b 100644 --- a/site/components/3__custom_event_generation/ceg_overview/index.html +++ b/site/components/3__custom_event_generation/ceg_overview/index.html @@ -12,8 +12,9 @@ + - + @@ -21,10 +22,10 @@ - + - + @@ -66,8 +67,11 @@ + + + @@ -131,6 +135,7 @@
    @@ -152,33 +157,34 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - + + - + diff --git a/site/components/3__custom_event_generation/sdr_demo/index.html b/site/components/3__custom_event_generation/sdr_demo/index.html index f2c1b17..cdad270 100644 --- a/site/components/3__custom_event_generation/sdr_demo/index.html +++ b/site/components/3__custom_event_generation/sdr_demo/index.html @@ -10,8 +10,9 @@ + - + @@ -19,10 +20,10 @@ - + - + @@ -64,8 +65,11 @@ + + + @@ -129,6 +133,7 @@
    @@ -150,33 +155,34 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + @@ -280,6 +301,7 @@
    + @@ -299,14 +321,18 @@ - -
  • - Overview + + + + Overview + + +
  • @@ -314,14 +340,18 @@ - -
  • - Getting Started + + + + Getting Started + + +
  • @@ -329,79 +359,108 @@ - - -
  • - + + + + + +
  • - - - - - - - - +
  • @@ -517,9 +576,10 @@ Success! Perfect Transmission!
    + + + Back to top + @@ -546,10 +606,11 @@ Success! Perfect Transmission!
    - + + - + diff --git a/site/getting_started/index.html b/site/getting_started/index.html index dda97e2..2dd36ee 100644 --- a/site/getting_started/index.html +++ b/site/getting_started/index.html @@ -14,8 +14,9 @@ + - + @@ -23,10 +24,10 @@ - + - + @@ -68,8 +69,11 @@ + + + @@ -133,6 +137,7 @@
    @@ -154,33 +159,34 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - + + - + diff --git a/site/index.html b/site/index.html index 4259a26..016677c 100644 --- a/site/index.html +++ b/site/index.html @@ -12,8 +12,9 @@ + - + @@ -21,10 +22,10 @@ - + - + @@ -66,8 +67,11 @@ + + + @@ -131,6 +135,7 @@
    @@ -152,33 +157,34 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + @@ -286,6 +307,7 @@
    + @@ -305,8 +327,6 @@ - - @@ -321,12 +341,24 @@ - Overview + + + + Overview + + + @@ -368,14 +400,18 @@ - -
  • - Getting Started + + + + Getting Started + + +
  • @@ -383,79 +419,108 @@ - - -
  • - + + + + + +
  • - - - - - - - - +
  • @@ -503,9 +568,10 @@
    + + + Back to top + @@ -532,10 +598,11 @@
    - + + - + diff --git a/site/search/search_index.json b/site/search/search_index.json index 050dda0..e38e292 100644 --- a/site/search/search_index.json +++ b/site/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Overview","text":"

    Open-source modular toolkit for simulating high-fidelity pulsar X-ray events.

    "},{"location":"#introduction-to-openxnav","title":"Introduction to OpenXNAV","text":"

    OpenXNAV is designed to aid development and testing of Pulsar-based Autonomous Navigation (XNAV) Positioning, Navigation, and Timing (PNT) solutions.

    You can read our IEEE paper to learn more: IEEE.org.

    "},{"location":"#components","title":"Components","text":"
    • Pulsar Querying
    • Mission Planning
    • Timing & Event Generation
    "},{"location":"getting_started/","title":"Getting Started","text":"

    Each component of OpenXNAV can be used individually, or strung together as an end-to-end pipeline. To get started with OpenXNAV, select the module you are interested in leveraging and access the documentation.

    "},{"location":"getting_started/#pulsar-querying","title":"Pulsar Querying","text":"

    Query for all known pulsars catalogued in the ATNF database by providing a coordinate in space, and a search radius.

    "},{"location":"getting_started/#mission-planning","title":"Mission Planning","text":"

    Model the desired flight path, taking into account spacecraft orientation, viewing angle and line of sight.

    "},{"location":"getting_started/#timing-event-generation","title":"Timing & Event Generation","text":"

    Generate representative photon arrival events at the location of interest along the user-defined trajectory.

    "},{"location":"components/1__pulsar_querying/pq_overview/","title":"Pulsar Querying","text":""},{"location":"components/1__pulsar_querying/pq_overview/#installation","title":"Installation","text":"

    Before using the OpenXNAV Pulsar Querying Tool, you will need to install the necessary python packages. You can do this using your preferred python package manager, but instructions are provided below for using Anaconda

    Inside the open-xnav/1__pulsar_querying/ directory, there is an environment.yml file. This file can be passed to your preferred package manager to create a new environment that can run the tool.

    "},{"location":"components/1__pulsar_querying/pq_overview/#create-new-environment","title":"Create New Environment","text":"

    The default environment name in environment.yml is openXNAV-gui. If you wish to change the environment name, simply edit environment.yml before creating the environment.

    Open your Anaconda Prompt (or activate Anaconda in a terminal window). Navigate to open-xnav/`1__pulsar_querying/ and run the following command:

    conda env create -f environment.yaml\n

    To activate your environment, run the following command:

    conda activate openXNAV-gui\n
    NOTE: If you altered the environment name, you will need to alter the above command to reflect that new name.

    "},{"location":"components/1__pulsar_querying/pq_overview/#install-kivymd","title":"Install KivyMD","text":"

    The tool also depends on KivyMD, which is a library built off of the popular Kivy library. This package is not available through conda, so you must install it using pip.

    First, make sure you have activated the openXNAV-gui environment in your terminal. Then, run the following command:

    pip install kivymd\n

    If you are getting a ReadTimeoutError response during installation, you might be using a VPN or have a slower internet connection. If this happens, try running the following instead:

    pip install --default-timeout=1000 kivymd\n

    If that still does not work, you can troubleshoot your issues further using the pip documentation here.

    "},{"location":"components/1__pulsar_querying/pq_overview/#using-the-tool","title":"Using The Tool","text":""},{"location":"components/1__pulsar_querying/pq_overview/#loadgenerate-database","title":"Load/Generate Database","text":"

    Once you have successfully installed all the required packages, you are ready to run the tool!

    First, ensure you have navigated to open-xnav/1__pulsar_querying/ in your terminal and have your openXNAV-gui environment activated.

    Then, simply run the following in your terminal:

    python run.py\n

    Upon startup, the tool will need to pull the current ATNF Pulsar Catalogue from the web. This process only need to be done the first time you open the application.

    However, if you wish to update the database, simply delete the .../pulsar_database/ directory from your file system. Then, relaunch the application. Once the database has been generated, you can continue begin querying.

    You should see the OpenXNAV launch window with the blue Launch Application button active. In the future, when you open the application, the tool will locate the previously-generated database and you can quickly continue to the querying functionality.

    "},{"location":"components/1__pulsar_querying/pq_overview/#query-for-pulsars","title":"Query For Pulsars","text":"

    After you click Launch Application, the query tool will display.

    There are three fields that you need to provide to execute a query:

    • Right Ascension (HH:MM:SS)
    • Declination (DD:MM:SS)
    • Search Radius (Degrees)

    These values will create a query, searching for all known pulsars that are within a given search radius of the provided coordinates in space.

    The OpenXNAV tool leverages the open-source psrqpy library. More information about this package, and how queries are executed, can be found here.

    The query results will display to the GUI interface, and will also be stored in a sub-directory within .../query_results/.

    For information about how these sub-directories are tagged, see below.

    "},{"location":"components/1__pulsar_querying/pq_overview/#tagging-results","title":"Tagging Results","text":"

    There is an optional Tag field that OpenXNAV also provides. This allows you to specify the tag for this query you are about to execute. If a tag is provided, that will be used to name the sub-directory within .../query_results/ where all pulsars returned by the query are stored.

    Sample Queries

    Below are couple sample queries that you can run to get familiar with the OpenXNAV tool. There are additional sample query results contained in the .../query_results/ directory.

    Query Right Ascension Declination Radius Parker Solar Probe 9.805475733988583 12.005839937612905 15.0 L2 18:24:32.00819 -24:52:10.720 30.0"},{"location":"components/1__pulsar_querying/pq_overview/#output-files","title":"Output Files","text":""},{"location":"components/1__pulsar_querying/pq_overview/#stk-integration","title":"STK Integration","text":"

    Right now, the OpenXNAV Pulsar Querying Tool only outputs pulsar data into the .st format. This is the format that is required by STK to perform subsequent mission planning.

    To display the format of this file, here is J00012_5431.st as an example:

    stk.v.12.0\nWrittenBy    OpenXNAV\n\nBEGIN Star\n\n    Name         J0012_5431\n\n    BEGIN PathDescription\n\n        Epoch         58912.0\n        RefFrame         J2000\n        RightAscension        3.097083333333333\n        Declination       +54:31:47\n        ProperMotionRAPerYr      0\n        ProperMotionDecPerYr         0\n        Parallax          0\n        RadialVelocity        0.0000000000000000e+00\n\n    END PathDescription\n\n    BEGIN PhysicalData\n\n        Magnitude         None\n\n    END PhysicalData\n\n    BEGIN IdentityData\n\n        Id       0\n\n    END IdentityData\n\n    BEGIN Extensions\n\n        BEGIN ExternData\n        END ExternData\n\n        BEGIN ADFFileData\n        END ADFFileData\n\n        BEGIN AccessConstraints\n            LineOfSight IncludeIntervals\n\n            UsePreferredMaxStep No\n            PreferredMaxStep 360\n        END AccessConstraints\n\n        BEGIN Desc\n        END Desc\n\n        BEGIN Crdn\n        END Crdn\n\n        BEGIN Graphics\n\n            BEGIN Attributes\n\n                MarkerColor      #00ff00\n                LabelColor       #00ff00\n                MarkerStyle      2\n                FontStyle        0\n\n            END Attributes\n\n            BEGIN Graphics\n\n                Show         On\n                Inherit      On\n                ShowLabel        On\n                ShowMarker       On\n\n            END Graphics\n        END Graphics\n\n        BEGIN VO\n        END VO\n\n    END Extensions\n\nEND Star\n

    You will need to provide these .st file(s) to STK to successfully execute OpenXNAV's mission planning functionality.

    "},{"location":"components/1__pulsar_querying/pq_overview/#other-file-formats","title":"Other File Formats","text":"

    However, if you would like pulsar information to be stored/saved in a different format, you can modify the source code.

    Navigate to queryPulsar.py and locate the following function:

    def saveToFile(self, root_directory) ...\n
    Here, you can alter/update the code to print the pulsar information into your desired format. Once this function has been updated, query results will automatically store in this new format. All query results will still appear in .../query_results/.

    "},{"location":"components/2__mission_planning/mp_overview/","title":"Mission Planning","text":"

    In this Python notebook, the mission_planning module from the OpenXNAV library is demonstrated.

    We start by importing the necessary libraries:

    from astropy import units as u\nfrom astropy.coordinates import SkyCoord,get_body\nfrom astropy.time import Time,TimeDelta\nfrom astropy.table import Table,QTable\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pandas as pd\n

    Next we define the necessary variables that we will use to instantiate the orbit. We will define an elliptical orbit directly by its orbital elements in this example. Other options, which are currently commented out, are a circular orbit (special case of elliptical orbit where eccentricity = 0) and an elliptical orbit defined by its burnout trajectory.

    # User definitions for elliptical orbital elements\ne = 0.3           # eccentricity of the orbit\na = 750000*u.m    # semi-major axis \ninc = 20*u.deg    # inclination of orbit\nw = 90*u.deg      # argument of periapsis\nv_0 = 0*u.deg     # initial eccentric anomaly\nOmega = 90*u.deg  # longitude of ascending node\nimport warnings\nwarnings.filterwarnings('ignore',message='leap-second file is expired')\nt = Time.now() + TimeDelta(120*u.day) + TimeDelta(np.linspace(0,800,51)*u.s)\n# Alternative: User definitions for elliptical orbital insertion \n# (note that this is just an example and would not generate the \n# same trajectory as the one above defined directly by orbital elements)\n#e = 0.1          # eccentricity of the orbit, also user defined\n#a = 750000*u.m   # m semi-major axis \n#B = 70*u.deg     # azimuth heading measured in degrees clockwise from north\n#dec = 20*u.deg   # geocentric latitude in degrees (declination) of burnout\n#v_0 = 0*u.deg    # initial eccentric anomaly\n

    We can now do the same thing with a low-fidelity elliptical orbit, starting with the EllipticalOrbit class:

    from mission_planning import EllipticalOrbit\neo = EllipticalOrbit(t,a,e,v_0=v_0,\ninc=inc,w=w,\nOmega=Omega)\nplt.figure()\nplt.plot(eo.x.to(u.km),eo.y.to(u.km),'b.')\n#plt.xlim([-a/u.km,a/u.km])\n#plt.ylim([-a/u.km,a/u.km])\nplt.show()\n

    While the above plot is represented in two dimensions as the projection of the orbit onto the XY-plane, this orbit was actually instantiated in 3D. To show the trajectory in the 3D Cartesian reference frame with the center of Earth at the origin, we just have to plot it in the 3D figure:

    fig = plt.figure()\nax = fig.add_subplot(projection='3d')\nax.scatter(eo.x.to(u.km),eo.y.to(u.km),eo.z.to(u.km))\nplt.show()\n

    "},{"location":"components/2__mission_planning/mp_overview/#creating-vectors-from-pulsar-to-space-objects-to-look-for-access","title":"Creating vectors from pulsar to space objects to look for access","text":"

    In order to better demonstrate the pulsar access calculation functions in the OpenXNAV mission_planning module, we will create a SkyCoord object representing the moon, but with a distorted size and orbit to ensure some obfuscation of a chosen pulsar (whose coordinates are also exaggerated for demonstration purposes).

    from mission_planning import plot_accesses\nmoon = SkyCoord(\nx = -284405*u.m,\ny = 249415*u.m,\nz = 0*u.m,\nframe='gcrs',\nrepresentation_type = 'cartesian'\n)\n#moon_rad = 1740*u.km # actual radius of the moon \nmoon_rad = 150*u.km # fake news \n# assuming we have the location of the pulsars, using one as an example\npulsar = SkyCoord(\nx = -853215*u.m,\ny = 748245*u.m,\nz = 0*u.km,\nframe='gcrs',\nrepresentation_type = 'cartesian'\n)\naccess = eo.pulsar_access(pulsar,moon,moon_rad)\n# create figure to plot pulsar access\nfig = plt.figure()\nax = fig.add_subplot(projection='3d')\nax.scatter(pulsar.x.to(u.km),pulsar.y.to(u.km),pulsar.z.to(u.km),label='pulsar')\nax.scatter(eo.x.to(u.km),eo.y.to(u.km),eo.z.to(u.km),label='spacecraft')\nax.scatter(moon.x.to(u.km),moon.y.to(u.km),moon.z.to(u.km),label='moon',s=500)\nplt.legend()\nplt.show()\nfig = plt.figure()\nax = fig.add_subplot()\nax = plot_accesses(ax,t,{'pulsar':access})\n

    We can also instantiate an EllipticalOrbit object with high fidelity. This version of the class calculates the eccentric anomaly at each time in the time array in order to calculate a more exact position.

    There is currently a bug in this version that causes it to only output positive x and positive z values, so we'll need to fix that. (Negative values shown below are there because x and z are positive before coordinate rotation to account for longitude of ascending node, orbital inclination, and argument of periapsis)

    eo_h = EllipticalOrbit(t,a,e,v_0=v_0,\ninc=inc,w=w,\nOmega=Omega,\nhifi=True)\nplt.figure()\nplt.plot(eo_h.x,eo_h.y,'b.')\nplt.xlim([-a/u.m,a/u.m])\nplt.ylim([-a/u.m,a/u.m])\nplt.show()\nfig = plt.figure()\nax = fig.add_subplot(projection='3d')\nax.scatter(eo_h.x,eo_h.y,eo_h.z)\nplt.show()\n

    "},{"location":"components/2__mission_planning/mp_overview/#using-the-actual-position-of-known-celestial-bodies","title":"Using the actual position of known celestial bodies","text":""},{"location":"components/2__mission_planning/mp_overview/#example-1-circular-orbit","title":"Example 1 - Circular Orbit","text":"

    Next we will take advantage of the get_body and pulsar_access_export functionalities of Astropy and OpenXNAV Mission Planning, respectively.

    Astropy allows us to create a SkyCoord object using the actual location of the moon at any time or array of times. We will make our moon much bigger than in real life to ensure that we obfuscate some pulsars for demonstration purposes. We will define a new orbit circular orbit using the CircularOrbit class, which is a special case of the EllipticalOrbit class in which eccentricity and orbital inclination are zero.

    from mission_planning import CircularOrbit\n# User definitions for circular orbit\nr = 360000*u.km\nt0 = Time('2023-08-24 12:12:15.932083')\nt = t0 + TimeDelta(np.linspace(0,25,100)*u.day)\nmoon = get_body('moon',t)\nmoon.representation_type='cartesian'\nMOON_RAD = 1740*u.km\nearth = get_body('earth',t)\nearth.representation_type = 'cartesian'\nEARTH_RAD = 6378.14*u.km\nco = CircularOrbit(t,r)\n

    Next we will create an astropy.table.Table object with some pulsars that we want to load in to our pulsar access export function. The table is shown and created here for demonstration purposes; however, tables with this format can be created in the OpenXNAV pulsar query module.

    name = [    'J0002+6216' , 'J0006+1834' , 'J0007+7303' , 'J0011+08' , 'J0012+5431']\nraJ_deg = [   0.74238    ,   1.52       ,  1.7571      ,  2.9       ,   3.0971     ] * u.deg\ndecJ_deg = [ 62.26928    ,  18.5831     ,  1.7571      ,  8.17      ,  54.5297     ] * u.deg\ndist_kpc = [  6.357      ,   0.86       ,  1.4         ,  5.399     ,   5.425      ] * u.kpc\nt = Table([name,raJ_deg,decJ_deg,dist_kpc],\nnames = ['NAME','RAJD','DECJD','DIST'])\nt.write('some_pulsars.fits',overwrite=True)\nprint(t)\n
       NAME      RAJD   DECJD    DIST\n             deg     deg     kpc \n---------- ------- -------- -----\nJ0002+6216 0.74238 62.26928 6.357\nJ0006+1834    1.52  18.5831  0.86\nJ0007+7303  1.7571   1.7571   1.4\n  J0011+08     2.9     8.17 5.399\nJ0012+5431  3.0971  54.5297 5.425\n
    "},{"location":"components/2__mission_planning/mp_overview/#using-the-pulsar_access_export-method","title":"Using the pulsar_access_export method","text":"

    Now that we have our spacecraft, moon, and pulsar table, we can use the pulsar_access_export method to create a table and plot of pulsar accesses. Both this method and the pulsar_access function allow you to account for obfuscation from multiple celestial bodies; just make sure to define them as shown below, entered before the keyword arguments and alternating between the SkyCoord object representing the celestial body and the radius of the body represented as an astropy.units.Quantity object.

    pulsars_qtbl = QTable.read('some_pulsars.fits')\n# 3D plot of satellite orbit and moon\nfig1 = plt.figure()\nax1 = fig1.add_subplot(projection='3d')\nax1.scatter(moon.x.to(u.km),moon.y.to(u.km),moon.z.to(u.km),label='moon',s=100)\nax1.scatter(co.x.to(u.km),co.y.to(u.km),co.z.to(u.km),label='satellite in cirular orbit')\nax1.scatter(earth.x.to(u.km),earth.y.to(u.km),earth.z.to(u.km),label='earth',s=500)\nplt.legend(loc='upper left')\n# Plot of pulsar accesses\n_,(fig2,ax2) = co.pulsar_access_export(pulsars_qtbl,\nmoon,MOON_RAD,\nearth,EARTH_RAD,\nmake_csv=False,\nmake_fig=True,save_fig=False)\n

    "},{"location":"components/2__mission_planning/mp_overview/#example-2-elliptical-orbit","title":"Example 2 - Elliptical Orbit","text":"

    Next we will define a new elliptical orbit from the EllipticalOrbit class in which eccentricity and orbital inclination are non-zero.

    # User definitions for elliptical orbital elements\ne = 0.3           # eccentricity of the orbit\na = 30000*u.km    # semi-major axis \ninc = 20*u.deg    # inclination of orbit\nw = 90*u.deg      # argument of periapsis\nv_0 = 0*u.deg     # initial eccentric anomaly\nOmega = 90*u.deg  # longitude of ascending node\nt0 = Time('2023-08-24 12:12:15.932')\nt = t0 + TimeDelta(np.linspace(0,25,1000)*u.day)\nmoon = get_body('moon',t)\nmoon.representation_type='cartesian'\nMOON_RAD = 1740*u.km\nearth = SkyCoord(x=0*u.m,y=0*u.m,z=0*u.m,frame='gcrs',representation_type='cartesian')\nEARTH_RAD = 6378.14*u.km\neo2 = EllipticalOrbit(t,a,e,v_0=v_0,\ninc=inc,w=w,\nOmega=Omega)\nfig = plt.figure()\nax = fig.add_subplot(projection='3d')\nax.scatter(eo2.x.to(u.km),eo2.y.to(u.km),eo2.z.to(u.km))\nplt.show()\n

    Next we will create a CSV with some pulsars that we want to load in to our pulsar access export function. The CSV is shown and created here for demonstration purposes:

    name = [    'J0002+6216' , 'J0006+1834' , 'J0007+7303' , 'J0011+08' , 'J0012+5431']\nraJ_deg = [   0.74238    ,   1.52       ,  1.7571      ,  2.9       ,   3.0971     ] * u.deg\ndecJ_deg = [ 62.26928    ,  18.5831     ,  1.7571      ,  8.17      ,  54.5297     ] * u.deg\ndist_kpc = [  6.357      ,   0.86       ,  1.4         ,  5.399     ,   5.425      ] * u.kpc\ntbl = Table([name,raJ_deg,decJ_deg,dist_kpc],\nnames = ['NAME','RAJD','DECJD','DIST'])\ntbl.write('some_pulsars.fits',overwrite=True)\nprint(tbl)\n
       NAME      RAJD   DECJD    DIST\n             deg     deg     kpc \n---------- ------- -------- -----\nJ0002+6216 0.74238 62.26928 6.357\nJ0006+1834    1.52  18.5831  0.86\nJ0007+7303  1.7571   1.7571   1.4\n  J0011+08     2.9     8.17 5.399\nJ0012+5431  3.0971  54.5297 5.425\n
    "},{"location":"components/2__mission_planning/mp_overview/#using-the-pulsar_access_export-method_1","title":"Using the pulsar_access_export method","text":"

    Now that we have our spacecraft, moon, and pulsar CSV, we can use the pulsar_access_export method to create a table and plot of pulsar accesses. Both this method and the pulsar_access function allow you to account for obfuscation from multiple celestial bodies; just make sure to define them as shown below, entered before the keyword arguments and alternating between the SkyCoord object representing the celestial body and the radius of the body represented as an astropy.units.Quantity object.

    As part of the pulsar_access_export method call, we can write all pulsar access data to a CSV file. This CSV can then be used in the pulsar photon time-of-arrival simulation module to model the X-ray pulse sequence that the spacecraft would observe at those coordinates.

    pulsars_qtbl = QTable.read('some_pulsars.fits')\n# 3D plot of satellite orbit\nfig1 = plt.figure()\nax1 = fig1.add_subplot(projection='3d')\nax1.scatter(eo2.x.to(u.km),eo2.y.to(u.km),eo2.z.to(u.km),label='satellite in elliptical orbit')\nax1.scatter(earth.x.to(u.km),earth.y.to(u.km),earth.z.to(u.km),label='earth',s=200)\nplt.legend(loc='upper left')\n# 3D plot of satellite orbit and moon\nfig2 = plt.figure()\nax2 = fig2.add_subplot(projection='3d')\nax2.scatter(moon.x.to(u.km),moon.y.to(u.km),moon.z.to(u.km),label='moon',s=100)\nax2.scatter(eo2.x.to(u.km),eo2.y.to(u.km),eo2.z.to(u.km),label='satellite in elliptical orbit')\nax2.scatter(earth.x.to(u.km),earth.y.to(u.km),earth.z.to(u.km),label='earth',s=200)\nplt.legend(loc='upper left')\n# Plot of pulsar accesses, and save pulsar access table to CSV\naccesses,(fig3,ax3) = eo2.pulsar_access_export(pulsars_qtbl,\nmoon,MOON_RAD,\nearth,EARTH_RAD,\nmake_csv=True,save_csv=True,\nmake_fig=True,save_fig=False)\n

    The breaks in the plot above might be hard to see since they are so small compared to the scale of the timeline displayed. We have therefore represented the breaks in tabular form below.

    # Create DataFrame containing all times at which access to at least one pulsar is interrupted\naccess_breaks = accesses[accesses.all(axis=1) == False]\naccess_breaks\n
    Time_JDate Spacecraft_pos_X_km Spacecraft_pos_Y_km Spacecraft_pos_Z_km Spacecraft_vel_X_kmps Spacecraft_vel_Y_kmps Spacecraft_vel_Z_kmps J0002+6216 J0006+1834 J0007+7303 J0011+08 J0012+5431 0 2.460181e+06 -19733.545037 2.343791e-12 4.132736e-13 4.667259 0.000000 0.000000 True False False False True 24 2.460182e+06 -19722.356542 -8.518943e+02 -1.662908e+01 4.663209 0.190622 0.065196 True False False False True 48 2.460182e+06 -19688.801001 -1.703092e+03 -3.324457e+01 4.651077 0.380744 0.130222 True False False False True 72 2.460183e+06 -19632.908273 -2.552897e+03 -4.983288e+01 4.630912 0.569870 0.194907 True True False False True 96 2.460183e+06 -19554.728216 -3.400614e+03 -6.638041e+01 4.602798 0.757509 0.259083 True True False False True 120 2.460184e+06 -19454.330828 -4.245547e+03 -8.287361e+01 4.566851 0.943180 0.322587 True True False False True 143 2.460185e+06 -19264.410077 5.493859e+03 1.072408e+02 4.499325 -1.214310 -0.415318 True True False True True 144 2.460185e+06 -19331.806438 -5.087002e+03 -9.929892e+01 4.523216 1.126412 0.385256 True True False False True 167 2.460185e+06 -19397.632920 4.654341e+03 9.085332e+01 4.546627 -1.032427 -0.353111 True True False False True 168 2.460185e+06 -19187.265950 -5.924286e+03 -1.156428e+02 4.472073 1.306749 0.446935 True True False False True 191 2.460186e+06 -19508.779991 3.811009e+03 7.439137e+01 4.586325 -0.847881 -0.289993 True True False False True 192 2.460186e+06 -19020.841125 -6.756708e+03 -1.318918e+02 4.413626 1.483752 0.507473 True True False False True 215 2.460186e+06 -19597.751010 2.964556e+03 5.786850e+01 4.618256 -0.661138 -0.226122 True True False False True 239 2.460187e+06 -19664.466140 2.115677e+03 4.129829e+01 4.642291 -0.472672 -0.161663 True True False False True 263 2.460188e+06 -19708.865772 1.265068e+03 2.469429e+01 4.658329 -0.282972 -0.096782 True True False False True 287 2.460188e+06 -19730.910356 4.134251e+02 8.070109e+00 4.666305 -0.092530 -0.031647 True False False False True 311 2.460189e+06 -19730.580291 -4.385562e+02 -8.560672e+00 4.666185 0.098154 0.033571 True False False False True 333 2.460189e+06 -13839.201092 1.850473e+04 3.612147e+02 2.807521 -3.552673 -1.215086 True True False True True 334 2.460189e+06 -18399.018428 9.194010e+03 1.794682e+02 4.199348 -1.985878 -0.679210 True True False True True 335 2.460189e+06 -19707.875871 -1.290179e+03 -2.518445e+01 4.657971 0.288581 0.098700 True False False False True 359 2.460190e+06 -19662.817284 -2.140747e+03 -4.178765e+01 4.641696 0.478252 0.163572 True True False False True 383 2.460191e+06 -19595.444668 -2.989564e+03 -5.835666e+01 4.617427 0.666673 0.228016 True True False False True 407 2.460191e+06 -19505.818229 -3.835935e+03 -7.487792e+01 4.585264 0.853359 0.291866 True True False False True 431 2.460192e+06 -19394.018402 -4.679164e+03 -9.133787e+01 4.545339 1.037832 0.354960 True True False False True 454 2.460192e+06 -19335.736565 5.062236e+03 9.881549e+01 4.524612 -1.121046 -0.383420 True True False True True 455 2.460192e+06 -19260.146075 -5.518559e+03 -1.077230e+02 4.497816 1.219630 0.417138 True True False False True 478 2.460193e+06 -19457.609710 4.220669e+03 8.238798e+01 4.568022 -0.937736 -0.320724 True True False False True 479 2.460193e+06 -19104.322848 -6.353426e+03 -1.240197e+02 4.442885 1.398305 0.478248 True True False False True 502 2.460194e+06 -19557.352895 3.375643e+03 6.589298e+01 4.603740 -0.752000 -0.257199 True True False False True 526 2.460194e+06 -19634.876395 2.527855e+03 4.934405e+01 4.631621 -0.564310 -0.193005 True True False False True 550 2.460195e+06 -19690.110807 1.677999e+03 3.275475e+01 4.651550 -0.375147 -0.128308 True True False False True 574 2.460195e+06 -19723.006865 8.267705e+02 1.613866e+01 4.663444 -0.185003 -0.063275 True True False False True 598 2.460196e+06 -19733.535299 -2.513369e+01 -4.906128e-01 4.667255 0.005626 0.001924 True False False False True 622 2.460197e+06 -19721.686753 -8.770174e+02 -1.711949e+01 4.662967 0.196240 0.067118 True False False False True 646 2.460197e+06 -19687.471756 -1.728184e+03 -3.373437e+01 4.650597 0.386340 0.132136 True False False False True 670 2.460198e+06 -19630.920755 -2.577938e+03 -5.032167e+01 4.630196 0.575429 0.196808 True True False False True 694 2.460198e+06 -19552.084202 -3.425582e+03 -6.686780e+01 4.601849 0.763017 0.260967 True True False False True 718 2.460199e+06 -19451.032689 -4.270423e+03 -8.335919e+01 4.565673 0.948623 0.324448 True True False False True 741 2.460200e+06 -19268.654973 5.469155e+03 1.067586e+02 4.500827 -1.208987 -0.413498 True True False True True 742 2.460200e+06 -19327.857151 -5.111765e+03 -9.978229e+01 4.521814 1.131776 0.387090 True True False False True 765 2.460200e+06 -19401.228226 4.629514e+03 9.036870e+01 4.547908 -1.027019 -0.351261 True True False False True 766 2.460200e+06 -19182.669102 -5.948915e+03 -1.161236e+02 4.470452 1.312021 0.448737 True True False False True 789 2.460201e+06 -19511.722453 3.786080e+03 7.390476e+01 4.587378 -0.842402 -0.288118 True True False False True 790 2.460201e+06 -19015.600922 -6.781183e+03 -1.323695e+02 4.411793 1.488919 0.509240 True True False False True 813 2.460201e+06 -19600.037983 2.939546e+03 5.738031e+01 4.619079 -0.655600 -0.224229 True True False False True 837 2.460202e+06 -19666.095577 2.090606e+03 4.080890e+01 4.642879 -0.467091 -0.159755 True True False False True 861 2.460203e+06 -19709.836218 1.239957e+03 2.420411e+01 4.658680 -0.277362 -0.094863 True True False False True 885 2.460203e+06 -19731.220949 3.882936e+02 7.579540e+00 4.666417 -0.086906 -0.029724 True False False False True 909 2.460204e+06 -19730.230755 -4.636870e+02 -9.051228e+00 4.666059 0.103778 0.035494 True False False False True 933 2.460204e+06 -19706.866516 -1.315289e+03 -2.567460e+01 4.657606 0.294189 0.100619 True False False False True 957 2.460205e+06 -19661.149008 -2.165815e+03 -4.227698e+01 4.641094 0.483830 0.165480 True True False False True 981 2.460206e+06 -19593.118960 -3.014570e+03 -5.884478e+01 4.616590 0.672208 0.229909 True True False False True"},{"location":"components/2__mission_planning/mp_overview/#substituting-stk-for-openxnav-mission-planning","title":"Substituting STK for OpenXNAV Mission Planning","text":"

    As an alternative to the mission_planning module built into OpenXNAV, users can also plan their missions and generate trajectory and pulsar access inputs using the mission planning software of their choice, such as ANSYS STK. STK is very visual, and a great option if you\u2019re starting your mission plan from scratch and want a lot of flexibility in designing your spacecraft trajectory.

    STK users who choose this route should follow the following steps:

    1. Create a new scenario in STK, including the time over which you are interested in analyzing.
    2. Export the .st files from the OpenXNAV Pulsar Query module and then open them within your new scenario as star objects:

    1. Add in a new satellite object and customize the trajectory to your desired level of complexity:

    1. Create planets for any celestial bodies you would like to be included as obstacles in viewing pulsars (ex: Moon):

    1. Within your satellite object, create a special constraint (i.e. object exclusions) and select your obstacle planets:

    1. Go to Analysis, create accesses between the satellite and the imported pulsar over your scenario window:

    1. Export the access windows as an image and the satellite trajectory in ECEF text file with position and velocity:

    "},{"location":"components/3__custom_event_generation/ceg_overview/","title":"Timing & Event Generation","text":""},{"location":"components/3__custom_event_generation/ceg_overview/#generating-events","title":"Generating Events","text":"

    In this Python notebook, the event_generation module from the PLANTS library is demonstrated.

    We start by importing the necessary libraries:

    %load_ext autoreload\n%autoreload 2\nfrom pint_backend import *\nimport pulsar_definitions\npint.logging.setup(level=\"INFO\")\n

    Loads the ephemerides kernel

    pint.solar_system_ephemerides.load_kernel(\"de440\")\n
    \u001b[1mINFO    \u001b[0m (pint.solar_system_ephemerides ): \u001b[1mSet solar system ephemeris to de440 through astropy\u001b[0m\n

    Creates the time vector that the user hopes to observe at and adds additional error if desired. Specifies what pulsar model to use

    time_interval = astrotime.Time( ['2022-07-11T16:00:01.000', '2022-07-11T16:21:01.000'], format='isot', scale='utc')\nobs_fs = 100e6\nn_toa = 10\nerror = 5 * u.us\napply_error = False\nmodel_name = \"j0218\" \n

    Loads in the navigation data provided by STK and generates a spacecraft object off of that navigation data. Note that spacecraft is a custom class created in the PINT backend

    time, pos, vel = load_nav_data(\"XNAVSAT_TEMEofDate_Position_Velocity_JD.txt\")\nmy_spacecraft = SpaceCraft(\"my_spacecraft\", time, pos, vel, overwrite = True)\n

    Generates the times of arrival at the barycenter compared to the spacecraft. Note that printing the time of arrival generated is slightly different at the two locations

    if(model_name == \"j0218\"):  \npulsar_of_interest = PulsarObj(pulsar_definitions.J0218)\nelif(model_name == \"b1821\"):\npulsar_of_interest = PulsarObj(pulsar_definitions.B1821)\ntoas_barycenter = pint.simulation.make_fake_toas_uniform(\ntime_interval[0].mjd, time_interval[1].mjd, n_toa, model=pulsar_of_interest.model, freq = 1e15*u.Hz, obs='barycenter',  error=error)\ntoas_spacecraft = pint.simulation.make_fake_toas_uniform(\ntime_interval[0].mjd, time_interval[1].mjd, n_toa, model=pulsar_of_interest.model, freq = 1e15*u.Hz, obs = \"my_spacecraft\",  error=error)\nprint(\"Barycenter first TOA: \" + str(toas_barycenter.get_mjds(\"True\")[0].utc.iso))\nprint(\"Spacecraft first TOA: \" + str(toas_spacecraft.get_mjds(\"True\")[0].utc.iso))\n
    \u001b[33m\u001b[1mWARNING \u001b[0m (pint.logging                  ): \u001b[33m\u001b[1m/opt/anaconda/lib/python3.10/site-packages/pint/models/timing_model.py:373 UserWarning: PINT only supports 'T2CMETHOD IAU2000B'\u001b[0m\n\u001b[33m\u001b[1mWARNING \u001b[0m (pint.logging                  ): \u001b[33m\u001b[1m/opt/anaconda/lib/python3.10/site-packages/pint/models/model_builder.py:139 UserWarning: Unrecognized parfile line 'EPHVER 2'\u001b[0m\n\u001b[1mINFO    \u001b[0m (pint.simulation               ): \u001b[1mUsing CLOCK = TT(TAI), so setting include_bipm = False\u001b[0m\n\u001b[1mINFO    \u001b[0m (pint.models.absolute_phase    ): \u001b[1mThe TZRSITE is set at the solar system barycenter.\u001b[0m\n\u001b[1mINFO    \u001b[0m (pint.models.absolute_phase    ): \u001b[1mTZRFRQ was 0.0 or None. Setting to infinite frequency.\u001b[0m\n\u001b[1mINFO    \u001b[0m (pint.simulation               ): \u001b[1mUsing CLOCK = TT(TAI), so setting include_bipm = False\u001b[0m\n\n\nBarycenter first TOA: 2022-07-11 15:58:51.816031354\nSpacecraft first TOA: 2022-07-11 15:58:51.815489874\n
    %matplotlib inline\nresolution_factor = 1\npulsar_of_interest.lightcurve.plot_lightcurve()\ntime_vec, photon_vec, probability_arr = pulsar_of_interest.lightcurve.create_toa_vec(0, 10, k=4,resolution_factor= resolution_factor)\n

    %matplotlib inline\nplt.plot(time_vec[0:10000], photon_vec[0:10000])\nplt.xlabel(\"Time (s)\")\nplt.ylabel(\"Number of photons received\")\nplt.title(\"Photon vector over 25 ms\")\n
    Text(0.5, 1.0, 'Photon vector over 25 ms')\n

    snip = time_vec\nindices = np.argwhere(photon_vec != 0).flatten()\nplt.hist(snip[indices], bins = 500)\nplt.title(\"Histogram of photons received with bin resolution = 60 ms\")\nplt.xlabel(\"Time (s)\")\nplt.ylabel(\"Number of photons received\")\n
    Text(0, 0.5, 'Number of photons received')\n

    %matplotlib inline\nbarycenter_toas =  create_obs_time_vec(toas_barycenter.first_MJD, time_vec)\npulse_fold_barycenter = LightProfile.pulse_folding(barycenter_toas, photon_vec, pulsar_of_interest.lightcurve, mjd = True, start_offset = toas_barycenter.first_MJD, resolution_factor = resolution_factor)\nplt.plot(pulsar_of_interest.lightcurve.phase_list, pulse_fold_barycenter)\nplt.xlabel(\"Phase\")\nplt.ylabel(\"Count\")\nspacecraft_toas = create_obs_time_vec(toas_spacecraft.first_MJD, time_vec)\npulse_fold_spacecraft = LightProfile.pulse_folding(spacecraft_toas, photon_vec, pulsar_of_interest.lightcurve, mjd = True, start_offset = toas_barycenter.first_MJD, resolution_factor = resolution_factor)\nplt.plot(pulsar_of_interest.lightcurve.phase_list, pulse_fold_spacecraft)\nplt.legend(['Barycenter', 'Spacecraft'])\n# plt.plot(pulse_fold_spacecraft.phase_list, pulse_fold_barycenter)\n# plt.show()\n
    <matplotlib.legend.Legend at 0x7f9a6dc79120>\n

    An example of what happens if you fold the pulse with the wrong pulsar of interest

    pulse_fold_barycenter = LightProfile.pulse_folding(barycenter_toas, photon_vec, pulsar_of_interest.lightcurve, mjd = True, start_offset = toas_barycenter.first_MJD, resolution_factor = resolution_factor)\nplt.plot(pulsar_of_interest.lightcurve.phase_list, pulse_fold_barycenter)\nplt.xlabel(\"Phase\")\nplt.ylabel(\"Count\")\n
    Text(0, 0.5, 'Count')\n

    np.save(\"pulsar_vec.npy\", np.asarray(photon_vec))\n
    "},{"location":"components/3__custom_event_generation/ceg_overview/#hardware-in-the-loop-sdrs","title":"Hardware In The Loop (SDRs)","text":"

    In this notebook, we will walk through setup and operation of SDRs to transmit pulse train data for pulsar signal simulation.

    "},{"location":"components/3__custom_event_generation/ceg_overview/#checking-sdr-connectivity","title":"Checking SDR Connectivity","text":"

    To start, it is necessary to make sure you have successfully mounted the SDRs to your PC via USB. You can check this by executing the following commands in a command prompt:

    # ping 192.168.2.1\n# ping 192.168.2.2\n

    For each of these commands, you should see four data packets successfully sent to the SDR and received back by the PC.

    Next, it will be necessary to check that both SDRs can transmit and receive data to themselves. You can do so by executing the following code. Before running this code, make sure both SDRs are mounted to your PC and have been pinged successfully, and that each one has a BNC cable connecting its Rx port to its Tx port.

    import numpy as np\nimport adi\nimport matplotlib.pyplot as plt\nimport sdr_io\nsample_rate = 1e6 # Hz\ncenter_freq = 915e6 # Hz\ntx_data = np.load('test_vec.npy')\ntx_length = 5000\nplot_rx_pulse_train = True\nplot_rx_samples = True\nplot_fft = True\ncheck_fid = True\nsdr1 = \"ip:192.168.2.1\"\nsdr2 = \"ip:192.168.2.2\"\nsdr_io.sdr_tx_rx(sample_rate,center_freq,\nsdr1,sdr1,\ntx_data,tx_length,\nFalse,False, False, False)\nsdr_io.sdr_tx_rx(sample_rate,center_freq,\nsdr2,sdr2,\ntx_data,tx_length,\nFalse,False, False, False)\n

    Now that you have verified both SDRs can transmit and receive data to and from your PC, connect the Tx port of the \"X-RAY EMITTER\" SDR to the Rx port of the \"X_RAY DETECTOR\" SDR and execute the following code. This will transmit the same test pulse as above, but between the two SDRs instead of within each one.

    sdr_io.sdr_tx_rx(sample_rate,center_freq,\nsdr1,sdr2,\ntx_data,tx_length,\nplot_rx_pulse_train,plot_rx_samples,plot_fft,check_fid)\n

    Out of phase by 1141\nSuccess! Perfect Transmission!\n

    Once you have verified that the SDRs can communicate with one another, you are ready to proceed with data transmission.

    "},{"location":"components/3__custom_event_generation/ceg_overview/#transmitting-pulsar-simulation-data","title":"Transmitting Pulsar Simulation Data","text":"

    After generating a pulse train from the OpenXNAV software, transmit it from the \"Emitter\" SDR to the \"Detector\" SDR by loading it through the code below.

    tx_data_name = \"pulsar_vec.npy\" # insert filename for pulse train here\ntx_data = np.load(tx_data_name)\ntx_data = tx_data[:5000]\ntx_length = len(tx_data)\nplot_rx_samples = True # once connectivity and fidelic transmission is verified,\n# this is redundant\nplot_fft = True # no longer concerned with freq domain - only concerned \n# with transmitted pulses\ncheck_fid = True # we have already verified connectivity - no need to check again\nprint(\"Transmitted data\")\nplt.plot(tx_data)\nplt.show()\nprint(\"Received data\")\nsdr_io.sdr_tx_rx(sample_rate,center_freq,\nsdr1,sdr2,\ntx_data,tx_length,\nplot_rx_pulse_train,plot_rx_samples,plot_fft,check_fid)\n
    Transmitted data\n

    Received data\n

    Out of phase by 2890\nSuccess! Perfect Transmission!\n
    "},{"location":"components/3__custom_event_generation/sdr_demo/","title":"Pulse Transmission between Software-Defined Radios (SDRs)","text":"

    In this notebook, we will walk through setup and operation of SDRs to transmit pulse train data for pulsar signal simulation.

    "},{"location":"components/3__custom_event_generation/sdr_demo/#checking-sdr-connectivity","title":"Checking SDR Connectivity","text":"

    To start, it is necessary to make sure you have successfully mounted the SDRs to your PC via USB. You can check this by executing the following commands in a command prompt:

    # ping 192.168.2.1\n# ping 192.168.2.2\n

    For each of these commands, you should see four data packets successfully sent to the SDR and received back by the PC.

    Next, it will be necessary to check that both SDRs can transmit and receive data to themselves. You can do so by executing the following code. Before running this code, make sure both SDRs are mounted to your PC and have been pinged successfully, and that each one has a BNC cable connecting its Rx port to its Tx port.

    import numpy as np\nimport adi\nimport matplotlib.pyplot as plt\nimport sdr_io\nsample_rate = 1e6 # Hz\ncenter_freq = 915e6 # Hz\ntx_data = np.load('test_vec.npy')\ntx_length = 5000\nplot_rx_pulse_train = True\nplot_rx_samples = True\nplot_fft = True\ncheck_fid = True\nsdr1 = \"ip:192.168.2.1\"\nsdr2 = \"ip:192.168.2.2\"\nsdr_io.sdr_tx_rx(sample_rate,center_freq,\nsdr1,sdr1,\ntx_data,tx_length,\nFalse,False, False, False)\nsdr_io.sdr_tx_rx(sample_rate,center_freq,\nsdr2,sdr2,\ntx_data,tx_length,\nFalse,False, False, False)\n

    Now that you have verified both SDRs can transmit and receive data to and from your PC, connect the Tx port of the \"X-RAY EMITTER\" SDR to the Rx port of the \"X_RAY DETECTOR\" SDR and execute the following code. This will transmit the same test pulse as above, but between the two SDRs instead of within each one.

    sdr_io.sdr_tx_rx(sample_rate,center_freq,\nsdr1,sdr2,\ntx_data,tx_length,\nplot_rx_pulse_train,plot_rx_samples,plot_fft,check_fid)\n

    Out of phase by 1141\nSuccess! Perfect Transmission!\n

    Once you have verified that the SDRs can communicate with one another, you are ready to proceed with data transmission.

    "},{"location":"components/3__custom_event_generation/sdr_demo/#transmitting-pulsar-simulation-data","title":"Transmitting Pulsar Simulation Data","text":"

    After generating a pulse train from the OpenXNAV software, transmit it from the \"Emitter\" SDR to the \"Detector\" SDR by loading it through the code below.

    tx_data_name = \"pulsar_vec.npy\" # insert filename for pulse train here\ntx_data = np.load(tx_data_name)\ntx_data = tx_data[:5000]\ntx_length = len(tx_data)\nplot_rx_samples = True # once connectivity and fidelic transmission is verified,\n# this is redundant\nplot_fft = True # no longer concerned with freq domain - only concerned \n# with transmitted pulses\ncheck_fid = True # we have already verified connectivity - no need to check again\nprint(\"Transmitted data\")\nplt.plot(tx_data)\nplt.show()\nprint(\"Received data\")\nsdr_io.sdr_tx_rx(sample_rate,center_freq,\nsdr1,sdr2,\ntx_data,tx_length,\nplot_rx_pulse_train,plot_rx_samples,plot_fft,check_fid)\n
    Transmitted data\n

    Received data\n

    Out of phase by 2890\nSuccess! Perfect Transmission!\n
    "}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Overview","text":"

    Open-source modular toolkit for simulating high-fidelity pulsar X-ray events.

    "},{"location":"#introduction-to-openxnav","title":"Introduction to OpenXNAV","text":"

    OpenXNAV is designed to aid development and testing of Pulsar-based Autonomous Navigation (XNAV) Positioning, Navigation, and Timing (PNT) solutions.

    You can read our IEEE paper to learn more: IEEE.org.

    "},{"location":"#components","title":"Components","text":"
    • Pulsar Querying
    • Mission Planning
    • Timing & Event Generation
    "},{"location":"getting_started/","title":"Getting Started","text":"

    Each component of OpenXNAV can be used individually, or strung together as an end-to-end pipeline. To get started with OpenXNAV, select the module you are interested in leveraging and access the documentation.

    "},{"location":"getting_started/#pulsar-querying","title":"Pulsar Querying","text":"

    Query for all known pulsars catalogued in the ATNF database by providing a coordinate in space, and a search radius.

    "},{"location":"getting_started/#mission-planning","title":"Mission Planning","text":"

    Model the desired flight path, taking into account spacecraft orientation, viewing angle and line of sight.

    "},{"location":"getting_started/#timing-event-generation","title":"Timing & Event Generation","text":"

    Generate representative photon arrival events at the location of interest along the user-defined trajectory.

    "},{"location":"components/1__pulsar_querying/pq_overview/","title":"Pulsar Querying","text":""},{"location":"components/1__pulsar_querying/pq_overview/#installation","title":"Installation","text":"

    Before using the OpenXNAV Pulsar Querying Tool, you will need to install the necessary python packages. You can do this using your preferred python package manager, but instructions are provided below for using Anaconda

    Inside the open-xnav/1__pulsar_querying/ directory, there is an environment.yml file. This file can be passed to your preferred package manager to create a new environment that can run the tool.

    "},{"location":"components/1__pulsar_querying/pq_overview/#create-new-environment","title":"Create New Environment","text":"

    The default environment name in environment.yml is openXNAV-gui. If you wish to change the environment name, simply edit environment.yml before creating the environment.

    Open your Anaconda Prompt (or activate Anaconda in a terminal window). Navigate to open-xnav/`1__pulsar_querying/ and run the following command:

    conda env create -f environment.yaml\n

    To activate your environment, run the following command:

    conda activate openXNAV-gui\n
    NOTE: If you altered the environment name, you will need to alter the above command to reflect that new name.

    "},{"location":"components/1__pulsar_querying/pq_overview/#install-kivymd","title":"Install KivyMD","text":"

    The tool also depends on KivyMD, which is a library built off of the popular Kivy library. This package is not available through conda, so you must install it using pip.

    First, make sure you have activated the openXNAV-gui environment in your terminal. Then, run the following command:

    pip install kivymd\n

    If you are getting a ReadTimeoutError response during installation, you might be using a VPN or have a slower internet connection. If this happens, try running the following instead:

    pip install --default-timeout=1000 kivymd\n

    If that still does not work, you can troubleshoot your issues further using the pip documentation here.

    "},{"location":"components/1__pulsar_querying/pq_overview/#using-the-tool","title":"Using The Tool","text":""},{"location":"components/1__pulsar_querying/pq_overview/#loadgenerate-database","title":"Load/Generate Database","text":"

    Once you have successfully installed all the required packages, you are ready to run the tool!

    First, ensure you have navigated to open-xnav/1__pulsar_querying/ in your terminal and have your openXNAV-gui environment activated.

    Then, simply run the following in your terminal:

    python run.py\n

    Upon startup, the tool will need to pull the current ATNF Pulsar Catalogue from the web. This process only need to be done the first time you open the application.

    However, if you wish to update the database, simply delete the .../pulsar_database/ directory from your file system. Then, relaunch the application. Once the database has been generated, you can continue begin querying.

    You should see the OpenXNAV launch window with the blue Launch Application button active. In the future, when you open the application, the tool will locate the previously-generated database and you can quickly continue to the querying functionality.

    "},{"location":"components/1__pulsar_querying/pq_overview/#query-for-pulsars","title":"Query For Pulsars","text":"

    After you click Launch Application, the query tool will display.

    There are three fields that you need to provide to execute a query:

    • Right Ascension (HH:MM:SS)
    • Declination (DD:MM:SS)
    • Search Radius (Degrees)

    These values will create a query, searching for all known pulsars that are within a given search radius of the provided coordinates in space.

    The OpenXNAV tool leverages the open-source psrqpy library. More information about this package, and how queries are executed, can be found here.

    The query results will display to the GUI interface, and will also be stored in a sub-directory within .../query_results/.

    For information about how these sub-directories are tagged, see below.

    "},{"location":"components/1__pulsar_querying/pq_overview/#tagging-results","title":"Tagging Results","text":"

    There is an optional Tag field that OpenXNAV also provides. This allows you to specify the tag for this query you are about to execute. If a tag is provided, that will be used to name the sub-directory within .../query_results/ where all pulsars returned by the query are stored.

    Sample Queries

    Below are couple sample queries that you can run to get familiar with the OpenXNAV tool. There are additional sample query results contained in the .../query_results/ directory.

    Query Right Ascension Declination Radius Parker Solar Probe 9.805475733988583 12.005839937612905 15.0 L2 18:24:32.00819 -24:52:10.720 30.0"},{"location":"components/1__pulsar_querying/pq_overview/#output-files","title":"Output Files","text":""},{"location":"components/1__pulsar_querying/pq_overview/#stk-integration","title":"STK Integration","text":"

    Right now, the OpenXNAV Pulsar Querying Tool only outputs pulsar data into the .st format. This is the format that is required by STK to perform subsequent mission planning.

    To display the format of this file, here is J00012_5431.st as an example:

    stk.v.12.0\nWrittenBy    OpenXNAV\n\nBEGIN Star\n\n    Name         J0012_5431\n\n    BEGIN PathDescription\n\n        Epoch         58912.0\n        RefFrame         J2000\n        RightAscension        3.097083333333333\n        Declination       +54:31:47\n        ProperMotionRAPerYr      0\n        ProperMotionDecPerYr         0\n        Parallax          0\n        RadialVelocity        0.0000000000000000e+00\n\n    END PathDescription\n\n    BEGIN PhysicalData\n\n        Magnitude         None\n\n    END PhysicalData\n\n    BEGIN IdentityData\n\n        Id       0\n\n    END IdentityData\n\n\n    BEGIN Extensions\n\n        BEGIN ExternData\n        END ExternData\n\n        BEGIN ADFFileData\n        END ADFFileData\n\n        BEGIN AccessConstraints\n            LineOfSight IncludeIntervals\n\n            UsePreferredMaxStep No\n            PreferredMaxStep 360\n        END AccessConstraints\n\n        BEGIN Desc\n        END Desc\n\n        BEGIN Crdn\n        END Crdn\n\n        BEGIN Graphics\n\n            BEGIN Attributes\n\n                MarkerColor      #00ff00\n                LabelColor       #00ff00\n                MarkerStyle      2\n                FontStyle        0\n\n            END Attributes\n\n            BEGIN Graphics\n\n                Show         On\n                Inherit      On\n                ShowLabel        On\n                ShowMarker       On\n\n            END Graphics\n        END Graphics\n\n        BEGIN VO\n        END VO\n\n    END Extensions\n\nEND Star\n

    You will need to provide these .st file(s) to STK to successfully execute OpenXNAV's mission planning functionality.

    "},{"location":"components/1__pulsar_querying/pq_overview/#other-file-formats","title":"Other File Formats","text":"

    However, if you would like pulsar information to be stored/saved in a different format, you can modify the source code.

    Navigate to queryPulsar.py and locate the following function:

    def saveToFile(self, root_directory) ...\n
    Here, you can alter/update the code to print the pulsar information into your desired format. Once this function has been updated, query results will automatically store in this new format. All query results will still appear in .../query_results/.

    "},{"location":"components/2__mission_planning/mp_overview/","title":"Mission Planning","text":"

    In this Python notebook, the mission_planning module from the OpenXNAV library is demonstrated.

    We start by importing the necessary libraries:

    from astropy import units as u\nfrom astropy.coordinates import SkyCoord,get_body\nfrom astropy.time import Time,TimeDelta\nfrom astropy.table import Table,QTable\n\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pandas as pd\n

    Next we define the necessary variables that we will use to instantiate the orbit. We will define an elliptical orbit directly by its orbital elements in this example. Other options, which are currently commented out, are a circular orbit (special case of elliptical orbit where eccentricity = 0) and an elliptical orbit defined by its burnout trajectory.

    # User definitions for elliptical orbital elements\n\ne = 0.3           # eccentricity of the orbit\na = 750000*u.m    # semi-major axis \ninc = 20*u.deg    # inclination of orbit\nw = 90*u.deg      # argument of periapsis\nv_0 = 0*u.deg     # initial eccentric anomaly\nOmega = 90*u.deg  # longitude of ascending node\n\nimport warnings\nwarnings.filterwarnings('ignore',message='leap-second file is expired')\nt = Time.now() + TimeDelta(120*u.day) + TimeDelta(np.linspace(0,800,51)*u.s)\n\n# Alternative: User definitions for elliptical orbital insertion \n# (note that this is just an example and would not generate the \n# same trajectory as the one above defined directly by orbital elements)\n\n#e = 0.1          # eccentricity of the orbit, also user defined\n#a = 750000*u.m   # m semi-major axis \n#B = 70*u.deg     # azimuth heading measured in degrees clockwise from north\n#dec = 20*u.deg   # geocentric latitude in degrees (declination) of burnout\n#v_0 = 0*u.deg    # initial eccentric anomaly\n

    We can now do the same thing with a low-fidelity elliptical orbit, starting with the EllipticalOrbit class:

    from mission_planning import EllipticalOrbit\n\neo = EllipticalOrbit(t,a,e,v_0=v_0,\n                     inc=inc,w=w,\n                     Omega=Omega)\n\nplt.figure()\nplt.plot(eo.x.to(u.km),eo.y.to(u.km),'b.')\n#plt.xlim([-a/u.km,a/u.km])\n#plt.ylim([-a/u.km,a/u.km])\nplt.show()\n

    While the above plot is represented in two dimensions as the projection of the orbit onto the XY-plane, this orbit was actually instantiated in 3D. To show the trajectory in the 3D Cartesian reference frame with the center of Earth at the origin, we just have to plot it in the 3D figure:

    fig = plt.figure()\n\nax = fig.add_subplot(projection='3d')\nax.scatter(eo.x.to(u.km),eo.y.to(u.km),eo.z.to(u.km))\n\nplt.show()\n

    "},{"location":"components/2__mission_planning/mp_overview/#creating-vectors-from-pulsar-to-space-objects-to-look-for-access","title":"Creating vectors from pulsar to space objects to look for access","text":"

    In order to better demonstrate the pulsar access calculation functions in the OpenXNAV mission_planning module, we will create a SkyCoord object representing the moon, but with a distorted size and orbit to ensure some obfuscation of a chosen pulsar (whose coordinates are also exaggerated for demonstration purposes).

    from mission_planning import plot_accesses\n\nmoon = SkyCoord(\n    x = -284405*u.m,\n    y = 249415*u.m,\n    z = 0*u.m,\n    frame='gcrs',\n    representation_type = 'cartesian'\n)\n\n#moon_rad = 1740*u.km # actual radius of the moon \nmoon_rad = 150*u.km # fake news \n\n\n# assuming we have the location of the pulsars, using one as an example\npulsar = SkyCoord(\n    x = -853215*u.m,\n    y = 748245*u.m,\n    z = 0*u.km,\n    frame='gcrs',\n    representation_type = 'cartesian'\n)\n\naccess = eo.pulsar_access(pulsar,moon,moon_rad)\n\n# create figure to plot pulsar access\nfig = plt.figure()\n\nax = fig.add_subplot(projection='3d')\nax.scatter(pulsar.x.to(u.km),pulsar.y.to(u.km),pulsar.z.to(u.km),label='pulsar')\nax.scatter(eo.x.to(u.km),eo.y.to(u.km),eo.z.to(u.km),label='spacecraft')\nax.scatter(moon.x.to(u.km),moon.y.to(u.km),moon.z.to(u.km),label='moon',s=500)\nplt.legend()\n\nplt.show()\n\nfig = plt.figure()\nax = fig.add_subplot()\nax = plot_accesses(ax,t,{'pulsar':access})\n

    We can also instantiate an EllipticalOrbit object with high fidelity. This version of the class calculates the eccentric anomaly at each time in the time array in order to calculate a more exact position.

    There is currently a bug in this version that causes it to only output positive x and positive z values, so we'll need to fix that. (Negative values shown below are there because x and z are positive before coordinate rotation to account for longitude of ascending node, orbital inclination, and argument of periapsis)

    eo_h = EllipticalOrbit(t,a,e,v_0=v_0,\n                        inc=inc,w=w,\n                        Omega=Omega,\n                        hifi=True)\n\nplt.figure()\nplt.plot(eo_h.x,eo_h.y,'b.')\nplt.xlim([-a/u.m,a/u.m])\nplt.ylim([-a/u.m,a/u.m])\nplt.show()\n\nfig = plt.figure()\n\nax = fig.add_subplot(projection='3d')\nax.scatter(eo_h.x,eo_h.y,eo_h.z)\n\nplt.show()\n

    "},{"location":"components/2__mission_planning/mp_overview/#using-the-actual-position-of-known-celestial-bodies","title":"Using the actual position of known celestial bodies","text":""},{"location":"components/2__mission_planning/mp_overview/#example-1-circular-orbit","title":"Example 1 - Circular Orbit","text":"

    Next we will take advantage of the get_body and pulsar_access_export functionalities of Astropy and OpenXNAV Mission Planning, respectively.

    Astropy allows us to create a SkyCoord object using the actual location of the moon at any time or array of times. We will make our moon much bigger than in real life to ensure that we obfuscate some pulsars for demonstration purposes. We will define a new orbit circular orbit using the CircularOrbit class, which is a special case of the EllipticalOrbit class in which eccentricity and orbital inclination are zero.

    from mission_planning import CircularOrbit\n\n# User definitions for circular orbit\nr = 360000*u.km\nt0 = Time('2023-08-24 12:12:15.932083')\nt = t0 + TimeDelta(np.linspace(0,25,100)*u.day)\n\nmoon = get_body('moon',t)\nmoon.representation_type='cartesian'\nMOON_RAD = 1740*u.km\n\nearth = get_body('earth',t)\nearth.representation_type = 'cartesian'\nEARTH_RAD = 6378.14*u.km\n\nco = CircularOrbit(t,r)\n

    Next we will create an astropy.table.Table object with some pulsars that we want to load in to our pulsar access export function. The table is shown and created here for demonstration purposes; however, tables with this format can be created in the OpenXNAV pulsar query module.

    name = [    'J0002+6216' , 'J0006+1834' , 'J0007+7303' , 'J0011+08' , 'J0012+5431']\nraJ_deg = [   0.74238    ,   1.52       ,  1.7571      ,  2.9       ,   3.0971     ] * u.deg\ndecJ_deg = [ 62.26928    ,  18.5831     ,  1.7571      ,  8.17      ,  54.5297     ] * u.deg\ndist_kpc = [  6.357      ,   0.86       ,  1.4         ,  5.399     ,   5.425      ] * u.kpc\n\nt = Table([name,raJ_deg,decJ_deg,dist_kpc],\n          names = ['NAME','RAJD','DECJD','DIST'])\n\nt.write('some_pulsars.fits',overwrite=True)\nprint(t)\n
       NAME      RAJD   DECJD    DIST\n             deg     deg     kpc \n---------- ------- -------- -----\nJ0002+6216 0.74238 62.26928 6.357\nJ0006+1834    1.52  18.5831  0.86\nJ0007+7303  1.7571   1.7571   1.4\n  J0011+08     2.9     8.17 5.399\nJ0012+5431  3.0971  54.5297 5.425\n
    "},{"location":"components/2__mission_planning/mp_overview/#using-the-pulsar_access_export-method","title":"Using the pulsar_access_export method","text":"

    Now that we have our spacecraft, moon, and pulsar table, we can use the pulsar_access_export method to create a table and plot of pulsar accesses. Both this method and the pulsar_access function allow you to account for obfuscation from multiple celestial bodies; just make sure to define them as shown below, entered before the keyword arguments and alternating between the SkyCoord object representing the celestial body and the radius of the body represented as an astropy.units.Quantity object.

    pulsars_qtbl = QTable.read('some_pulsars.fits')\n\n# 3D plot of satellite orbit and moon\nfig1 = plt.figure()\nax1 = fig1.add_subplot(projection='3d')\nax1.scatter(moon.x.to(u.km),moon.y.to(u.km),moon.z.to(u.km),label='moon',s=100)\nax1.scatter(co.x.to(u.km),co.y.to(u.km),co.z.to(u.km),label='satellite in cirular orbit')\nax1.scatter(earth.x.to(u.km),earth.y.to(u.km),earth.z.to(u.km),label='earth',s=500)\nplt.legend(loc='upper left')\n\n# Plot of pulsar accesses\n_,(fig2,ax2) = co.pulsar_access_export(pulsars_qtbl,\n                                       moon,MOON_RAD,\n                                       earth,EARTH_RAD,\n                                       make_csv=False,\n                                       make_fig=True,save_fig=False)\n

    "},{"location":"components/2__mission_planning/mp_overview/#example-2-elliptical-orbit","title":"Example 2 - Elliptical Orbit","text":"

    Next we will define a new elliptical orbit from the EllipticalOrbit class in which eccentricity and orbital inclination are non-zero.

    # User definitions for elliptical orbital elements\n\ne = 0.3           # eccentricity of the orbit\na = 30000*u.km    # semi-major axis \ninc = 20*u.deg    # inclination of orbit\nw = 90*u.deg      # argument of periapsis\nv_0 = 0*u.deg     # initial eccentric anomaly\nOmega = 90*u.deg  # longitude of ascending node\n\nt0 = Time('2023-08-24 12:12:15.932')\nt = t0 + TimeDelta(np.linspace(0,25,1000)*u.day)\n\nmoon = get_body('moon',t)\nmoon.representation_type='cartesian'\nMOON_RAD = 1740*u.km\n\nearth = SkyCoord(x=0*u.m,y=0*u.m,z=0*u.m,frame='gcrs',representation_type='cartesian')\nEARTH_RAD = 6378.14*u.km\n\neo2 = EllipticalOrbit(t,a,e,v_0=v_0,\n                     inc=inc,w=w,\n                     Omega=Omega)\n\nfig = plt.figure()\n\nax = fig.add_subplot(projection='3d')\nax.scatter(eo2.x.to(u.km),eo2.y.to(u.km),eo2.z.to(u.km))\n\nplt.show()\n

    Next we will create a CSV with some pulsars that we want to load in to our pulsar access export function. The CSV is shown and created here for demonstration purposes:

    name = [    'J0002+6216' , 'J0006+1834' , 'J0007+7303' , 'J0011+08' , 'J0012+5431']\nraJ_deg = [   0.74238    ,   1.52       ,  1.7571      ,  2.9       ,   3.0971     ] * u.deg\ndecJ_deg = [ 62.26928    ,  18.5831     ,  1.7571      ,  8.17      ,  54.5297     ] * u.deg\ndist_kpc = [  6.357      ,   0.86       ,  1.4         ,  5.399     ,   5.425      ] * u.kpc\n\ntbl = Table([name,raJ_deg,decJ_deg,dist_kpc],\n          names = ['NAME','RAJD','DECJD','DIST'])\n\ntbl.write('some_pulsars.fits',overwrite=True)\nprint(tbl)\n
       NAME      RAJD   DECJD    DIST\n             deg     deg     kpc \n---------- ------- -------- -----\nJ0002+6216 0.74238 62.26928 6.357\nJ0006+1834    1.52  18.5831  0.86\nJ0007+7303  1.7571   1.7571   1.4\n  J0011+08     2.9     8.17 5.399\nJ0012+5431  3.0971  54.5297 5.425\n
    "},{"location":"components/2__mission_planning/mp_overview/#using-the-pulsar_access_export-method_1","title":"Using the pulsar_access_export method","text":"

    Now that we have our spacecraft, moon, and pulsar CSV, we can use the pulsar_access_export method to create a table and plot of pulsar accesses. Both this method and the pulsar_access function allow you to account for obfuscation from multiple celestial bodies; just make sure to define them as shown below, entered before the keyword arguments and alternating between the SkyCoord object representing the celestial body and the radius of the body represented as an astropy.units.Quantity object.

    As part of the pulsar_access_export method call, we can write all pulsar access data to a CSV file. This CSV can then be used in the pulsar photon time-of-arrival simulation module to model the X-ray pulse sequence that the spacecraft would observe at those coordinates.

    pulsars_qtbl = QTable.read('some_pulsars.fits')\n\n# 3D plot of satellite orbit\nfig1 = plt.figure()\nax1 = fig1.add_subplot(projection='3d')\nax1.scatter(eo2.x.to(u.km),eo2.y.to(u.km),eo2.z.to(u.km),label='satellite in elliptical orbit')\nax1.scatter(earth.x.to(u.km),earth.y.to(u.km),earth.z.to(u.km),label='earth',s=200)\nplt.legend(loc='upper left')\n\n# 3D plot of satellite orbit and moon\nfig2 = plt.figure()\nax2 = fig2.add_subplot(projection='3d')\nax2.scatter(moon.x.to(u.km),moon.y.to(u.km),moon.z.to(u.km),label='moon',s=100)\nax2.scatter(eo2.x.to(u.km),eo2.y.to(u.km),eo2.z.to(u.km),label='satellite in elliptical orbit')\nax2.scatter(earth.x.to(u.km),earth.y.to(u.km),earth.z.to(u.km),label='earth',s=200)\nplt.legend(loc='upper left')\n\n# Plot of pulsar accesses, and save pulsar access table to CSV\naccesses,(fig3,ax3) = eo2.pulsar_access_export(pulsars_qtbl,\n                                               moon,MOON_RAD,\n                                               earth,EARTH_RAD,\n                                               make_csv=True,save_csv=True,\n                                               make_fig=True,save_fig=False)\n

    The breaks in the plot above might be hard to see since they are so small compared to the scale of the timeline displayed. We have therefore represented the breaks in tabular form below.

    # Create DataFrame containing all times at which access to at least one pulsar is interrupted\naccess_breaks = accesses[accesses.all(axis=1) == False]\naccess_breaks\n
    Time_JDate Spacecraft_pos_X_km Spacecraft_pos_Y_km Spacecraft_pos_Z_km Spacecraft_vel_X_kmps Spacecraft_vel_Y_kmps Spacecraft_vel_Z_kmps J0002+6216 J0006+1834 J0007+7303 J0011+08 J0012+5431 0 2.460181e+06 -19733.545037 2.343791e-12 4.132736e-13 4.667259 0.000000 0.000000 True False False False True 24 2.460182e+06 -19722.356542 -8.518943e+02 -1.662908e+01 4.663209 0.190622 0.065196 True False False False True 48 2.460182e+06 -19688.801001 -1.703092e+03 -3.324457e+01 4.651077 0.380744 0.130222 True False False False True 72 2.460183e+06 -19632.908273 -2.552897e+03 -4.983288e+01 4.630912 0.569870 0.194907 True True False False True 96 2.460183e+06 -19554.728216 -3.400614e+03 -6.638041e+01 4.602798 0.757509 0.259083 True True False False True 120 2.460184e+06 -19454.330828 -4.245547e+03 -8.287361e+01 4.566851 0.943180 0.322587 True True False False True 143 2.460185e+06 -19264.410077 5.493859e+03 1.072408e+02 4.499325 -1.214310 -0.415318 True True False True True 144 2.460185e+06 -19331.806438 -5.087002e+03 -9.929892e+01 4.523216 1.126412 0.385256 True True False False True 167 2.460185e+06 -19397.632920 4.654341e+03 9.085332e+01 4.546627 -1.032427 -0.353111 True True False False True 168 2.460185e+06 -19187.265950 -5.924286e+03 -1.156428e+02 4.472073 1.306749 0.446935 True True False False True 191 2.460186e+06 -19508.779991 3.811009e+03 7.439137e+01 4.586325 -0.847881 -0.289993 True True False False True 192 2.460186e+06 -19020.841125 -6.756708e+03 -1.318918e+02 4.413626 1.483752 0.507473 True True False False True 215 2.460186e+06 -19597.751010 2.964556e+03 5.786850e+01 4.618256 -0.661138 -0.226122 True True False False True 239 2.460187e+06 -19664.466140 2.115677e+03 4.129829e+01 4.642291 -0.472672 -0.161663 True True False False True 263 2.460188e+06 -19708.865772 1.265068e+03 2.469429e+01 4.658329 -0.282972 -0.096782 True True False False True 287 2.460188e+06 -19730.910356 4.134251e+02 8.070109e+00 4.666305 -0.092530 -0.031647 True False False False True 311 2.460189e+06 -19730.580291 -4.385562e+02 -8.560672e+00 4.666185 0.098154 0.033571 True False False False True 333 2.460189e+06 -13839.201092 1.850473e+04 3.612147e+02 2.807521 -3.552673 -1.215086 True True False True True 334 2.460189e+06 -18399.018428 9.194010e+03 1.794682e+02 4.199348 -1.985878 -0.679210 True True False True True 335 2.460189e+06 -19707.875871 -1.290179e+03 -2.518445e+01 4.657971 0.288581 0.098700 True False False False True 359 2.460190e+06 -19662.817284 -2.140747e+03 -4.178765e+01 4.641696 0.478252 0.163572 True True False False True 383 2.460191e+06 -19595.444668 -2.989564e+03 -5.835666e+01 4.617427 0.666673 0.228016 True True False False True 407 2.460191e+06 -19505.818229 -3.835935e+03 -7.487792e+01 4.585264 0.853359 0.291866 True True False False True 431 2.460192e+06 -19394.018402 -4.679164e+03 -9.133787e+01 4.545339 1.037832 0.354960 True True False False True 454 2.460192e+06 -19335.736565 5.062236e+03 9.881549e+01 4.524612 -1.121046 -0.383420 True True False True True 455 2.460192e+06 -19260.146075 -5.518559e+03 -1.077230e+02 4.497816 1.219630 0.417138 True True False False True 478 2.460193e+06 -19457.609710 4.220669e+03 8.238798e+01 4.568022 -0.937736 -0.320724 True True False False True 479 2.460193e+06 -19104.322848 -6.353426e+03 -1.240197e+02 4.442885 1.398305 0.478248 True True False False True 502 2.460194e+06 -19557.352895 3.375643e+03 6.589298e+01 4.603740 -0.752000 -0.257199 True True False False True 526 2.460194e+06 -19634.876395 2.527855e+03 4.934405e+01 4.631621 -0.564310 -0.193005 True True False False True 550 2.460195e+06 -19690.110807 1.677999e+03 3.275475e+01 4.651550 -0.375147 -0.128308 True True False False True 574 2.460195e+06 -19723.006865 8.267705e+02 1.613866e+01 4.663444 -0.185003 -0.063275 True True False False True 598 2.460196e+06 -19733.535299 -2.513369e+01 -4.906128e-01 4.667255 0.005626 0.001924 True False False False True 622 2.460197e+06 -19721.686753 -8.770174e+02 -1.711949e+01 4.662967 0.196240 0.067118 True False False False True 646 2.460197e+06 -19687.471756 -1.728184e+03 -3.373437e+01 4.650597 0.386340 0.132136 True False False False True 670 2.460198e+06 -19630.920755 -2.577938e+03 -5.032167e+01 4.630196 0.575429 0.196808 True True False False True 694 2.460198e+06 -19552.084202 -3.425582e+03 -6.686780e+01 4.601849 0.763017 0.260967 True True False False True 718 2.460199e+06 -19451.032689 -4.270423e+03 -8.335919e+01 4.565673 0.948623 0.324448 True True False False True 741 2.460200e+06 -19268.654973 5.469155e+03 1.067586e+02 4.500827 -1.208987 -0.413498 True True False True True 742 2.460200e+06 -19327.857151 -5.111765e+03 -9.978229e+01 4.521814 1.131776 0.387090 True True False False True 765 2.460200e+06 -19401.228226 4.629514e+03 9.036870e+01 4.547908 -1.027019 -0.351261 True True False False True 766 2.460200e+06 -19182.669102 -5.948915e+03 -1.161236e+02 4.470452 1.312021 0.448737 True True False False True 789 2.460201e+06 -19511.722453 3.786080e+03 7.390476e+01 4.587378 -0.842402 -0.288118 True True False False True 790 2.460201e+06 -19015.600922 -6.781183e+03 -1.323695e+02 4.411793 1.488919 0.509240 True True False False True 813 2.460201e+06 -19600.037983 2.939546e+03 5.738031e+01 4.619079 -0.655600 -0.224229 True True False False True 837 2.460202e+06 -19666.095577 2.090606e+03 4.080890e+01 4.642879 -0.467091 -0.159755 True True False False True 861 2.460203e+06 -19709.836218 1.239957e+03 2.420411e+01 4.658680 -0.277362 -0.094863 True True False False True 885 2.460203e+06 -19731.220949 3.882936e+02 7.579540e+00 4.666417 -0.086906 -0.029724 True False False False True 909 2.460204e+06 -19730.230755 -4.636870e+02 -9.051228e+00 4.666059 0.103778 0.035494 True False False False True 933 2.460204e+06 -19706.866516 -1.315289e+03 -2.567460e+01 4.657606 0.294189 0.100619 True False False False True 957 2.460205e+06 -19661.149008 -2.165815e+03 -4.227698e+01 4.641094 0.483830 0.165480 True True False False True 981 2.460206e+06 -19593.118960 -3.014570e+03 -5.884478e+01 4.616590 0.672208 0.229909 True True False False True"},{"location":"components/2__mission_planning/mp_overview/#substituting-stk-for-openxnav-mission-planning","title":"Substituting STK for OpenXNAV Mission Planning","text":"

    As an alternative to the mission_planning module built into OpenXNAV, users can also plan their missions and generate trajectory and pulsar access inputs using the mission planning software of their choice, such as ANSYS STK. STK is very visual, and a great option if you\u2019re starting your mission plan from scratch and want a lot of flexibility in designing your spacecraft trajectory.

    STK users who choose this route should follow the following steps:

    1. Create a new scenario in STK, including the time over which you are interested in analyzing.
    2. Export the .st files from the OpenXNAV Pulsar Query module and then open them within your new scenario as star objects:

    1. Add in a new satellite object and customize the trajectory to your desired level of complexity:

    1. Create planets for any celestial bodies you would like to be included as obstacles in viewing pulsars (ex: Moon):

    1. Within your satellite object, create a special constraint (i.e. object exclusions) and select your obstacle planets:

    1. Go to Analysis, create accesses between the satellite and the imported pulsar over your scenario window:

    1. Export the access windows as an image and the satellite trajectory in ECEF text file with position and velocity:

    "},{"location":"components/3__custom_event_generation/ceg_overview/","title":"Timing & Event Generation","text":""},{"location":"components/3__custom_event_generation/ceg_overview/#generating-events","title":"Generating Events","text":"

    In this Python notebook, the event_generation module from the PLANTS library is demonstrated.

    We start by importing the necessary libraries:

    %load_ext autoreload\n%autoreload 2\nfrom pint_backend import *\nimport pulsar_definitions\npint.logging.setup(level=\"INFO\")\n

    Loads the ephemerides kernel

    pint.solar_system_ephemerides.load_kernel(\"de440\")\n
    \u001b[1mINFO    \u001b[0m (pint.solar_system_ephemerides ): \u001b[1mSet solar system ephemeris to de440 through astropy\u001b[0m\n

    Creates the time vector that the user hopes to observe at and adds additional error if desired. Specifies what pulsar model to use

    time_interval = astrotime.Time( ['2022-07-11T16:00:01.000', '2022-07-11T16:21:01.000'], format='isot', scale='utc')\nobs_fs = 100e6\nn_toa = 10\nerror = 5 * u.us\napply_error = False\nmodel_name = \"j0218\" \n

    Loads in the navigation data provided by STK and generates a spacecraft object off of that navigation data. Note that spacecraft is a custom class created in the PINT backend

    time, pos, vel = load_nav_data(\"XNAVSAT_TEMEofDate_Position_Velocity_JD.txt\")\nmy_spacecraft = SpaceCraft(\"my_spacecraft\", time, pos, vel, overwrite = True)\n

    Generates the times of arrival at the barycenter compared to the spacecraft. Note that printing the time of arrival generated is slightly different at the two locations

    if(model_name == \"j0218\"):  \n    pulsar_of_interest = PulsarObj(pulsar_definitions.J0218)\nelif(model_name == \"b1821\"):\n    pulsar_of_interest = PulsarObj(pulsar_definitions.B1821)\ntoas_barycenter = pint.simulation.make_fake_toas_uniform(\n    time_interval[0].mjd, time_interval[1].mjd, n_toa, model=pulsar_of_interest.model, freq = 1e15*u.Hz, obs='barycenter',  error=error)\ntoas_spacecraft = pint.simulation.make_fake_toas_uniform(\n    time_interval[0].mjd, time_interval[1].mjd, n_toa, model=pulsar_of_interest.model, freq = 1e15*u.Hz, obs = \"my_spacecraft\",  error=error)\n\n\n\nprint(\"Barycenter first TOA: \" + str(toas_barycenter.get_mjds(\"True\")[0].utc.iso))\nprint(\"Spacecraft first TOA: \" + str(toas_spacecraft.get_mjds(\"True\")[0].utc.iso))\n
    \u001b[33m\u001b[1mWARNING \u001b[0m (pint.logging                  ): \u001b[33m\u001b[1m/opt/anaconda/lib/python3.10/site-packages/pint/models/timing_model.py:373 UserWarning: PINT only supports 'T2CMETHOD IAU2000B'\u001b[0m\n\u001b[33m\u001b[1mWARNING \u001b[0m (pint.logging                  ): \u001b[33m\u001b[1m/opt/anaconda/lib/python3.10/site-packages/pint/models/model_builder.py:139 UserWarning: Unrecognized parfile line 'EPHVER 2'\u001b[0m\n\u001b[1mINFO    \u001b[0m (pint.simulation               ): \u001b[1mUsing CLOCK = TT(TAI), so setting include_bipm = False\u001b[0m\n\u001b[1mINFO    \u001b[0m (pint.models.absolute_phase    ): \u001b[1mThe TZRSITE is set at the solar system barycenter.\u001b[0m\n\u001b[1mINFO    \u001b[0m (pint.models.absolute_phase    ): \u001b[1mTZRFRQ was 0.0 or None. Setting to infinite frequency.\u001b[0m\n\u001b[1mINFO    \u001b[0m (pint.simulation               ): \u001b[1mUsing CLOCK = TT(TAI), so setting include_bipm = False\u001b[0m\n\n\nBarycenter first TOA: 2022-07-11 15:58:51.816031354\nSpacecraft first TOA: 2022-07-11 15:58:51.815489874\n
    %matplotlib inline\nresolution_factor = 1\npulsar_of_interest.lightcurve.plot_lightcurve()\ntime_vec, photon_vec, probability_arr = pulsar_of_interest.lightcurve.create_toa_vec(0, 10, k=4,resolution_factor= resolution_factor)\n

    %matplotlib inline\nplt.plot(time_vec[0:10000], photon_vec[0:10000])\nplt.xlabel(\"Time (s)\")\nplt.ylabel(\"Number of photons received\")\nplt.title(\"Photon vector over 25 ms\")\n
    Text(0.5, 1.0, 'Photon vector over 25 ms')\n

    snip = time_vec\nindices = np.argwhere(photon_vec != 0).flatten()\nplt.hist(snip[indices], bins = 500)\nplt.title(\"Histogram of photons received with bin resolution = 60 ms\")\nplt.xlabel(\"Time (s)\")\nplt.ylabel(\"Number of photons received\")\n
    Text(0, 0.5, 'Number of photons received')\n

    %matplotlib inline\nbarycenter_toas =  create_obs_time_vec(toas_barycenter.first_MJD, time_vec)\npulse_fold_barycenter = LightProfile.pulse_folding(barycenter_toas, photon_vec, pulsar_of_interest.lightcurve, mjd = True, start_offset = toas_barycenter.first_MJD, resolution_factor = resolution_factor)\n\nplt.plot(pulsar_of_interest.lightcurve.phase_list, pulse_fold_barycenter)\nplt.xlabel(\"Phase\")\nplt.ylabel(\"Count\")\nspacecraft_toas = create_obs_time_vec(toas_spacecraft.first_MJD, time_vec)\npulse_fold_spacecraft = LightProfile.pulse_folding(spacecraft_toas, photon_vec, pulsar_of_interest.lightcurve, mjd = True, start_offset = toas_barycenter.first_MJD, resolution_factor = resolution_factor)\nplt.plot(pulsar_of_interest.lightcurve.phase_list, pulse_fold_spacecraft)\nplt.legend(['Barycenter', 'Spacecraft'])\n# plt.plot(pulse_fold_spacecraft.phase_list, pulse_fold_barycenter)\n# plt.show()\n
    <matplotlib.legend.Legend at 0x7f9a6dc79120>\n

    An example of what happens if you fold the pulse with the wrong pulsar of interest

    pulse_fold_barycenter = LightProfile.pulse_folding(barycenter_toas, photon_vec, pulsar_of_interest.lightcurve, mjd = True, start_offset = toas_barycenter.first_MJD, resolution_factor = resolution_factor)\nplt.plot(pulsar_of_interest.lightcurve.phase_list, pulse_fold_barycenter)\nplt.xlabel(\"Phase\")\nplt.ylabel(\"Count\")\n
    Text(0, 0.5, 'Count')\n

    np.save(\"pulsar_vec.npy\", np.asarray(photon_vec))\n
    "},{"location":"components/3__custom_event_generation/ceg_overview/#hardware-in-the-loop-sdrs","title":"Hardware In The Loop (SDRs)","text":"

    In this notebook, we will walk through setup and operation of SDRs to transmit pulse train data for pulsar signal simulation.

    "},{"location":"components/3__custom_event_generation/ceg_overview/#checking-sdr-connectivity","title":"Checking SDR Connectivity","text":"

    To start, it is necessary to make sure you have successfully mounted the SDRs to your PC via USB. You can check this by executing the following commands in a command prompt:

    # ping 192.168.2.1\n# ping 192.168.2.2\n

    For each of these commands, you should see four data packets successfully sent to the SDR and received back by the PC.

    Next, it will be necessary to check that both SDRs can transmit and receive data to themselves. You can do so by executing the following code. Before running this code, make sure both SDRs are mounted to your PC and have been pinged successfully, and that each one has a BNC cable connecting its Rx port to its Tx port.

    import numpy as np\nimport adi\nimport matplotlib.pyplot as plt\nimport sdr_io\n\nsample_rate = 1e6 # Hz\ncenter_freq = 915e6 # Hz\n\ntx_data = np.load('test_vec.npy')\ntx_length = 5000\n\nplot_rx_pulse_train = True\nplot_rx_samples = True\nplot_fft = True\ncheck_fid = True\n\nsdr1 = \"ip:192.168.2.1\"\nsdr2 = \"ip:192.168.2.2\"\n\nsdr_io.sdr_tx_rx(sample_rate,center_freq,\n                 sdr1,sdr1,\n                 tx_data,tx_length,\n                 False,False, False, False)\n\nsdr_io.sdr_tx_rx(sample_rate,center_freq,\n                 sdr2,sdr2,\n                 tx_data,tx_length,\n                 False,False, False, False)\n

    Now that you have verified both SDRs can transmit and receive data to and from your PC, connect the Tx port of the \"X-RAY EMITTER\" SDR to the Rx port of the \"X_RAY DETECTOR\" SDR and execute the following code. This will transmit the same test pulse as above, but between the two SDRs instead of within each one.

    sdr_io.sdr_tx_rx(sample_rate,center_freq,\n                 sdr1,sdr2,\n                 tx_data,tx_length,\n                 plot_rx_pulse_train,plot_rx_samples,plot_fft,check_fid)\n

    Out of phase by 1141\nSuccess! Perfect Transmission!\n

    Once you have verified that the SDRs can communicate with one another, you are ready to proceed with data transmission.

    "},{"location":"components/3__custom_event_generation/ceg_overview/#transmitting-pulsar-simulation-data","title":"Transmitting Pulsar Simulation Data","text":"

    After generating a pulse train from the OpenXNAV software, transmit it from the \"Emitter\" SDR to the \"Detector\" SDR by loading it through the code below.

    tx_data_name = \"pulsar_vec.npy\" # insert filename for pulse train here\ntx_data = np.load(tx_data_name)\ntx_data = tx_data[:5000]\ntx_length = len(tx_data)\n\nplot_rx_samples = True # once connectivity and fidelic transmission is verified,\n                        # this is redundant\nplot_fft = True # no longer concerned with freq domain - only concerned \n                        # with transmitted pulses\ncheck_fid = True # we have already verified connectivity - no need to check again\nprint(\"Transmitted data\")\nplt.plot(tx_data)\nplt.show()\nprint(\"Received data\")\nsdr_io.sdr_tx_rx(sample_rate,center_freq,\n                 sdr1,sdr2,\n                 tx_data,tx_length,\n                 plot_rx_pulse_train,plot_rx_samples,plot_fft,check_fid)\n
    Transmitted data\n

    Received data\n

    Out of phase by 2890\nSuccess! Perfect Transmission!\n
    "},{"location":"components/3__custom_event_generation/sdr_demo/","title":"Pulse Transmission between Software-Defined Radios (SDRs)","text":"

    In this notebook, we will walk through setup and operation of SDRs to transmit pulse train data for pulsar signal simulation.

    "},{"location":"components/3__custom_event_generation/sdr_demo/#checking-sdr-connectivity","title":"Checking SDR Connectivity","text":"

    To start, it is necessary to make sure you have successfully mounted the SDRs to your PC via USB. You can check this by executing the following commands in a command prompt:

    # ping 192.168.2.1\n# ping 192.168.2.2\n

    For each of these commands, you should see four data packets successfully sent to the SDR and received back by the PC.

    Next, it will be necessary to check that both SDRs can transmit and receive data to themselves. You can do so by executing the following code. Before running this code, make sure both SDRs are mounted to your PC and have been pinged successfully, and that each one has a BNC cable connecting its Rx port to its Tx port.

    import numpy as np\nimport adi\nimport matplotlib.pyplot as plt\nimport sdr_io\n\nsample_rate = 1e6 # Hz\ncenter_freq = 915e6 # Hz\n\ntx_data = np.load('test_vec.npy')\ntx_length = 5000\n\nplot_rx_pulse_train = True\nplot_rx_samples = True\nplot_fft = True\ncheck_fid = True\n\nsdr1 = \"ip:192.168.2.1\"\nsdr2 = \"ip:192.168.2.2\"\n\nsdr_io.sdr_tx_rx(sample_rate,center_freq,\n                 sdr1,sdr1,\n                 tx_data,tx_length,\n                 False,False, False, False)\n\nsdr_io.sdr_tx_rx(sample_rate,center_freq,\n                 sdr2,sdr2,\n                 tx_data,tx_length,\n                 False,False, False, False)\n

    Now that you have verified both SDRs can transmit and receive data to and from your PC, connect the Tx port of the \"X-RAY EMITTER\" SDR to the Rx port of the \"X_RAY DETECTOR\" SDR and execute the following code. This will transmit the same test pulse as above, but between the two SDRs instead of within each one.

    sdr_io.sdr_tx_rx(sample_rate,center_freq,\n                 sdr1,sdr2,\n                 tx_data,tx_length,\n                 plot_rx_pulse_train,plot_rx_samples,plot_fft,check_fid)\n

    Out of phase by 1141\nSuccess! Perfect Transmission!\n

    Once you have verified that the SDRs can communicate with one another, you are ready to proceed with data transmission.

    "},{"location":"components/3__custom_event_generation/sdr_demo/#transmitting-pulsar-simulation-data","title":"Transmitting Pulsar Simulation Data","text":"

    After generating a pulse train from the OpenXNAV software, transmit it from the \"Emitter\" SDR to the \"Detector\" SDR by loading it through the code below.

    tx_data_name = \"pulsar_vec.npy\" # insert filename for pulse train here\ntx_data = np.load(tx_data_name)\ntx_data = tx_data[:5000]\ntx_length = len(tx_data)\n\nplot_rx_samples = True # once connectivity and fidelic transmission is verified,\n                        # this is redundant\nplot_fft = True # no longer concerned with freq domain - only concerned \n                        # with transmitted pulses\ncheck_fid = True # we have already verified connectivity - no need to check again\nprint(\"Transmitted data\")\nplt.plot(tx_data)\nplt.show()\nprint(\"Received data\")\nsdr_io.sdr_tx_rx(sample_rate,center_freq,\n                 sdr1,sdr2,\n                 tx_data,tx_length,\n                 plot_rx_pulse_train,plot_rx_samples,plot_fft,check_fid)\n
    Transmitted data\n

    Received data\n

    Out of phase by 2890\nSuccess! Perfect Transmission!\n
    "}]} \ No newline at end of file diff --git a/site/sitemap.xml.gz b/site/sitemap.xml.gz index 8bb091bdedc84a771c3a1b83464400183bf84c34..3c740e007d7b3383b1e87af997cfe854fe77f6a4 100644 GIT binary patch delta 12 Tcmb=gXOr*d;IJy1$W{pe7ODe# delta 12 Tcmb=gXOr*d;Mf{Bk*yK{7{LSL