I skal nok holde tungen lige i munden når I læser dette ;-)
Jeg har lavet et program der opsamler data fra et datakort. Ud over at blive skrevet i en tekstfil, skal der også løbende på skærmen plottes de målte datapunkter i et xy-plan. Når denne graf er fyldt skal de data der er plottet komprimeres så de kun fylder halvdelen og de næste data plottes så i den næste del.
For at spare lidt på hukommelsen forestiller jeg mig at datapunkterne puttes i et array AF EN FAST STØRRELSE. fx 100 rækker. Når arrayet er fyldt op, kasseres hvert andet punkt og de resterende flyttes til de første 50 rækker. Det er lykkedes for mig at få programmet til det (se kode nedenfor).
Det der er mit problem er at indlæse punkterne efterfølgende med dobbelt så lange intervaller, så tidsaksen bliver ved med at "virke" lineær. Man kunne gange Timer1.Interval med 2 hver gang, men der skal ikke mange fordoblinger til før det bliver for stort. Programmet skal kunne køre i 10 dage, så med 100 punkter vil det jo kun blive en indlæsning 10 gange i døgnet efter 10 dage, hvorimod der er i den første halve time skal indlæses punkter meget oftere.
En løsning hvor hvert andet målepunkt ikke puttes i arrayet vil være at foretrække. Når arrayet så er fyldt 3. gang, skal kun hvert 4. punkt puttes i arrayet. 4 gang -> hvert 8. punkt osv...
Nedenstående kode (bruger VB6 og ikke noget med .NET tak) skulle gerne illustrere hvad jeg mener.
-------------------------------- Option Explicit
Dim screendata(0 To 99, 0 To 1) Dim v As Long Dim i As Integer Dim d As Long Dim n As Integer
Private Sub Command1_Click() Timer1.Enabled = True End Sub
Private Sub Timer1_Timer() 'formel der genererer data til testbrug. 'Erstattes med måledata senere v = 10 * Sin(0.36 * i) + 50
'Data fyldes i arrayet ind til det er fyldt If i < 99 Then i = i + 1 screendata(i, 0) = i screendata(i, 1) = v
'Dernæst skal hvert andet data punkt kasseres ' og resten fyldes ind på de første 50 pladser Else: 'pluk værdier med lige index numre og put dem i array screendata's plads 0-50 For n = 0 To 99 Step 2 screendata(n / 2, 1) = screendata(n, 1) Next n 'slet værdier i arrayet over 50 For n = 51 To 99 screendata(n, 1) = "" Next n 'start indskrivning af nye data ved række 50 i = 50
'Tæller der kunne tænkes anvendt til at fjerne punkter som 'beskrevet nedenfor d = d * 2 End If
'De aktuelle værdier i arrayet plottes MSChart1.ChartData = screendata
End Sub -------------------------------
Håber I forstår hvad jeg mener ... og at nogen kan give et bud på hvilken kode der skal til for kun at putte hvert "d'ende" punkt i arrayet.
Uden i øvrigt at kunne hjælpe dig med problematikken omkring 'komprimering' af dit array, har jeg følgende kommentar:
Hvorfor ikke lade arrayet (et andet array) indeholde samtlige målepunkter? Et målepunkt hver 0,5 sekund = 1728000 punkter på 10 døgn. Selv hvis arrayet holder Doubles vil du ikke belaste
hukommelsen mere end 4-5 Mb. Det er da ikke alverden?
Og med hensyn til at bearbejde arrayet (f.eks. trække 100 punkter ud, jævnt fordelt), ja så med f.eks. en 1 GHz processor (for at tage et lavt tal), vil du kunne løbe igennem arrayet på nogle
millisekunder. I hvert fald kan du sagtens lave de operationer der skal laves, inden næste tick af timeren. For i øvrigt skal du ikke løbe igennem hele arrayet -se nedenfor.
Det er svært at sige hvad den samlede belastning på computeren vil være, men det er mit bud, at belastningen på
hukommelsen vil være under 10 Mb (og der er vel ingen i dag der har under 128 Mb RAM), og på processoren vil der så
være en spidsbelastning hvert halve sekund, men det skulle ikke betyde alverden, hvis blot du får nogle DoEvents med i
koden.
Her er en skitse til hvad du så kunne gøre:
Erklær et Basisarray, feks Public BaseArray(2000000) As ? Erklær en tæller feks Public lCount As Long Erklær et PlotArray feks Public screendata(99) As ?
I timeren gør du følgende:
lCount=lCount+1 BaseArray(lCount)='Dine måledata' Dim lFactor As Long
lFactor=Int(lCount/100) 'her skal laves lidt betingelse for lCount<100
'skal kun gøres hver gang lCount er vokset med 100, evt tjek med en anden tæller For i=0 to 99 screendata=Basearray(i*lFactor) Next i
screendata vil så kun få nye værdier hver gang lCount er vokset med 100, men det gør den jo på bare 50 sekunder.
Dette vil trække 100 punkter ud, jævnt fordelt over den forløbne tid, men jeg kan ikke rigtig gennemskue, om det er det du vil, jævnfør din bemærkning om at "tidsaksen skal virke lineær".
Jeg skulle nok have fortalt at den computer programmet skal køre på er en meget udtjent sag. Win98, 32 (eller 64 MB) ram. Tror også CPU'en er under 1 GHz.
Desuden bliver der i det endelige program flere dimensioner kolonner i arrayet i det der skal logges flere signaler (10 i alt tror jeg). Det skal så vises som forskellige kurver.
Men tak for dit forslag - jeg kigger lige lidt nærmere på det og skal nok vende tilbage.
Private Sub Command1_Click() Timer1.Enabled = True End Sub
Private Sub Timer1_Timer() 'formel der genererer data til testbrug. 'Erstattes med måledata senere v = 10 * Sin(0.36 * i) + 50
'Data fyldes i arrayet ind til det er fyldt
If i < 99 And i Mod i2 = 0 Then i = i + 1 screendata(i, 0) = i screendata(i, 1) = v
'Dernæst skal hvert andet data punkt kasseres ' og resten fyldes ind på de første 50 pladser Else: 'pluk værdier med lige index numre og put dem i array screendata's plads 0-50 i2 = i2 * 2 For n = 0 To 99 Step 2 screendata(n / 2, 1) = screendata(n, 1) Next n 'slet værdier i arrayet over 50 For n = 51 To 99 screendata(n, 1) = "" Next n 'start indskrivning af nye data ved række 50 i = 50
'Tæller der kunne tænkes anvendt til at fjerne punkter som 'beskrevet nedenfor d = d * 2 End If
'De aktuelle værdier i arrayet plottes MSChart1.ChartData = screendata
Private Sub Command1_Click() Timer1.Enabled = True End Sub
Private Sub Timer1_Timer() 'formel der genererer data til testbrug. 'Erstattes med måledata senere v = 10 * Sin(0.36 * i) + 50
'Data fyldes i arrayet ind til det er fyldt i3 = i3 + 1 If i < 99 And i3 Mod i2 = 0 Then i = i + 1 screendata(i, 0) = i screendata(i, 1) = v
'Dernæst skal hvert andet data punkt kasseres ' og resten fyldes ind på de første 50 pladser Else: 'pluk værdier med lige index numre og put dem i array screendata's plads 0-50 i2 = i2 * 2: i3 = 0 For n = 0 To 99 Step 2 screendata(n / 2, 1) = screendata(n, 1) Next n 'slet værdier i arrayet over 50 For n = 51 To 99 screendata(n, 1) = "" Next n 'start indskrivning af nye data ved række 50 i = 50
'Tæller der kunne tænkes anvendt til at fjerne punkter som 'beskrevet nedenfor d = d * 2 End If
'De aktuelle værdier i arrayet plottes MSChart1.ChartData = screendata
Tak for dit svar. Der var et par bugs i det, men det ledte mig på rette spor og nu virker det :-) Derfor har jeg besluttet at vi deler pointene lige, så hvis du du vil kaste et svar...
For en god ordens skyld præsenterer jeg her den endelige løsning. Har af andre grunde måtte erstatte MSChart med en hjemmetegnet graf af line-commands, så der er nogle små-ændringer pga. dette. Bl.a. er arrayet blevet dynamisk, men med en begrænsning i størrelsen på 800. Koden kan sikkert godt optimeres yderligere, men det tager jeg en anden gang. Here we go:
Option Explicit
Dim v0 As Single Dim v1 As Single Dim i As Integer Dim d As Single Dim n As Integer Dim i2 As Integer Dim i3 As Long Dim x As Long Dim screendata() As Single
Private Sub Form_Load() i2 = 1 i3 = 0
Timer1.Interval = 2250 * 0.01 ReDim screendata(1) screendata(0) = 0 Timer1.Enabled = False Command1.Caption = "Start" End Sub
Private Sub Command1_Click() Timer1.Enabled = True End Sub
Private Sub Timer1_Timer() 'formel der genererer data til testbrug. 'Erstattes med måledata senere v0 = 4 * 0.036 * x
'Data fyldes i arrayet ind til 800 punkter
If UBound(screendata) < 799 Then
Select Case d = i3 Mod i2 Case d = 0 ReDim Preserve screendata(i) screendata(i) = v0
i = i + 1 'hjemmebrygget sub der plotter data i screendata DrawSignal screendata() Case d <> 0 End Select
i3 = i3 + 1
'Dernæst skal hvert andet data punkt kasseres ' og resten fyldes ind på de første 400 pladser Else:
'plukker værdier med lige index numre og putter 'dem i array screendatas plads 0-400 For n = 0 To 799 Step 2 screendata(n / 2) = screendata(n) Next n
'slet værdier i arrayet fra index 401 ReDim Preserve screendata(400) 'igen tegnes grafen DrawSignal screendata()
'start indskrivning af nye data ved række 400 i = 400 'nulstilling af tællere i2 = i2 * 2 i3 = 0 x = 0
Godt du fik det til at virke. Det er en fantastisk følelse når det lykkes :o)
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.