วิธีการคำนวณจุดคงที่ at2 บน FPGA


12

ฉันต้องการคอมพิวเตอร์atan2(x,y)ใน FPGA ที่มีกระแสข้อมูลเข้า / ออกอย่างต่อเนื่อง ฉันจัดการเพื่อใช้มันโดยใช้เมล็ด CORDIC ที่ยังไม่ผ่านการควบคุม แต่เพื่อให้ได้ความแม่นยำที่ฉันต้องการฉันต้องดำเนินการซ้ำ 32 ครั้ง สิ่งนี้นำไปสู่ ​​LUT จำนวนมากที่อุทิศให้กับภารกิจนี้ ฉันพยายามเปลี่ยนโฟลว์เพื่อใช้เมล็ด CORDIC ที่ไม่ได้ควบคุมบางส่วน แต่แล้วฉันต้องการความถี่สัญญาณนาฬิกาคูณเพื่อรันลูปซ้ำ ๆ ในขณะที่ยังคงอินพุต / เอาต์พุตไหลต่อเนื่อง ด้วยสิ่งนี้ฉันไม่สามารถทำตามกำหนดเวลาได้

atan2(x,y)ดังนั้นตอนนี้ฉันกำลังเอื้อมมือออกหาวิธีทางเลือกของการใช้คอมพิวเตอร์

ฉันคิดเกี่ยวกับการใช้ตารางการค้นหา block-RAM พร้อมการแก้ไข แต่เนื่องจากมี 2 ตัวแปรฉันจะต้องใช้ตารางการค้นหา 2 มิติและนี่เป็นทรัพยากรที่ใช้ทรัพยากรมากในแง่ของการใช้งาน block-RAM

ฉันคิดถึงการใช้ความจริงที่atan2(x,y)เกี่ยวข้องatan(x/y)กับการปรับควอดเรน ปัญหาเกี่ยวกับสิ่งนี้คือx/yต้องการการแบ่งที่แท้จริงเนื่องจากyไม่ใช่ค่าคงที่และการแบ่งส่วนบน FPGA นั้นใช้ทรัพยากรอย่างมาก

มีวิธีการใหม่ ๆ ที่จะนำไปใช้atan2(x,y)กับ FPGA ที่จะส่งผลให้การใช้ LUT ลดลง แต่ยังให้ความแม่นยำที่ดีหรือไม่?


2
อัตรานาฬิกาการประมวลผลของคุณคืออะไรและอัตราการป้อนข้อมูลของคุณ?
Jim Clay

ความแม่นยำที่คุณต้องการคืออะไร? ฉันสมมติว่าคุณกำลังใช้การคำนวณคงที่ด้วย คุณใช้ความลึกระดับใด ประมาณพหุนาม (หรือ LUT) atan2ที่มีการปรับวอดเป็นวิธีการทั่วไปในการดำเนินการ ไม่แน่ใจว่าคุณจะได้รับโดยไม่มีการแบ่งแม้ว่า
Jason R

นาฬิกาอินพุตเป็น 150MHz อัตราการป้อนข้อมูลคือ 150 MSamps / วินาที โดยทั่วไปฉันจะได้รับอินพุตใหม่ทุกรอบนาฬิกา การมีความหน่วงค่อนข้างดี แต่ฉันต้องสร้างเอาต์พุตที่ 150 MSamps / วินาทีเช่นกัน
2913869

แบบจำลองของฉันแสดงว่าฉันสามารถอยู่กับประมาณ 1 * 10 ^ -9 ไม่แน่ใจว่าบิตจุดคงที่ต่ำสุดที่แน่นอน แต่ฉันได้รับการจำลองด้วยรูปแบบจุดคงที่
Q10.32

บทความนี้atan2จะอธิบายถึงการดำเนินการแก้ไขจุด คุณยังจะต้องแบ่งแม้ว่า
Matt L.

คำตอบ:


20

คุณสามารถใช้ลอการิทึมเพื่อกำจัดการหาร สำหรับ(x,y)ในจตุภาคแรก:

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

Atan (2 ^ z)

รูปที่ 1 พล็อตของ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 (c)

log2(c)

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

ข้อผิดพลาดของการประมาณ atan (2 ^ z)

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

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

สำหรับการอ้างอิงในภายหลังนี่คือสคริปต์ Python clunky ที่ฉันใช้ในการคำนวณข้อผิดพลาดโดยประมาณ:

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,

โดยที่และเป็นต้นฉบับและตารางที่กรองแล้วทั้งสองทอดและน้ำหนักเป็น{16} การปรับสภาพท้าย (แถวแรกและแถวสุดท้ายในสมการข้างต้น) ลดข้อผิดพลาดที่ปลายตารางเมื่อเทียบกับการใช้ตัวอย่างของฟังก์ชันนอกตารางเนื่องจากไม่จำเป็นต้องปรับตัวอย่างแรกและตัวอย่างสุดท้ายเพื่อลดข้อผิดพลาดจากการแก้ไข ระหว่างมันและตัวอย่างอยู่นอกตาราง ตารางย่อยที่มีช่วงการสุ่มตัวอย่างที่แตกต่างกันควรทำการกรองแยกต่างหากล่วงหน้า ค่าของน้ำหนักถูกพบโดยย่อให้เล็กที่สุดเพื่อเพิ่มเลขชี้กำลัง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

สำหรับ<1 การใช้ prefilter เกี่ยวกับข้อผิดพลาดประมาณครึ่งและง่ายกว่าการทำตารางให้สมบูรณ์0a<1

ข้อผิดพลาดโดยประมาณที่มีและไม่มีพรีฟิลเตอร์และการปรับสภาพสิ้นสุด

รูปที่ 4. ข้อผิดพลาดการประมาณของจาก 11 ตัวอย่างที่มีและไม่มีตัวกรองล่วงหน้าและมีและไม่มีการปรับสภาพสิ้นสุด prefilter มีการเข้าถึงค่าของฟังก์ชั่นนอกตารางlog2(a)

บทความนี้น่าจะนำเสนอขั้นตอนวิธีการที่คล้ายกันมาก: อาร์เตียร์เรสโวลต์และเจ Valls“ FPGA-การดำเนินงานของ Atan (Y / X) ตามการเปลี่ยนแปลงลอการิทึมและเทคนิค LUT ตามวารสารสถาปัตยกรรมระบบฉบับ . 56, 2010 บทคัดย่อกล่าวว่าการติดตั้งของพวกเขาเต้นตามอัลกอริธึมที่ใช้ CORDIC ก่อนหน้านี้ในด้านความเร็วและอัลกอริธึมที่ใช้ LUT ในขนาดรอยเท้า


3
Matthew Gambrell และฉันได้ออกแบบชิปเสียงของ Yamaha YM3812 (โดยไมโครสโคป) แบบย้อนกลับและได้พบกับมันในทำนองเดียวกันบันทึก / exp อ่านเฉพาะหน่วยความจำ (ROM) ตาราง ยามาฮ่าได้ใช้เคล็ดลับเพิ่มเติมในการแทนที่ทุก ๆ วินาทีในแต่ละตารางโดยมีความแตกต่างจากรายการก่อนหน้า สำหรับฟังก์ชั่นที่ราบรื่นความแตกต่างจะใช้บิตและพื้นที่ชิปน้อยกว่าในการแทนฟังก์ชัน พวกเขามี adder บนชิปที่สามารถใช้เพื่อเพิ่มความแตกต่างให้กับรายการก่อนหน้า
Olli Niemitalo

3
ขอบคุณมาก! ฉันชอบการใช้ประโยชน์จากคุณสมบัติทางคณิตศาสตร์เหล่านี้ ฉันจะพัฒนาซิมส์ MATLAB นี้และถ้าทุกอย่างดูดีให้เข้าสู่ HDL ฉันจะรายงานการประหยัด LUT ของฉันคืนให้เมื่อทุกอย่างเรียบร้อย
2913869

ฉันใช้คำอธิบายของคุณเป็นแนวทางและฉันมีความสุขที่ได้พักที่ลดลงโดย LUT เกือบ 60% ฉันจำเป็นต้องลด BRAMs ดังนั้นฉันจึงหาว่าฉันสามารถรับข้อผิดพลาดสูงสุดที่สอดคล้องกันในตาราง ATAN ของฉันโดยทำการสุ่มตัวอย่างแบบไม่สม่ำเสมอ: ฉันมี LUT BRAM หลายตัว (จำนวนบิตที่อยู่เดียวกันทั้งหมด) ใกล้เคียงกับ ศูนย์ยิ่งการสุ่มตัวอย่างเร็วขึ้น ฉันเลือกช่วงตารางของฉันให้มีอำนาจเป็น 2 ดังนั้นฉันจึงสามารถตรวจจับช่วงที่ฉันอยู่ด้วยได้อย่างง่ายดายและทำการสร้างดัชนีตารางอัตโนมัติผ่านการจัดการบิต ฉันใช้สมมาตร atan เช่นกันดังนั้นฉันจึงเก็บรูปคลื่นเพียงครึ่งเดียว
2913869

นอกจากนี้ฉันอาจพลาดการแก้ไขบางส่วนของคุณ แต่ฉันจัดการเพื่อนำไปใช้ 2 ^ z โดยแยกออกเป็น 2 ^ {if} = 2 ^ i * 2 ^ {0.f} โดยที่ฉันคือส่วนจำนวนเต็มและ f คือ ส่วนที่เป็นเศษส่วน 2 ^ i นั้นง่ายการจัดการเพียงเล็กน้อยและ 2 ^ {0.f} มีช่วงที่ จำกัด จึงให้ยืม LUT ได้ดีด้วยการแก้ไข ฉันยังจัดการกรณีลบ: 2 ^ {- if} = 2 ^ {- i} * 1 / (2 ^ {0.f} ดังนั้นอีกหนึ่งตารางสำหรับ 1/2 ^ {0.f} ขั้นตอนต่อไปของฉัน อาจจะใช้พลังของการสุ่มตัวอย่างแบบ 2 แบบ / แบบไม่สม่ำเสมอบน log2 (y) LUT ซึ่งดูเหมือนว่ามันจะเป็นรูปแบบคลื่นที่สมบูรณ์แบบสำหรับสิ่งนั้นไชโย!
2913869

1
แล้วฉันก็พลาดขั้นตอนนั้นไปทั้งหมด ฉันจะลองตอนนี้ ควรช่วยฉัน LUT ให้มากขึ้นและเพิ่มมากขึ้นอีกด้วย
user2913869
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.