Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: Python: Lokitiedoston luku ja tietojen analysointi

Sivun loppuun

Yamato [10.04.2016 14:02:32]

#

Toteutin Arduinolla dataloggerin joka kerää auton/mp:n anturidataa.

Data on tällä hetkellä tämännäköistä

[rivi, kaasu, rpm, map, lambda1, lambda2]

1,	0,	1400,	260,	0.98,	1.05,
2,	1,	1550,	275,	1.02,	1.03,
3,	0.9,	1600,	290,	1.04,	0.97,

Tässä vaiheessa yritän keksiä, miten ohjelman saisi käymään läpi koko lokitiedoston ja laskemaan lambda-arvojen keskiarvon tiettyjen ehtojen mukaisesti.
Kaasun eri asentovälejä (prosenttia auki) on 22 kpl ja kierroslukualueita 31 kpl. Lambda-arvojen keskiarvot pitäisi saada esitettyä kaikilla kaasun asennoilla ja kullakin kaasun asennolla kaikilla kierroslukualueilla.

Millainen olisi fiksu toteutus?

Alla oleva koodin pätkä osaa tutkia yhden tapauksen 682:sta.

'''Data'''

import sys



#Constant variables

ThrottlePos = 1 #index number for Throttle position
RPM = 2         #index number for RPM

#Functions here

def Analyze_Data(cyl):

    #Variables for this function

    Lambda = 0
    Counter = 0

    if cyl == 1:
        Read_Lambda = 4
    else:
        Read_Lambda = 5

    Data = open("LoggedData.txt", "r")

    for line in Data:
        list = line.split(',')
        if  0 <= float(list[(ThrottlePos)]) < 1:
            if  500 <= float(list[RPM]) < 1500:
                Lambda += float(list[(Read_Lambda)])
                Counter += 1
                print list[ThrottlePos], list[RPM], list[(Read_Lambda)]
            #elif 1500 <= float(list[RPM]) < 2000:
            #    Lambda += float(list[(Read_Lambda)])
            #    Counter += 1
            #    print list[ThrottlePos], list[RPM], list[(Read_Lambda)]
    print 'Average lambda: ', Lambda/Counter
    Data.close()


def main():

    Selected_Cyl = 1

    Analyze_Data(Selected_Cyl);


if __name__ == '__main__':
  main()

jlaire [10.04.2016 16:33:45]

#

Dictionaryyn voi tallentaa erilliset arvot kaikille (throttle, rpm)-pareille.

Menevätkö lukurajat säännölisesti throttlessa yhden välein ja rpm:ssä tuhannen välein alkaen 500:sta? Tässä nopea esimerkkitoteutus.

INDEX_THROTTLE = 1
INDEX_RPM = 2
INDEX_LAMBDA1 = 4
INDEX_LAMBDA2 = 5

def make_key(throttle, rpm):
    throttle = int(throttle)
    rpm = int((rpm - 500) / 1000)
    return (throttle, rpm)

def show_key(key):
    throttle, rpm = key
    return '%d <= throttle < %d, %d <= rpm < %d' % (
        throttle,
        throttle + 1,
        rpm * 1000 + 500,
        rpm * 1000 + 1500,
    )

def analyze_data():
    counts = {}
    lambdas1 = {}
    lambdas2 = {}

    with open("LoggedData.txt", "r") as data:
        for line in data:
            values = [float(x) for x in line.split(',')[:6]]
            key = make_key(values[INDEX_THROTTLE], values[INDEX_RPM])
            lambdas1[key] = values[INDEX_LAMBDA1] + lambdas1.get(key, 0)
            lambdas2[key] = values[INDEX_LAMBDA2] + lambdas2.get(key, 0)
            counts[key] = 1 + counts.get(key, 0)

    for key in sorted(counts.keys()):
        avg1 = lambdas1[key] / counts[key]
        avg2 = lambdas2[key] / counts[key]
        print('Average lambdas for (%s): %f, %f' % (show_key(key), avg1, avg2))

if __name__ == '__main__':
    analyze_data()
$ python2 yamato.py
Average lambdas for (0 <= throttle < 1, 500 <= rpm < 1500): 0.980000, 1.050000
Average lambdas for (0 <= throttle < 1, 1500 <= rpm < 2500): 1.040000, 0.970000
Average lambdas for (1 <= throttle < 2, 1500 <= rpm < 2500): 1.020000, 1.030000

Yamato [10.04.2016 18:19:32]

#

Kiitos, siinä tulikin melkein valmis ratkaisu.

Lukurajat eivät mene säännöllisesti, enkä pysty niihin vaikuttamaan. Rajat näkee linkin takaa löytyvästä kuvakaappauksesta moottorinohjaussoftasta.

Kuvakaappaus

Ajatuksena on saada näkymään lokidata vastaavalla tavalla, jonka pohjalta voi tehdä tarvittavat muutokset moottorinohjaukseen eli tässä tapauksessa ruiskutettavan polttoaineen määrään.

Täytyy opiskella lisää for -looppien ja dictionaryjen sielunelämää. Vaikuttaa erittäin kätevältä. Ideatasolla ymmärrän tuon kirjoittamasi koodin, mutta en riittävästi pystyäkseni muokkaamaan mieleiseksi.

jlaire [10.04.2016 20:26:48]

#

Idea on siis, että jos esimerkiksi throttle=0.9 ja rpm=1599, nämä pyöristetään alaspäin lähimpään rajaan, tässä tapauksessa throttle -> 0 ja rpm -> 1470. Kun tätä normalisoitua paria käytetään dictionaryn avaimena, kaikki samojen rajojen välissä olevat (throttle,rpm)-parit lasketaan samaan keskiarvoon.

Rajat voi tallentaa listaan ja etsimisen voi tehdä silmukalla.

INDEX_THROTTLE = 1
INDEX_RPM = 2
INDEX_LAMBDA1 = 4
INDEX_LAMBDA2 = 5

THROTTLE_LIMITS = [
    0, 1, 2, 3, 4, 5, 6, 8, 10, 15, 20, 25, 30, 35, 40, 50, 60, 70, 80, 100,
]

RPM_LIMITS = [
    0, 800, 1050, 1250, 1470, 1600, 1800, 2000, 2200, 2300, 2400, 2500, 2600,
    2800, 3000, 3250, 3500, 3750, 4000, 4500, 5000, 5500, 6000, 6500, 7000,
    7500, 8000, 8500, 9000, 9500, 10000, 10500,
]

def find_lower(x, values):
    for a, b in zip(values, values[1:]):
        if a <= x < b:
            return a
    return values[-1]

def make_key(throttle, rpm):
    throttle = find_lower(throttle, THROTTLE_LIMITS)
    rpm = find_lower(rpm, RPM_LIMITS)
    return (throttle, rpm)

def show_key(key):
    return 'throttle >= %d, rpm >= %d' % key

# ... loput niin kuin ennenkin
Average lambdas for (throttle >= 0, rpm >= 1250): 0.980000, 1.050000
Average lambdas for (throttle >= 0, rpm >= 1600): 1.040000, 0.970000
Average lambdas for (throttle >= 1, rpm >= 1470): 1.020000, 1.030000

Chiman [14.04.2016 16:06:49]

#

jlaire kirjoitti:

def find_lower(x, values):
    for a, b in zip(values, values[1:]):
        if a <= x < b:
            return a
    return values[-1]

Irrallisena toteutusteknisenä vinkkinä mainitsen, että tuossa voisi hyödyntää myös bisect.bisect_left-funktiota, joka etsii nousevassa järjestyksessä olevasta listasta annettua arvoa vastaavan kohdan indeksin binäärihakua käyttäen.

Tässä sovelluskohteessa tuon merkitys on olematon, mutta tämä oli lähinnä aasinsilta siihen, että haluan rohkaista kaikkia Pythoniin perehtyviä selaamaan standardikirjaston tarjonnan läpi. Sieltä löytyy vaikka mitä hyödyllistä.

Yamato [14.04.2016 17:28:34]

#

Kiitos vinkeistä. Lisäilin ohjelmaan oman osion MAP/RPM datan esittämiselle ja funktion, joka määrittää meneekö esitetty data Throtte/RPM vai MAP/RPM karttaan.

Nyt tuo data pitäisi saada visuaaliseen muotoon samaan tapaan kuin aiemmin linkkaamassani kuvassa. Pythoniin on näköjään vaikka minkälaisia lisäpalikoita tarjolla, millä toteutus onnistuu. Kunhan osaisi valita sopivimman.

Chiman [15.04.2016 18:27:21]

#

Yamato kirjoitti:

Nyt tuo data pitäisi saada visuaaliseen muotoon samaan tapaan kuin aiemmin linkkaamassani kuvassa. Pythoniin on näköjään vaikka minkälaisia lisäpalikoita tarjolla, millä toteutus onnistuu. Kunhan osaisi valita sopivimman.

Tekisin tuollaisen taulukkomuodon HTML:llä, jota on helppo tuottaa suoraan Pythonilla ilman mitään lisäpalikkaa. Kuvaksi sen saa kuvaruutukaappauksella ja tallentamalla esim. PNG-muotoon.

Joku toinen voisi käyttää SVG-muotoa. Joku kolmas kirjoittaisi datat CSV-muotoon, veisi sen taulukkolaskentaohjelmaan ja määrittäisi siellä solujen väriarvot lukujen perusteella. Ja se neljäs hoitaisi homman Pythonin lisäpalikalla.

Yamato [15.04.2016 23:22:39]

#

Kokeilin harjoituksen vuoksi kirjoittaa datan CSV-tiedostoon.

fo = open("datacsv.csv", "w")
fo.write('Throtte/RPMs,,')
for y in THROTTLE_LIMITS:
    fo.write('%s,' % (y))

for x in RPM_LIMITS:
    fo.write('\n %s,' % (x))
    for y in THROTTLE_LIMITS:
        if lambdas1.get((y, x), 0) != 0:
            lambda_value = lambdas1.get((y, x), 0)/ counts.get((y, x), 0)
            lambda_value = round(lambda_value ,2)
            #print lambda_value
            fo.write('%s,' % (lambda_value))
        else:
            fo.write(',')
Throtte/RPMs,,0,1,2,3,4,5,6,8,10,15,20,25,30,35,40,50,60,70,80,100,
 0,,,,,,,,,,0.96,,1.03,,,,,0.97,,0.91,,
 800,,,,,,,,,,0.99,,,,,,0.92,,,,,
 1050,,,,,,,,,,,,0.92,,1.08,,,,1.0,,,
 1250,,,,,,,,,,,,,,,,,,,,,
 1470,,,,,,,,,,,0.92,,,,,1.09,,,,,
 1600,,,,,,,,,,,,,1.0,,,,,1.0,,,

Ei ole ehkä "kaunis" ratkaisu, mutta tekee mitä pyydetään.

Pitää silti koittaa saada aikaan Python -pohjainen ratkaisu. Tavoitteena olisi tehdä vielä jonkunlainen GUI, jolla saa haettua lokitiedoston Arduinon muistikortilta yms. pientä.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta