2020-12-02, 12:29
  #1
Medlem
Eftersom den digitala signalprocessen går över Librtlsdr behöver vi kalla på Python-wrappern PyrtlSDR.read_sample() varje gång vi skall hämta en ny sample.

Detta görs med en while-loop i normala fall på samma sätt som man kör övrig kod i ett program.

Problemet med en while-loop är att den genomför sin cykel i en processorcykel, vilket gör loopen någon miljon gånger snabbare än den sample_rate som signalen kommer i. Vilket gör att hela avkodningen av signalen blir avhuggen i delar som inte sen kan sättas ihop.

Hur kan man få ner frekvensen av loopen så att den hinner processa hela signalen?
Kod:
from rtlsdr import RtlSdr
sdr = RtlSdr()

# configure sdr-device
sdr.sample_rate = 1.024e6  # Hz
sdr.center_freq = 169.8e6  # Hz
sdr.freq_correction = 60   # PPM
sdr.gain = 5
sample_factor = 64

def get_sample(sample_factor):
    #sample from the RTL_SDR
    return sdr.read_samples(sample_factor*1024)


def correct_dc_offset(sample):

    #DC CORRECTION
    #Correcting the dc spike and the center_freq
    dc_corr = np.exp(1j * (2 * np.pi * (-offset_frequency / sdr.sample_rate) *
                      np.arange(0, len(sample))))

    return sample * dc_corr

def decimate_and_filter (sample):
    #DECIMATION AND FILTERING

    # limit the sampling rate using decimation.
    dec_sample_rate = sdr.sample_rate // dec_factor

    # Butterwoth filter N=3th order, Wn = inverse decimate factor *2
    dec_low_filter = sig.butter(N=3, Wn=1 / (dec_factor * 2))

    # filter the signal
    sample = sig.filtfilt(*dec_low_filter, sample)
    
    # decimate
    return sample[::dec_factor], dec_sample_rate

def main():
    flag =True
    while flag:
        sample, dec_sample_r = decimate_and_filter(correct_dc_offset(get_sample(sample_factor)))
       
    sdr.close()
        
main()


Alternativt att man på något sätt ser till att den array som innehåller bits från signalavkodningen blir fylld tills den har korrekt antal bits, men problemet här är att vi kan få gamla bitar från förra samplen då sample-loopen går snabbare än signalen.

Här är demoduleringen:


Vilket är bäst?

1) strypa while-loopen på något sätt?
2) se till i demoduleringen att vi har rätt bit-antal för varje array? Men hur ser vi till att vi då får alla bitar som vi ska ha på korrekt ställe?
Citera
2020-12-02, 18:55
  #2
Moderator
vhes avatar
Jag har, rent krasst, inte en susning om vad det här är, så jag kan ha missat poängen helt, men...

det verkar som om rtlsdr har ett async-interface med vilket man kan iterera över samples (vad det nu är) i en ström. Jag antar att det interfacet i sin tur ser till att du inte får dubletter av datan? Om det är bökligt att skriva om ditt program till async kanske du kan ta en titt på implementationen i alla fall och se hur de gör?

https://pyrtlsdr.readthedocs.io/en/latest/rtlsdraio.html
Citera
2020-12-02, 20:37
  #3
Medlem
Citat:
Ursprungligen postat av vhe
Jag har, rent krasst, inte en susning om vad det här är, så jag kan ha missat poängen helt, men...

det verkar som om rtlsdr har ett async-interface med vilket man kan iterera över samples (vad det nu är) i en ström. Jag antar att det interfacet i sin tur ser till att du inte får dubletter av datan? Om det är bökligt att skriva om ditt program till async kanske du kan ta en titt på implementationen i alla fall och se hur de gör?

https://pyrtlsdr.readthedocs.io/en/latest/rtlsdraio.html


Okej, ber om ursäkt för en otydligt trådstart, detta forum har ingen signalanalysdel. Sedan en reprimand: Se till att citera iaf nicket så man kan se när du har svarat :P Sedan är det bra om man är insatt i frågans ämne, men du är välkommen.

Det du ser framför dig är en digital version av din fm-radio du har på fönsterbrädet. SDR är en mjukvaruradio som kan ta emot ett brett spektrum av radiosignaler. Eftersom att vi nu försöker titta in i den analoga världen med ett digitalt instrument behöver vi ta ett prov av den analoga sinuskurvan som din radiosignal är. Detta prov kallar vi "sample" för vi tar en bit av signalen och sedan översätter den till en digital representation mellan sinus och cosinus.

Det vi för trådens syfte har problem med nu är att pythonfunktionen för att kalla på funktionen Rtlsdr.read_sample() måste loopas för att den skall ta ett prov, precis som vilken annan funktion som helst. Detta gör jag i koden ovan via en while-loop. Men som du vet är en while-loop inte ens en processorcykel så den går i mikrosekunder i en frekvens på flera GHz (processorns klockfrekvens) och radiosignalens meddelande går i runt 1200bit/s i 1.024MHz
Som du ser hinner jag kalla på ett nytt prov en miljon gånger innan jag har fått hela meddelandet jag vill ha.

Jag har testat asyncio och håller på att bolla med den. Jag funderar på att throttla den, men hur vet jag inte. Jag måste throttla ner den till en tidsintervall där jag får med hela meddelandet, sedan om det är kanske 1000 samples eller 100 samples är inte nu viktigt. Bara att jag inte startar om hela processen igen en miljon gånger.

JAg dumpade avkodningen av aynciofunktionen i en fil och den blev 800mb (!) på 3 sekunder! Den fyller då textfilen med matriser som innehåller de bitar som sedan blir det meddelande jag vill ha. Men 800mb är på tok för mycket för de nästan 400bit jag skall ha för ett meddelande. Så den samplar om hela meddelandet ett antal gånger om.
Citera
2020-12-06, 09:10
  #4
Medlem
Citat:
Ursprungligen postat av Methos

Jag har testat asyncio och håller på att bolla med den. Jag funderar på att throttla den, men hur vet jag inte etc...

JAg dumpade avkodningen av aynciofunktionen i en fil och den blev 800mb (!) på 3 sekunder!

Dumpade du verkligen enligt Vhe:s instructioner, dvs typ

Kod:
import asyncio
from rtlsdr import RtlSdr


f = open("apa","wb") # sync file io, because i can't write asyncio code

async def streaming():
    sdr = RtlSdr()
    sdr.sample_rate = 1.024e6  # Hz
    sdr.center_freq = 169.8e6  # Hz
    sdr.freq_correction = 60   # PPM
    sdr.gain = 5

    async for samples in sdr.stream():
        # do something with samples
        f.write(sample) # Replace with Methos algorithm

    # to stop streaming:
    await sdr.stop()

    # done
    sdr.close()

loop = asyncio.get_event_loop()
loop.run_until_complete(streaming())

och fick 800 MB på 3 sekunder? Async-interfacet borde serva dina samples efterhand som de finns tillgängliga om det funkar korrekt
Citera
2020-12-06, 10:39
  #5
Medlem
Citat:
Ursprungligen postat av smurfarfrasse
Dumpade du verkligen enligt Vhe:s instructioner, dvs typ

Kod:
import asyncio
from rtlsdr import RtlSdr


f = open("apa","wb") # sync file io, because i can't write asyncio code

async def streaming():
    sdr = RtlSdr()
    sdr.sample_rate = 1.024e6  # Hz
    sdr.center_freq = 169.8e6  # Hz
    sdr.freq_correction = 60   # PPM
    sdr.gain = 5

    async for samples in sdr.stream():
        # do something with samples
        f.write(sample) # Replace with Methos algorithm

    # to stop streaming:
    await sdr.stop()

    # done
    sdr.close()

loop = asyncio.get_event_loop()
loop.run_until_complete(streaming())

och fick 800 MB på 3 sekunder? Async-interfacet borde serva dina samples efterhand som de finns tillgängliga om det funkar korrekt

JAg dumpade "samples" i en avkodad bool-array enligt koden som är citerad sist i mitt inlägg. Ja, jag fick 800mb/s från den. Det har att göra med att både async och vanliga samplar en miljon gånger i sekunden (pga klockfrekvensen på en normal dator. Den hackar således upp hela sändningen i flera arraykonstellationer.

Utan asyncio.Throttler kommer loopen fortfarande att gå i cykler som styrs av GLIB och CPUns frekvens.
Citera
2020-12-06, 11:43
  #6
Moderator
Neksnors avatar
Har verkligen ingen koll på python, men funkar det inte att lägga in ett anrop till någon delay-funktion i while-loopen? Men det förutsätter att du vet hur mycket loppen måste bromsas varje varv.
Citera
2020-12-09, 01:08
  #7
Medlem

Kodencitaten är inte vad du kör, eftersom det saknas tex definition för dec_factor och import for sigpy.signal. Det blir mycket lättare att förstå vad du försöker göra om koden är körbar, eftersom den som är ute och cyklar per definition inte vet vad den håller på med och då även har problem med att beskriva problemet. Det är förstås helt ok, hade frågeställaren vetat hade han/hon inte behövt fråga.

Det du skriver om sampling och klockfrekvens är helt fel, din while-loop går inte ett varv per klockcykel. Du visar inte heller hur din avkodningsfunktion är kopplad till din inläsning av "sample", vilket gör att jag gissar vad du försöker göra:

du har en mainfunktion som i varje varv av while-loopen läser in 64K samples. du multiplicerar dessa samples med en komplex exp-funkion (är detta en nermixning av signalen, för att få den till basbandet? Din kommentar är i så fall extremt vilseledande, beskriv annars gärna mer utförligt vad tanken är med detta. Det var länge sedan jag läste signalteori och digitala filter). Sedan lågpassfiltreras och decimerars resultatet finns i variablerna samples och dec_sample_r ( som är den nya samplingsfrekvensen)

Sedan har du din avkodarfunktion som du vill ska jobba på dessa nya samples. men eftersom du inte har någon klocka att låsa din avkodare på är du inte säker på att hela ditt meddelande finns med i de 64 K (= ca 64 ms) som en read_sample() täcker. Nästa read_sample kommer att ge nästa 64 ms och nästan garanterat kommer din signal att hamna på gränsen

Är din "sample_factor" är satt för att få meddelandet att få plats i en read_samples()? I så fall kanske man kan göra en cirkulär buffer, så att du alltid har lite extra för att få med "svansen".
Annars får du skriva om din avkodare så att den har kvar sitt tillstånd mellan anrop. Då är det bara att mata på med outputen från main-loopen.

Nu måste jag sova, så jag hinner inte förhandsgranska. Jag ber om ursäkt om jag svamlar, jag har nog corona...
Citera
2020-12-09, 12:07
  #8
Medlem
Citat:
Ursprungligen postat av smurfarfrasse
Kodencitaten är inte vad du kör, eftersom det saknas tex definition för dec_factor och import for sigpy.signal. Det blir mycket lättare att förstå vad du försöker göra om koden är körbar, eftersom den som är ute och cyklar per definition inte vet vad den håller på med och då även har problem med att beskriva problemet. Det är förstås helt ok, hade frågeställaren vetat hade han/hon inte behövt fråga.


Eftersom att du inte har någon SDR-dongel så är det inte ens möjligt att köra koden, då den kommer att hänga sig på att LibRtlsdr inte hittar din hårdvara. Jag vet vad jag håller på med och hela koden finns i första inlägget.


Citat:
Det du skriver om sampling och klockfrekvens är helt fel, din while-loop går inte ett varv per klockcykel. Du visar inte heller hur din avkodningsfunktion är kopplad till din inläsning av "sample", vilket gör att jag gissar vad du försöker göra:

Om inte while-loopen loopar efter en räknecykel i CPUn så är något som är konstigt, då en cykel just är en instruktion.

Min avkodningsfunktion justerar signalens två komplexa signaler och syncar den i tid, sedan kodar den av signalens [-1],[1] till True/False eller 1/0 i en array. Funktionen använder Early-Late-metoden för att synca signalerna i fas.



Citat:
du har en mainfunktion som i varje varv av while-loopen läser in 64K samples. du multiplicerar dessa samples med en komplex exp-funkion (är detta en nermixning av signalen, för att få den till basbandet? Din kommentar är i så fall extremt vilseledande, beskriv annars gärna mer utförligt vad tanken är med detta. Det var länge sedan jag läste signalteori och digitala filter). Sedan lågpassfiltreras och decimerars resultatet finns i variablerna samples och dec_sample_r ( som är den nya samplingsfrekvensen)

För varje loop tar den och triggar sdr.read_samples() som går och hämtar x antal samples @ 8bit i varje sample från LibrtlSDR (och hårdvaran), sedan för jag genom den 1D-array som formas av IQ in till en frekvenskorrigering som korrigerar dela DC-spiken och dels ser till att min använda frekvens är centrerad. Detta för att LibrtlSDRs egen frekvenskorrigering inte verkar fungera så där jätte bra, därför ser jag till att den sker manuellt. Sedan för jag genom samma array i en funktion som decimerar och filtrerar signalen till korrekt bandbredd. Sedan ser jag till att synka faserna av de två komplexa signaler som finns i sample så att de är i fas tidsmässigt. Sedan skall avkodning av array ske till bits för FSK-modulering.



Citat:
Sedan har du din avkodarfunktion som du vill ska jobba på dessa nya samples. men eftersom du inte har någon klocka att låsa din avkodare på är du inte säker på att hela ditt meddelande finns med i de 64 K (= ca 64 ms) som en read_sample() täcker. Nästa read_sample kommer att ge nästa 64 ms och nästan garanterat kommer din signal att hamna på gränsen

Precis. För varje gång jag triggar sdr.read_samples tar den en avläsning på x antal samples och således får jag en väldigt upphackad array i slutändan.

Citat:
Är din "sample_factor" är satt för att få meddelandet att få plats i en read_samples()? I så fall kanske man kan göra en cirkulär buffer, så att du alltid har lite extra för att få med "svansen".
Annars får du skriva om din avkodare så att den har kvar sitt tillstånd mellan anrop. Då är det bara att mata på med outputen från main-loopen.

sample_factor är just en faktor (sample_factor*1024), som experiment använde jag samma variabel för att lättare justera antal samples så i exemplet är den nog bara som en variabel som jag kan justera med alla andra config-variabler (frekvens, sample_rate correction etc.) för att slippa scrolla ned och ändra den manuellt hela tiden.

Ditt sista stycke är nog det jag vill ha, lite som deque(), att ha en hink som fyller med samples tills det är hela meddelandet och sedan kan man avkoda den.

Man kan läsa kod snabbare än vad man kör den. Bättre att läsa den.
För koden är inte körbar utan hårdvara. Skall du köra den får du helt ta bort sdr.read_samples och lägga till en ljudfil eller en np.array-fil och köra np eller scipy på den.
Citera
2020-12-10, 03:27
  #9
Medlem
Citat:
Ursprungligen postat av Methos
Hur kan man få ner frekvensen av loopen så att den hinner processa hela signalen?

Verkar saknas en del i koden för att den ska starta överhuvudtaget.

Kod:
diff --git a/rtl.py b/rtl.py
index ddb0040..731b73d 100644
--- a/rtl.py
+++ b/rtl.py
@@ -1,6 +1,12 @@
+import np
+from scipy import signal
 from rtlsdr import RtlSdr
+sig = signal
 sdr = RtlSdr()
 
+offset_frequency = 0 # ?
+dec_factor = 1 # ?
+
 # configure sdr-device
 sdr.sample_rate = 1.024e6  # Hz
 sdr.center_freq = 169.8e6  # Hz
__________________
Senast redigerad av Hominem 2020-12-10 kl. 03:31.
Citera
2020-12-10, 15:19
  #10
Medlem
Citat:
Ursprungligen postat av Hominem
Verkar saknas en del i koden för att den ska starta överhuvudtaget.

Kod:
diff --git a/rtl.py b/rtl.py
index ddb0040..731b73d 100644
--- a/rtl.py
+++ b/rtl.py
@@ -1,6 +1,12 @@
+import np
+from scipy import signal
 from rtlsdr import RtlSdr
+sig = signal
 sdr = RtlSdr()
 
+offset_frequency = 0 # ?
+dec_factor = 1 # ?
+
 # configure sdr-device
 sdr.sample_rate = 1.024e6  # Hz
 sdr.center_freq = 169.8e6  # Hz

Varför har du kört en git diff på koden? Varför läser du inte inläggen innan du ger dig in i onödiga saker?
Du kan inte köra koden utan LibRTLSDR och en RTL-sdr-dongel. Du kommer att få Error redan på importen av RTLSDR då den inte hittar varken lib eller hårdvaran.

Sedan klistrade jag in de bitar som är relevanta för ämnet. Denna gång var det While loopens beteende.
Den har ingenting att göra med scipy.signal.filtfilt() som du av någon anledning gjorde en git diff på.

Alla variabler hittar du i koden och du finner vad det är i funktionserna, såsom dec_factor, är rätt så självutnämnande; decimerinsfaktor, dvs nämnaren i en divition.
Citera
2020-12-10, 15:45
  #11
Medlem
Citat:
Ursprungligen postat av Methos
Varför har du kört en git diff på koden? Varför läser du inte inläggen innan du ger dig in i onödiga saker?
Du kan inte köra koden utan LibRTLSDR och en RTL-sdr-dongel. Du kommer att få Error redan på importen av RTLSDR då den inte hittar varken lib eller hårdvaran.

Sedan klistrade jag in de bitar som är relevanta för ämnet. Denna gång var det While loopens beteende.
Den har ingenting att göra med scipy.signal.filtfilt() som du av någon anledning gjorde en git diff på.

Alla variabler hittar du i koden och du finner vad det är i funktionserna, såsom dec_factor, är rätt så självutnämnande; decimerinsfaktor, dvs nämnaren i en divition.

Får jag inte lägga in din kod i ett lokalt git repo?

Jag har en dvb-t mottagare med kretsen och jag har installerat libbarna.

Om din kod inte är körbar så räkna inte med hjälp.

Förresten får jag ut en del från demoduleringen när jag lade till mina ändring och ett anrop till den funktionen, kommer som en lista av True och false.
__________________
Senast redigerad av Hominem 2020-12-10 kl. 15:50.
Citera
2020-12-10, 16:10
  #12
Medlem
Citat:
Ursprungligen postat av Hominem
Får jag inte lägga in din kod i ett lokalt git repo?

Jag har en dvb-t mottagare med kretsen och jag har installerat libbarna.

Om din kod inte är körbar så räkna inte med hjälp.

Förresten får jag ut en del från demoduleringen när jag lade till mina ändring och ett anrop till den funktionen, kommer som en lista av True och false.

Ja, Det du har kört är en körbar kod som avkodar signalerna till en bool-array, vilket jag skrev i min trådstart. Problemet som tråden handlar om är att den bool-array du har hittat inte är komplett. Om du kör koden länge ser du snart att du har ett flertal array som printas ut. Alla är ett unikt resultat av en körning av read_sample() och det är just där problemet ligger: loopen behöver på något sätt synkas med själva signalen så att man får med hela sändningen i avkodningen. Nu körs den en miljon gånger snabbare än den bit rate som signalen kommer i.

Så, koden fungerar.
Citera
  • 1
  • 2

Skapa ett konto eller logga in för att kommentera

Du måste vara medlem för att kunna kommentera

Skapa ett konto

Det är enkelt att registrera ett nytt konto

Bli medlem

Logga in

Har du redan ett konto? Logga in här

Logga in