Nächsten Wert aus Tabelle suchen
-
Servus,
ich habe eine Tabelle mit Messwerten, welche ich nicht sortieren darf.
Eon -> f(U,I,T)
Jetzt versuche ich bei einem bestimmten Arbeitspunkt, den nächstliegenden Wert aus der Tabelle auszulesen. Das funktioniert aber nicht wirklich.int CSVInterface::FindTransferCharacter(int size, double* aT,double* aU,double* aI,double dT,double dU,double dI) { // double* T - Array Temperatur // double* U - Array Spannung // double* I - Array Strom // double T - Arbeitspunkt Temperatur // double U - Arbeitspunkt Spannung // double I - Arbeitspunkt Strom int i; int n1=0; double F1,F2; vector<double> dF; dF.resize(size,0); for(i=0;aT[i]!=0;i++) { if((abs(dT-aT[i]) == 0) && (abs(dU-aU[i]) == 0) && (abs(dI-aI[i]) == 0)) { return i; } else if((abs(dT-aT[i]) == 0) && (abs(dU-aU[i]) == 0)) { F1 = (dI-aI[i]); F2 = (dI-aI[n1]); } else if((abs(dT-aT[i]) == 0) && (abs(dI-aI[i]) == 0)) { F1 = (dU-aU[i]); F2 = (dU-aU[n1]); } else if((abs(dU-aU[i]) == 0) && (abs(dI-aI[i]) == 0)) { F1 = (dT-aT[i]); F2 = (aT[n1]); } else if(abs(dT-aT[i]) == 0) { F1 = (dU-aU[i]) * (dI-aI[i]); F2 = (dU-aU[n1]) * (dI-aI[n1]); } else if(abs(dU-aU[i]) == 0) { F1 = (dT-aT[i]) * (dI-aI[i]); F2 = (dT-aT[n1]) * (dI-aI[n1]); } else if(abs(dI-aI[i]) == 0) { F1 = (dT-aT[i]) * (dU-aU[i]); F2 = (dT-aT[n1]) * (dU-aU[n1]); } else { F1 = (dT-aT[i]) * (dU-aU[i]) * (dI-aI[i]); F2 = (dT-aT[n1]) * (dU-aU[n1]) * (dI-aI[n1]); } // if if(dF[i] < dF[n1]) n1 = i; if(i==0) dF[i] = F1; else dF[i] = abs(abs(F1) - abs(F2)); } // for n1=0; for(i=0;aT[i]!=0;i++) { cout << dF[i] << endl; } cout << "-> " << n1 << "\t" << dF[n1] << endl; return n1; }Was ich hier tu ist:
1. Eine Raum, Fläche, Länge errechnen durch die Entfernung des Parameter und der Tabellenwerte
F1 = (dT-aT[i]) * (dU-aU[i]) * (dI-aI[i]);
F2 = (dT-aT[n1]) * (dU-aU[n1]) * (dI-aI[n1]);
2. Der kleinste Raum(Fläche,Länge) gibt das nächstliegende Wertepaar an.
Es liefert aber nicht die richtigen Werte!Gibt es eine andere Möglichkeit dieses Ziel zu erreichen. Wie wird das bei LookUp Tabellen gemacht.
-
hi,
Verständnisfrage zu:for(i=0;aT[i]!=0;i++) {
if((abs(dT-aT[i]) == 0) && (abs(dU-aU[i]) == 0) && (abs(dI-aI[i]) == 0)) {
return i;Diese if ist nur dann erfüllt, wenn das Tripel (dT, dU, dI) auch tatsächlich in den Vektoren aT etc enthalten ist. Dasselbe gilt für die anderen if's. Trifft das zu?
Zum Verständis deines Problems könnte auch ein kleines Zahlenbeispiel, was du hier einstelltst, beitragen
Grüsse von Ney
-
Stimmt.
Zuerst wird überprüft, ob der Arbeitspunkt mit den Tabellenwerten übereinstimmt. Das mach ich für drei, zwei und einen Wert.
Ohne diese Abfrage würde z.B. (dT-aT[i]) zu Null werden und deshalb
F1 = (dT-aT[i]) * (dU-aU[i]) * (dI-aI[i]) zu Null.Was nicht funktioniert, ist das bei der Suche oft ein falscher Messwert zurückgegeben wird.
Ich versuche halt den Messwert zu finden, der die geringste Abweichung zu dem Arbeitspunkt hat. Bei der Suche müssten sich der zweit und drittnächste Punkt ergeben, damit ich daraus eine Kurve interpolieren und auch extrapolieren kann.
Mathematisch hab ich da keine Probleme mit, aber ich hänge ja schon beim Programmieren, wenn es um die Messwerte finden geht. Gibt es denn kein schlaues Verfahren was mir nicht bekannt ist. Ich habe leider nichts genaues über das Thema LookUpTable gefunden. Aber das scheint mir das richtige zu sein. Zumindest muss man da auch den nächstliegenden Punkt aus einer Tabelle bestimmen können.
-
etsmart schrieb:
Mathematisch hab ich da keine Probleme mit, aber ich hänge ja schon beim Programmieren, wenn es um die Messwerte finden geht. Gibt es denn kein schlaues Verfahren was mir nicht bekannt ist. Ich habe leider nichts genaues über das Thema LookUpTable gefunden. Aber das scheint mir das richtige zu sein. Zumindest muss man da auch den nächstliegenden Punkt aus einer Tabelle bestimmen können.
Um den nächstliegenden Punkt zu finden, musst Du alle Punkte abfragen und bewerten, zumal sie nach Deiner Aussage nicht sortiert sind. Eine andere Möglichkeit gibt es nicht.
etsmart schrieb:
Was nicht funktioniert, ist das bei der Suche oft ein falscher Messwert zurückgegeben wird.
Ein Zahlenbeispiel wäre hilfreich. Obwohl ich meine, dass es an Deiner Methode liegt, den 'Raum' zu bestimmen. Mal angenommen, Du hast zwei Punkte
1.) T=23C U=220V I=50mA=0.05A
2.) T=23C U=300V I=60mA=0.06A
weiter hast Du einen Wert sagen wir mal bei
T=23C U=221V I=0.05A
dieser liegt doch wohl 'näher' an 1.) als an 2.), aber Deine Raum-Berechnung ergibt:
1.) |220-221| = 1 T und I sind gleich, werden also nicht berücksichtigt und
2.) |300-221| * |0.06-0.05| = 0.79
also ist der Raum bei 2.) kleiner als bei 1.), was aber offensichtlich falsch ist.Ich würde Dir vorschlagen, die Werte für T, U und I auf einen sinnvollen Bereich zu normieren, so dass die einzelnen Werte immer im Bereich von 0 bis 1 liegen und dann die Quadratsumme dieser normierten Werte zu bestimmen.
In C++ gibt es für eine solche Suche den Algorithmus min_element, der aber mit einem Iterator-Paar arbeitet. Du hast als Input aber drei (Paare) von Iteratoren bzw. Pointern. Wenn Du die Messwerte in eine Struktur (z.B. TUI) zusammenfasst, so könnte der Code so aussehen:
int /*CSVInterface::*/FindTransferCharacter( int size, TUI* aTUI, TUI dTUI ) { return std::min_element( aTUI, aTUI + size, LessEON( dTUI ) ) - aTUI; }LessEON ist ein Funktor, der zwei Mess-(TUI-)Werte vergleicht; etwa so
class LessEON { public: explicit LessEON( const TUI& tui ) : m_ref( tui ) {} // -- liefert 'true' falls a näher an m_ref liegt, als b bool operator()( const TUI& a, const TUI& b ) const { return abstand( a - m_ref ) < abstand( b - m_ref ); } private: TUI m_ref; };so und jetzt fehlt nur noch die TUI-Struktur, mit der man rechnen kann
struct TUI // Tripel Temperatur, Spannung, Strom { TUI( double t, double u, double i ) : m_T( t ), m_U( u ), m_I( i ) {} TUI operator-( const TUI& b ) const { return TUI( m_T - b.m_T, m_U - b.m_U, m_I - b.m_I ); } friend double abstand( const TUI& tui ) { // das wäre der Raum-Algorithmus .. if( tui.m_T == 0.0 && tui.m_U == 0.0 && tui.m_I == 0.0 ) return 0.0; double erg = 1.0; if( tui.m_T != 0.0 ) erg *= std::abs( tui.m_T ); if( tui.m_U != 0.0 ) erg *= std::abs( tui.m_U ); if( tui.m_I != 0.0 ) erg *= std::abs( tui.m_I ); return erg; } private: double m_T, m_U, m_I; };alternativ dazu - normierte Werte in TUI vorausgesetzt
friend double abstand( const TUI& tui ) { return tui.m_T * tui.m_T + tui.m_U * tui.m_U + tui.m_I * tui.m_I; }Gruß
Werner