Kann nicht so schwer sein...
Gegeben sind zwei Sekundenwerte im Bereich 0 bis 59.
Ein Ziel (es geht um AVR Assembler) soll angesprungen werden, wenn die
"Zeit" um >= 3 Sekunden abweicht.
Ich kämpfe mit dem Overflow, den es ja leider nicht gibt. Wenn nämlich
Wert a = 0 und Wert b = 59 ist, darf das Ziel NICHT angesprungen werden,
da die Abweichung nur 1 Sekunde ist....
Wie macht man das am elegantesten ohne Multiplikationen (ausser
Bitshifts)?
[Mod: Threadtitel versinnvollt]
Das Ergebnis ist alleine aus den Sekundenwerten nicht eindeutig
bestimmbar.
a = 0, b =59 kann eine Differenz von 1s, 1m1s, 2m1s, 3m1s, ... und
ebenso 59s, 1m59s, 2m59, 3m59, ... sein.
Ohne Randbedingungen oder besser noch vollständige Zeitinformation ist
die Differenz nicht eindeutig und damit kann keine eindeutige
Entscheidung getroffen werden ob die Differenz >= 3s ist.
Was eine Multiplikation daran ändern soll erschließt sich mit nicht.
Hannes J. schrieb:> Was eine Multiplikation daran ändern soll erschließt sich mit nicht.
Mglw. soll die 'Multiplikation' lediglich das Vorzeichen bearbeiten,
resp. den Absolutwert bilden.
Das kann man aber auch mit Sortierung vor Differenzbildung hinbekommen.
Zum subject des Threads würde ich allerdings zu eine Leukotomie oder
'tiefe Hirnstimulation' raten.
Ereignis 1 triggert einen Timer und wenn dieser >3 sec ist wird die
Aktion gestartet. Dann kann es keinen Überlauf geben.
Oder verstehe ich da etwas falsch ?
Jan schrieb:> Ich kämpfe mit dem Overflow, den es ja leider nicht gibt. Wenn nämlich> Wert a = 0 und Wert b = 59 ist, darf das Ziel NICHT angesprungen werden,> da die Abweichung nur 1 Sekunde ist.
Warum soll da nur 1s Abweichung sein? Woran kann man das erkennen? Wer
garantiert, dass hier der Unterschied nicht tatsächlich 59 Sekunden
sind?
Welche Abweichung hast du, wenn ein Zähler auf 10 und der andere auf 50
ist?
Ist die Abweichung dann 20s oder 40s oder kann sie auch 1m20s sein?
Welche Abweichung hast du, wenn ein Zähler auf 5 und der andere auf 10
ist?
Ist die Abweichung dann 5s oder 55s?
Oder andersrum: wie stellst du sicher, dass die Abweichung kleiner als
57s bleibt? Denn sobald die Abweichung größer als 57s wird, ist für dich
die Abweichung rechnerisch wieder kleiner als 3.
Muss man also die Vergangenheit kennen?
Jan schrieb:> Ein Ziel soll angesprungen werden, wenn die> "Zeit" um >= 3 Sekunden abweicht.> Wert a = 0 und Wert b = 59
Dazwischen liegen aus meiner Sicht 59 Sekunden. Das ist >3, als muss das
Ziel angesprungen werden.
> Ich kämpfe mit dem Overflow...> da die Abweichung nur 1 Sekunde ist
Auch das kann richtig sein. Also darf das Ziel nicht angesprungen
werden.
Oder anders gesagt: Es fehlt eine nötige Information. Rein mathematisch
ist dieses "Problem" unlösbar.
Xerxes schrieb:> Oder verstehe ich da etwas falsch ?
Der OT hat 2 Variablen!
Das Problem hatte ich mal bei einer Tochteruhrsteuerung. Ist-Zeit und
Soll-Zeit, die mit Tasten verstellbar war. Habe dann alles in Sekunden
gemacht und - um 24 Uhr - wer stellt dann auch die Zeit um...?!
Hilft jetzt dem OP nicht so... Sorry.
Gruss Chregu
Wenn ich Zeitspannen messe, dann mache ich das normalerweise mit
fortlaufenden Counter als 32 oder 64 Bit unsigned Integer:
1
starte_etwas();
2
start=systick();
3
4
while(noch_nicht_fertig)
5
{
6
now=systick();
7
8
if((now-start)>limit)
9
{
10
print("Die maximale Zeit wurde überschritten");
11
}
12
}
Selbstverständlich geht das auch in Assembler.
Wichtig ist die Subtraktion, denn dann stimmt die Rechnung auch, wenn
der Zähler zwischendurch einmal übergelaufen ist. Er darf aber nicht
öfter als 1x überlaufen.
Dein Zähler muss entsprechend groß genug sein. Du hast geschrieben, dass
deine Aktion auch 3m59 (oder mehr) dauern kann. Mit 0..59 Sekunden geht
das nicht, weil das mehrere Überläufe ergeben würde.
(prx) A. K. schrieb:>> Was eine Multiplikation daran ändern soll erschließt sich mit nicht.> Minute * 60 + Sekunde
Er hat aber keine Minuten-Info. Genau die fehlt ihm, da kann auch
Mathematik nichts zaubern.
Außerdem war seine Bedingung:
Jan schrieb:> Wie macht man das am elegantesten ohne Multiplikationen?
Jan schrieb:> Ein Ziel (es geht um AVR Assembler) soll angesprungen werden, wenn die> "Zeit" um >= 3 Sekunden abweicht.Jan schrieb:> Wenn nämlich> Wert a = 0 und Wert b = 59 ist, darf das Ziel NICHT angesprungen werden,> da die Abweichung nur 1 Sekunde ist....
Damit kann niemand was anfangen. Was ist "die Zeit"?
Du versuchst, den zweiten Schritt (Code) vor dem ersten Schritt
(Funktion) zu machen.
Du mußt erst die Funktion eindeutig und vollständig beschreiben, dann
kann man auch einfach ein Programm daraus machen.
Jan schrieb:> Ein Ziel (es geht um AVR Assembler) soll angesprungen werden, wenn die> "Zeit" um >= 3 Sekunden abweicht.
Erstmal muss klar sein, wie groß die maximale Abweichung sein kann.
Moby schrieb im Beitrag #6934345:
>> Erstmal muss klar sein, wie groß die maximale Abweichung sein kann.> Schreibt er doch. 2 Sekunden für den Nicht-Sprung!> Da sie nicht angegeben wurde nehme ich an das die Differenzen unter 1> Minute liegen.Hannes J. schrieb:> kann eine Differenz von 1s, 1m1s, 2m1s, 3m1s, ... und> ebenso 59s, 1m59s, 2m59, 3m59, ... sein.
Dem hat Jan nicht widersprochen. Im Gegenteil, Jan schrieb dass er mit
Überläufen nicht klar kommt. Also müssen wir erstmal davon ausgehen,
dass Hannes das korrekt erkannt hat.
Mit Variablen die nur bis 59 Sekunden gehen kann man nicht Zeitspannen
messen, die ein vielfaches davon dauern.
ohne Minuteninformation ist die Zeitangabe nicht vollständig.
Du könntest Berechnungen die eine große Differenz ergeben ignorieren
oder hart einen Minutenwechsel annehmen.
Habs nur in C++
Wäre schön wenn der Jan sich bald mal weider dazu meldet. Da er den
Thread aus meiner Sicht in der Nacht begonnen hat, liegt er jetzt
vielleicht noch im Bett. Wir müssen uns wohl oder übel gedulden.
Wobei >= 3 Sekunden auch >3 && <57 bzw. >1 && <59 bedeuten kann: 0 und
59 sind halt nicht 1s sondern [0..2]s. 0, wenn die Abfrage im Takt der
Umschaltung erfolgt (59er vorher, der 0er nachher), 2 wenn der 0er grad
noch nicht und dann der 59 gerade umgesprungen ist.
Oder anders ausgedrückt: selbst 2 exakt parallele Timer (0 Abweichung)
werden immer wieder mal 1 Differenz haben.
Hi
Eine relativ einfache Lösung gibt es, wenn die "Fehlermeldung" nicht
sofort erfolgen muss, sondern um die angegebenen 2 Sekunden verzögert
werden darf. Da bei einem Überlauf die Vergleichszeit ebenfalls max 1
Sekunde später erfolgen muss,setzt man einfach ein kleines Zeitfenster
beim Wechsel von 59 nach 0 und sperrt für 2 Sekunden die Auswertung.
Gruß oldmax
Moby schrieb im Beitrag #6934367:
> Wolfgang schrieb:>> Erstmal muss klar sein, wie groß die maximale Abweichung sein kann.>> Schreibt er doch. 2 Sekunden für den Nicht-Sprung!
Schlaumeier - und wie will er erkennen, ob es sich um eine Abweichung
von <=2 Sekunden handelt, wenn seine Eingangsvariablen nicht zwischen 1
und 61 unterscheiden können.
Wolfgang schrieb:> wenn seine Eingangsvariablen nicht zwischen 1 und 61 unterscheiden> können.
Das ist doch nicht das Thema.
Es geht um Sekunden, nicht Zufallszahlen. Bevor es 50s oder gar 60s
Differenz werden, hat er wohl schon einige Sprünge mit entsprechenden
Maßnahmen ausgeführt.
Ich gehe jetzt mal davon aus, dass die beiden Uhren nicht innerhalb
einer Minute so weit auseinander driften. Dann würde ich alle 60 sec
testen u.z. um genau n min.30 sec. Hier kann ich dann ((t1 - t2) &&
0b01111111) >= 3 testen, ohne das Problem 57, 58, 59, 0, 1, 2
berücksichtigen zu müssen. (t1 und t2 sind int8_t, ...&& 0b01111111 um
den Betrag zu erhalten.)
Nächster Schritt ist dann zu prüfen, welche Uhr falsch geht (woher soll
man das wissen?).
Um den Fall zu berücksichtigen, dass einer der Uhren zwischen sec 27 bis
33 stehen bleibt, muss man dann zusätzlich noch andere Dinge überprüfen.
Das ist dann aber ein größerer Systemfehler.
Gruß
Hi
Ist ja toll, wie schnell aus einer einfachen, zugegeben ein kleines
extra Schmankerl gibt's, Aufgabe gleich eine Uhr daraus wird. Und wie
schnell Sekunden zu Minuten werden. Also bleibt doch Mal auf dem
Teppich. So wie sich die Aufgabe stellt, kann die Differenz gar nicht
größer 2 Werden,des sei denn, es gibt einen Überlauf eines der
Sekundenzähler. Dann aber ist die Differenz auch weit über der 2.
Entweder, man zieht in einem solchen Fall noch Mal von der Differenz 60
ab, oder addiert 60, je nach Ergebnis, um die reale Differenz zu
erhalten, oder man setzt die Überwachung für die Überlaufproblematik
aus.
Möglich: Differenz =0, Compare-Befehl Ergebnis gleich
Differenz > oder < 0, aber < 2 und >-2, dann keine Aktion
Differenz > oder < 2 dann Differenz =Differenz - oder + 60
Entweder, die Differenz befindet sich nun im erlaubten Bereich, oder
aber es darf eine Meldung erfolgen.
Sollte nun leicht umsetzbar sein
Gruß oldmax
> ist nur nicht intuitiv ;-)
Und vor allem: Scheisse-langsam. Das sind halt so Sachen, die man in C
nicht sofort beim Eintippen bemerkt, in Asm aber schon...
Stefan ⛄ F. schrieb:> Wenn der TO ausdrücklich keine Multiplikation will, dann wohl auch keine> Division.
Deshalb habe ich ja auch die (bisher) kürzeste Version zuerst
geschrieben:
A. S. schrieb:> int d=t1-t2;> if(d<0) d=-d; // alternativ abs> if(d>=3 && d<= 57) ...
Ich würde sagen Jan hat uns einfach verarscht. Ebenso peinlich ist wie
einige sich Randbedingungen hinzudichten um die Aufgabe zu "lösen", nur
um als Programmier-Helden dazustehen.
So, da bin ich wieder.
Ja, es wurde gestern sehr spät und ja, ich hatte in der Tat eine
Hirnblockade, nämlich zu erkennen, dass das gar kein triviales Problem
ist.
Deshalb hier mehr Details zum eigentlichen Problem, weil die Aussage,
ich habe nur die Sekunden, falsch ist. Ich hatte es damals schon
gedanklich kaputtoptimiert. Sorry. :(
Zur Vorgeschichte, falls es wen interessiert:
Ich entwerfe grad eine Smart-Home Steuerung. Bisher hängen gut 30 Geräte
im Bus. Da das ganze über Funk läuft, muss das Teil kryptographisch
abgesichert sein. Dazu benötigt man auch einen Schutz vor
Replay-Angriffen. Da kann man zwar das challenge-response Verfahren
nehmen, aber da ich auch mit Broadcasts arbeite (quasi 1:n Beziehung),
kann man das hier nicht nehmen. Deshalb braucht es eine network time.
Dazu gibt es dann einen authoritären time_server, der die Pakete via
Broadcast ins Netz sendet.
Jetzt zum Problem:
Die Geräte erhalten in regelmässigen Abständen die Zeit vom time server
via Broadcast. Diese Geräte sollen die Zeit aber nur dann übernehmen,
wenn die Abweichung lokale<->remote >= 3 Sekunden ist. Warum? Der Jitter
beträgt 1 Sekunde, da die Zeit nur auf 1s genau übertragen wird. Wenn
jetzt z.B. eine Uhr die Zeit anzeigt, könnte sie immer um 1 Sekunde vor-
und zurück springen. Das ist unschön und soll vermieden werden.
Dazu habe ich eine datetime-Lib programmiert, die die Zeit in eine
struct packt. Das sieht so aus:
1
.section .bss
2
RAM_datetime:
3
RAM_datetime_second: .space 1
4
RAM_datetime_minute: .space 1
5
RAM_datetime_hour: .space 1
6
RAM_datetime_day: .space 1
7
RAM_datetime_weekday: .space 1
8
RAM_datetime_month: .space 1
9
RAM_datetime_year: .space 1
10
.text
Wenn also ein Gerät die Zeit erhält, hat es im RAM zu dieser Zeit zwei
structs. Einmal die von sich selbst, und einmal die von remote. Es soll
dann passieren: IF Abweichung >= 3s then ramcopy remote to myself.
In Assembler gibt es keine structs, aber ich denke, dass ist das
passenste Synonym.
Die RICHTIGE Lösung wäre, jetzt erstmal eine Funktion
datetime_to_big_number zu basteln. Das ist aber extrem aufwändig für
einen µC und deshalb möchte ich das gerne vermeiden.
Jan schrieb:> Das ist aber extrem aufwändig für> einen µC und deshalb möchte ich das gerne vermeiden.
Die Lösung ist hingegen recht einfach: Verschicke die Uhrzeit nur im
Fenster zwischen 4 und 56 Sekunden.
Dann ist alles gleich und Du kannst die Sekunden vergleichen.
Jan schrieb:> Die Geräte erhalten in regelmässigen Abständen die Zeit vom time server> via Broadcast.
Jan schrieb:> Die Geräte erhalten in regelmässigen Abständen die Zeit vom time server> via Broadcast. Diese Geräte sollen die Zeit aber nur dann übernehmen,> wenn die Abweichung lokale<->remote >= 3 Sekunden ist. Warum? Der Jitter> beträgt 1 Sekunde, da die Zeit nur auf 1s genau übertragen wird. Wenn> jetzt z.B. eine Uhr die Zeit anzeigt, könnte sie immer um 1 Sekunde vor-> und zurück springen. Das ist unschön und soll vermieden werden.
Warum machst du es nicht wie die Bahnhofsuhren? Das funktioniert seit
Jahrzehnten.
Der Sekundentakt der Slave ist so eingestellt, dass die Uhren etwas zu
schnell laufen. Nach dem 59. Sekundenpuls halten sie an und warten auf
den Minutensynchronisationsimpuls vom Master. Mit dem Puls springt der
Sekundenzähler auf 0 und die Uhr bekommt ihren Minutenpuls.
Falls Du das Zeitfenster nicht steuern kannst:
a) Vergleiche vom Jahr runter bis zur ersten Differenz
Wenn es nur die Sekunden anders sind, --> vergleichen und ggf. springen
Sonst den kleineren in eine dritte Instanz (ggf. auf dem Stack)
kopieren, um 3 Sekunden erhöhen und springen, wenn es noch immer kleiner
ist.
Ich nehme ja an, dass Du für +1Sekunde Operationen hast. Jedenfalls
braucht es dann keine Multiplikation.
achs schrieb:> Jan schrieb:>> Das ist aber extrem aufwändig für>> einen µC und deshalb möchte ich das gerne vermeiden.>> Die Lösung ist hingegen recht einfach: Verschicke die Uhrzeit nur im> Fenster zwischen 4 und 56 Sekunden.>> Dann ist alles gleich und Du kannst die Sekunden vergleichen.
Auf sowas ähnliches kam ich auch schon. Allerdings so rum, dass ich
Pakete ausserhalb dieses Fensters einfach ignoriere.
Wäre wohl die einfachste Variante.
Jan schrieb:> Der Jitter beträgt 1 Sekunde, da die Zeit nur auf 1s genau übertragen wird. >
Wenn jetzt z.B. eine Uhr die Zeit anzeigt, könnte sie immer um 1 Sekunde
> vor- und zurück springen. Das ist unschön und soll vermieden werden.
Wenn sie aber gleich 3 Sekunden springt, dann ist das schöner? Warum
statt der selbsterfundenen 3 Sekunden nicht gleich 5? Dann wäre noch
viel länger "kein Vor- und Zurückspringen" zu sehen. Denn das machst du
ja mit deinem Programm: du wartest, bis die Abweichung riesig ist und
machst dann einen gewaltigen Schritt damit danach wieder lange "Ruhe"
ist.
Mich würde eine Uhr kirre machen, wenn die zwischendurch selber Sekunden
auslässt oder einfügt.
In der Praxis macht man das so, dass man eine Uhr hat, die selbständig
"auf die Minute" genau macht, und die Sekunden werden innerhalb dieser
Minute "gerecht" verteilt und die Geschwindigkeit der Slave-Uhr so der
Geschwindigkeit der Master-Uhr ständig nachregelt. So eine Regelung ist
allerdings deutlich mehr Aufwand als die Bastelei mit den springenden
Sekunden.
Jan schrieb:> Wäre wohl die einfachste Variante.
Das erscheint mir das Motto für die Software von heute.
Lothar M. schrieb:>> Der Jitter beträgt 1 Sekunde, da die Zeit nur auf 1s genau übertragen wird. >> Wenn jetzt z.B. eine Uhr die Zeit anzeigt, könnte sie immer um 1 Sekunde>> vor- und zurück springen. Das ist unschön und soll vermieden werden.> Wenn sie aber gleich 3 Sekunden springt, dann ist das schöner?
Warum sollte sie da ständig springen? Oder wie lange dauert es, bis ein
08/15 Quarz >2s abweicht!
Die Frage (war schon) ist doch, warum "so oft" die Zeit senden, so dass
das irgendwie stören könnte?!
@Lothar:
Prinzipiell ist die einfachste Variante immer den komplexeren zu
bevorzugen, solange sie die gegebene Aufgabe zufriedenstellend erfüllt.
Alleine schon aus Gründen der Wartbarkeit.
Dann vermischt du hier Jitter und Drift. Das hat miteinander jedoch
nichts zu tun. Der Drift liegt bei +-50ppm und der Grund, warum ich bei
3 Sekunden hart springen will ist, dass es woanders noch eine drift
compensation gibt, die nochmal anders (und ganz ohne Sprünge)
funktioniert.
Durch die drift compensation kommt der harte Sprung in der Praxis auch
nur dann vor, wenn man den authoritativen Zeitserver hart einstellt.
Auch das kommt in der Praxis nicht vor, jedoch geht es hier um eine
self-repair Eigenschaft des Systems. Im Fall eines Bugs will man nämlich
nicht zig Geräte von Hand resetten gehen.
Die netzweite Systemzeit als runtergebrochenes lokales Datum+Uhrzeit zu
verwalten, hat sich nicht bewährt. Jedes Hantieren damit bereitet
Probleme, insb wenn auch noch Zeitzonen/Sommerzeitumschaltungen
beteiligt sind.
Aber, ähnlich wie bei der Wahl der Programmiersprache, muß Jan wohl
diese Erfahrung erst selbst machen ;-)
Hi
Nun, nach dem Eingangspost bin ich von einer Schulaufgabe ausgegangen.
Da strengt man sich an, eine einfach verständliche Lösung anzubieten,
dabei weiß der TO genau, was er will und hat die Lösung sogar schon im
Kopf.
Vorführen nenn ich sowas, aber wenn du es nötig hast...
Gruß oldmax
Martin V. schrieb:> Hi> Nun, nach dem Eingangspost bin ich von einer Schulaufgabe ausgegangen.> Da strengt man sich an, eine einfach verständliche Lösung anzubieten,> dabei weiß der TO genau, was er will und hat die Lösung sogar schon im> Kopf.> Vorführen nenn ich sowas, aber wenn du es nötig hast...> Gruß oldmax
Martin, was hast Du anders erwartet?
Sind wir nicht alle - irgendwie - schmale, unbedeutende Zampanos? Immer
auf der Suche nach der großen Bühne - nach den Brettern, die die Welt
bedeuten? In unserer eigenen, kargen, inferioren Welt?
Ertrag‘s mit Fassung! Oder mach‘s wie aller anderen auch: Zerrede jeden
Ansatz mit einem eigenen, banalen Gegen-Ansatz. Hauptsache Du bist
schnell und sagst was, auch wenn Du nichts zu sagen hast.
Und falls Du der Meinung bist, Du hättest was zu sagen - formuliere
dieses „Was“ unbedingt als Frage.
Alois