Design Problem

I'm having some trouble with design at the moment. I guess one of my questions is: Can a problem always be solved using object oriented design? Let me explain the system to you and then I'll elaborate on where I'm having trouble.

I'm writing software to determine the attitude of an aircraft (how it is oriented in 3d space - i.e. bank angle etc.) using an array of GPS receivers. Here are some of the objects I've identified:

1. Satellite: There are m of these
2. Receiver: Receives GPS signals from m space vehicles and outputs measurement data and navigation data. There are n receivers.
3. Baseline: Represents the line vector between between the primary receiver and any secondary receiver. So for n receivers there are n-1 baselines.
4. User: In this case the aircraft. Such attributes would include: position, velocity and attitude.

So in my head I've been saying this:

A user 'has n-1 baselines'.
A baseline 'has 2 receivers' (1 primary and one secondary)

Which I've taking in programming terms to be:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class User{
   ...
   Receiver recs[n];
   Baseline baselines[n-1];
   ...
   //Class User will have to give receiver pointers to the baselines.
}

class Baseline{
   ...
   Receiver* primRec;
   Receiver* secRec;
   ...
}

class Receiver{
   ...
}


Now I guess why this is causing me some trouble is because the data is coming into the receivers. To solve for the attitude, data from 2 receivers needs to be combined in the baseline and then data from n-1 baselines need to be combined to get the final attitude solution.

So as you can see, data is floating "up". I'm not used to this.

The event which should trigger the software to attempt to get an attitude solution is when the primary receiver obtains a nav message. So then the primary receiver would have to let all of the baselines know it has the nav message. Then the baselines would have to get data from the receivers and perform some calculations on the data. Then the baselines would need to pass that data to user, where the data from each baseline is used in calculations to determine the attitude of the aircraft, which is then stored in a private variable in the User class.

So this would require that the primary receiver holds pointers to the baselines it is part of or pointers to functions ('eventHandlers') in these Baseline instances. Then further, each baseline would need a pointer to the user object or a function of that user object. So pretty much, it is a mess.

From experience, things are simpler when data flows down - i.e. data would come in at user and filter down the hierarchy. However this can't happen here - or at least I can't see how that would happen here.

Sorry for the long post. Any general guidance would be really appreciated. It just feels weird having so much circular dependency - I think that is what you call it.

So:

1. Does the messy/complicated solution I posted seem reasonable?
2. Should I move away from OOP for this problem?

Again, any help would be greatly appreciated.

Nick.
I'm a little unclear on some concepts here. Mainly what the baselines are supposed to be. From your description you say it's just a vector -- but then you have it doing things like processing and sending messages. Why would a vector do that? Wouldn't the receivers be doing that?

So I guess I don't understand the difference between the receivers and the baselines.

As for your current approach, I find it questionable. Mainly because you give the User ownership of the Receivers, which doesn't really make much sense (if the User is an airplane, that would imply the receivers are on or are part of the airplane, which they're clearly not).

As for your two questions:

1. It seems doable. And I think that any scenario that has two-way communication between objects is going to get a little mussy. However I think you could definitely clean it up a bit.

2. I would try to stick with OOP. OOP is more difficult to design for, but it makes the code easier to write and maintain. A little more work now will save you a lot of work later. I don't see why OOP should be avoided here.


I'd like to help with the design more, as this is quite interesting. If you can bare with me and explain a bit more about exactly what the baselines are, I'd appreciate it.
Last edited on
Thanks Disch!

You're correct about the baselines. A baseline is just a line vector between two receivers. So I agree with you that they shouldn't be doing any processing/message sending. I'll get back to this after I clear up some other things.

The receivers are on the aeroplane - sorry I didn't really make that clear initially. There are n receivers placed on the aircraft; for example if n = 3 we might have a receiver on each wing and one somewhere near the tail.

So for 3 receivers there are two baselines - graphically a baseline is a line between the primary receiver and a secondary receiver (for this discussion take the receiver near the tail to be the primary receiver).

Now, each receiver has a thread. They are always reading signals sent from satellites and storing the measurement data in private members. So each receiver stores measurement data from m satellites; I store this data in a structure: MeasData. For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//File: Receiver.h

struct MeasData {
   ...
}

class Receiver{

   vector<MeasData> measData;
   double xBodyPos;
   double yBodyPos;
   double zBodyPos;
   HANDLE threadHandle;
   ...

   public:

   Receiver(double xBP, double yBP, double zBP)
   : measData(m), //Initialise measData vector, set size to m.
     xBodyPos(xBP),
     yBodyPos(yBP),
     zBodyPos(zBP)
   {}
   ...
}

unsigned _stdcall threadFunction(void * params); //This "continuously" reads in data from the actual receiver (hardware).


So lets have another crack at this, writing it out seems to help today.

The user (aeroplane) has n receivers. A baseline represents the relative position of two receivers (the primary receiver and a secondary receiver). When the primary receiver gets a "NavMessage" we want to try obtain an attitude solution. So "who" does the primary receiver tell solve for the attitude. The User doesn't sound like a bad idea.

So the primary receiver calls User::determineAttitude(). Now the User has to determine the attitude. For each baseline the user will have some calculations to perform between the two receivers "on" that baseline, the results of these calculations should be stored in the baseline object - since the result of the calculation is the baseline vector in another set of axes: There is a known-constant baseline vector which represents the vector between two receivers in the body axes (axes fixed to the user body), and then there is the baseline vector whose components change as the orientation of the aircraft changes - this baseline vector is measured in the ECEF (Earth-Centered-Earth-Fixed) axes. Once we have determined each baselines ECEF vector, there is one final compuation involving the ecef baselines.

So maybe now you can see why I was doing computation within the Baseline object. Yes the Baseline object is just a line vector between two receivers. But to get that line vector in the ECEF axes we need to perform calculations which involve data from the two receivers "on" that baseline. However, it does seem simpler to have the event handler in the user object.

Sorry this post has been so long, I've really just been typing my thoughts. I guess some of issues brought up are:

1. Is the baseline an object which has two receivers. Or is it a relationship between two receivers. I'm not sure what this would mean in terms of OOP. Maybe you can tell me if there is a different.

2. If the primary receiver triggers an event it seems like the event handler would be better placed in the user class, since the User owns the Receiver - the baselines do not own their receivers.

Is it possible I am trying to "objectise" (I just made that word up) too much? Like should Baseline just be a struct containing two Receiver pointers? After writing this is seems like there are really only two objects; the user (User) and the receivers (Receiver).

Seems a little bit easier now. I think giving the User control of the solution process as early as possible cleans things up a little bit.

Any thoughts?

Nick.
The receivers are on the aeroplane - sorry I didn't really make that clear initially.


Okay this is making a lot more sense now. For whatever reason I thought the receivers were on the ground -- but that seems silly now that I think about it XD

Now, each receiver has a thread. They are always reading signals sent from satellites and storing the measurement data in private members. [snip] When the primary receiver gets a "NavMessage" we want to try obtain an attitude solution.


Okay so if I'm understanding this right:

- The receiver gets the nav message from the satellite
- In response to this, all other receivers must be polled and attitude solution must be calculated
- The calculated value(s) ultimately needs to find their way to ... the user? Or do they go back to the satellite? (The user makes more sense)

1. Is the baseline an object which has two receivers. Or is it a relationship between two receivers. I'm not sure what this would mean in terms of OOP. Maybe you can tell me if there is a different.


If the baseline is just a vector then it should just be a vector... that is, nothing but x,y,z values specifying orientation and magnitude (and maybe some helper functions and overloaded operators). A vector doesn't need to know anything about receivers or users or satellites.

2. If the primary receiver triggers an event it seems like the event handler would be better placed in the user class, since the User owns the Receiver - the baselines do not own their receivers.


Yeah see the Baselines don't own anything because they're just a measurement. I think you're way overcomplicating this by including them as part of the equation.


Here's my first take on it:

- class Vector which just has X,Y,Z. Probably as doubles -- or better yet make it a template.

- class Receiver which has an event queue, manages its own thread, communicates with the satellites, etc, etc.

- class PrimaryReceiver, derived from Receiver. This class would own other Receivers, as well as Vectors to have the baselines. It would also have a pointer to its own (the User)

- class User, owns a single PrimaryReceiver.



The way I see it, when PrimaryReceiver gets the nav message, it polls each of the other Receivers, calculates whatever info needs to be calculated, and sends the result to to the User (via a function or some event system)



It does make more sense for the User to own the Receivers though.... so maybe my approach doesn't really make sense.

Maybe instead of naming it "PrimaryReceiver" you could name it "GPS" or something, but have it do the same thing. Then it makes more sense for it to own the receivers.
Last edited on
Disch you are a genius! You are right, PrimaryReceiver is the key! This will significantly improve the implementation. The primary receiver is the parent of the other receivers! I'm such an idiot. Thanks so much for this!

On another note. You've probably answered 90% of my questions on this forum. The time you've spend helping me and other is much appreciated. I hope one day I can start putting back into this forum - I've got a lot more to learn before that can happen.

I'll reply to this thread in a couple days to let you know how it turns out. I'm pretty excited about your idea though.

Thanks again!

Nick.
I'm happy to help =)
Topic archived. No new replies allowed.