Skip to main content

Traitement audio avec Raspberry Pi et Pmods

Présentation

La tâche principale consiste à appliquer des effets audio à un signal d’entrée. Pour simplifier le plus possible, les deux effets audio choisis pour ce projet comme preuve de concept sont l’effet d’écho et le pitch bend. La nature de ces effets sera abordée plus loin dans ce guide.

Block diagram showing circuit operation

Le Raspberry Pi possède la puissance de traitement nécessaire pour modifier un signal d’entrée en temps quasi réel. Par défaut, il ne dispose pas des périphériques nécessaires pour acquérir et lire ces signaux. Cependant, avec l’aide de l’adaptateur Pmod HAT et des Pmods de Digilent, une grande variété de modules périphériques Plug'n’Play peuvent être facilement branchés sur l’ordinateur monocarte. Nous captons le son, le modifions, puis le restituons. Tout d’abord, le signal audio est introduit dans un convertisseur analogique-numérique (CAN). La plupart des CAN ne peuvent pas traiter directement un signal d’entrée audio brut, il peut donc être nécessaire de conditionner le signal. Une fois le signal numérique traité, il doit être reconverti dans le domaine analogique à l’aide d’un convertisseur numérique-analogique (CNA). Avant d’envoyer le signal généré à un amplificateur ou à un haut-parleur actif, un conditionnement peut être à nouveau nécessaire.


Pour contrôler l’effet audio, nous créons l’interface utilisateur. Pour cette application, trois éléments de contrôle seront utilisés : un encodeur rotatif pour régler le degré de l’effet appliqué, un interrupteur pour changer le type d’effet et un bouton pour réinitialiser l’état du dispositif. Comme l’utilisateur a besoin d’un retour d’information sur l’état des commandes, un graphique à barres composé de 8 LED sera utilisé comme affichage. Une LED de mise sous tension est également utile, car elle peut indiquer si le circuit externe est alimenté ou non.

Configuration du Raspberry Pi

Nous utiliserons Python 3 pour ce projet, qui est préinstallé sur le système d’exploitation Raspberry Pi (version 3.7), mais le Python par défaut est Python 2. Pour faciliter les choses, Python 3 doit être défini comme l’interpréteur par défaut. Ouvrez un terminal sur Raspberry Pi, puis saisissez :

sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 1

Ensuite, les paquets Python nécessaires doivent être installés ou mis à niveau vers la dernière version, avec la commande suivante :

 

pip install numpy matplotlib gpiozero RPi.GPIO spidev --upgrade

Comme nous allons utiliser des périphériques contrôlés par l’interface SPI, cette interface doit être activée. Ouvrez les paramètres de configuration avec :

 

sudo raspi-config

Sélectionnez « Options d’interface », puis « SPI » ; activez l’interface en sélectionnant « Oui ».

Signal d’entrée

Pmod AD1

Image of a Pmod AD1 board

Le Raspberry Pi ne peut pas échantillonner les signaux analogiques directement, nous utilisons donc le Pmod AD1 de Digilent, un CAN 12 bits et 1MS/s. Le Pmod AD1 est alimenté par l’AD7476A d’Analog Devices. Il communique avec le Raspberry Pi via l’interface SPI.

La conversion suit cette formule : n=212*Vin/Vref — n étant le nombre de sortie, Vin la tension d’entrée et Vref la tension de référence, qui est égale à la tension d’alimentation (3,3V). Cependant, le CAN ne peut pas gérer une tension inférieure à 0V ou supérieure à la tension de référence. Bien que l’amplitude du signal audio sur la plupart des appareils soit assez faible (environ 1V), il a un décalage de 0V. La plage de tension est comprise entre -1V et 1V. Pour résoudre ce problème, il faut construire un circuit de conditionnement.

Conditionnement du signal d’entrée

Comme l’amplitude du signal audio est nettement inférieure à la tension de référence (2*A<Vref), il suffit d’ajouter un décalage positif au signal pour le faire passer au-dessus de 0V. Pour ce faire, un amplificateur sommateur sera utilisé, comme le montre l’image ci-dessous.

Input Signal Conditioning Circuit

Dans cette configuration, la tension de décalage souhaitée est définie par les résistances R4 et R5 : Voffset=VSS*R4/(R4+R5), VSS étant la tension d’alimentation négative. La tension de sortie est obtenue selon la formule suivante : Vout=-(Vin*R2/R1+Voffset*R2/R3)=-(Vin*R2/R1+VSS*R4/[R4+R5]), auquel cas les résistances R4 et R5 règlent la tension de décalage et les résistances R1 et R2 règlent l’amplification. Même si le signal est inversé, cela n’aura aucun impact sur le circuit.

Alimentations électriques

Alors que le Raspberry Pi dispose d’une alimentation 5V sur les broches 2 et 4, le circuit de conditionnement nécessite une alimentation négative. Pour obtenir une tension d’alimentation négative, nous pouvons utiliser le convertisseur DC-DC isolé LTM8067. Tout d’abord, branchons l’entrée à l’alimentation et à la mise à la terre 5 V. Ensuite, mettons à la terre la broche de sortie positive du convertisseur. Comme l’entrée et la sortie sont isolées, la mise à la terre de la broche positive ne court-circuite pas le module. Le potentiel de tension de la broche négative, par rapport à la masse du Raspberry Pi, sera inférieur à 0 V. N'essayez pas avec un convertisseur non isolé ! Utilisez un voltmètre pour mesurer la tension de sortie négative. Tournez le potentiomètre avec un tournevis jusqu’à ce que vous obteniez -5 V.

Signal de sortie

Pmod DA3

Image of a Pmod DA3 board

Le Raspberry Pi ne possède qu’une seule sortie analogique, la prise audio de 3,5 mm, qui est utilisée pour le système audio. Pour avoir une sortie séparée pour le signal audio traité, on utilise le Pmod DA3 de Digilent. Le Pmod DA3 est un convertisseur numérique-analogique (CNA) 16 bits alimenté par l’AD5541A d’Analog Devices. Le Pmod DA3 peut communiquer avec le Raspberry Pi via l’interface SPI.

La conversion suit cette formule : Vout=n*Vref/216, Vout étant la tension de sortie, n le nombre d’entrée et Vref la tension de référence, qui est égale à 2,5V (référence interne). Comme le CNA ne peut traiter que des nombres non signés de 16 bits, aucune tension inférieure à 0V ou supérieure à Vref ne peut être obtenue dans la sortie. Cependant, un amplificateur ou un haut-parleur actif « attend » un signal d’entrée avec un décalage de 0V et une amplitude maximale de 1V, ce qui rend nécessaire de conditionner le signal de sortie.

Conditionnement du signal de sortie

La plage 0-2,5V permet un signal de sortie d’une amplitude de 1V si elle a un décalage d’au moins 1V. La compensation peut être supprimée avec un condensateur de découplage suivi d’un suiveur de tension. Un filtre passe-bas peut également être nécessaire dans la sortie. L’alimentation négative du suiveur de tension provient du convertisseur DC-DC mentionné précédemment, qui est un régulateur de commutation (convertisseur Flyback), il génère donc un bruit de commutation à haute fréquence. En raison des limitations de vitesse du Raspberry Pi, le taux d’échantillonnage est également limité. Avec une fréquence d’échantillonnage réduite, la sortie peut comporter des arêtes vives, il faut donc également filtrer les harmoniques des fréquences de sortie.

Les voyelles de la parole humaine peuvent atteindre des fréquences allant jusqu’à 2 kHz, tandis que les consonnes atteignent des fréquences allant jusqu’à 6 kHz. Si l’on utilise un simple filtre passe-bas, concevoir la fréquence de coupure entre 3 kHz et 4 kHz semble raisonnable, car la majorité des sons se situe en dessous de 3,5 kHz (source).

Output Signal Conditioning Circuit

Si les valeurs standard des résistances et des condensateurs sont utilisées, la fréquence de coupure du filtre devient fc=1/(2*π*R8*C2)=3.4KHz.

Interface utilisateur

Pmod ENC

Image of a Pmod ENC board

Avec le Pmod ENC, nous pouvons utiliser un interrupteur pour activer le traitement audio, un encodeur rotatif pour régler le degré de l’effet, et un bouton de réinitialisation.

Pmod 8LD

Image of a Pmod 8LD board

Le Pmod 8LD contient 8 LED à haute luminosité qui sont contrôlées par des niveaux logiques à faible consommation. Cela peut donner un retour d’information à l’utilisateur.

Témoin d’alimentation

Bien que le Raspberry Pi dispose d’une LED de mise sous tension, un second voyant lumineux est utile pour indiquer si les circuits de conditionnement sont alimentés ou non. Pour construire le témoin d’alimentation, il suffit de connecter une LED à l’alimentation 5V en série à une résistance de limitation de courant.

Power Indicator Circuit

La valeur de la résistance de limitation de courant peut être calculée avec la formule suivante : R9=(VCC-VLED)/ILED — VLED étant la tension directe de la LED (généralement autour de 1,8 V pour les LED rouges), ILED étant le courant souhaité à travers la LED. La résistance doit être choisie pour que ce courant soit inférieur au maximum. La luminosité d’une LED est proportionnelle au courant qui la traverse. Si l’on désire un voyant plus faible, il faut choisir une résistance de valeur plus élevée.

Interfaçage de Pmods avec le Raspberry Pi

Pmod HAT Adapter

Image of Pmod HAT Adapter

Nous pouvons connecter les Pmods de Digilent au Raspberry Pi grâce à l’adaptateur Pmod HAT. L’adaptateur Pmod HAT décompose le connecteur GPIO 40 broches du Raspberry Pi en trois connecteurs Pmod 2x6 de Digilent (JA, JB et JC) et chacun d’entre eux peut également être utilisé comme deux connecteurs Pmod 1x6 séparés (par exemple, JA peut être séparé en JAA et JAB). Tous les ports Pmod contiennent une masse et une broche 3.3V pour alimenter le Pmod branché. Alors que tous les ports peuvent être utilisés comme GPIO (Entrée-sortie à usage général), certains ports ont des fonctionnalités supplémentaires : JAA et JBA peuvent être utilisés pour brancher des Pmods dotés d’une interface SPI, l’interface I2C peut être utilisée sur un port JBB, et l’UART sur un port JCA. L’adaptateur peut être alimenté directement à partir du Raspberry Pi, ou à partir d’une alimentation externe de 5V via la prise jack DC Barrel (n’utilisez pas les deux en même temps !).

Les connexions suivantes sont recommandées :

Port adaptateur Pmod HAT Pmod connecté Protocol Used
JAA Pmod AD1 SPI
JAB Pmod ENC GPIO
JBA Pmod DA3 SPI
JC Pmod 8LD GPIO

Pour raccorder le Pmod AD1 et le Pmod ENC au port JA de l’adaptateur Pmod HAT, on peut utiliser la tête de test à 12 points Pmod TPH2.

Image of Pmod TPH2 board

Le circuit complet

Une fois les circuits de conditionnement, l’alimentation négative et le témoin d’alimentation assemblés sur une platine d’expérimentation, connectez le rail 5V à la broche 2 du connecteur GPIO 40 broches du Raspberry Pi et le rail GND à la broche 39. De cette façon, les circuits de la platine d’expérimentation seront alimentés. Connectez la sortie du premier circuit de conditionnement au canal A1 du Pmod AD1 et l’entrée du deuxième circuit de conditionnement au connecteur SMA du Pmod DA3 (il est également possible d’insérer un câble MTE au lieu d’un connecteur SMA mâle dans la prise).

The complete circuit

Logiciel

Comme indiqué précédemment, le logiciel contrôlant le processeur audio sera écrit en Python3. Le projet se compose de six modules, qui seront présentés selon une approche descendante.

main.py

Le module principal contient les paramètres les plus importants du projet et initialise les autres modules. Chaque quantité importante doit apparaître à un endroit accessible, comme le début du module principal, pour faciliter le réglage.

# global variables
spi_clock_speed = int(4e06)   # spi clock frequency in Hz
sample_time = 5e-05  # seconds between samples
buffer_size = 5000  # data points in the buffer
DEBUG = "None"  # "ADC", "DAC", "PROC", "ALL" or "None"
adc_res = 4095  # resolution of the ADC
dac_res = 65535  # resolution of the DAC

Le Raspberry Pi a 4 tâches importantes à accomplir : la réception des entrées audio, le traitement des signaux audio, l’émission de signaux et la communication avec l’utilisateur. Si ces tâches sont effectuées l’une après l’autre, il y a deux défauts majeurs

  1. Un retard important entre la voix d’entrée et la voix de sortie (le délai lors duquel le signal est enregistré, traité et lu)
  2. Interruptions dans la voix de sortie.

Pour les éviter, les tâches doivent être effectuées en parallèle.

L’interface utilisateur peut être réalisée avec le module Python gpiozero qui utilise des événements asynchrones (comme des interruptions sur un microcontrôleur) pour communiquer avec l’utilisateur. Le module principal ne fait qu’attribuer des actions à ces événements.

# set user interface actions
# increment/decrement a value, when the rotary encoder is rotated
UI.enc.when_rotated = UI.set_value
# reset the value, when the button is pressed
UI.btn.when_pressed = UI.reset_value
# set a flag according to the state of the switch
UI.swt.when_pressed = UI.change_mode
UI.swt.when_released = UI.change_mode

Le Raspberry Pi 4 Modèle B est doté d’un processeur Cortex-A72 à quatre cœurs, ce qui nous permet d’exécuter des tâches sur différents cœurs du processeur via le module Python de multitraitement. Le premier processus principal ne fera qu’initialiser les autres processus enfants. Un processus enfant enregistre les données d’entrée, l’autre traite les données et le dernier les restitue.

Pour éviter les interruptions dans la sortie, trois tampons partagés sont utilisés : le processus d’enregistrement remplit les trois tampons l’un après l’autre. Si le premier tampon est vidé par le processus du lecteur, tout le processus recommence. Le traitement des données attend l’enregistreur et modifie le contenu des tampons.

Diagram showing the three shared buffers

Les drapeaux partagés sont utilisés pour signaler l’état de chaque tampon.

 

# create shared lists
manager = multiprocessing.Manager()
# 3 buffers to use them in rotation
buffer = manager.list([[], [], []])
# flags to signal aquisition state
get_flag = manager.list([False, False, False])
# flags to signal processing state
set_flag = manager.list([False, False, False])
# flags to signal write-out state
ready_flag = manager.list([True, True, True])

Le wrapper lance les processus enfants, puis attend qu’ils se terminent (le programme se termine par Ctrl+C).

 

# main part
if __name__ == "__main__":
    UI.reset_value()   # reset counter

    # initialize processes
    acquisition = multiprocessing.Process(target=DI.acquire_data)
    processing = multiprocessing.Process(target=DP.process_data)
    playing = multiprocessing.Process(target=DO.output_data)

    # start threads
    acquisition.start()
    processing.start()
    playing.start()

    # wait for exit condition
    acquisition.join()
    processing.join()
    playing.join()

    UI.reset_value()   # reset counters

    # terminate processes
    acquisition.terminate()
    processing.terminate()
    playing.terminate()

user_interface.py

Le module d’interface utilisateur contient toutes les fonctions d’interaction avec l’utilisateur. Ces fonctions

  1. Règlent une variable en fonction de l’état du codeur rotatif
  2. Allument les LED en fonction de cette variable
  3. Modifient l’état du drapeau en fonction de la position du commutateur (le commutateur doit être tiré vers le haut ou vers le bas, sinon les bords ne sont pas détectés)
  4. Réinitialisent toutes les valeurs et tous les drapeaux en appuyant sur le bouton de réinitialisation.
def set_value():
    # map the counter between 0 and 1 using the rotary encoder
    global param
    param[0] = enc.steps / (2 * enc.max_steps) + 0.5
    set_leds()  # set LED states
    return
def set_leds():
    global param
    # set the leds on/off according to the counter
    if param[1]:
        led.value = param[0]
    else:
        led.value = -param[0]
    return
def change_mode():
    # switch the flag
    global param
    param[1] = bool(swt.value)
    # force software pull-up/-down
    if param[1]:
        GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    else:
        GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
    set_leds()  # set LED states
    return
def reset_value():
    # reset the counter
    global param
    param[0] = 0
    enc.steps = -enc.max_steps  # reset rotary encoder state
    param[1] = bool(swt.value)  # reset switch state
    set_leds()  # reset LED states
    return

Le module utilise les membres du paquet Python gpiozero pour manipuler plus facilement les périphériques d’entrée/sortie.

 

# initialize devices
# Rotary Encoder
enc = RotaryEncoder(19, 21)
btn = Button(20)
swt = Button(18)

# pull down the switch
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

# LEDs
led = LEDBarGraph(16, 14, 15, 17, 4, 12, 5, 6)

Les valeurs et les drapeaux reçus sont stockés dans une liste partagée afin qu’ils soient disponibles pour les autres processus.

 

# shared user-interface parameters
manager = multiprocessing.Manager()
param = manager.list([0, False])

data_input.py

Le module d’entrée de données est responsable de l’initialisation de la communication SPI avec le Pmod AD1 en utilisant le paquet Python spidev. Ce module remplit un tampon avec les mots de données de 12 bits reçus, en attendant après chaque acquisition pendant un délai prédéfini (l’attente entre les échantillons est nécessaire pour s’assurer que le délai entre deux échantillons est toujours le même - sinon, des décalages de hauteur peuvent se produire), et active les drapeaux lorsque le tampon est rempli afin de signaler son état aux autres processus.

 

# initialize ADC
adc = spidev.SpiDev()
adc.open(SPI_port, CS_pin)
adc.max_speed_hz = main.spi_clock_speed
for _ in range(main.buffer_size):
  # measure start time
  start_time = time.perf_counter()

  # read data bytes
  adc_raw = adc.readbytes(2)
  # recreate the number from the bytes
  adc_number = adc_raw[1] | (adc_raw[0] << 8)
  # insert the number in the buffer
  buff.append(adc_number)

  # check the duration of the operation
  duration = time.perf_counter() - start_time
  # wait if necessary
  if main.sample_time > duration:
    time.sleep(main.sample_time - duration)
# assign buffer and set flags
if main.ready_flag[0]:
  main.buffer[0] = buff
  main.get_flag[0] = True
  main.ready_flag[0] = False
  continue_flag = True
elif main.ready_flag[1]:
  main.buffer[1] = buff
  main.get_flag[1] = True
  main.ready_flag[1] = False
  continue_flag = True
elif main.ready_flag[2]:
  main.buffer[2] = buff
  main.get_flag[2] = True
  main.ready_flag[2] = False
  continue_flag = True

data_output.py

Le module de sortie des données ressemble fortement au module d’entrée des données. Il contrôle le CNA via le SPI à l’aide du paquet Python spidev. Cependant, le module de sortie vérifie les drapeaux globaux décrivant l’état des trois tampons avant que le tampon ne soit traité. Après l’envoi des échantillons du tampon au CNA, le temps d’attente peut ne pas être égal au temps d’attente du CAN. En effet, le premier élément de chaque tampon contient des informations sur le décalage de hauteur requis (pour appliquer cet effet).

 

# output buffer
if case != None and len(buff) != 0:
  # calculate the duration of a sample
  # (this is needed because of the pitchbend effect)
  sample_duration = main.sample_time - buff[0]
  # discard the first sample
  # (this contains information about the pitch)
  buff.pop(0)

  # output every sample
  for point in buff:
    # measure start time
    start_time = time.perf_counter()

    # get high byte
    highbyte = point >> 8
    # get low byte
    lowbyte = point & 0xFF
    # send both bytes
    dac.writebytes([highbyte, lowbyte])

    # check the duration of the operation
    duration = time.perf_counter() - start_time
    # wait if necessary
    if sample_duration > duration:
      time.sleep(sample_duration - duration)

data_processing.py

Le module de traitement des données vérifie les drapeaux globaux avant de traiter le tampon. Il est nécessaire que les processus soient synchronisés. Ce module mappe le tampon d’entrée entre -1 et 1 (valeurs normalisées), applique l’un des effets sur le tampon normalisé en fonction de l’état du commutateur de commande et de l’encodeur rotatif, interpole le tampon normalisé en fonction de la résolution du CNA, et insère le décalage temporel requis dans la première position. Les effets audio « écho » et « pitch bend » sont créés dans un module séparé.

# normalize values
buff = [interp(element, [0, main.adc_res], [-1, 1]) for element in buff]
# apply audio effect
bend = 0    # store the timeshift if needed
if UI.param[1]:
  bend = AE.pitchbend(UI.param[0], main.sample_time)
else:
  buff = AE.echo(buff, UI.param[0], main.sample_time)
# scale buffer
buff = [round(interp(element, [-1, 1], [0, main.dac_res])) for element in buff]

# insert timeshift
buff.insert(0, bend)

audio_effects.py

Ce module contient quelques constantes qui définissent les propriétés des effets audio :

  1. echo_mag définit l’intensité sonore de l’effet d’écho,
  2. echo_del définit le délai maximal de l’écho en millisecondes (si un délai plus important est utilisé, la taille du tampon doit également être augmentée, ce qui entraîne une latence plus importante, alors qu’avec un délai plus court, nous pourrions obtenir un effet de réverbération au lieu d’un écho)
  3. pitch_bend définit la quantité maximale de décalage de hauteur par rapport à la fréquence d’échantillonnage (si l’audio est échantillonné toutes les 50 microsecondes, un décalage maximal de 0,25 entraîne un retard de 37,5 microsecondes entre les échantillons de sortie, la fréquence du signal de sortie sera donc 1,33 fois plus élevée).
echo_mag = 0.8  # echo magnitude between 0 and 1
echo_del = 100  # maximum delay for echo (in ms)
pitch_bend = 0.25   # maximum delay for pitchbend
                    # in % compared to the sample time

 

Le premier effet, le pitch_bend, calcule la différence de retard entre les échantillons en multipliant le temps d’échantillonnage initial avec le compteur de position de l’encodeur rotatif et la quantité maximale de décalage de hauteur. Cette valeur sera insérée ultérieurement au début du tampon.

def pitchbend(counter, sample_time):
    # calculate sample delay/advance for pitch bending
    bend = sample_time * counter * pitch_bend
    return bend

L’effet d’écho prend le tampon initial et crée une version retardée à partir de celui-ci, en calculant le nombre d’échantillons pour chaque temps de retard, puis en insérant autant de 0 au début du tampon. Le tampon retardé est atténué selon la constante echo_mag, puis il est ajouté au tampon initial.

def echo(buffer, counter, sample_time):
    # count delay for samples
    counter = round(echo_del * counter / (sample_time * 1000))
    # create dummy buffer
    delay = [0 for _ in range(counter)]
    # shift samples to get the echo
    delayed_buff = delay + buffer
    # add the echo to the original buffer
    result = [buffer[index] + echo_mag * delayed_buff[index]
              for index in range(len(buffer))]
    return result

Débogage

Débogage du matériel

Analog Discovery 2 peut être utilisé, ainsi que le logiciel WaveForms pour déboguer le matériel. Connectez le fil négatif de l’entrée analogique du canal 1 (fil orange-blanc) de l’AD2 à la masse du Raspberry Pi, puis utilisez le fil positif (fil orange), pour mesurer les tensions et afficher les signaux analogiques sur différents points du circuit. Affichez les résultats avec l’instrument Oscilloscope dans WaveForms. Utilisez un signal d’entrée de fréquence et d’amplitude fixes afin de savoir à quelle sortie vous attendre.

Les tensions et les signaux analogiques qu’il est recommandé de visualiser sont le rail négatif de l’alimentation (il doit être d’environ -5V), la sortie du diviseur de tension dans lecircuit de conditionnement d’entrée(il doit être d’environ -1,5V), la sortie ducircuit de conditionnement d’entrée(l’entrée dans l’image est un signal sinusoïdal de 1KHz avec une intensité sonore de 50 %),

Waveforms screen showing a signwave

la sortie du CNA (la mauvaise qualité est due à la faible fréquence d’échantillonnage),

Wavforms - output of the DAC

la sortie du circuit de conditionnement de sortie,

Wavforms - the output of the output conditioning circuit,

et la sortie de l’ensemble du dispositif, après le filtre passe-bas.

Waveforms - output of the whole device, after the low-pass filter

Si un ou plusieurs signaux ne sont pas dans la plage attendue, le rapport de conversion du convertisseur DC-DC doit être modifié à l’aide du potentiomètre. Pour modifier l’amplitude d’un signal, il faut modifier les résistances respectives.

Utilisez le Pmod TPH2 entre l’adaptateur Pmod HAT et le CNA ou CAN pour avoir des points de test sur les signaux SPI. Connectez les broches d’E/S numériques de l’AD2 aux points de test, puis utilisez l’instrument Analyseur logique dans WaveForms pour visualiser les données entrantes/sortantes.

Waveforms - showing the select, clock and data lines

Débogage du logiciel

Alors que les signaux d’entrée et de sortie peuvent être facilement visualisés à l’aide de l’oscilloscope ou de l’analyseur logique, il existe des « signaux » internes, des étages de différents tampons, qui n’existent que virtuellement. Pour visualiser ces points de données, le module Python matplotlib.pyplot peut être utilisé. Pour abréger le nom du module et afficher sa fonction, il peut être importé dans le projet sous le nom de « debug ».

# display the buffer if needed
if main.DEBUG == "ADC" or main.DEBUG == "ALL":
  debug.plot(buff)
  debug.show()

Réglage

Les performances de l’application dépendent de certains paramètres clés. Deux des valeurs les plus importantes de l’ensemble du projet sont le temps d’échantillonnage et la taille de la mémoire tampon. La réduction du temps d’échantillonnage augmente la qualité de la sortie et la bande passante (avant le filtre passe-bas), mais le temps nécessaire au remplissage de chaque tampon est également augmenté. Si le tampon est rempli trop lentement, des interruptions dans la sortie apparaissent. Cela peut être corrigé si la taille du tampon est réduite, mais avec une taille de tampon réduite, l’effet d’écho ne peut pas être appliqué, et des problèmes avec le timing du pitch bend apparaissent également. Avec un temps d’échantillonnage très court, le décalage de hauteur dans l’audio de sortie peut apparaître de manière aléatoire. La solution consiste à trouver un équilibre entre une bonne qualité audio et un fonctionnement ininterrompu.

Résultats

Quelques résultats avec un temps d’échantillonnage de 50 microsecondes et un tampon de 5 000 échantillons :

Entrée audio - voix de femme

Sortie audio - voix de femme

Voix de femme, 50 % d’écho

Voix de femme, 100 % d’écho

Voix de femme, 50 % de décalage de hauteur

Voix de femme, 100 % de décalage de hauteur

Entrée audio - voix d’homme

Sortie audio - voix d’homme

Voix d’homme, 50 % d’écho

Voix d’homme, 100 % d’écho

Voix d’homme, 50 % de décalage de hauteur

Voix d’homme, 100 % de décalage de hauteur

Love learn engineering in hands-on approach. Interested in new technology. Work in Digilent as International Sales and Distribution Manager.

Commentaires

DesignSpark Electrical Logolinkedin