CaractĂ©ristiques du filtrage des fenĂȘtres sur FPGA

Bonjour Ă  tous! Cet article se concentrera sur une partie importante du traitement numĂ©rique du signal - le filtrage du signal de fenĂȘtre, en particulier sur les FPGA. L'article montrera comment concevoir des fenĂȘtres classiques de longueur standard et des fenĂȘtres "longues" de 64K Ă  16M + Ă©chantillons. Le langage de dĂ©veloppement principal est le VHDL, la base de l'Ă©lĂ©ment est les derniers cristaux FPGA Xilinx des derniĂšres familles: ce sont Ultrascale, Ultrascale +, 7-series. L'article montrera l'implĂ©mentation de CORDIC - le noyau de base pour configurer les fonctions de fenĂȘtre de n'importe quelle durĂ©e, ainsi que les fonctions de fenĂȘtre de base. L'article dĂ©crit la mĂ©thode de conception utilisant des langages de haut niveau C / C ++ dans Vivado HLS. Comme d'habitude, Ă  la fin de l'article, vous trouverez un lien vers les codes sources du projet.

KDPV: un schĂ©ma typique de transmission de signal via des nƓuds DSP pour des tĂąches d'analyse de spectre.



Présentation


GrĂące au cours «Traitement numĂ©rique du signal», de nombreuses personnes savent que pour une forme d'onde sinusoĂŻdale infinie dans le temps, son spectre est une fonction delta Ă  la frĂ©quence du signal. En pratique, le spectre d'un signal harmonique limitĂ© dans le temps rĂ©el est Ă©quivalent Ă  la fonction ~ sin (x) / x , et la largeur du lobe principal dĂ©pend de la durĂ©e de l'intervalle d'analyse du signal T. La limite de temps n'est rien d'autre que la multiplication du signal par une enveloppe rectangulaire. Il est connu du cours DSP que la multiplication des signaux dans le domaine temporel est une convolution de leurs spectres dans le domaine frĂ©quentiel (et vice versa), par consĂ©quent, le spectre de l'enveloppe rectangulaire limitĂ©e du signal harmonique est Ă©quivalent Ă  ~ sinc (x). Cela est Ă©galement dĂ» au fait que nous ne pouvons pas intĂ©grer le signal sur un intervalle de temps infini, et la transformĂ©e de Fourier sous forme discrĂšte, exprimĂ©e par une somme finie, est limitĂ©e par le nombre d'Ă©chantillons. En rĂšgle gĂ©nĂ©rale, la longueur de la FFT dans les appareils de traitement numĂ©rique FPGA modernes prend des valeurs NFFT de 8 Ă  plusieurs millions de points. En d'autres termes, le spectre du signal d'entrĂ©e est calculĂ© sur l'intervalle T , qui dans de nombreux cas est Ă©gal Ă  NFFT . En limitant le signal Ă  l'intervalle T , on impose ainsi une «fenĂȘtre» rectangulaire d'une durĂ©e de T Ă©chantillons. Par consĂ©quent, le spectre rĂ©sultant est le spectre du signal harmonique multipliĂ© et de l'enveloppe rectangulaire. Dans les tĂąches DSP, des fenĂȘtres de formes diverses ont Ă©tĂ© inventĂ©es depuis longtemps, qui, superposĂ©es Ă  un signal dans le domaine temporel, peuvent amĂ©liorer ses caractĂ©ristiques spectrales. Un grand nombre de fenĂȘtres diffĂ©rentes est principalement dĂ» Ă  l'une des principales caractĂ©ristiques de toute superposition de fenĂȘtres. Cette caractĂ©ristique s'exprime dans la relation entre le niveau des lobes latĂ©raux et la largeur du lobe central. Un schĂ©ma bien connu: plus la suppression des lobes latĂ©raux est forte, plus le lobe principal est large et vice versa.

L'une des applications des fonctions de fenĂȘtre: dĂ©tection de signaux faibles sur fond de plus forts en supprimant le niveau des lobes latĂ©raux. Les principales fonctions de la fenĂȘtre dans les tĂąches DSP sont une fenĂȘtre triangulaire, sinusoĂŻdale, Lanczos, Hann, Hamming, Blackman, Harris, Blackman-Harris, une fenĂȘtre Ă  toit plat, Natall, Gauss, une fenĂȘtre Kaiser et bien d'autres. La plupart d'entre eux sont exprimĂ©s Ă  travers une sĂ©rie finie en additionnant des signaux harmoniques avec des poids spĂ©cifiques. Les fenĂȘtres de forme complexe sont calculĂ©es en prenant un exposant (fenĂȘtre gaussienne) ou une fonction de Bessel modifiĂ©e (fenĂȘtre de Kaiser), et ne seront pas prises en compte dans cet article. Vous pouvez en savoir plus sur les fonctions des fenĂȘtres dans la littĂ©rature, que je donnerai traditionnellement Ă  la fin de l'article.

La figure suivante montre les fonctions de fenĂȘtre typiques et leurs caractĂ©ristiques spectrales construites Ă  l'aide des outils de CAO Matlab.



Implémentation


Au dĂ©but de l'article, j'ai insĂ©rĂ© KDPV, qui montre en termes gĂ©nĂ©raux un diagramme structurel de la multiplication des donnĂ©es d'entrĂ©e par une fonction de fenĂȘtre. De toute Ă©vidence, la façon la plus simple d'implĂ©menter le stockage d'une fonction de fenĂȘtre dans le FPGA est de l'Ă©crire en mĂ©moire (bloc RAMB ou distribuĂ© distribuĂ© - cela n'a pas beaucoup d'importance), puis de rĂ©cupĂ©rer cycliquement les donnĂ©es lorsque les Ă©chantillons d'entrĂ©e du signal arrivent. En rĂšgle gĂ©nĂ©rale, dans les FPGA modernes, la quantitĂ© de mĂ©moire interne permet de stocker des fonctions de fenĂȘtre de tailles relativement petites, qui sont ensuite multipliĂ©es par les signaux d'entrĂ©e entrants. Par petite, je veux dire des fonctions de fenĂȘtre jusqu'Ă  64 Ko d'Ă©chantillons.

Mais que faire si la fonction de fenĂȘtre est trop longue? Par exemple, 1M de lectures. Il est facile de calculer que pour une telle fonction de fenĂȘtre prĂ©sentĂ©e dans une grille de bits 32 bits, NRAMB = 1024 * 1024 * 32/32768 = 1024 cellules de mĂ©moire de bloc des cristaux FPGA Xilinx de type RAMB36K sont nĂ©cessaires. Et pour 16 millions d'Ă©chantillons? 16 mille cellules mĂ©moire! Pas un seul FPGA moderne n'a autant de mĂ©moire. Pour de nombreux FPGA, c'est trop, et dans d'autres cas, c'est une utilisation inutile des ressources FPGA (et, bien sĂ»r, de l'argent du client).

À cet Ă©gard, vous devez trouver une mĂ©thode pour gĂ©nĂ©rer des Ă©chantillons de fonction de fenĂȘtre directement sur le FPGA Ă  la volĂ©e, sans Ă©crire les coefficients du pĂ©riphĂ©rique distant dans la mĂ©moire de bloc. Heureusement, les choses de base ont longtemps Ă©tĂ© inventĂ©es pour nous. En utilisant un algorithme tel que CORDIC (la mĂ©thode numĂ©rique par numĂ©rique ), il est possible de concevoir de nombreuses fonctions de fenĂȘtre dont les formules sont exprimĂ©es en termes de signaux harmoniques (Blackman-Harris, Hann, Hamming, Nattal, etc.)

CORDIC


CORDIC est une méthode itérative simple et pratique pour calculer la rotation d'un systÚme de coordonnées, qui vous permet de calculer des fonctions complexes en effectuant des opérations d'addition et de décalage primitives. En utilisant l'algorithme CORDIC, on peut calculer les valeurs des signaux harmoniques sin (x), cos (x), trouver la phase - atan (x) et atan2 (x, y), les fonctions trigonométriques hyperboliques, faire pivoter le vecteur, extraire la racine du nombre, etc.

Au dĂ©but, je voulais prendre le noyau CORDIC fini et rĂ©duire la quantitĂ© de travail, mais j'ai une longue aversion pour les noyaux Xilinx. AprĂšs avoir Ă©tudiĂ© les rĂ©fĂ©rentiels sur le github, j'ai rĂ©alisĂ© que tous les cƓurs prĂ©sentĂ©s ne conviennent pas pour un certain nombre de raisons (mal documentĂ©s et illisibles, non universels, conçus pour une tĂąche spĂ©cifique ou une base d'Ă©lĂ©ments, Ă©crits en verilog , etc.). Ensuite, j'ai demandĂ© au camarade Lazifo de faire ce travail pour moi. Bien sĂ»r, il s'en est occupĂ©, car la mise en Ɠuvre de CORDIC est l'une des tĂąches les plus simples dans le domaine des DSP. Mais comme je suis impatient, parallĂšlement Ă  son travail, j'ai Ă©crit mon vĂ©lo avec mon propre noyau paramĂ©trĂ©. Les principales caractĂ©ristiques sont la profondeur de bits configurable des signaux de sortie DATA_WIDTH et la phase d'entrĂ©e normalisĂ©e PHASE_WIDTH de -1 Ă  1, et la prĂ©cision des calculs de PRECISION . Le cƓur CORDIC est exĂ©cutĂ© selon le circuit parallĂšle du pipeline - Ă  chaque cycle d'horloge, le cƓur est prĂȘt Ă  effectuer des calculs et Ă  recevoir des Ă©chantillons d'entrĂ©e. Le noyau passe N cycles pour calculer l'Ă©chantillon de sortie, dont le nombre dĂ©pend de la capacitĂ© des Ă©chantillons de sortie (plus la capacitĂ© est grande, plus il y a d'itĂ©rations pour calculer la valeur de sortie). Tous les calculs se font en parallĂšle. Ainsi, CORDIC est le noyau de base pour crĂ©er des fonctions de fenĂȘtre.

Fonctions de fenĂȘtre


Dans le cadre de cet article, je ne rĂ©alise que les fonctions de fenĂȘtre qui s'expriment Ă  travers des signaux harmoniques (Hann, Hamming, Blackman-Harris de divers ordres, etc.). Que faut-il pour cela? En termes gĂ©nĂ©raux, la formule de construction d'une fenĂȘtre ressemble Ă  une sĂ©rie de longueur finie.



Un certain ensemble de coefficients a k et de membres de la sĂ©rie dĂ©termine le nom de la fenĂȘtre. La fenĂȘtre Blackman-Harris la plus populaire et la plus utilisĂ©e est d'ordre diffĂ©rent (de 3 Ă  11). Voici un tableau des coefficients pour les fenĂȘtres Blackman-Harris:



En principe, l'ensemble de fenĂȘtres Blackman-Harris est applicable Ă  de nombreux problĂšmes d'analyse spectrale, et il n'est pas nĂ©cessaire d'essayer d'utiliser des fenĂȘtres complexes telles que Gauss ou Kaiser. Les fenĂȘtres nattales ou Ă  toit plat ne sont qu'une variĂ©tĂ© de fenĂȘtres avec des poids diffĂ©rents, mais les mĂȘmes principes de base que Blackman-Harris. On sait que plus il y a de membres de la sĂ©rie, plus la suppression du niveau des lobes latĂ©raux est forte (sous rĂ©serve d'un choix raisonnable de la profondeur de bits de la fonction fenĂȘtre). En fonction de la tĂąche, le dĂ©veloppeur n'a qu'Ă  choisir le type de fenĂȘtres utilisĂ©es.

Implémentation FPGA - approche traditionnelle


Tous les noyaux des fonctions de fenĂȘtre sont conçus en utilisant l'approche classique pour dĂ©crire les circuits numĂ©riques dans les FPGA et sont Ă©crits en langage VHDL. Voici une liste des composants fabriquĂ©s:

  • bh_win_7term - Blackman-Harris 7 order, une fenĂȘtre avec suppression maximale des Ă©chafaudages latĂ©raux.
  • bh_win_5term - Commande Blackman-Harris 5, comprend une fenĂȘtre avec un dessus plat.
  • bh_win_4term - Blackman-Harris 4 commandes, comprend les fenĂȘtres Nattal et Blackman-Nattal.
  • bh_win_3term - Blackman-Harris 3 commandes,
  • hamming_win - FenĂȘtres Hamming et Hann.

Le code source du composant de fenĂȘtre Blackman-Harris est de 3 ordres de grandeur:

entity bh_win_3term is generic ( TD : time:=0.5ns; --! Time delay PHI_WIDTH : integer:=10; --! Signal period = 2^PHI_WIDTH DAT_WIDTH : integer:=16; --! Output data width XSERIES : string:="ULTRA" --! for 6/7 series: "7SERIES"; for ULTRASCALE: "ULTRA"; ); port ( RESET : in std_logic; --! Global reset CLK : in std_logic; --! System clock AA0 : in std_logic_vector(DAT_WIDTH-1 downto 0); -- A0 AA1 : in std_logic_vector(DAT_WIDTH-1 downto 0); -- A1 AA2 : in std_logic_vector(DAT_WIDTH-1 downto 0); -- A2 ENABLE : in std_logic; --! Clock enable DT_WIN : out std_logic_vector(DAT_WIDTH-1 downto 0); --! Output DT_VLD : out std_logic --! Output data valid ); end bh_win_3term; 

Dans certains cas, j'ai utilisĂ© la bibliothĂšque UNISIM pour incorporer les nƓuds DSP48E1 et DSP48E2 dans le projet, ce qui me permet finalement d'augmenter la vitesse des calculs en raison du pipelining Ă  l'intĂ©rieur de ces blocs, mais comme l'a montrĂ© la pratique, il est plus rapide et plus facile de donner libre cours et d'Ă©crire quelque chose comme P = A * B + C et spĂ©cifiez les directives suivantes dans le code:

 attribute USE_DSP of <signal_name>: signal is "YES"; 

Cela fonctionne bien et définit de maniÚre rigide le type d'élément sur lequel la fonction mathématique est implémentée pour le synthétiseur.

Vivado hls


De plus, j'ai implĂ©mentĂ© tous les cƓurs Ă  l'aide des outils Vivado HLS . Je vais Ă©numĂ©rer les principaux avantages de Vivado HLS: haute vitesse de conception ( time-to-market ) dans les langages de haut niveau C ou C ++, modĂ©lisation rapide des nƓuds dĂ©veloppĂ©s en raison de l'absence d'un concept de frĂ©quence d'horloge, configuration flexible des solutions (en termes de ressources et de performances) en introduisant pragmas et directives dans le projet, ainsi qu'un seuil d'entrĂ©e bas pour les dĂ©veloppeurs dans les langages de haut niveau. Le principal inconvĂ©nient est le coĂ»t sous-optimal des ressources FPGA par rapport Ă  l'approche classique. De plus, il n'est pas possible d'atteindre les vitesses fournies par les anciennes mĂ©thodes RTL classiques (VHDL, Verilog, SV). Eh bien, le plus gros inconvĂ©nient est de danser avec un tambourin, mais cela est caractĂ©ristique de tous les CAD de Xilinx. (Remarque: dans le dĂ©bogueur Vivado HLS et dans le modĂšle C ++ rĂ©el, des rĂ©sultats souvent diffĂ©rents ont Ă©tĂ© obtenus, car Vivado HLS fonctionne de maniĂšre tordue en utilisant les avantages de la prĂ©cision arbitraire ).

L'image suivante montre le journal du noyau CORDIC synthétisé dans Vivado HLS. Il est assez informatif et affiche de nombreuses informations utiles: la quantité de ressources utilisées, l'interface utilisateur du noyau, les boucles et leurs propriétés, le retard dans le calcul, l'intervalle de calcul de la valeur de sortie (important lors de la conception de circuits série et parallÚles):



Vous pouvez Ă©galement voir comment calculer les donnĂ©es dans divers composants (fonctions). On peut voir qu'Ă  la phase zĂ©ro, les donnĂ©es de phase sont lues et aux Ă©tapes 7 et 8, le rĂ©sultat du nƓud CORDIC est affichĂ©.


Le résultat de Vivado HLS: un noyau RTL synthétisé créé à partir de code C. Le journal montre que dans l'analyse de temps, le noyau réussit toutes les restrictions:



Un autre gros avantage de Vivado HLS est que pour vĂ©rifier le rĂ©sultat, elle fait elle-mĂȘme un banc d'essai du code RTL synthĂ©tisĂ© basĂ© sur le modĂšle qui a Ă©tĂ© utilisĂ© pour vĂ©rifier le code C. Cela peut ĂȘtre un test primitif, mais je pense qu'il est trĂšs cool et assez pratique pour comparer le fonctionnement de l'algorithme en C et en HDL. Ci-dessous, une capture d'Ă©cran de Vivado montrant une simulation du modĂšle de fonction de noyau d'une fonction de fenĂȘtre obtenue par Vivado HLS:



Ainsi, pour toutes les fonctions de fenĂȘtre, des rĂ©sultats similaires ont Ă©tĂ© obtenus, quelle que soit la mĂ©thode de conception - en VHDL ou en C ++. Cependant, dans le premier cas, une plus grande frĂ©quence de fonctionnement et un plus petit nombre de ressources sont atteints, et dans le second cas, la vitesse de conception maximale est atteinte. Les deux approches ont droit Ă  la vie.

J'ai calculé précisément combien de temps je consacrerais au développement en utilisant différentes méthodes. J'ai implémenté un projet C ++ dans Vivado HLS ~ 12 fois plus rapidement qu'en VHDL.

Comparaison des approches


Comparez le code source pour HDL et C ++ pour le noyau CORDIC. L'algorithme, comme cela a été dit précédemment, est basé sur les opérations d'addition, de soustraction et de décalage. Sur VHDL, cela ressemble à ceci: il y a trois vecteurs de données - l'un est responsable de la rotation de l'angle, et les deux autres déterminent la longueur du vecteur le long des axes X et Y, ce qui équivaut à sin et cos (voir l'image du wiki):



En calculant itérativement la valeur Z, les valeurs X et Y sont calculées en parallÚle. Le processus de recherche cyclique des valeurs de sortie sur HDL:

 constant ROM_LUT : rom_array := ( x"400000000000", x"25C80A3B3BE6", x"13F670B6BDC7", x"0A2223A83BBB", x"05161A861CB1", x"028BAFC2B209", x"0145EC3CB850", x"00A2F8AA23A9", x"00517CA68DA2", x"0028BE5D7661", x"00145F300123", x"000A2F982950", x"000517CC19C0", x"00028BE60D83", x"000145F306D6", x"0000A2F9836D", x"0000517CC1B7", x"000028BE60DC", x"0000145F306E", x"00000A2F9837", x"00000517CC1B", x"0000028BE60E", x"00000145F307", x"000000A2F983", x"000000517CC2", x"00000028BE61", x"000000145F30", x"0000000A2F98", x"0000000517CC", x"000000028BE6", x"0000000145F3", x"00000000A2FA", x"00000000517D", x"0000000028BE", x"00000000145F", x"000000000A30", x"000000000518", x"00000000028C", x"000000000146", x"0000000000A3", x"000000000051", x"000000000029", x"000000000014", x"00000000000A", x"000000000005", x"000000000003", x"000000000001", x"000000000000" ); pr_crd: process(clk, reset) begin if (reset = '1') then ---- Reset sine / cosine / angle vector ---- sigX <= (others => (others => '0')); sigY <= (others => (others => '0')); sigZ <= (others => (others => '0')); elsif rising_edge(clk) then sigX(0) <= init_x; sigY(0) <= init_y; sigZ(0) <= init_z; ---- calculate sine & cosine ---- lpXY: for ii in 0 to DATA_WIDTH-2 loop if (sigZ(ii)(sigZ(ii)'left) = '1') then sigX(ii+1) <= sigX(ii) + sigY(ii)(DATA_WIDTH+PRECISION-1 downto ii); sigY(ii+1) <= sigY(ii) - sigX(ii)(DATA_WIDTH+PRECISION-1 downto ii); else sigX(ii+1) <= sigX(ii) - sigY(ii)(DATA_WIDTH+PRECISION-1 downto ii); sigY(ii+1) <= sigY(ii) + sigX(ii)(DATA_WIDTH+PRECISION-1 downto ii); end if; end loop; ---- calculate phase ---- lpZ: for ii in 0 to DATA_WIDTH-2 loop if (sigZ(ii)(sigZ(ii)'left) = '1') then sigZ(ii+1) <= sigZ(ii) + ROM_TABLE(ii); else sigZ(ii+1) <= sigZ(ii) - ROM_TABLE(ii); end if; end loop; end if; end process; 

En C ++, dans Vivado HLS, le code est presque identique, mais l'enregistrement est plusieurs fois plus court:

 // Unrolled loop // int k; stg: for (k = 0; k < NWIDTH; k++) { #pragma HLS UNROLL if (z[k] < 0) { x[k+1] = x[k] + (y[k] >> k); y[k+1] = y[k] - (x[k] >> k); z[k+1] = z[k] + lut_angle[k]; } else { x[k+1] = x[k] - (y[k] >> k); y[k+1] = y[k] + (x[k] >> k); z[k+1] = z[k] - lut_angle[k]; } } 


Apparemment, le mĂȘme cycle avec dĂ©calage et ajouts est utilisĂ©. Cependant, par dĂ©faut, toutes les boucles dans Vivado HLS sont «rĂ©duites» et exĂ©cutĂ©es sĂ©quentiellement, comme prĂ©vu pour le langage C ++. L'introduction du pragma HLS UNROLL ou HLS PIPELINE convertit les calculs sĂ©rie en parallĂšle. Cela conduit Ă  une augmentation des ressources FPGA, cependant, il vous permet de calculer et de soumettre de nouvelles valeurs au cƓur Ă  chaque cycle d'horloge.

Les rĂ©sultats de la synthĂšse du projet en VHDL et C ++ sont prĂ©sentĂ©s dans la figure ci-dessous. Comme vous pouvez le voir, logiquement, la diffĂ©rence est deux fois en faveur de l'approche traditionnelle. Pour d'autres ressources FPGA, l'Ă©cart est insignifiant. Je n'ai pas approfondi l'optimisation du projet en C ++, mais sans ambiguĂŻtĂ© en dĂ©finissant diverses directives ou en modifiant partiellement le code, le nombre de ressources utilisĂ©es peut ĂȘtre rĂ©duit. Dans les deux cas, les synchronisations ont convergĂ© pour une frĂ©quence centrale donnĂ©e de ~ 350 MHz.


Caractéristiques d'implémentation


Étant donnĂ© que les calculs sont effectuĂ©s dans un format Ă  virgule fixe, les fonctions de fenĂȘtre ont un certain nombre de fonctionnalitĂ©s qui doivent ĂȘtre prises en compte lors de la conception de systĂšmes DSP sur FPGA. Par exemple, plus la profondeur de bits des donnĂ©es de fonction de fenĂȘtre est grande, meilleure est la prĂ©cision de la superposition de fenĂȘtre. D'un autre cĂŽtĂ©, avec une profondeur de bits insuffisante de la fonction de fenĂȘtre, des distorsions seront introduites dans la forme d'onde rĂ©sultante, ce qui affectera la qualitĂ© des caractĂ©ristiques spectrales. Par exemple, une fonction de fenĂȘtre doit avoir au moins 20 bits lorsqu'elle est multipliĂ©e par un signal d'une durĂ©e de 2 ^ 20 = 1M d'Ă©chantillons.

Conclusion


Cet article montre une façon de concevoir des fonctions de fenĂȘtre sans utiliser de mĂ©moire externe ou de mĂ©moire de bloc FPGA. La mĂ©thode d'utilisation exclusive des ressources logiques des FPGA (et dans certains cas des blocs DSP) est donnĂ©e. En utilisant l'algorithme CORDIC, il est possible d'obtenir des fonctions de fenĂȘtre de n'importe quelle profondeur de bit (dans des limites raisonnables), de n'importe quelle longueur et ordre, et donc d'avoir un ensemble de pratiquement toutes les caractĂ©ristiques spectrales de la fenĂȘtre.

Dans le cadre de l'une des Ă©tudes, j'ai rĂ©ussi Ă  obtenir un noyau fonctionnant de maniĂšre stable de la fonction de fenĂȘtre Blackman-Harris de 5 et 7 ordres de grandeur sur des Ă©chantillons de 1 M Ă  une frĂ©quence de ~ 375 MHz, et Ă©galement Ă  crĂ©er un gĂ©nĂ©rateur de coefficients rotatifs pour une FFT basĂ©e sur CORDIC Ă  une frĂ©quence de ~ 400 MHz. Cristal FPGA utilisĂ©: Kintex Ultrascale + (xcku11p-ffva1156-2-e).

Lien vers le projet github ici . Le projet contient un modĂšle mathĂ©matique dans Matlab, des codes sources pour les fonctions de fenĂȘtre et CORDIC en VHDL, ainsi que des modĂšles des fonctions de fenĂȘtre rĂ©pertoriĂ©es en C ++ pour Vivado HLS.

Articles utiles



Je conseille également un livre trÚs populaire sur DSP - Ayficher E., Jervis B. Digital signal processing. Approche pratique

Merci de votre attention!

Source: https://habr.com/ru/post/fr427361/


All Articles