Ah. ok. als het "relais en schakelgedoe" al in die verzwakkers zit, dan is het probleem nog inderdaad alleen maar het programmeren.
Dan wordt de code in princiepe:
code:
float verzwakking[] = {16, 1, 2, 4, 8, 0.1, 0.2, 0.4, 0.8, 1, 2, 4, 8};
Ik heb de onderste twee verzwakkers ingevoerd. Als je gaat meten dat de verschillende 1,2,4 verzwakkingen niet precies hetzelfde zijn, voer je DIE natuurlijk in. De 0-e entry is aangekoppeld aan relais-output-0, de 1-e entry aan relais-output-1 enz.
Als je dus de combinatie 0-5-7-9 hebt, dan tel je elementen 16, 0.1, 0.4 en 1 bij mekaar op en krijg je 17.5. Dit coderen we met een bitvector. 2^0 + 2^5 + 2^7 + 2^9 = 0x2a1 (ik reken dat liever in HEX uit, dat vind ik makkelijker).
Ieder getal onder de 8192 is dan dus een combinatie van welke er aan-en-uit zijn. En op basis van de bitjes kan je dan bepalen wat de demping zou zijn bij die combinatie.
code:
float attenuation (int combination)
{
float att;
att = 0.0;
for (i=0;i<13;i++)
if (combination & (1<<i)) att += verzwakking[i];
return att;
}
De simpele zoekmethode is dan:
code:
int find_combination (float wantedvalue)
{
int i, bestcombi;
float bestdiff, diff;
// start with combi 0 as the best combi.
bestdiff = abs (wantedvalue - attenuation (0));
bestcombi = 0;
for (i=1;i<8192;i++) {
diff = abs (wantedevalue - attenuation (i));
if (diff < bestdiff) {
bestcombi = i;
bestdiff = diff;
}
}
return bestcombi;
}
Dit is met 13 relais die aan of uit kunnen staan denk ik nog net te doen. Zeker als je dit een beetje optimaliseert: De demping is eigenlijk een float, maar als je die in "honderste-DB" noteert, dan worden alle db-getallen gewoon een int. Dit vereenvoudigt de boel zodanig dat je arduino die 8000 combinaties wel in ordegrootte 1 sec kan uitrekenen.
Verder, maar dat wordt lastiger programmeren, kan je je realiseren dat je op zoek bent naar de HOOGSTE waarde kleiner dan de gewenste waarde. Daarnaast wil je de KLEINSTE waarde GROTER dan de gewenste waarde weten. Weet je die twee, hoef je alleen maar je kiezen tussen die twee: 1 van deze twee zit het dichts bij de gewenste waarde.
Deze twee waardes opzoeken is logisch gezien precies hetzelfde: Ben je op zoek naar de kleinste waarde groter dan gewenste waarde dan is dat hetzelfde als het complement van hoogste waarde groter dan ALLES_BIJ_MEKAAR-wantedvalue. Efficient 1 van de twee vinden, betekent dat je de andere ook zo kan vinden.
Dan moet je de boel voorstellen als een boom. Op iedere node beslis je of er een bitje aan-of-uit moet. Op het hoogste niveau bit 0, daaronder bit 1 enz.
Zoek je de hoogste waarde kleiner dan de gewenste waarde, dan kan je hele stukken zoek-ruimte uitsluiten zodra je OVER de gewenste waarde heengaat. Het wordt nooit meer minder.
Verder moet het ook mogelijk zijn een grens te stellen aan de andere kant. De zoek-boom wordt zo behoorlijk geknot en je zou dan veel grotere bomen moeten kunnen afzoeken.
Een "super snelle" benadering van de gewenste combinatie kan vast ook door de waardes allemaal te sorteren, en dan "greedy" vanaf de grootste waarde te beginnen, zodra je er overheen gaat neem je dit bitje niet.
Zou je deze truuk vantevoren laten lopen, dan heb je al een heel redelijke schatting. Die moet bij het aflopen van de complete boom al snel grote takken kunnen uitsluiten.
Mocht je verder willen zoeken op dit gebied, het heet "branch and bound".
Anderzijds, al dat afzoeken van complete bomen is denk ik niet zo heel nodig. Dat sorteren en dan grote-stappen-snel-thuis zal al HEEL aardig in de buurt komen. Gooi je er dan nog een: we hebben twee "ongeveer VIER" waardes in de tabel, probeer de andere eens". Dan heb je met zeg 5 nieuwe evaluaties waarschijnlijk een stuk betere oplossing. (als in: in 90% van de gevallen had je al de allerbeste oplossing, maar van de 10% die niet al de optimale was, vind je in 9% van de gevallen zo alsnog de allerbeste).
Dan had jij het over een i2c EEPROM. Dat lijkt me niet nodig. Enerzijds is voor deze toepassing het prima te doen om je array na de meting "voor altijd" in je programma te zetten. Wil je het gaan verkopen en andere mensen hun eigen calibratie er in laten zetten, dan is het minder praktisch, maar voor je eigen situatie is het toch prima dat je 1x JOU calibratiegetallen in je sketch zet?
Vind je dat toch niet, dan heeft de arduino een 256 byte eeprom aan boord.
Ik bedenk me net een andere optie. Doe een heel simpele "greedy" in de arduino. Maar reken ALLE mogelijkheden na op je PC. Reken ook op de PC uit wat de "greedy" zou doen. Is er een ander resultaat, moet de arduino weten van deze uitzondering.
@ericP, volgens mij wil Bram niet zomaar in stapjes van 1dB de verzwakking tussen 0 en 31 kunnen instellen, maar een gewenste waarde in 0.01dB in die range. Nu er "binaire" waardes zijn tot de 0.1dB, zou je de normaliter alleen de veelvouden van 0.1dB kunnen bereiken. Maar als nu je 0.2dB niet 0.20dB is, maar gemeten kan worden op 0.18dB, dan zijn er ineens een aantal waardes die je nauwkeuriger kan benaderen (en met de huidige nominale waardes OOK waardes die je minder goed kan halen!)