C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Downcast vermeiden durch besseres Design ?

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (German)
View previous topic :: View next topic  
Author Message
Guest






PostPosted: Tue Mar 20, 2007 12:01 am    Post subject: Downcast vermeiden durch besseres Design ? Reply with quote



Hallo zusammen,
ich versuche gerade einen Kalman Filter in C++ zu implementieren, habe
allerdings noch (Design) Problem.
Nachfolgend mein aktueller Code: ( Man möge mir evt. Syntaxfehler
verzeihen, ich habe die Klassen für
das Posting gekürzt )

class ExtendedKalmanFilter
{
public:
ExtendedKalmanFilter( const unsigned int& numStates );
virtual ~ExtendedKalmanFilter( );

void executePredictionStep( const KalmanFilterControlVector& u );
{
// Die Referenz zu den benötigten Matritzen bestimmen
KalmanFilterStateVector& x = onGetStateVector( );
KalmanFilterLinearisedSystemModel& A = onGetLinearisedSystemModel( );

// 1.) Das linearisierte System Model [A] aktualisieren
A.updateSystemModel( x, u );

// ...Snip...
}

protected:
// Den State Vector [x] anfordern
virtual KalmanFilterStateVector& onGetStateVector( ) = 0;

// Das Linearisierte System Model [A] anfordern
virtual KalmanFilterLinearisedSystemModel&
onGetLinearisedSystemModel( ) = 0;
};


class SixStateExtendedKalmanFilter
: public ExtendedKalmanFilter
{
public:
SixStateExtendedKalmanFilter( );
virtual ~SixStateExtendedKalmanFilter( );


private:
// Den State Vector [x] anfordern
KalmanFilterStateVector& onGetStateVector( );

// Das Linearisierte System Model [A] anfordern
KalmanFilterLinearisedSystemModel& onGetLinearisedSystemModel( );


private:
SixStateExtendedKalmanFilterStateVector m_x;
SixStateExtendedKalmanFilterLinearisedSystemModel m_A;

};


class KalmanFilterLinearisedSystemModel
: public Matrix
{
public:
KalmanFilterLinearisedSystemModel( const unsigned int& numStates );
virtual ~KalmanFilterLinearisedSystemModel( );

// Das linearisierte System Model aktualisieren. Die Inputs sind:
// - State Vector [x]
// - Control Vector [u]
virtual void updateSystemModel( const KalmanFilterStateVector& x,
const KalmanFilterControlVector& u ) = 0;
};


class SixStateExtendedKalmanFilterLinearisedSystemModel
: public KalmanFilterLinearisedSystemModel
{
public:
SixStateExtendedKalmanFilterLinearisedSystemModel( );
virtual ~SixStateExtendedKalmanFilterLinearisedSystemModel( );

// Das linearisierte System Model aktualisieren. Die Inputs sind:
// - State Vector [x]
// - Control Vector [u]
void updateSystemModel( const KalmanFilterStateVector& x, const
KalmanFilterControlVector& u )
{
// Die Elemente aus dem State Vector auslesen
//const double phi = x.getElement( 0, 0 );
//const double theta = x.getElement( 0, 1 );
//const double psi = x.getElement( 0, 2 );
// Ein direkter Zugriff auf die Matrix Elemente ist nicht so
toll...

// Tue etwas sinnvolles...
}
};


class KalmanFilterStateVector
: public Matrix
{
public:
KalmanFilterStateVector( const unsigned int& numStates );
virtual ~KalmanFilterStateVector( );
};


class SixStateExtendedKalmanFilterStateVector
: public KalmanFilterStateVector
{
public:
SixStateExtendedKalmanFilterStateVector( );
virtual ~SixStateExtendedKalmanFilterStateVector( );

double getPhi( ) const
{
return getElement( 0, 0 );
}

double getTheta( ) const
{
return getElement( 0, 1 );
}

double getPsi( ) const
{
return getElement( 0, 2 );
}
};


Meine Idee zu dem Design war folgende:
Der Kalman Filter benötigt unterschiedliche Matritzen und Vektoren
( StateVector, ControlVector, SystemModel und einige mehr ).
Die konkreten Implementierungen dieser Matrizten ist bei jedem Filter
unterschiedlich. Aus diesem Grund habe ich für all diese
Matritzen Basisklassen eingeführt. Mein konkreter Kalman Filter
(SixStateExtendedKalmanFilter) hat nun eine passende Anzahl von
Klassen die sich alle von ihren Basisklassen ableiten und die konkrete
Filter Implementierung besitzen.

Die Gemeinsamkeit verschiedener Kalman Filter ist der Algorithmus
( wann muss, in welcher Reihenfolge, welche Matrix angewendet
werden ).
Ein Teil des Algorithmus steckt in der executePredictionStep()
Methode. In der Methode werden die virtuelle Methoden aufgerufen,
die im SixStateExtendedKalmanFilter definiert sind. Diese geben die
Basisklassen Referenzen auf die Matritzen zurück. Im weiteren
Verlauf wird die updateSystemModel() Methode aufgerufen. Die Methode
bekommt eine Referenz auf die Basisklassen übergeben.
Genau hier liegt mein Problem, denn innerhalb der updateSystemModel()
Methode würde ich gerne auf die Methoden der abgeleiteten
Klasse zugreifen ( getPhi(), getTheta(), getPsi() ).

Ein einfacher Weg wär sicher ein dynamic_cast. Das gefällt mir jedoch
nicht so gut weil ein cast oft für ein schlechtes Design
spricht ( Ja, manchmal muss man casten, aber oft lässt es sich
vermeiden Smile )

Eine andere Möglichkeit wäre es für die Basisklasse des
KalmanFilterStateVector eine virtuelle Methode zu finden, die
allgemein
genug ist, um alle möglichen Kalman Filter abzudecken. So eine Methode
gibt es aber nicht denke ich, da die Filter zu unterschiedlich
sein können.

Dann habe ich noch an das Visitor Pattern gedacht. Das klappt aber
auch nicht, da der Visitor dann die Konkrete Implementierung
des KalmanFilterStateVector kennen muss.

Irgendwie ist der Wurm drin Smile Da ich sicher nicht der erste bin der
so ein Problem hat, hoffe ich das ihr mir ein paar Denkanstösse
geben könnt. Vielleicht ist mein bisheriger Ansatz auch einfach nur
"Müll" vielleicht habt ihr bessere Ideen ?


Danke sagt
Markus
Back to top
Guest






PostPosted: Wed Mar 21, 2007 9:59 am    Post subject: Re: Downcast vermeiden durch besseres Design ? Reply with quote



Hat niemand eine Idee oder war es zu undeutlich beschrieben ?

Gruss
Markus
Back to top
Guest






PostPosted: Mon Mar 26, 2007 6:53 pm    Post subject: Re: Downcast vermeiden durch besseres Design ? Reply with quote



On 21 Mrz., 06:59, DesignPatt...@web.de wrote:
Quote:
Hat niemand eine Idee oder war es zu undeutlich beschrieben ?

Gruss
Markus

Hallo Markus,

das ganze klingt als würdest du spezialiserte Methoden aufrufen
wollen, abhängig von den konkreten Klassen. Vielleicht kannst du das
ganze mit einem Template angehen, bei dem du die Funktion
spezialisierst.

Eventuell etwas in der Art:
template <typename T>
void updateSystemModel(T& mydata)
{
// do stuff
}

Möglicherweise ist es auch ein DoubleDispatch-Problem? Ich kann es
ehrlich gesagt nicht aus deiner Beschreibung entnehmen Wink
http://en.wikipedia.org/wiki/Double_dispatch

Gruß

Georg
Back to top
Marcel Müller
Guest





PostPosted: Fri Mar 30, 2007 12:34 am    Post subject: Re: Downcast vermeiden durch besseres Design ? Reply with quote

DesignPattern (AT) web (DOT) de wrote:
Quote:
Hat niemand eine Idee oder war es zu undeutlich beschrieben ?

Vielleicht war es nicht auf das Wesentliche reduziert. Also kurz hinter
"class ExtendedKalmanFilter" habe ich aufgehört zu lesen.

Falls das Problem wiklich so speziell ist, dass man die Semantik eines
Kalman-Filters dafür kennen muss, kann ich nicht helfen.
Andernfalls will ich nicht, weil der Code für mich zu unverständlich
ist. Die Identifier lesen sich für mich so gut wie zufällige Zeichenfolgen.


Marcel
Back to top
Thorsten Nitz
Guest





PostPosted: Sat Mar 31, 2007 8:38 pm    Post subject: Re: Downcast vermeiden durch besseres Design ? Reply with quote

DesignPattern (AT) web (DOT) de schrieb:

[ jede Menge Code ]

Den Zweck Deiner Architektur habe ich nicht sicher ergründen können.
Hier meine Anmerkungen zu dem, was ich verstanden zu haben glaube.

Quote:
Meine Idee zu dem Design war folgende:
Der Kalman Filter benötigt unterschiedliche Matritzen und Vektoren
( StateVector, ControlVector, SystemModel und einige mehr ).
Die konkreten Implementierungen dieser Matrizten ist bei jedem Filter
unterschiedlich.

Nein, das glaube ich nicht. Die in den Matrizen gespeicherten
Zahlenwerte sind bei jedem Filter verschieden. Die Art und Weise, wie
auf sie zugrgriffen wird, ist traditionell immer gleich: mit zwei
Integer-Zahle für die Zeile und die Spalte. Entsprechend für die
Vektoren. Somit gibt es mindestens ein gemeinsames Interface.

Quote:
Die Gemeinsamkeit verschiedener Kalman Filter ist der Algorithmus
( wann muss, in welcher Reihenfolge, welche Matrix angewendet
werden ).

Genau. Weitere Gemeinsamkeit in Deinem Code sind die Gesetze der
Linearen Algebra, nach denen Matrizen mit zwei Indizes indiziert werden,
Vektoren mit einem, und die Vorschrift für die Multiplikation zwischen
Matrix und Vektor.

Quote:
Ein Teil des Algorithmus steckt in der executePredictionStep()
Methode. In der Methode werden die virtuelle Methoden aufgerufen,
die im SixStateExtendedKalmanFilter definiert sind.

In dieser Methode wird ein im Filter gespeicherter Vektor mit einer
ebenfalls gespeicherten Matrix multipliziert. Da braucht es nichts
virtuelles.

Quote:
Diese geben die
Basisklassen Referenzen auf die Matritzen zurück. Im weiteren
Verlauf wird die updateSystemModel() Methode aufgerufen. Die Methode
bekommt eine Referenz auf die Basisklassen übergeben.
Genau hier liegt mein Problem, denn innerhalb der updateSystemModel()
Methode würde ich gerne auf die Methoden der abgeleiteten
Klasse zugreifen ( getPhi(), getTheta(), getPsi() ).

Wo kommen die Name Phi, Theta, Psi her? Die Elemente eines Vektors
heißen "0", "1", "2" usw.

Wenn Phi, Psi und Theta Namen aus der Anwendungswelt sind, so braucht
die Kalman-Filter-Implementierung sie nicht zu kennen. Verpacke Deine
Anwendungsdaten so, dass sie von außen unter den Anwendugsnamen und im
Filter in der mathematischen Index-Schreibweise sichtbar sind.

Möglicherweise ist sogar die Information, dass ein Kalman-Filter
eingesetzt wird, aus Anwendungssicht ein Implementationsdetail.

Ich denke an etwa folgende Programmstruktur:

struct Messdaten {
double phi, psi, theta;
}

struct Ergebnis {
double schuhgroesse, taillenweite, alter;
}

// Berechnet Schuhgröße, Alter und Taillenweite aus drei
// Peilwinkeln
class Schuhgeschaeft
{
private:
KalmanFilter* myFilter;

public:
Schuhgeschaeft()
{ // Hier wird der Kalmanfilter problemgerecht aufgesetzt.
// Die Matrixelemente ergeben sich aus den fachlichen
// Anforderungen.
Matrix stateChangeMatrix( 3 ); // 3 Zeile, 3 Spalten
stateChangeMatrix.set(0, 0, 47.11 ); // Setze Elemente
// ...
Matrix transformMatrix( 3 );
transformMatrix.set( 0, 0, 3.14 );
// ...

myFilter = new KalmanFilter( 3, // Dimension des linearen Modells
stateChangeMatrix,
transformMatrix );
}

void verarbeiteMessdaten( Messdaten md )
{
Vector v(3);
v[0] = md.phi;
v[1] = md.psi;
v[2] = md.theta;
myKalmanFilter->processNextElement( v );
}

Ergebnis wasKommtRaus()
{
Ergebnis e;
Vector v = myKalmanFilter->getInternalState();
e.schuhgroesse = v[0];
e.taillenweite = v[2];
e.alter = v[1];
return e;
}
};

Mit diesem Design schreibst Du Matrix, Vector und KalmanFilter in Deinem
Leben nur einmal. Die Abbildung der FAchlichkeit auf die mathematische
Methodik musst Du in jedem Fall programmieren. Hier hast Du alles
beisammen in der Klasse Schuhgeschaeft.

Tschö, wa!
Thorsten
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (German) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.