2012-11-26 22 views
5

Tôi vừa hoàn thành một dự án DDS, trên một Atmel AVR sử dụng ASM, và đi đến kết luận rằng một bảng tra cứu 8 bit và 8 bit DAC tạo ra quá nhiều lượng tử hóa biến dạng ở tần số thấp; vì thiếu từ ngữ tốt hơn, tôi nhận được một làn sóng sin với hiệu ứng bậc thang trên dao động của tôi.DDS Interpolation - 8bit Atmel AVR ASM tới 12 bit DAC

Rõ ràng, nếu tôi làm mịn dạng sóng với LPF lớn, tôi gặp vấn đề với biên độ ở tần số cao hơn. Về lý thuyết, nâng cấp từ 8 bit lên 12 bit DAC và sử dụng nội suy với 4 bit quan trọng nhất sẽ cho phép tôi nâng điểm cắt của bộ lọc lên một lượng đủ lớn để giảm bớt các vấn đề với biên độ dạng sóng ở tần số cao hơn. Vấn đề của tôi là tôi không có một đầu mối làm thế nào để làm điều này hoặc nếu có một cách dễ dàng hơn để loại bỏ các hiệu ứng dây kéo .. có lẽ 12 bit bảng tra cứu? Cho đến nay, tôi đã tạo ra một vòng lặp vô hạn và mỗi khi vòng lặp hoàn thành một chu kỳ, một giá trị được gửi đến DAC dựa trên vị trí của con trỏ liên quan đến bảng tra cứu. Đây là nơi tôi bị lẫn lộn. Tôi đã đọc tấn thông tin về điều này và vẫn chưa tìm thấy một ví dụ làm việc. Nếu tôi có một vòng lặp vô hạn, làm thế nào tôi phải nhồi nhét các giá trị nội suy giữa các giá trị tra cứu bảng? Về điều tốt nhất mà tôi có thể nghĩ đến là (a + b)/2; Tôi có thể có thể thực hiện điều này và nhận thêm một chút hoặc tương đương với bảng điểm 512 điểm, nhưng tôi muốn nghĩ rằng có một cách dễ dàng hơn hoặc thứ gì đó có khả năng mang lại kết quả tốt hơn. Tôi không biết C hoặc làm thế nào để sử dụng nó, nhưng tôi sẽ cung cấp cho nó một thử nếu nó là thận trọng.

Hiện tại, đồng hồ của tôi ở mức 1MHZ và có thể tôi đến 16MHZ nếu cần.

Đây là mẫu mã của tôi:

; Đặt đầu ra sinewave làm mặc định

ldi  ZH, High(sine*2); setup Z pointer hi 
    ldi  ZL, Low(sine*2) ; setup Z pointer lo 

; Clear accumulator

clr  r29    ; clear accumulator 

; Cài đặt bộ cộng đăng ký

ldi  r24,0x50  ; Fine adder value change register 
    ldi  r25,0x08  ; Middle adder value change register 
    ldi  r26,0x00  ; Coarse adder value change register 

LOOP1:

add  r28,r24   ; 1 Adder values carry over to higher registers. Higher registers raise freq. in larger steps 
    adc  r29,r25   ; 1 
    adc  r30,r26   ; 1 r30 is database address pointer for Z register 
    lpm  r0, Z   ; 3 (Load Program Memory) Reads byte from database into the destination register based on Z pointer 
    out  PORTD,r0 


    rjmp LOOP1   ; 2 => 9 cycles 

Trả lời

2

Nếu LUT của bạn có 256 mục, trước tiên bạn có thể sử dụng R29 đăng ký (mà dường như đi từ 0 đến 255) là yếu tố rộng giữa hai mẫu liên tiếp .

Output = (LUT[r30] * (256 - r29) + LUT[r30+1] * r29) >> 8;

Also this thread thảo luận nhiều giải pháp thay thế thực tế này sang thế hệ sóng sin.

EDIT Công thức thực hiện cuốn sách văn bản tuyến tính suy

y = a*(1-t) + b*t, with 0<=t<1 

Vì vậy mà y = a, khi t = 0 và y = b, khi t = 1. Chuyển bằng 8 có nghĩa là thuật ngữ nội suy t được chia cho 256 sau phép nhân. Trong biểu thức LUT [r30 + 1] Tôi giả định một modulo 256 modul ngầm, vì r30 là 8-bit (phải không?).

Mở rộng LUT đến 12 bit phải được thực hiện riêng biệt, khi chia cho 4 thay vì sẽ chỉ làm tăng lỗi lượng tử hóa trong LUT.

enter image description here

Các nội suy sẽ xảy ra lúc nào cũng liên quan đến chỉ số số nguyên trong LUT, bất kể nếu nhiều mẫu rơi xuống cùng một phạm vi ví dụ. LUT 2 và LUT [3]. Về mặt toán học Lut [R], LUT [R + 1] chính xác hơn [R-1], [R], nhưng trong thực tế thì không có sự khác biệt, vì hệ thống kiểm tra của con người không có pha tham chiếu tuyệt đối.

+0

Cảm ơn câu trả lời của bạn. Tôi không hiểu nó. Tại sao phải thay đổi 8 bit? Phần đầu tiên của phương trình có thể rất dễ dàng tràn các thanh ghi. Sẽ không LUT [r30 + 1] thay đổi pha của dạng sóng, không tiến tới bước nhạy cảm thời gian tiếp theo của con trỏ? Nó sẽ không có ý nghĩa hơn để truy vấn bước con trỏ trước đó? –

Các vấn đề liên quan