FPGA पर निर्धारित बिंदु atan2 की गणना के तरीके


12

मुझे atan2(x,y)डेटा के निरंतर इनपुट / आउटपुट स्ट्रीम के साथ एक FPGA पर कंप्यूटिंग की आवश्यकता है । मैं इसे अनियंत्रित, पाइपलाइन किए गए CORDIC कर्नेल का उपयोग करके लागू करने में कामयाब रहा, लेकिन मुझे जिस सटीकता की आवश्यकता है, उसे प्राप्त करने के लिए मुझे 32 पुनरावृत्तियों का प्रदर्शन करना पड़ा। इससे LUTs की एक बड़ी मात्रा इस एक कार्य के लिए समर्पित हो गई। मैंने आंशिक रूप से अनियंत्रित CORDIC कर्नेल का उपयोग करने के लिए प्रवाह को बदलने की कोशिश की, लेकिन तब मुझे लगातार इनपुट / आउटपुट प्रवाह को बनाए रखते हुए दोहराया लूप निष्पादित करने के लिए एक गुणा घड़ी आवृत्ति की आवश्यकता थी। इससे मैं टाइमिंग को पूरा नहीं कर पाया।

इसलिए अब मैं कंप्यूटिंग के वैकल्पिक तरीकों के लिए पहुंच रहा हूं atan2(x,y)

मैंने प्रक्षेप के साथ ब्लॉक-रैम लुकअप टेबलों का उपयोग करने के बारे में सोचा, लेकिन चूंकि 2 चर हैं इसलिए मुझे लुकअप तालिकाओं के 2 आयामों की आवश्यकता होगी, और यह ब्लॉक-रैम उपयोग के संदर्भ में बहुत ही संसाधन गहन है।

मैंने तब इस तथ्य का उपयोग करने के बारे में सोचा जो कि चतुर्थांश समायोजन atan2(x,y)से संबंधित है atan(x/y)। इसके साथ समस्या यह है कि x/yएक सच्चे विभाजन की आवश्यकता है क्योंकि yनिरंतर नहीं है, और FPGAs पर विभाजन बहुत संसाधन गहन हैं।

atan2(x,y)FPGA पर लागू करने के लिए और अधिक उपन्यास तरीके हैं जो कम LUT उपयोग में परिणाम करेंगे, लेकिन फिर भी अच्छी सटीकता प्रदान करेंगे?


2
आपकी प्रसंस्करण घड़ी दर और आपकी इनपुट डेटा दर क्या है?
जिम क्ले

आपको क्या सटीकता की आवश्यकता है? मुझे लगता है कि आप निश्चित-बिंदु संगणना का उपयोग कर रहे हैं। आप किस गहराई का उपयोग कर रहे हैं? चतुर्भुज समायोजन के साथ एक बहुपद सन्निकटन (या LUT) को लागू करने के लिए एक सामान्य तरीका है atan2। यकीन नहीं अगर आप एक विभाजन के बिना प्राप्त कर सकते हैं, हालांकि।
जेसन आर

इनपुट घड़ी 150MHz है, इनपुट डेटा दर 150 MSamps / sec है। मूल रूप से मुझे हर घड़ी चक्र में एक नया इनपुट मिलता है। विलंबता होना ठीक है, लेकिन मुझे 150 MSamps / sec पर भी आउटपुट का उत्पादन करना होगा।
user2913869

मेरे सिमुलेशन शो मैं लगभग 1 * 10 ^ -9 के साथ रह सकते हैं। पूर्ण न्यूनतम निश्चित बिंदु बिट्स पर यकीन नहीं है, लेकिन मैं Q10.32 निश्चित बिंदु प्रारूप के साथ अनुकरण कर रहा हूं
user2913869

यह लेख एक निश्चित बिंदु के कार्यान्वयन के बारे में बताता है atan2। आपको अभी भी एक विभाजन की आवश्यकता होगी।
मैट एल।

जवाबों:


20

आप विभाजन से छुटकारा पाने के लिए लघुगणक का उपयोग कर सकते हैं। के लिए (x,y) पहली वृत्त का चतुर्थ भाग में:

z=log2(y)log2(x)atan2(y,x)=atan(y/x)=atan(2z)

atan (2 ^ z)

चित्र 1. अतन का प्लॉट ( 2 z )atan(2z)

atan(2z)30<z<30atan(2z)=π2atan(2z)(x,y)log2(a)

b=floor(log2(a))c=a2blog2(a)=b+log2(c)

bclog2(c)1c<2

log2 (ग)

log2(c)

214+1=16385log2(c)30×212+1=122881atan(2z)0<z<30z

अतन की त्रुटि (2 ^ z) सन्निकटन

atan(2z)zz0z<1floor(log2(z))=0

atan(2z)0z<1floor(log2(z))z1atan(2z)z0z<32

बाद के संदर्भ के लिए, यहाँ क्लिंक पाइथन स्क्रिप्ट है जिसका उपयोग मैंने अनुमानित त्रुटियों की गणना के लिए किया था:

from numpy import *
from math import *
N = 10
M = 20
x = array(range(N + 1))/double(N) + 1
y = empty(N + 1, double)
for i in range(N + 1):
    y[i] = log(x[i], 2)

maxErr = 0
for i in range(N):
    for j in range(M):
        a = y[i] + (y[i + 1] - y[i])*j/M
        if N*M < 1000: 
            print str((i*M + j)/double(N*M) + 1) + ' ' + str(a)
        b = log((i*M + j)/double(N*M) + 1, 2)
        err = abs(a - b)
        if err > maxErr:
            maxErr = err

print maxErr

y2 = empty(N + 1, double)
for i in range(1, N):
    y2[i] = -1.0/16.0*y[i-1] + 9.0/8.0*y[i] - 1.0/16.0*y[i+1]


y2[0] = -1.0/16.0*log(-1.0/N + 1, 2) + 9.0/8.0*y[0] - 1.0/16.0*y[1]
y2[N] = -1.0/16.0*y[N-1] + 9.0/8.0*y[N] - 1.0/16.0*log((N+1.0)/N + 1, 2)

maxErr = 0
for i in range(N):
    for j in range(M):
        a = y2[i] + (y2[i + 1] - y2[i])*j/M
        b = log((i*M + j)/double(N*M) + 1, 2)
        if N*M < 1000: 
            print a
        err = abs(a - b)
        if err > maxErr:
            maxErr = err

print maxErr

y2[0] = 15.0/16.0*y[0] + 1.0/8.0*y[1] - 1.0/16.0*y[2]
y2[N] = -1.0/16.0*y[N - 2] + 1.0/8.0*y[N - 1] + 15.0/16.0*y[N]

maxErr = 0
for i in range(N):
    for j in range(M):
        a = y2[i] + (y2[i + 1] - y2[i])*j/M
        b = log((i*M + j)/double(N*M) + 1, 2)
        if N*M < 1000: 
            print str(a) + ' ' + str(b)
        err = abs(a - b)
        if err > maxErr:
            maxErr = err

print maxErr

P = 32
NN = 13
M = 8
for k in range(NN):
    N = 2**k
    x = array(range(N*P + 1))/double(N)
    y = empty((N*P + 1, NN), double)
    maxErr = zeros(P)
    for i in range(N*P + 1):
        y[i] = atan(2**x[i])

    for i in range(N*P):
        for j in range(M):
            a = y[i] + (y[i + 1] - y[i])*j/M
            b = atan(2**((i*M + j)/double(N*M)))
            err = abs(a - b)
            if (i*M + j > 0 and err > maxErr[int(i/N)]):
                maxErr[int(i/N)] = err

    print N
    for i in range(P):
        print str(i) + " " + str(maxErr[i])    

f(x)f^(x)f(x)Δx

f^(x)f(x)(Δx)2limΔx0f(x)+f(x+Δx)2f(x+Δx2)(Δx)2=(Δx)2f(x)8,

जहां के दूसरे व्युत्पन्न है और निरपेक्ष त्रुटि की एक स्थानीय अधिकतम होती है। उपरोक्त के साथ हमें अनुमान मिलते हैं:f(x)f(x)x

atan^(2z)atan(2z)(Δz)22z(14z)ln(2)28(4z+1)2,log2^(a)log2(a)(Δa)28a2ln(2).

क्योंकि फ़ंक्शन अवतल होते हैं और नमूने फ़ंक्शन से मेल खाते हैं, त्रुटि हमेशा एक दिशा में होती है। यदि प्रत्येक सैंपल अंतराल के बाद एक बार फिर से आगे बढ़ने के लिए त्रुटि का संकेत दिया गया था, तो स्थानीय अधिकतम निरपेक्ष त्रुटि को आधा किया जा सकता है। रैखिक प्रक्षेप के साथ, इष्टतम परिणाम के करीब प्रत्येक तालिका को प्रीफ़िल्टर करके प्राप्त किया जा सकता है:

y[k]={b0x[k]+b1x[k+1]+b2x[k+2]if k=0,c1x[k1]+c0x[k]+c1x[k+1]if 0<k<N,b2x[k2]+b1x[k1]+b0x[k]if k=N,

जहाँ और मूल हैं और फ़िल्टर्ड टेबल दोनों फैले हुए हैं और वज़न । अंत कंडीशनिंग (उपरोक्त समीकरण में पहली और अंतिम पंक्ति) तालिका के बाहर फ़ंक्शन के नमूनों का उपयोग करने की तुलना में तालिका के सिरों पर त्रुटि को कम करती है, क्योंकि प्रक्षेप से त्रुटि को कम करने के लिए पहले और अंतिम नमूने को समायोजित करने की आवश्यकता नहीं है इसके बीच और मेज के बाहर एक नमूना। अलग-अलग नमूने अंतराल के साथ सबटाइबल्स को अलग से पूर्वनिर्मित किया जाना चाहिए। वजन के मूल्यों बढ़ती प्रतिपादक के लिए क्रमिक रूप से कम करके पाए गएxy0kNc0=98,c1=116,b0=1516,b1=18,b2=116c0,c1N अनुमानित त्रुटि का अधिकतम निरपेक्ष मान:

(Δx)NlimΔx0(c1f(xΔx)+c0f(x)+c1f(x+Δx))(1a)+(c1f(x)+c0f(x+Δx)+c1f(x+2Δx))af(x+aΔx)(Δx)N={(c0+2c11)f(x)if N=0,|c1=1c020if N=1,1+aa2c02(Δx)2f(x)if N=2,|c0=98

अंतर-नमूना प्रक्षेप पदों के लिए अवतल या उत्तल फ़ंक्शन (उदाहरण के लिए ) के साथ । उन वज़न को हल करने के साथ, अंत कंडीशनिंग वज़न मान समान रूप से अधिकतम पूर्ण मान को न्यूनतम करके पाए गए:0a<1f(x)f(x)=exb0,b1,b2

(Δx)NlimΔx0(b0f(x)+b1f(x+Δx)+b2f(x+2Δx))(1a)+(c1f(x)+c0f(x+Δx)+c1f(x+2Δx))af(x+aΔx)(Δx)N={(b0+b1+b21+a(1b0b1b2))f(x)if N=0,|b2=1b0b1(a1)(2b0+b12)Δxf(x)if N=1,|b1=22b0(12a2+(2316b0)a+b01)(Δx)2f(x)if N=2,|b0=1516

के लिए। प्रीफ़िल्टर का उपयोग सन्निकटन त्रुटि को आधा कर देता है और तालिकाओं के पूर्ण अनुकूलन की तुलना में करना आसान होता है।0a<1

Prefilter और अंत कंडीशनिंग के साथ और बिना त्रुटि की त्रुटि

चित्रा 4. 11 नमूनों में से, बिना और पूर्व कंडीशनिंग के साथ और बिना, नमूने के की त्रुटि । अंत कंडीशनिंग के बिना प्रीफ़िल्टर में टेबल के ठीक बाहर फ़ंक्शन के मूल्यों तक पहुंच होती है।log2(a)

यह आलेख संभवतः एक बहुत ही समान एल्गोरिथ्म प्रस्तुत करता है: आर। गुटिरेज़, वी। टोरेस, और जे। वॉल्स, " लॉगरिदमिक ट्रांसफॉर्मेशन और LUT- आधारित तकनीकों के आधार पर एटान (Y / X) का FPGA-कार्यान्वयन, " जर्नल ऑफ़ सिस्टम्स आर्किटेक्चर , वॉल्यूम । 56, 2010. अमूर्त का कहना है कि उनका कार्यान्वयन गति में पिछले CORDIC- आधारित एल्गोरिदम और फुट आकार में LUT- आधारित एल्गोरिदम धड़कता है।


3
मैथ्यू गैम्ब्रेल और मैंने 1985 के यामाहा YM3812 साउंड चिप (माइक्रोस्कोपी द्वारा) को उलट दिया है और इसमें पाया गया है कि समान लॉग / ऍक्स्प रीड ओनली मेमोरी (ROM) टेबल है। यामाहा ने पिछली प्रविष्टि के अंतर से प्रत्येक तालिका में प्रत्येक दूसरी प्रविष्टि को बदलने की एक अतिरिक्त चाल का उपयोग किया था। सुचारू कार्यों के लिए, अंतर फ़ंक्शन की तुलना में कम बिट्स और चिप क्षेत्र का प्रतिनिधित्व करता है। उनके पास पहले से ही चिप पर एक योजक था जिसे वे पिछली प्रविष्टि में अंतर जोड़ने के लिए उपयोग करने में सक्षम थे।
ओली नीमितालो

3
आपका बहुत बहुत धन्यवाद! मुझे गणितीय गुणों के इस प्रकार के कारनामों से प्यार है। मैं निश्चित रूप से इस के कुछ MATLAB सिम विकसित करूंगा, और अगर सब कुछ ठीक लगता है, तो एचडीएल पर जाएं। जब सब हो जाएगा तो मैं अपनी LUTs बचत की रिपोर्ट करूंगा।
user2913869

मैंने आपके विवरण को एक मार्गदर्शक के रूप में इस्तेमाल किया और मुझे यह रहकर खुशी हुई कि मैंने LUTs को लगभग 60% कम कर दिया। मुझे BRAMs को कम करने की आवश्यकता थी, इसलिए मुझे लगा कि मैं गैर-समान नमूनाकरण करके अपने ATAN तालिका में एक अधिकतम अधिकतम त्रुटि प्राप्त कर सकता हूं: मेरे पास कई LUT BRAMs (सभी समान पता बिट्स) थे, करीब शून्य, तेजी से नमूना। मैंने अपनी तालिका श्रृंखलाओं को 2 की शक्तियां चुना ताकि मैं आसानी से यह पता लगा सकूं कि मैं किस श्रेणी में हूं और थोड़ा हेरफेर के माध्यम से स्वचालित तालिका अनुक्रमण करता हूं। मैंने एटान समरूपता लागू की और इसलिए मैंने केवल आधे तरंग को संग्रहीत किया।
user2913869

इसके अलावा, मैं आपके कुछ संपादनों को याद कर सकता हूं, लेकिन मैंने 2 ^ z को 2 ^ {if} = 2 ^ i * 2 ^ {0.f} में विभाजित करके लागू किया, जहां मैं पूर्णांक भाग और f है आंशिक भाग। 2 ^ मैं सरल है, बस थोड़ा हेरफेर है, और 2 ^ {0.f} की एक सीमित सीमा थी, इसलिए यह प्रक्षेप के साथ LUT को अच्छी तरह से उधार देता है। मैंने नकारात्मक मामले को भी संभाला: 2 ^ {- if} = 2 ^ {- i} * 1 / (2 ^ 0. 0.}। तो 1/2 ^ {0.f} के लिए एक और तालिका। मेरा अगला कदम। log2 (y) LUTs पर 2 रेंज / नॉन-यूनिफ़ॉर्म सैंपलिंग की शक्ति को लागू करने के लिए हो सकता है, क्योंकि ऐसा लगता है कि यह उस तरह की चीज़ के लिए सही उम्मीदवार तरंग होगा। चीयर्स!
user2913869

1
लोल युप मैं पूरी तरह से उस कदम से चूक गया। मैं कोशिश कर रहा हूँ कि अब। मुझे और भी अधिक LUTs और उससे भी अधिक BRAMs को बचाना चाहिए
user2913869
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.