Elektroda.pl
Elektroda.pl
X
Arrow Multisolution Day
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Algorytmy zmiennoprzecinkowe dla układów FPGA i ASIC

ghost666 08 Lip 2018 17:02 1443 0
  • Generacja natywnego kodu HDL dla operacji zmiennorzecinkowych pozwala na implementację tego rodzaju operacji na sprzęcie z wykorzystaniem VHDLa lub Veriloga. Wszystko to bez mozolnej i trudnej konwersji na liczby stałoprzecinkowe.

    Dane zmiennoprzecinkowe to preferowany typ zmiennych, w aplikacjach modelowania i symulacji, gdzie liczy się wysoka dokładność tych algorytmów. Tradycyjnie jednakże, jeśli chcemy zaimplementować tego rodzaju algorytmy na układach programowalnych (FPGA) czy w układach ASIC, naszym jedynym wyborem jest konwersja każdego typu zmiennej w naszym algorytmie na zmienne stałoprzecinkowe. Wszystko po to, aby zmniejszyć zapotrzebowanie sprzętowe tych algorytmów oraz zwiększyć prędkość obliczeń. Konwersja liczb zmienno- na stałoprzecinkowe jest jednak czasami bardzo problematyczna, a ponadto zmniejsza precyzję liczb. Za każdym razem musimy dokonywać wyboru pomiędzy matematyczną precyzją a długością słowa w algorytmie. W aplikacjach, które wymagają wysokiego zakres dynamiki lub dużego poziomu precyzji (na przykład w systemach z pętlami sprzężenia zwrotnego) implementacja typów stałoprzecinkowych może zająć inżynierom długie tygodnie lub nawet miesiące na etapie implementacji. Ponadto, jeśli potrzebujemy dużej precyzji, to słowa stałoprzecinkowe zajmować mogą bardzo wiele bitów.

    W poniższym artykule przedstawimy stworzone przez MathWorks sposób na natywną obsługę zmiennoprzecinkowych typów danych na układach ASIC oraz FPGA. Jako przykład implementacji tych mechanizmów wykorzystamy filtr cyfrowy o odpowiedzi nieskończonej (IIR). Następnie omówimy wyzwania, jakie wiążą się z korzystaniem z typów stałoprzecinkowych i porównamy jakie kompromisy musimy podjąć, wybierając pomiędzy typami stało- i zmiennoprzecinkowymi.

    Zaprezentujemy w artykule także, jak połączenie danych zmienno- i stałoprzecinkowych w naszym oprogramowaniu może dać nam wyższą dokładność, skrócić czas konwersji liczb w realnych zastosowaniach oraz pomóc w oszczędzaniu zasobów sprzętowych układu. Przekonamy się, że bezpośrednie obliczenia na liczbach zmiennoprzecinkowych także bywają bardzo ważne i mogą istotnie przyspieszyć działanie wielu urządzeń, jeśli są poprawnie zaimportowane, szczególnie w przypadkach, gdzie kluczowy jest duży zakres dynamiki.

    Natywne wsparcie dla liczb zmiennoprzecinkowych - jak to działa

    HDL Coder implementuje arytmetykę pojedynczej precyzji emulując wszystkie operacje na zasobach układu FPGA lub ASIC (patrz rysunek 1). Wygenerowane w ten sposób układy logiczne 'rozpakowują' wejściową liczbę zmiennoprzecinkową na osobne liczby - znak, wykładnik i mantysę, które mają szerokość, odpowiednio, 1, 8 i 23 bitów.

    Algorytmy zmiennoprzecinkowe dla układów FPGA i ASIC




    Rys.1. Sposób mapowania liczb zmiennoprzecinkowych o pojedynczej precyzji na zasobach sprzętowych układu FPGA lub ASIC.


    Wygenerowany w ten sposób kod VHDLa lub Veriloga realizuje odpowiednie operacje matematyczne (na przykład mnożenie, jak pokazano na rysunku 1) - niezależnie obliczany jest znak liczby, mnożenie rzędów wielkości oraz dodani wykładników i idąca za tym normalizacja, konieczna do obliczenia wyniku. Ostatnia faza obliczeń to logika odpowiedzialna za spakowanie poszczególnych elementów - znaku, wykładnika i mantysy - do danej typu zmiennoprzecinkowego.

    Jak pogodzić dynamiczny zakres danych z konwersją na liczny stałoprzecinkowe

    Weźmy jako przykład proste wyrażenie takie jak (1-a)/(1+a). Musi ono być zaimplementowane z dużym zakresem dynamiki; może być naturalnie przetłumaczone z wykorzystaniem danych zmiennoprzecinkowych o pojedynczej precyzji, jak na rysunku 2.

    Algorytmy zmiennoprzecinkowe dla układów FPGA i ASIC
    Rys.2. Implementacja obliczenia (1-a)/(1+a) na arytmetyce zmiennoprzecinkowej o pojedynczej precyzji.


    Jednakże implementacja powyższego problemu w arytmetyce stałoprzecinkowej wymaga sporo zachodu, jak ilustruje to rysunek 3

    Algorytmy zmiennoprzecinkowe dla układów FPGA i ASIC
    Rys.3. Implementacja obliczenia (1-a)/(1+a) na arytmetyce stałoprzecinkowej.


    Na przykład, problemem jest to, że musimy w dzieleniu osobno potraktować mnożenie i odwracanie liczby, a także wykorzystywać metody aproksymacji, takie jak metoda Newtona-Raphsona, korzystać z stabelaryzowanych danych (LUTów) dla nieliniowej operacji odwracania, wykorzystywać różne typy danych, by kontrolować rozrost bitowości rozwiązania, wybrać odpowiednie typy dla licznika i mianownika, wykorzystywać konkretne typy dla wyjścia obliczeń, dla akumulatorów, dla składników sumy, odjemnej i odjemnika...

    Eksplorowanie opcji implementacji filtra IIR

    Przyjrzyjmy się naszemu przykładowi - filtrowi o nieskończonej odpowiedzi impulsowej (IIR). Algorytm ten wymaga wysokiego zakresu dynamiki obliczeń z uwagi na implementację pętli sprzężenia zwrotnego. Czyni go to trudnym w implementacji z wykorzystaniem liczb stałoprzecinkowych. Rysunek 4a pokazuje środowisko testowe, które wykorzystywać będziemy do porównania działania trzech wersji tego samego filtra IIR z sygnałem sinusoidalnym z szumem na wejściu. Sinus ma amplitudę równą jeden a dodany szum nieznacznie ją zwiększa.

    Algorytmy zmiennoprzecinkowe dla układów FPGA i ASIC
    Rys.4a. Trzy implementacje filtra IIR z zaszumionym sinusem na wejściu.


    Pierwsza wersja tego filtra (rysunek 4b) to algorytm podwójnej precyzji. Druga wersja to taki sam algorytm zmiennoprzecinkowy, ale z liczbami o pojedynczej precyzji. Z kolei trzecia wersja (rysunek 4c) to algorytm zrealizowany na liczbach stałoprzecinkowych. Liczby te wykorzystują słowo o długości 22 bitów do zapisu liczby - jeden bit to znak, a 21 bitów reprezentuje ułamek. W tej wersji implementacji pozostawiono zero bitów do reprezentacji wartości całkowitej, jako że przy zadanej amplitudzie sinusa osiągać on będzie jedynie wartości od -1 do 1. Jeśli chcemy, aby ta implementacja działała także dla szerszego grona przypadków, to musimy także zadbać o implementację amplitud większych niż ±1.

    Algorytmy zmiennoprzecinkowe dla układów FPGA i ASIC
    Rys.4b. Implementacja filtra IIR_filter, pokazana dla zmiennych o podwójnej precyzji; dla pojedynczej precyzji będzie analogiczna, jedynie z innymi typami.

    Algorytmy zmiennoprzecinkowe dla układów FPGA i ASIC
    Rys.4. Implementacja filtra IIR_filter_fixpt, która wykorzystuje zmienne typów stałoprzecinkowych.


    Środowisko testowe zostało zestawione tak, by porównać wyniki działania filtra o pojedynczej precyzji i filtra stałoprzecinkowego z wynikami pracy filtra z danymi zmiennoprzecinkowymi o podwójnej precyzji, który w naszych rozważaniach traktować będziemy jako złoty wzór. W obu przypadkach utrata precyzji wprowadzi jakiegoś rzędu błąd. Pytanie, na jakie musimy sobie odpowiedzieć, to czy takiego rzędu błąd jest akceptowalny w naszej konkretnej aplikacji.

    Do generacji kodu dla zmiennych stałoprzecinkowych wykorzystany został pakiet Fixed-Point Designer; ustawiono go na poziom tolerancji błędu równy 1%. Rysunek 5 pokazuje wyniki porównania pracy poszczególnych filtrów. Błąd dla danych zmiennoprzecinkowych o pojedynczej precyzji wynosi około 10e-8, a dla danych stałoprzecinkowych jest na poziomie 10e-5 - mieści się doskonale w wyspecyfikowanych przez nas wcześniej ramach. Jeśli aplikacja, nad którą pracujemy, wymaga wyższego poziomu precyzji, to konieczne może być zwiększenie długości słowa danych typu stałoprzecinkowego.

    Algorytmy zmiennoprzecinkowe dla układów FPGA i ASIC
    Rys.5. Wyniki porównania działania filtrów IIR: o pojedynczej precyzji (u góry) i stałoprzecinkowego (na dole) z filtrem zmiennoprzecinkowym o podwójnej precyzji.


    Skupienie się na tego rodzaju problemach z kwantyzacją wymaga sporego doświadczenie w zakresie projektowania sprzętu, zrozumienia różnorodności wejść systemowych, czystego zdefiniowania wymagań co do systemu oraz pewnej pomocy ze strony pakietów takich jak Fixed-Point Designer. Te wysiłki, o ile pozwalają zazwyczaj na zmniejszenie wielkości algorytmu do implementacji w układzie scalonych. Ale co w przypadku, gdy musimy w układzie szybko zaimplementować prototyp, albo kiedy wymagania dotyczące precyzji algorytmu utrudniają kompaktową implementację algorytmu. Rozwiązaniem w tym przypadku jest wykorzystanie natywnych zmiennych typu zmiennoprzecinkowego o pojedynczej precyzji.

    Wykorzystanie natywnych typów zmiennoprzecinkowych

    Wykorzystanie natywnego wsparcia dla danych zmiennoprzecinkowych ma dwie zalety:

    * Nie trzeba poświęcać czasu na analizę, jaka minimalna liczba bitów pozwala osiągnąć dostateczną precyzję dla spodziewanych wartości danych wejściowych.
    * Zakres dynamiki danych skaluje się dużo lepiej przy stałym 'koszcie' zmiennej, wynoszącym 32 bity.

    Taki sposób projektowania algorytmów dla układów FPGA i ASIC jest także o wiele prostszy. Z bitami znaku, wykładnika i mantysy można oddać o wiele szerszy zakres liczb. Tabela na rysunku 6 porównuje wykorzystanie danych typów zmienoprzecinkowego i stałoprzecinkowego w implementacji filtra IIR dla typów danych pokazanych na rysunku 5.

    Algorytmy zmiennoprzecinkowe dla układów FPGA i ASIC
    Rys.6. Porównanie pomiędzy zmienno- i stałoprzecinkowymi implementacjami filtra IIR.


    Jeśli porównujemy obliczenia prowadzone dla danych zmiennoprzecinkowych i stałoprzecinkowych, to pamiętajmy, iż implementacja tego pierwszego typu wymaga więcej operacji arytmetycznych, co przekłada się na większe wykorzystanie zasobów sprzętowych w układzie FPGA czy ASIC. Jeśli ten parametr jest istotny w naszej aplikacji, to konieczne będzie zmniejszenie precyzji, by zredukować ilość zajmowanych zasobów sprzętowych. Dodatkowo, możliwe jest wykorzystywanie w systemie mieszanki danych zmienno- i stałoprzecinkowych, aby osiągnąć optymalną precyzję, wydajność numeryczną i zużycie sprzętu.

    Zarządzanie zajęciem sprzętu z wykorzystaniem natywnego wsparcia dla typów zmiennoprzecinkowych

    Wykorzystanie natywnego wsparcia układów dla danych zmiennoprzecinkowych jest prostym sposobem generacji kodu dla zastosowań w układach FPGA czy ASIC, gdy istotne jest osiągnięcie wysokiego zakresu dynamiki wykorzystywanych typów. Jednakże, w niektórych przypadkach, natywne wsparcie dla arytmetyki zmiennoprzecinkowej może przekraczać nasz budżet sprzętowy, co oznacza, iż konieczne jest zredukowanie wykorzystania sprzętu przez algorytmy - istnieje kilka sposobów, aby to zrobić:

    * Wykorzystanie optymalizacji kodu HDL: współdzielenia zasobów, albo innych metod optymalizacji na poziomie implementacji algorytmu, które wspierają generację kodu dla natywnego wsparcia typów zmiennoprzecinkowych. W ramach tych optymalizacji możliwe jest zmniejszenie obszaru w układzie, jaki zajmują złożone operacje, takie jak exp czy atan2, poprzez współdzielenie pomiędzy nimi zasobów i odpowiedniego multipleksowania danych.
    * Wykorzystanie procesu konwersji na dane stałoprzecinkowe, gdzie jest to możliwe: konwersja na liczby stałoprzecinkowe jest dosyć prostą operacją, szczególnie w operacjach bez dużych wymagań co do wielkiej dynamiki, czy pętli sprzężenia zwrotnego. Fixed-Point Designer pomaga w automatyzacji tego procesu. Nie zawsze taka droga jest możliwa - wtedy lepiej skorzystać z natywnego wsparcia operacji zmiennoprzecinkowych. Metoda ta wykorzystuje połączenie w jednym projekcie operacji zmienno- i stałoprzecinkowych, tworząc wyspy takich i takich danych, w zależności od wymagań danej operacji.
    * Tworzenie wysp obliczeń zmienno- i stałoprzecinkowych na poziomie projektu. Jeśli już zidentyfikowaliśmy elementy naszego algorytmu, które wymagają danych typu zmiennoprzecinkowego, to możliwe jest stworzenie wysp - na wejściu dane konwertowane są do typów zmiennoprzecinkowych, a na wyjściu z powrotem do stałoprzecinkowych. W ten sposób możliwe będzie uzyskanie spójnego algorytmu, który lokalnie używa konwersji zmienno-/stałoprzecinkowej do odgrodzenia od siebie wysp poszczególnych typów. Zilustrowano to na rysunku 7 na przykładzie części algorytmu sterowania silnikiem elektrycznym - obszary operacji wzmocnienia i obliczenia sinusa i kosinusa są odizolowaną wyspą danych typu zmiennoprzecinkowego.

    Algorytmy zmiennoprzecinkowe dla układów FPGA i ASIC
    Rys.7. Integracja typów zmienno- i stałoprzecinkowych w obrębie jednego projektu.


    Wybór pomiędzy typem zmiennoprzecinkowym, stałoprzecinkowym lub ich mieszanką w naszym projekcie jest dosyć prosty. Wystarczy kierować się następującymi zasadami:

    Wybierz typ zmiennoprzecinkowy dla całego swojego projektu jeżeli:

    * Nie masz doświadczenia z kwantyzacją do zmiennych stałoprzecinkowych.
    * Algorytm wykorzystuje mieszankę bardzo dużych i bardzo małych wartości danych.
    * Projekt wykorzystuje dużo zmiennych typu stałoprzecinkowego o słowie szerszym niż 32 bity.
    * Twój projekt wykorzystuje dużo operacji nieliniowych - dzielenia, modulo, rem, log, exp czy atan, które są trudne do konwersji na zmienne typu stałoprzecinkowego.
    * Masz projekt elastyczny pod względem zajmowanej w układzie powierzchni czy opóźnień w systemie (na przykład projektujesz system audio czy sterowania silnikiem, gdzie częstotliwości sygnałów nie są zbyt wysokie).

    Wybierz typ stałoprzecinkowy dla całego swojego projektu jeżeli:

    * Masz doświadczenie z kwantyzacją do zmiennych stałoprzecinkowych.
    * Konwersja algorytmu z jakiego korzystasz na typy stałoprzecinkowe jest prosta.
    * Masz ścisłe ograniczenia pod względem obszaru zajętego w strukturze FPGA czy układzie ASIC oraz maksymalnego opóźnienia sygnału.

    Wybierz mieszankę typów danych jeżeli:

    * Twój system to mieszanka układów kontrolnych z strumieniami danych o szerokim zakresie dynamiki.
    * Jedynie część Twojego układu jest problematyczna w kwantyzacji do danych stałoprzecinkowych.
    * Masz dostatecznie dużo sprzętowego marginesu, aby zmieścić w układzie ograniczone elementy algorytmów zmiennoprzecinkowych.

    Rzeczywisty przykład z wykorzystaniem natywnego wsparcia dla danych typu zmiennoprzecinkowego

    Na rysunku 8 widzimy wykres obrazujący, w jaki sposób zwiększanie zakresu dynamicznego zmiennych powoduje wzrost długości słowa w przypadku danych stałoprzecinkowych. Taki typ zmiennych w szeregu przypadków konsumuje więcej zasobów niż wersja z danymi zmiennoprzecinkowymi.

    Algorytmy zmiennoprzecinkowe dla układów FPGA i ASIC
    Rys.8. Wykorzystanie zasobów przez funkcję sqrt (pierwiastek kwadratowy) w funkcji długości słowa. Przy dłuższych słowach funkcja ta zajmuje więcej zasobów przy implementacji stałoprzecinkowej niż zmiennoprzecinkowej, której koszt jest niezależny od długości słowa.


    Aby zobaczyć, jak natywne wsparcie dla operacji zmiennoprzecinkowych sprawdza się w realnym przykładzie, rozważmy model samochodu elektrycznego, pokazany na rysunku 9. Taki skomplikowany układ zawiera w sobie wiele komponentów, między innymi akumulator, inwerter oraz silnik synchroniczny z magnesami stałymi (PMSM).

    Algorytmy zmiennoprzecinkowe dla układów FPGA i ASIC
    Rys.9. Model pojazdu elektrycznego.


    Na rysunku 10 widzimy, w jaki sposób poszczególne równania matematyczne implementują wszystkie komponenty systemu.

    Algorytmy zmiennoprzecinkowe dla układów FPGA i ASIC
    Rys.10. Równania matematyczne opisujące model pojazdu elektrycznego.


    Implementacja całego modelu z wykorzystaniem zmiennych stałooprzecinkowych byłaby ogromnym wyzwaniem z uwagi na wszystkie sprzężenia zwrotne pomiędzy poszczególnymi elementami. Implementacja takiego rozwiązania mogłaby zająć całe miesiące, aby zredukować poziom błędów kwantyzacji w poszczególnych komponentach elementów, zwłaszcza w złożonych pętlach sprzężenia zwrotnego pomiędzy silnikiem i inwerterem. Aby zredukować poziom błędu w tych systemach konieczne jest wykorzystanie długich słów, co przekłada się na zwiększone zużycie zasobów sprzętowych. W przypadku implementacji algorytmów korzystających z typów zmiennoprzecinkowych, można do modelu podejść bezpośrednio i łatwo.

    Na rysunku 11 pokazano, że wybór operacji zmiennoprzecinkowych jest odpowiedni w pętli sprzężenia zwrotnego pomiędzy komponentami - takie podejście zajmuje mniej sprzętu i działa lepiej w tym układzie w porównaniu do wykorzystania danych typu stałoprzecinkowego o tej samej długości słowa.

    Algorytmy zmiennoprzecinkowe dla układów FPGA i ASIC
    Rys.11. Porównanie implementacji sterowania pojazdem elektrycznym z wykorzystaniem typów stało- i zmiennoprzecinkowych.


    Kwantyzacja liczb zmiennoprzecinkowych tradycyjnie jest jednym z największych wyzwań w zakresie implementacji rozmaitych algorytmów na układach FPGA czy w układach ASIC. Natywne wsparcie dla liczb zmiennoprzecinkowych, dzięki generatorom kodu HDL, pozwalają na zautomatyzowane generowanie kodu w VHDLu czy Verilogu, który pozwala na wykorzystywanie liczb zmiennoprzecinkowych na nowoczesnych platformach wykorzystujących układy FPGA, takich jak liczne SoCe: Xilinx Zynq czy analogiczne systemy Intela.

    Najlepsze implementacje algorytmów jednakże, jak pokazuje powyższy przykład, to te, które łączą elementu z obu światów. W wielu projektach najlepiej sprawia się wykorzystanie obu typów zmiennych, w zależności od konkretnych wymagań danego bloku algorytmu.

    Źródła:
    https://www.eeweb.com/profile/kkintali2018/articles/targeting-floating-point-algorithms-for-fpga-or-asic-deployment
    Materiały firmy The MathWorks, Inc.


    Fajne!
  • Arrow Multisolution Day