diff --git a/Makefile b/Makefile
index a73ca9f..fa0d07a 100644
--- a/Makefile
+++ b/Makefile
@@ -85,6 +85,11 @@ html-nl:
$(SPHINXBUILD) -b html -D project="PySDR: Een handleiding voor SDR en DSP met Python" -D exclude_patterns=_build,index.rst,content/*,index-fr.rst,content-fr/*,index-ukraine.rst,content-ukraine/*,index-zh.rst,content-zh/*,index-es.rst,content-es/* -D master_doc=index-nl $(EXTENSIONS) . $(BUILDDIR)/nl/
@echo
@echo "Dutch Build finished. The HTML pages are in $(BUILDDIR)/nl/html."
+ @echo translating title of index and content pages
+ sed -i 's/PySDR: A Guide to SDR and DSP using Python/PySDR: Een handleiding voor SDR en DSP met Python/g' $(BUILDDIR)/nl/index-nl.html
+ sed -i 's/PySDR: A Guide to SDR and DSP using Python/PySDR: Een handleiding voor SDR en DSP met Python/g' $(BUILDDIR)/nl/content-nl/*.html
+ @echo removing chapter number from titles of each page
+ sed -i -E "s/
+ Welkom bij PySDR, een gratis online boek (geen Python-bibliotheek!) dat met een een overvloed aan diagrammen, animaties en Python-codevoorbeelden een zachte introductie biedt tot draadloze communicatie en software-gedefinieerde-radio (SDR). Van FFT's tot filters tot digitale modulatie tot ontvangen en verzenden via SDR's in Python, PySDR heeft het allemaal!
+
+
+
+ Het doel van PySDR is om de toegankelijkheid van onderwerpen die traditioneel met zware wiskunde in een aantal universiteiten worden behandeld, te vergroten. Alle inhoud die wordt gebruikt om PySDR te genereren, is open source en kun je
+ hier vinden.
+
+ Probeer eens te spelen met de onderstaande simulatie als voorproefje op RF signaalverwerking. De simulatie laat het frequentie- en tijdsdomein van een signaal zien dat bestaat uit een toon en witte Gaussische ruis.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/content-nl/filters.rst b/content-nl/filters.rst
index e11affa..3603e70 100644
--- a/content-nl/filters.rst
+++ b/content-nl/filters.rst
@@ -323,6 +323,101 @@ Dit kan lastig zijn om te vatten want we passen het filter toe op een signaal en
Maak je geen zorgen als dit stuk nog meer verwarring heeft veroorzaakt, 99% van de tijd gebruiken we alleen laagdoorlaatfilters met reële coëfficiënten.
+.. _convolution_nl-section:
+
+*************************
+Convolutie
+*************************
+
+We nemen een korte omleiding om de convolutie operatie te introduceren.
+Voel je vrij deze sectie over te slaan als je er al bekend mee bent.
+
+Een manier om twee signalen samen te voegen is door ze op te tellen.
+In het :ref:`freq-domain-chapter` hoofdstuk hebben we ontdekt hoe lineariteit geldt wanneer we twee signalen optellen.
+Convolutie is een andere manier om twee signalen te combineren, maar het is compleet anders dan optellen.
+Convolutie van twee signalen is alsof je ze over elkaar schuift en dan integreert.
+Het lijkt *enorm* op kruiscorrelatie, als je daar bekend mee bent.
+Het is in veel gevallen eigenlijk hetzelfde als kruiscorrelatie.
+Meestal gebruiken we het :code:`*` symbool om convolutie aan te geven.
+
+Ik ben overtuigd dat je convolutie het beste leert met hulp van voorbeelden.
+In dit eerste voorbeeld convolueren we twee blokgolven met elkaar.
+
+.. image:: ../_images/rect_rect_conv.gif
+ :scale: 100 %
+ :align: center
+
+Er zijn twee ingangssignalen (een rode en een blauwe) en de uitgang van de convolutie is in het zwart weergegeven.
+Je kunt zien dat de uitgang gelijk is aan de integratie van de twee signalen terwijl ze over elkaar schuiven.
+Omdat het gewoon schuivende integratie is, is het resultaat een driehoek met zijn maximum op het punt waar de twee golven perfect overlappen.
+
+Laten we nog een paar convoluties bekijken:
+
+.. image:: ../_images/rect_fat_rect_conv.gif
+ :scale: 90 %
+ :align: center
+
+|
+
+.. image:: ../_images/rect_exp_conv.gif
+ :scale: 90 %
+ :align: center
+
+|
+
+.. image:: ../_images/gaussian_gaussian_conv.gif
+ :scale: 90 %
+ :align: center
+
+Het convolueren van een Gaussische puls met een Gaussische puls geeft een Gaussische puls, maar breder en een lagere amplitude.
+
+Vanwege dit geschuif is de lengte van de uitgang groter dan de ingang.
+Als het ene signaal :code:`M` samples heeft en het ander signaal :code:`N` samples, dan geeft de convolutie van de twee signalen :code:`N+M-1` samples.
+Desalniettemin hebben functies zoals :code:`numpy.convolve()` een manier om aan te geven of je de volledige uitgang (:code:`max(M, N)` samples) wilt hebben, of alleen de samples waar de signalen overlapten(:code:`max(M, N) - min(M, N) + 1` als je nieuwsgierig was).
+Geen reden om in deze details verstrikt te raken.
+Probeer hieruit op te pikken dat de uitgang van een convolutie niet de lengte heeft van de ingangen.
+
+En waarom is convolutie interessant in digitale signaalbewerking?
+Om te beginnen, om een signaal te filteren, kunnen we simpelweg de impulsrespons van het filter nemen en convolueren met het signaal. Een FIR-filter voert dus convolutie uit.
+
+.. image:: ../_images/filter_convolve.png
+ :scale: 70 %
+ :align: center
+
+Dit is misschien verwarrend gezien we eerder zeiden dat convolutie twee ingangen en een uitgang heeft.
+De convolutie voert een wiskundige actie uit op twee 1D arrays. Een van die 1D arrays is de impulsrespons van het filter, de andere 1D array kan een stuk van het ingangssignaal zijn, en de uitgang is dan de gefilterde versie van de ingang.
+
+Laten we naar nog een voorbeeld kijken om dit duidelijk te maken. In het onderstaande voorbeeld stelt de driehoek de impulsrespons van ons filter voor. Het :green:`groene` signaal is het signaal wat gefilterd wordt.
+
+.. image:: ../_images/convolution.gif
+ :scale: 70 %
+ :align: center
+
+De :red:`rode` uitgang is het gefilterde signaal.
+
+Vraag: wat voor type filter was de driehoek?
+
+.. raw:: html
+
+
+ Antwoord:
+
+Het heeft de hoge frequentiecomponenten van het groene signaal gladgestreken (de scherpe overgangen van het vierkant) dus het gedraagt zich als een laagdoorlaatfilter.
+
+.. raw:: html
+
+
+
+Nu je convolutie begint te begrijpen zal ik de wiskundige vergelijking ervan geven. De asterisk (*) wordt normaal gebruikt om convolutie aan te geven:
+
+.. math::
+
+ (f * g)(t) = \int f(\tau) g(t - \tau) d\tau
+
+In de bovenstaande vergelijking is :math:`g(t)` een van de twee signalen, het wordt omgedraaid en over :math:`f(t)` heen geschoven. Je kunt :math:`g(t)` en :math:`f(t)` omwisselen zonder gevolgen, het blijft dezelfde vergelijking.
+Meestal wordt het kortere signaal gebruikt als zijnde :math:`g(t)`.
+Convolutie staat gelijk aan de kruiscorrelatie, :math:`\int f(\tau) g(t+\tau)`, in het geval dat :math:`g(t)` symmetrisch is, dus wanneer het omdraaien geen effect heeft.
+
*************************
Filterimplementatie
*************************
@@ -392,131 +487,167 @@ Dit is een laagdoorlaat IIR-filter.
Hopelijk kun je zien waarom dit minder stabiel is. De waarden zullen nooit volledig verdwijnen!
*************************
-Filterontwerptools
+Filterontwerp
*************************
-In de praktijk gebruiken de meeste mensen een ontwerptool of een functie om het filter te ontwerpen.
-Er zijn veel van zulk soort tools maar de studenten raad ik aan om deze gemakkelijke web app te gebruiken: http://t-filter.engineerjs.com. Het is gemaakt door Peter Isza en laat je de impuls- en frequentierespons zien.
-Op het moment van schrijven is de tool standaard ingesteld op een laagdoorlaatfilter met een doorlaatband van 0 tot 400 Hz en een stopband van 500 Hz en hoger.
-De sample-frequentie staat ingesteld op 2 kHz, dus de maximaal "zichtbare" frequentie is 1 kHz.
+In de praktijk gebruiken de meeste mensen een ontwerptool of een softwarefunctie (bijv. Python/SciPy) om het filter te ontwerpen.
+We zullen eerst laten zien wat mogelijk is binnen Python voordat we naar externe tools gaan kijken. Onze focus ligt op FIR filters, omdat deze het meest worden toegepast voor digitale signaalbewerking.
-.. image:: ../_images/filter_designer1.png
- :scale: 70 %
- :align: center
+Binnen Python
+#################
-Klik op de "Design Filter" knop om de coëfficiënten te genereren en de frequentierespons te weergeven.
+Als onderdeel van het ontwerpen van een filter, dus de coëfficiënten genereren voor onze gewenste respons, moeten we het type filter kiezen (laagdoorlaat, hoogdoorlaat, banddoorlaat of bandstop), de kantelfrequentie/frequenties, het aantal coëfficiënten en optioneel de transitiebreedte.
-.. image:: ../_images/filter_designer2.png
- :scale: 70 %
- :align: center
+Er zijn twee manieren in SciPy die we zullen gebruiken om FIR-filters te ontwerpen, beide gebruiken de zogenaamde "raam-methode". Als eerste is er :code:`scipy.signal.firwin()` wat het meest rechttoe rechtaan is; het geeft de coëfficiënten voor een FIR-filter met een lineaire fase. De functie heeft het aantal coëfficiënten en kantelfrequentie nodig (voor laagdoorlaat/hoogdoorlaat) en twee kantelfrequenties voor banddoorlaat/bandstop. Optioneel kun je de transitiebreedte geven. Als je de samplefrequentie via :code:`fs` doorgeeft, dan zijn de eenheden van je kantelfrequentie en transitiebreedte in Hz, maar als je het niet meegeeft dan zijn de frequenties genormaliseerd (0 tot 1 Hz). Het :code:`pass_zero` argument is standaard :code:`True`, maar als je een hoogdoorlaat- of banddoorlaatfilter wilt, dan moet je het op :code:`False` zetten; het geeft aan of 0 Hz in de doorlaatband moet zitten. Het wordt aangeraden om een oneven aantal coëfficiënten te gebruiken, en 101 coëfficiënten is een goed startpunt. Laten we bijvoorbeleld een banddoorlaatfilter maken van 100 kHz tot 200 kHz met een samplefrequentie van 1 MHz:
-Klik op de "Impulse Response" link boven de grafiek om de impulsrespons te zien, wat een weergave is van de coëfficiënten omdat dit een FIR filter betreft.
+.. code-block:: python
-.. image:: ../_images/filter_designer3.png
- :scale: 70 %
- :align: center
+ from scipy.signal import firwin
+ sample_rate = 1e6
+ h = firwin(101, [100e3, 200e3], pass_zero=False, fs=sample_rate)
+ print(h)
-De app kan zelfs de C broncode genereren waarmee je dit filter kunt implementeren en gebruiken.
-De app heeft geen manier om een IIR-filter te implementeren omdat deze over het algemeen veel lastiger zijn om te ontwerpen.
+De andere optie is om :code:`scipy.signal.firwin2()` te gebruiken, wat flexibeler is en gebruikt kan worden om filters met een aangepaste frequentierespons te ontwerpen, omdat je een lijst van frequenties en de gewenste versterking bij elke frequentie geeft. Het vereist ook het aantal coëfficiënten en ondersteunt dezelfde :code:`fs` parameter als hierboven genoemd. Laten we als voorbeeld een filter maken met een laagdoorlaatgebied tot 100 kHz, en een apart banddoorlaatgebied van 200 kHz tot 300 kHz, maar met de helft van de versterking van het laagdoorlaatgebied, en we zullen een transitiebreedte van 10 kHz gebruiken:
-.. _convolution_nl-section:
-*************************
-Convolutie
-*************************
+.. code-block:: python
-We nemen een korte omleiding om de convolutie operatie te introduceren.
-Voel je vrij deze sectie over te slaan als je er al bekend mee bent.
+ from scipy.signal import firwin2
+ sample_rate = 1e6
+ freqs = [0, 100e3, 110e3, 190e3, 200e3, 300e3, 310e3, 500e3]
+ gains = [1, 1, 0, 0, 0.5, 0.5, 0, 0]
+ h2 = firwin2(101, freqs, gains, fs=sample_rate)
+ print(h2)
-Een manier om twee signalen samen te voegen is door ze op te tellen.
-In het :ref:`freq-domain-chapter` hoofdstuk hebben we ontdekt hoe lineariteit geldt wanneer we twee signalen optellen.
-Convolutie is een andere manier om twee signalen te combineren, maar het is compleet anders dan optellen.
-Convolutie van twee signalen is alsof je ze over elkaar schuift en dan integreert.
-Het lijkt *enorm* op kruiscorrelatie, als je daar bekend mee bent.
-Het is in veel gevallen eigenlijk hetzelfde als kruiscorrelatie.
-Meestal gebruiken we het ::code::`*` symbool om convolutie aan te geven.
+Om het FIR filter ook echt op een signaal toe te kunnen passen zijn er verschillende opties, en ze vereisen allemaal een convolutie-operatie tussen de samples die we willen filteren en de coëfficiënten die we hierboven hebben gegenereerd:
-Ik ben overtuigd dat je convolutie het beste leert met hulp van voorbeelden.
-In dit eerste voorbeeld convolueren we twee blokgolven met elkaar.
+- :code:`np.convolve`
+- :code:`scipy.signal.convolve`
+- :code:`scipy.signal.fftconvolve`
+- :code:`scipy.signal.lfilter`
-.. image:: ../_images/rect_rect_conv.gif
- :scale: 100 %
- :align: center
+De bovenstaande convolutiefuncties hebben allemaal een :code:`mode` argument die de opties :code:`'full'`, :code:`'valid'`, of :code:`'same'` accepteert. Het verschil zit in de grootte van de uitvoer, omdat bij het uitvoeren van een convolutie, zoals we eerder in dit hoofdstuk hebben gezien, er aan het begin en einde overgangsverschijnselen kunnen ontstaan. De :code:`'valid'` optie bevat geen overgangsverschijnselen, maar de uitvoer zal iets kleiner zijn dan het signaal dat aan de functie is gegeven. De :code:`'same'` optie geeft een uitvoer die even groot is als het ingangssignaal, wat handig is bij het bijhouden van tijd of andere tijd-domein signaal eigenschappen. De :code:`'full'` optie bevat alle overgangsverschijnselen; het geeft de volledige convolutieresultaat.
-Er zijn twee ingangssignalen (een rode en een blauwe) en de uitgang van de convolutie is in het zwart weergegeven.
-Je kunt zien dat de uitgang gelijk is aan de integratie van de twee signalen terwijl ze over elkaar schuiven.
-Omdat het gewoon schuivende integratie is, is het resultaat een driehoek met zijn maximum op het punt waar de twee golven perfect overlappen.
+Nu gaan we alle vier convolutiefuncties op een testsignaal van witte Gausische-ruis toepassen met de filtercoefficienten die we hierboven hebben gemaakt. Let op dat :code:`lfilter` een extra argument heeft (de 2e) die altijd 1 is voor een FIR-filter.
-Laten we nog een paar convoluties bekijken:
+.. code-block:: python
-.. image:: ../_images/rect_fat_rect_conv.gif
- :scale: 90 %
- :align: center
+ import numpy as np
+ from scipy.signal import firwin2, convolve, fftconvolve, lfilter
-|
+ # Maak een testsignaal met gauschische ruis
+ sample_rate = 1e6 # Hz
+ N = 1000 # samples to simulate
+ x = np.random.randn(N) + 1j * np.random.randn(N)
-.. image:: ../_images/rect_exp_conv.gif
- :scale: 90 %
- :align: center
+ # We maken weer het fir filter zoals hierboven
+ freqs = [0, 100e3, 110e3, 190e3, 200e3, 300e3, 310e3, 500e3]
+ gains = [1, 1, 0, 0, 0.5, 0.5, 0, 0]
+ h2 = firwin2(101, freqs, gains, fs=sample_rate)
-|
+ # Het filter toepassen met de verschillende convolutiemethoden
+ x_numpy = np.convolve(h2, x)
+ x_scipy = convolve(h2, x) # scipys convolve
+ x_fft_convolve = fftconvolve(h2, x)
+ x_lfilter = lfilter(h2, 1, x) # Tweede argument is altijd 1 voor een FIR-filter
-.. image:: ../_images/gaussian_gaussian_conv.gif
- :scale: 90 %
+ # Bewijs dat ze allemaal hetzelfde resultaat geven
+ print(x_numpy[0:2])
+ print(x_scipy[0:2])
+ print(x_fft_convolve[0:2])
+ print(x_lfilter[0:2])
+
+Bovenstaande code laat zien hoe je de vier methoden kunt gebruiken, maar misschien vraag je je af welke het beste is. De onderstaande grafieken laten alle vier methoden zien voor verschillende hoevelheid coefficienten. Het werd uitgevoerd op een Intel Core i9-10900K.
+
+.. image:: ../_images/convolve_comparison_1000.svg
:align: center
+ :target: ../_images/convolve_comparison_1000.svg
-Het convolueren van een Gaussische puls met een Gaussische puls geeft een Gaussische puls, maar breder en een lagere amplitude.
+.. image:: ../_images/convolve_comparison_100000.svg
+ :align: center
+ :target: ../_images/convolve_comparison_100000.svg
-Vanwege dit geschuif is de lengte van de uitgang groter dan de ingang.
-Als het ene signaal :code:`M` samples heeft en het ander signaal :code:`N` samples, dan geeft de convolutie van de twee signalen :code:`N+M-1` samples.
-Desalniettemin hebben functies zoals :code:`numpy.convolve()` een manier om aan te geven of je de volledige uitgang (:code:`max(M, N)` samples) wilt hebben, of alleen de samples waar de signalen overlapten(:code:`max(M, N) - min(M, N) + 1` als je nieuwsgierig was).
-Geen reden om in deze details verstrikt te raken.
-Probeer hieruit op te pikken dat de uitgang van een convolutie niet de lengte heeft van de ingangen.
+Zoals je kunt zien, schakelt :code:`scypi.signal.convolve` automatisch over naar een FFT-gebaseerde methode bij een bepaalde invoergrootte. Hoe dan ook, :code:`fftconvolve` is de duidelijke winnaar voor deze grootte van coëfficiënten en invoer, wat vrij typische groottes zijn in RF-toepassingen. Veel code binnen PySDR gebruikt :code:`np.convolve:` simpelweg omdat het een import minder is en het prestatieverschil verwaarloosbaar is voor lage datarates of niet real-time toepassingen.
-En waarom is convolutie interessant in digitale signaalbewerking?
-Om te beginnen, om een signaal te filteren, kunnen we simpelweg de impulsrespons van het filter nemen en convolueren met het signaal. Een FIR-filter voert dus convolutie uit.
+Als laatste laten we dezelfde uitvoer in het frequentiedomein zien, zodat we eindelijke kunnen controleren of de firwin2-functie ook echt een filter heeft gegeven wat aan onze eisen voldoet. We beginnen met de code die ons :code:`h2` gaf:
-.. image:: ../_images/filter_convolve.png
- :scale: 70 %
- :align: center
+.. code-block:: python
-Dit is misschien verwarrend gezien we eerder zeiden dat convolutie twee ingangen en een uitgang heeft.
-De convolutie voert een wiskundige actie uit op twee 1D arrays. Een van die 1D arrays is de impulsrespons van het filter, de andere 1D array kan een stuk van het ingangssignaal zijn, en de uitgang is dan de gefilterde versie van de ingang.
+ # Simuleer een signaal van Gausische ruis
+ N = 100000 # signaallengte
+ x = np.random.randn(N) + 1j * np.random.randn(N) # complex signaal
+
+ # PSD van het ingangssignaal
+ PSD_input = 10*np.log10(np.fft.fftshift(np.abs(np.fft.fft(x))**2)/len(x))
+
+ # Filter toepassen
+ x = fftconvolve(x, h2, 'same')
+
+ # PSD van de uitgang laten zien
+ PSD_output = 10*np.log10(np.fft.fftshift(np.abs(np.fft.fft(x))**2)/len(x))
+ f = np.linspace(-sample_rate/2/1e6, sample_rate/2/1e6, len(PSD_output))
+ plt.plot(f, PSD_input, alpha=0.8)
+ plt.plot(f, PSD_output, alpha=0.8)
+ plt.xlabel('Frequency [MHz]')
+ plt.ylabel('PSD [dB]')
+ plt.axis([sample_rate/-2/1e6, sample_rate/2/1e6, -40, 20])
+ plt.legend(['Input', 'Output'], loc=1)
+ plt.grid()
+ plt.savefig('../_images/fftconvolve.svg', bbox_inches='tight')
+ plt.show()
-Laten we naar nog een voorbeeld kijken om dit duidelijk te maken. In het onderstaande voorbeeld stelt de driehoek de impulsrespons van ons filter voor. Het :green:`groene` signaal is het signaal wat gefilterd wordt.
+We zien dat het banddoorlaatgebied 3 dB lager ligt dan het laagdoorlaatgebied:
-.. image:: ../_images/convolution.gif
- :scale: 70 %
+.. image:: ../_images/fftconvolve.svg
:align: center
+ :target: ../_images/fftconvolve.svg
-De :red:`rode` uitgang is het gefilterde signaal.
+Buiten dit is er nog een obscure optie om een signaal te filteren genaamd :code:`scipy.signal.filtfilt`, wat "zero-phase filtering" uitvoert, wat helpt om kenmerken in een gefilterd tijdsignaal precies te behouden waar ze voorkomen in het ongefilterde signaal. Dit wordt gedaan door de filtercoëfficiënten twee keer toe te passen, eerst in de voorwaartse richting en dan in de omgekeerde richting. Dus de frequentierespons zal een gekwadrateerde versie zijn van wat je normaal zou krijgen. Voor meer informatie zie https://www.mathworks.com/help/signal/ref/filtfilt.html of https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.filtfilt.html.
-Vraag: wat voor type filter was de driehoek?
+Stateful Filtering
+##################
-.. raw:: html
+Als je een filter real-time wilt toepassen op opvolgende blokken van samples, dan heb je een stateful filter nodig. Dit betekent dat je elke aanroep de initiële condities geeft die uit de vorige aanroep van het filter zijn gehaald. Dit verwijdert overgangsverschijnselen die optreden wanneer een signaal start en stopt (immers, de samples die je tijdens opvolgende blokken invoert zijn aaneengesloten, mits je toepassing het kan bijhouden). De toestand moet tussen aanroepen worden opgeslagen, en moet ook aan het begin van je code worden geïnitialiseerd voor de eerste filteraanroep. Gelukkig bevat SciPy :code:`lfilter_zi` dat initiële condities voor lfilter genereert. Hieronder staat een voorbeeld van het verwerken van blokken aaneengesloten samples met stateful filtering:
-
- Antwoord:
+.. code-block:: python
-Het heeft de hoge frequentiecomponenten van het groene signaal gladgestreken (de scherpe overgangen van het vierkant) dus het gedraagt zich als een laagdoorlaatfilter.
+ b = taps
+ a = 1 # voor FIR, niet-1 voor IIR
+ zi = lfilter_zi(b, a) # bereken de initiële condities
+ while True:
+ samples = sdr.read_samples(num_samples) # Vervang dit met de functie van jouw SDR
+ samples_filtered, zi = lfilter(b, a, samples, zi=zi) # filter toepassen
-.. raw:: html
+Externe Tools
+#################
-
+Je kunt ook externe tools gebruiken om een eigen filter te ontwerpen. Voor studenten raad ik aan om deze gemakkelijke web app te gebruiken: http://t-filter.engineerjs.com. Het is gemaakt door Peter Isza en laat je de impuls- en frequentierespons zien.
+Op het moment van schrijven is de tool standaard ingesteld op een laagdoorlaatfilter met een doorlaatband van 0 tot 400 Hz en een stopband van 500 Hz en hoger.
+De sample-frequentie staat ingesteld op 2 kHz, dus de maximaal "zichtbare" frequentie is 1 kHz.
-Nu je convolutie begint te begrijpen zal ik de wiskundige vergelijking ervan geven. De asterisk (*) wordt normaal gebruikt om convolutie aan te geven:
+.. image:: ../_images/filter_designer1.png
+ :scale: 70 %
+ :align: center
-.. math::
+Klik op de "Design Filter" knop om de coëfficiënten te genereren en de frequentierespons te weergeven.
- (f * g)(t) = \int f(\tau) g(t - \tau) d\tau
-
-In de bovenstaande vergelijking is :math:`g(t)` een van de twee signalen, het wordt omgedraaid en over :math:`f(t)` heen geschoven. Je kunt :math:`g(t)` en :math:`f(t)` omwisselen zonder gevolgen, het blijft dezelfde vergelijking.
-Meestal wordt het kortere signaal gebruikt als zijnde :math:`g(t)`.
-Convolutie staat gelijk aan de kruiscorrelatie, :math:`\int f(\tau) g(t+\tau)`, in het geval dat :math:`g(t)` symmetrisch is, dus wanneer het omdraaien geen effect heeft.
+.. image:: ../_images/filter_designer2.png
+ :scale: 70 %
+ :align: center
-*************************
-Filterontwerp in Python
-*************************
-Nu gaan we een manier bekijken om in Python FIR-filters te ontwerpen.
+Klik op de "Impulse Response" link boven de grafiek om de impulsrespons te zien, wat een weergave is van de coëfficiënten omdat dit een FIR filter betreft.
+
+.. image:: ../_images/filter_designer3.png
+ :scale: 70 %
+ :align: center
+
+De app kan zelfs de C broncode genereren waarmee je dit filter kunt implementeren en gebruiken.
+De app heeft geen manier om een IIR-filter te implementeren omdat deze over het algemeen veel lastiger zijn om te ontwerpen.
+
+
+********************************
+Willekeurige frequentieresponsie
+********************************
+Nu gaan we een manier bekijken om in Python FIR-filters te ontwerpen op basis van onze gewenste frequentieresponsie.
Er zijn vele manieren om een filter te ontwerpen, wij zullen in het frequentiedomein starten en terugwerken naar de impulsrespons. Uiteindelijk wordt het filter ook zo beschreven (in coëfficiënten).
Je begint met jouw gewenste frequentierespons in een vector plaatsen.
diff --git a/content-nl/frequency_domain.rst b/content-nl/frequency_domain.rst
index 991ac4a..283e056 100644
--- a/content-nl/frequency_domain.rst
+++ b/content-nl/frequency_domain.rst
@@ -4,7 +4,7 @@
Het Frequentiedomein
#####################
-Dit hoofdstuk introduceert het frequentiedomein en behandelt de Fourierreeks, Fouriertransformatie, Fourier eigenschappen, FFT, vensterfuncties en spectrogrammen, door gebruik te maken van Python voorbeelden.
+Dit hoofdstuk introduceert het frequentiedomein en behandelt de Fourierreeks, Fouriertransformatie, Fouriereigenschappen, FFT, vensterfuncties en spectrogrammen, door gebruik te maken van Python voorbeelden.
Een van de coolste gevolgen van het leren over DSP en draadloze communicatie is dat je ook leert te denken in het frequentiedomein. De ervaring met het werken in het frequentiedomein is voor de meeste mensen gelimiteerd tot het aanpassen van de bas/mid/treble knoppen op het audiosysteem van een auto. De ervaring met het *zien* van het frequentiedomein is voor de meeste mensen gelimiteerd tot het zien van een audio equalizer, zoals deze clip:
@@ -192,7 +192,7 @@ Deze eigenschap is waarschijnlijk het makkelijkst om te begrijpen. Als we twee t
Dit vertelt ons ook dat als we enig signaal vermenigvuldigen met een factor, het signaal in het frequentiedomein met dezelfde factor zal groeien/krimpen.
Het nut van deze eigenschap zal duidelijker worden wanneer we meerdere signalen gaan optellen.
-1. Frequentieverschuiving:
+2. Frequentieverschuiving:
.. math::
e^{2 \pi j f_0 t}x(t) \leftrightarrow X(f-f_0)
@@ -214,7 +214,7 @@ Hier is nog een manier om deze eigenschap te laten zien:
:align: center
:alt: Visualization of a frequency shift by multiplying by a sine wave or sinusoid
-1. Vermenigvuldigen in de tijd
+3. Vermenigvuldigen in de tijd
.. math::
x(at) \leftrightarrow X\left(\frac{f}{a}\right)
@@ -235,7 +235,7 @@ Als tijd-frequentie vermenigvuldiging recht evenredig zou zijn in plaats van omg
Diegenen die met deze eigenschap bekend zijn, valt het misschien op dat er een factor mist; deze is weggelaten voor de eenvoud.
Praktisch gezien heeft deze factor geen invloed.
-1. Convolutie in de tijd
+4. Convolutie in de tijd
.. math::
\int x(\tau) y(t-\tau) d\tau \leftrightarrow X(f)Y(f)
@@ -352,12 +352,15 @@ Dit wordt logischer wanneer we meer over samplen leren en ervaring opdoen met on
**********************************
Volgorde in de tijd maakt niet uit
**********************************
-Nog een laatste eigenschap voordat we naar het gebruik van de FFT gaan.
-De FFT "mixt" soort van het ingangssignaal naar de uitgang, wat een andere schaal en eenheid heeft.
+Recall that an FFT is performed on many samples at once, i.e., you can't observe the frequency domain of a single instance in time (one sample); it needs a span of time to operate on (many samples).
+Een FFT wordt uitgevoerd op vele samples tegelijk, d.w.z., je kunt het frequentiedomein van een enkele tijdsinstantie (één sample) niet observeren; het heeft tijd nodig om te kunnen werken (vele samples).
+Eigenlijk "mixt" de FFT het ingangssignaal door elkaar om tot een uitgang te komen, wat een andere schaal en eenheid heeft.
We zitten namelijk niet langer in het tijddomein.
-Een goede manier om dit te onthouden is om te beseffen dat de volgorde waarin dingen in het tijddomein gebeuren geen invloed heeft op hoe het frequentiedomein er uit ziet.
-D.w.z., de FFT van het volgende signaal zal dezelfde twee pieken laten zien, want het signaal bestaat gewoon uit twee sinussen met verschillende frequenties.
+Een goede manier om de verschillen tussen de domeinen eigen te maken, is om te beseffen dat de volgorde waarin dingen in het tijddomein gebeuren, geen invloed heeft op hoe het frequentiedomein er uit ziet.
+D.w.z., een **enkele** FFT van de onderstaande signalen zal dezelfde twee pieken laten zien, want het signaal bestaat gewoon uit twee sinussen met verschillende frequenties.
Het feit dat er twee frequenties zijn, verandert niet wanneer we de volgorde van de sinussen omdraaien.
+Dit gaat er dan van uit dat beide sinussen binnen de samples vallen die we in de FFT stoppen.
+Als je de FFT-grootte verkleint, en meerdere FFT's uitvoert (zoals bij de spectrogrammen), dan zou je weer onderscheid kunnen maken tussen de twee sinussen.
.. image:: ../_images/fft_signal_order.png
:scale: 50 %
@@ -387,7 +390,7 @@ Als we :code:`s` plotten lijkt dit op:
:scale: 70 %
:align: center
-Laten we nu Numpy's FFT-functie gebruiken:
+Laten we nu NumPy's FFT-functie gebruiken:
.. code-block:: python
@@ -428,7 +431,7 @@ Het diagram hieronder laat zien wat deze FFT-shift doet:
:align: center
:alt: Reference diagram of the FFT shift function, showing positive and negative frequencies and DC
-Voor ons gemak heeft Numpy een FFT-shift functie :code:`np.fft.fftshift()`. Vervang de np.fft.fft() regel met:
+Voor ons gemak heeft NumPy een FFT-shift functie :code:`np.fft.fftshift()`. Vervang de np.fft.fft() regel met:
.. code-block:: python
diff --git a/content-nl/intro.rst b/content-nl/intro.rst
index 63692c4..4b05fad 100644
--- a/content-nl/intro.rst
+++ b/content-nl/intro.rst
@@ -11,10 +11,12 @@ Doel en doelgroep
Als eerste een paar belangrijke termen:
**Software-Defined Radio (SDR):**
- Nederlands: software gedefinieerde radio. Een radio dat software gebruikt om signaalbewerkingen uit te voeren die normaal in hardware worden gedaan.
+ Als *concept* verwijst het naar het gebruik van software om signaalbewerkingen voor radio/RF toepassingen uit te voeren die normaal in hardware worden gedaan. Deze software kan worden uitgevoerd op een algemene computer (CPU), FPGA of zelfs een GPU, en kan worden gebruikt voor real-time toepassingen of offline bewerking van opgenomen signalen. Alternatieve termen zijn "software radio" en "digitale radiosignaalbewerking".
+
+ Als *ding* (bijv. "een SDR") verwijst het meestal naar een apparaat waar je een antenne op aan kunt sluiten en RF-signalen mee kunt ontvangen waarbij de gedigitaliseerde RF-samples naar een computer worden gestuurd voor bewerking of opname (bijv. via USB, Ethernet, PCI). Veel SDR's hebben ook zendmogelijkheden, waardoor de computer samples naar de SDR kan sturen die vervolgens het signaal op een gespecificeerde radiofrequentie uitzendt. Sommige SDR's bevatten een ingebouwde computer.
**Digital signal Processing (DSP):**
- Nederlands: digitale signaalbewerking. Op een digitale manier signalen bewerken, in ons geval RF-signalen.
+ Op een digitale manier signalen bewerken, in ons geval RF-signalen.
Dit boek dient als een praktische introductie op de gebieden van DSP, SDR en draadloze communicatie. Het is ontworpen voor iemand die:
@@ -72,9 +74,10 @@ Bedankt aan iedereen die dit boek heeft gelezen en van feedback heeft voorzien,
- Deidre Stuffer
- Tarik Benaddi voor het `vertalen van PySDR naar het Frans `_
- Daniel Versluis voor het `vertalen van PySDR naar het Nederlands `_
-- `mrbloom `_ voor `vertalen van PySDR naar het Ukraiens `_
-- `Yimin Zhao `_ voor `vertalen van PySDR naar het Chinees `_
-
+- `mrbloom `_ voor het `vertalen van PySDR naar het Ukraiens `_
+- `Yimin Zhao `_ voor het `vertalen van PySDR naar het Chinees `_
+- `Eduardo Chancay `_ voor het `vertalen van PySDR naar het Spaans `_
+
**********************
Nederlandse vertaling
**********************
diff --git a/content-nl/noise.rst b/content-nl/noise.rst
index 53e8dc1..d312831 100644
--- a/content-nl/noise.rst
+++ b/content-nl/noise.rst
@@ -190,7 +190,7 @@ We kunnen dit zelf bewijzen door in Python wat ruis te genereren en daarna de FF
plt.plot(np.real(X), '.-') #reeele deel ipv lengte/modulus
plt.show()
-We merken op dat de randn() functie standaard een gemiddelde heeft van 0 en variantie van 1. Beide figuren zullen er ongeveer zo uitzien:
+We merken op dat de :code:`randn()` functie standaard een gemiddelde heeft van 0 en variantie van 1. Beide figuren zullen er ongeveer zo uitzien:
.. image:: ../_images/noise_python.png
:scale: 100 %
diff --git a/content-nl/pulse_shaping.rst b/content-nl/pulse_shaping.rst
index e98e8b6..7bfee0f 100644
--- a/content-nl/pulse_shaping.rst
+++ b/content-nl/pulse_shaping.rst
@@ -106,11 +106,12 @@ Het wordt een raised-cosine filter genoemd omdat bij een :math:`\beta=1` het fre
De impulsresponsie van het filter kun je beschrijven met:
.. math::
- h(t) = \frac{1}{T} \mathrm{sinc}\left( \frac{t}{T} \right) \frac{\cos\left(\frac{\pi\beta t}{T}\right)}{1 - \left( \frac{2 \beta t}{T} \right)^2}
+ h(t) = \mathrm{sinc}\left( \frac{t}{T} \right) \frac{\cos\left(\frac{\pi\beta t}{T}\right)}{1 - \left( \frac{2 \beta t}{T} \right)^2}
Je kunt `hier `_ meer lezen over de :math:`\mathrm{sinc}()` functie.
+Op andere plekken vind je misschien de vergelijking met een :math:`\frac{1}{T}` ervoor; dit zorgt ervoor dat het filter een versterking heeft zodat het uitgangssignaal dezelfde amplitude heeft als het ingangssignaal (dit is over het algemeen een gewoonte bij het ontwerpen van filters). Maar, omdat we het op een pulstrein van symbolen (bijv. 1'en en -1'en) toepassen en we niet willen dat de amplitude van die symbolen na de pulsvorming verandert, laten we dus die deling achterwege. Dit zal duidelijker worden wanneer we in het Pythonvoorbeeld duiken en de uitkomst weergeven.
-Dit is het raised-cosine filter. Die gaan we echter in tweeën splitsen en dan krijgen we het Root Raised Cosine (RRC) filter!
+Onthoud dat we dit filter egaal opsplitsen tussen Tx en Rx. Dan nu het Root Raised Cosine (RRC) filter!
Root Raised-Cosine Filter
#########################
diff --git a/content-nl/rds.rst b/content-nl/rds.rst
index 512fa80..6034468 100644
--- a/content-nl/rds.rst
+++ b/content-nl/rds.rst
@@ -307,8 +307,8 @@ Fijne Frequentiesynchronisatie uitvoeren
phase = 0
freq = 0
# deze parameters maken de regelaar sneller of langzamer (of instabiel)
- alpha = 100
- beta = 0.23
+ alpha = 8.0
+ beta = 0.02
out = np.zeros(N, dtype=np.complex64)
freq_log = []
for i in range(N):
@@ -738,7 +738,7 @@ Mocht je de code moeten tweaken om het werkend te krijgen met jouw opname of SDR
import matplotlib.pyplot as plt
# Read in signal
- x = np.fromfile('/home/versd/Downloads/fm_1027mhz_250ksps', dtype=complex64)
+ x = np.fromfile('/jouw/pad/fm_1027mhz_250ksps', dtype=complex64)
sample_rate = 250e3
center_freq = 102.7e6
@@ -796,8 +796,8 @@ Mocht je de code moeten tweaken om het werkend te krijgen met jouw opname of SDR
phase = 0
freq = 0
# deze parameters maken de regelaar sneller of langzamer (of instabiel)
- alpha = 100
- beta = 0.23
+ alpha = 8
+ beta = 0.02
out = np.zeros(N, dtype=np.complex64)
freq_log = []
for i in range(N):
diff --git a/content-nl/sampling.rst b/content-nl/sampling.rst
index 72e8dd5..1d76781 100644
--- a/content-nl/sampling.rst
+++ b/content-nl/sampling.rst
@@ -445,7 +445,6 @@ Uitgang:
Extra Leesmateriaal
********************
-#. http://rfic.eecs.berkeley.edu/~niknejad/ee242/pdf/eecs242_lect3_rxarch.pdf
-#. https://appliedacousticschalmers.github.io/scaling-of-the-dft/AES2020_eBrief/
+#. https://web.archive.org/web/20220613052830/http://rfic.eecs.berkeley.edu/~niknejad/ee242/pdf/eecs242_lect3_rxarch.pdf
diff --git a/index-nl.rst b/index-nl.rst
index 99900fe..27ab7fc 100644
--- a/index-nl.rst
+++ b/index-nl.rst
@@ -1,8 +1,10 @@
-==========================================================================
-PySDR: Een handleiding voor SDRs en digitale signaalbewerking met Python
-==========================================================================
+.. raw:: html
+ :file: _templates/homepage_nl.html
-door :ref:`Dr. Marc Lichtman`
+.. raw:: html
+
+
+