-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
420 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,7 +20,7 @@ | |
* Orbital Object ToolKit. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
import { RaeVec3, SpaceObjectType } from '../types/types'; | ||
import { Degrees, Kilometer, RaeVec3, SpaceObjectType } from '../types/types'; | ||
|
||
import { BaseObject } from './base-object'; | ||
import { Sat } from './sat'; | ||
|
@@ -31,12 +31,42 @@ interface ObjectInfo { | |
lat: number; | ||
lon: number; | ||
alt: number; | ||
minAz: Degrees; | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
thkruz
Author
Owner
|
||
maxAz: Degrees; | ||
minEl: Degrees; | ||
maxEl: Degrees; | ||
minRng: Kilometer; | ||
maxRng: Kilometer; | ||
} | ||
|
||
export enum PassType { | ||
OUT_OF_VIEW = -1, | ||
ENTER = 0, | ||
IN_VIEW = 1, | ||
EXIT = 2, | ||
} | ||
|
||
type Lookangles = { | ||
type: PassType; | ||
time: Date; | ||
az: number; | ||
el: number; | ||
rng: number; | ||
maxElPass?: number; | ||
}; | ||
|
||
const TAU = Math.PI * 2; | ||
|
||
export class Sensor extends BaseObject { | ||
public lat: number; | ||
public lon: number; | ||
public alt: number; | ||
public minAz: Degrees; | ||
public maxAz: Degrees; | ||
public minEl: Degrees; | ||
public maxEl: Degrees; | ||
public minRng: Kilometer; | ||
public maxRng: Kilometer; | ||
|
||
constructor(info: ObjectInfo) { | ||
// If there is a sensor type verify it is valid | ||
|
@@ -55,6 +85,70 @@ export class Sensor extends BaseObject { | |
|
||
super(info); | ||
|
||
this.validateInputData(info); | ||
} | ||
|
||
private validateInputData(info: ObjectInfo) { | ||
this.validateLla(info); | ||
this.validateFov(info); | ||
} | ||
|
||
private validateFov(info: ObjectInfo) { | ||
if (info.minAz >= 0 && info.minAz <= 360) { | ||
this.minAz = info.minAz; | ||
} else if (typeof info.minAz === 'undefined') { | ||
// Default is a telescope | ||
this.minAz = 0; | ||
} else { | ||
throw new Error('Invalid minimum azimuth - must be between 0 and 360'); | ||
} | ||
|
||
if (info.maxAz >= 0 && info.maxAz <= 360) { | ||
this.maxAz = info.maxAz; | ||
} else if (typeof info.maxAz === 'undefined') { | ||
// Default is a telescope | ||
this.maxAz = 360; | ||
} else { | ||
throw new Error('Invalid maximum azimuth - must be between 0 and 360'); | ||
} | ||
|
||
if (info.minEl >= 0 && info.minEl <= 90) { | ||
this.minEl = info.minEl; | ||
} else if (typeof info.minEl === 'undefined') { | ||
This comment has been minimized.
Sorry, something went wrong.
weedgrease
|
||
// Default is a telescope | ||
this.minEl = 0; | ||
} else { | ||
throw new Error('Invalid minimum elevation - must be between 0 and 90'); | ||
} | ||
|
||
if (info.maxEl >= 0 && info.maxEl <= 180) { | ||
this.maxEl = info.maxEl; | ||
} else if (typeof info.maxEl === 'undefined') { | ||
// Default is a telescope | ||
this.maxEl = 90; | ||
} else { | ||
throw new Error('Invalid maximum elevation - must be between 0 and 180'); | ||
} | ||
|
||
if (info.minRng >= 0) { | ||
this.minRng = info.minRng; | ||
} else if (typeof info.minRng === 'undefined') { | ||
// Default is a telescope | ||
this.minRng = 0; | ||
} else { | ||
throw new Error('Invalid minimum range - must be greater than 0'); | ||
} | ||
if (info.maxRng >= 0) { | ||
this.maxRng = info.maxRng; | ||
} else if (typeof info.maxRng === 'undefined') { | ||
// Default is a telescope | ||
this.maxRng = 50000; // arbitrary large number | ||
} else { | ||
throw new Error('Invalid maximum range - must be greater than 0'); | ||
} | ||
} | ||
|
||
private validateLla(info: ObjectInfo) { | ||
if (info.lat >= -90 && info.lat <= 90) { | ||
this.lat = info.lat; | ||
} else { | ||
|
@@ -83,4 +177,95 @@ export class Sensor extends BaseObject { | |
public getRae(sat: Sat, date: Date = this.time): RaeVec3 { | ||
return sat.getRae(this, date); | ||
} | ||
|
||
public isRaeInFov(rae: RaeVec3): boolean { | ||
if (rae.el < this.minEl || rae.el > this.maxEl) { | ||
return false; | ||
} | ||
|
||
if (rae.rng < this.minRng || rae.rng > this.maxRng) { | ||
return false; | ||
} | ||
|
||
if (this.minAz > this.maxAz) { | ||
// North Facing Sensors | ||
if (rae.az < this.minAz && rae.az > this.maxAz) { | ||
return false; | ||
} | ||
// Normal Facing Sensors | ||
} else if (rae.az < this.minAz || rae.az > this.maxAz) { | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
public isSatInFov(sat: Sat, date: Date = this.time): boolean { | ||
return this.isRaeInFov(this.getRae(sat, date)); | ||
} | ||
|
||
public calculatePasses(planningInterval: number, sat: Sat, date: Date = this.time) { | ||
let isInViewLast = false; | ||
let maxElThisPass = 0; | ||
const msnPlanPasses: Lookangles[] = []; | ||
const startTime = date.getTime(); | ||
|
||
for (let timeOffset = 0; timeOffset < planningInterval; timeOffset++) { | ||
const curTime = new Date(startTime + timeOffset * 1000); | ||
const rae = this.getRae(sat, curTime); | ||
|
||
// Radians to Degrees | ||
rae.az *= 360 / TAU; | ||
rae.el *= 360 / TAU; | ||
|
||
const isInView = this.isRaeInFov(rae); | ||
|
||
if (timeOffset === 0) { | ||
// Propagate Backwards to get the previous pass | ||
const oldRae = this.getRae(sat, new Date(Date.now() - 1 * 1000)); | ||
|
||
isInViewLast = this.isRaeInFov(oldRae); | ||
} | ||
|
||
const type = Sensor.getPassType(isInView, isInViewLast); | ||
|
||
maxElThisPass = Math.max(maxElThisPass, rae.el); | ||
|
||
if (type === PassType.ENTER || type === PassType.EXIT) { | ||
const pass = <Lookangles>{ | ||
type, | ||
time: curTime, | ||
az: rae.az, | ||
el: rae.el, | ||
rng: rae.rng, | ||
}; | ||
|
||
// Only set maxEl for EXIT passes | ||
if (type === PassType.EXIT) { | ||
pass.maxElPass = maxElThisPass; | ||
} | ||
|
||
msnPlanPasses.push(pass); | ||
maxElThisPass = 0; | ||
} | ||
|
||
isInViewLast = isInView; | ||
} | ||
|
||
return msnPlanPasses; | ||
} | ||
|
||
private static getPassType(isInView: boolean, isInViewLast: boolean) { | ||
let type = PassType.OUT_OF_VIEW; | ||
|
||
if (isInView && !isInViewLast) { | ||
type = PassType.ENTER; | ||
} else if (!isInView && isInViewLast) { | ||
type = PassType.EXIT; | ||
} else if (isInView && isInViewLast) { | ||
type = PassType.IN_VIEW; | ||
} | ||
|
||
return type; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`Basic Sensor functionality should create a lookangles array 1`] = ` | ||
Array [ | ||
Object { | ||
"az": 185.0321047837688, | ||
"el": 0.018932126219342378, | ||
"rng": 2320.7003088160936, | ||
"time": 2022-08-25T07:51:46.000Z, | ||
"type": 0, | ||
}, | ||
Object { | ||
"az": 286.6828392807201, | ||
"el": -0.03143720527465417, | ||
"maxElPass": 8.887905466445714, | ||
"rng": 2346.1443165688643, | ||
"time": 2022-08-25T08:00:03.000Z, | ||
"type": 2, | ||
}, | ||
Object { | ||
"az": 126.07032765927691, | ||
"el": 0.011464577747703686, | ||
"rng": 2327.848319797019, | ||
"time": 2022-08-25T09:27:12.000Z, | ||
"type": 0, | ||
}, | ||
Object { | ||
"az": 338.51245540232674, | ||
"el": -0.004776656652769985, | ||
"maxElPass": 28.303560760507143, | ||
"rng": 2353.0795991791333, | ||
"time": 2022-08-25T09:37:34.000Z, | ||
"type": 2, | ||
}, | ||
Object { | ||
"az": 24.30450924794974, | ||
"el": 0.021759132371179508, | ||
"rng": 2365.173163410431, | ||
"time": 2022-08-25T19:22:17.000Z, | ||
"type": 0, | ||
}, | ||
Object { | ||
"az": 230.35934291906204, | ||
"el": -0.029094115923272833, | ||
"maxElPass": 34.603325622933625, | ||
"rng": 2350.6620737684816, | ||
"time": 2022-08-25T19:32:54.000Z, | ||
"type": 2, | ||
}, | ||
Object { | ||
"az": 77.30327662230586, | ||
"el": 0.009671715968386793, | ||
"rng": 2358.781639064529, | ||
"time": 2022-08-25T21:00:08.000Z, | ||
"type": 0, | ||
}, | ||
Object { | ||
"az": 171.14122538519032, | ||
"el": -0.04352163512801034, | ||
"maxElPass": 7.334113831175358, | ||
"rng": 2346.370746417976, | ||
"time": 2022-08-25T21:08:00.000Z, | ||
"type": 2, | ||
}, | ||
] | ||
`; |
Oops, something went wrong.
@thkruz hey there! looking back here as i'm just getting started with your library but could these be marked as optional? further down it looks like there are some default values