Εισαγωγή

Η ψηφιακή επεξεργασία σημάτων (DSP) είναι η ραχοκοκαλιά των σύγχρονων ενσωματωμένων συστημάτων, επιτρέποντας τον ήχο σε πραγματικό χρόνο, βίντεο, τηλεμετρία και λειτουργίες επικοινωνίας. Γράφοντας αποτελεσματικό κώδικα C για εργασίες DSP άμεσα επιπτώσεις σύστημα overput, κατανάλωση ισχύος, και λανθάνουσα ισχύς. Σε αντίθεση με τον κώδικα γενικής χρήσης, οι αλγόριθμοι DSP πρέπει να εκτελούν μέσα σε αυστηρούς περιορισμούς χρονισμού, ενώ μεγιστοποιούν τη χρήση των περιορισμένων πόρων μνήμης και επεξεργασίας. Αυτός ο οδηγός επεκτείνεται στις βασικές αρχές και παρέχει ενεργές τεχνικές για τη γραφή κώδικα παραγωγής C βαθμού για εφαρμογές DSP, από την αριθμητική σταθερής σημασίας σε εξειδικευμένες βελτιστοποιήσεις υλικού.

Κατανόηση των βασικών δεδομένων του DSP σε Γ

Σε C, ο προγραμματιστής ελέγχει κάθε πτυχή της αναπαράστασης και της ροής δεδομένων, η οποία είναι κρίσιμη για την αποτελεσματική εκτέλεση. Ο κώδικας DSP συχνά τρέχει σε μικροελεγκτή ή ψηφιακούς επεξεργαστές σημάτων όπου το υλικό είναι σφιχτά συζευγμένος ⁇ για παράδειγμα, αφιερωμένες μονάδες MAC (πολλαπλές-συσσωρεύσιμες) ή SIMD διανυσματικές μηχανές. Μια βαθιά κατανόηση της ιεραρχίας μνήμης της αρχιτεκτονικής στόχου, σύνολο οδηγιών, και περιφερειακές δυνατότητες είναι απαραίτητη για τη συγγραφή αποτελεσματικού κώδικα C.

Βασικά χαρακτηριστικά του κωδικού DSP:

  • Επαναλαμβανόμενη αριθμητική: κυριαρχούν οι βρόχοι με λειτουργίες πολλαπλών προσδώσεων (π.χ. φίλτρα FIR).
  • Περιορισμός σε πραγματικό χρόνο: κάθε δείγμα πρέπει να υποβληθεί σε επεξεργασία εντός περιόδου δειγματοληψίας.
  • ⁇ ύμα δεδομένων: ⁇ συνεχών ροών εισόδου/εξόδου απαιτούν αποτελεσματική ρύθμιση και ελάχιστη αντιγραφή.
  • Μνήμη ζώνης ζώνης δεσμεύεται: πολλοί αλγόριθμοι DSP περιορίζονται από το πόσο γρήγορα μπορούν να μετακινηθούν τα δεδομένα, όχι από αριθμητικές πράξεις.

Για μια βασική αναφορά, βλέπε Analog Devices' DSP Basics.

Αριθμητικό σταθερών σημείων: Ακρίβεια χωρίς υπερκέφαλο επίπλευσης σημείου

Πολλοί επεξεργαστές DSP δεν διαθέτουν μονάδες κινητής υποδιαστολής υλικού (FPU) ή έχουν πιο αργούς FPU. Η αριθμητική σταθερής υποδιαστολής χρησιμοποιεί ακέραιες λειτουργίες με ένα έμμεσο σημείο radix, παρέχοντας ντετερμινιστική απόδοση και χαμηλότερη κατανάλωση ισχύος. Η πιο κοινή αναπαράσταση είναι Q σημειογραφία: Qm.n] όπου [m] τα bits είναι ακέραια μέρος και n bits κλασματικό μέρος. Για παράδειγμα, μια μορφή Q15 (1 bit σημείου, 15 κλασματικά bits) είναι πανταχού παρών σε 16-bit DSPs.

Εκτελεστικές λειτουργίες σταθερών σημείων σε Γ

Η προσθήκη σταθερού σημείου είναι απλή (απλά προσθέστε ακέραιους), αλλά ο πολλαπλασιασμός απαιτεί ρύθμιση του σημείου radix. Για τον πολλαπλασιασμό Q15, το προϊόν δύο αριθμών Q15 χρειάζεται ένα ενδιάμεσο αποτέλεσμα 32-bit, τότε μπορείτε δεξιά μετατόπιση κατά 15 bits για να επιστρέψετε στο Q15. Παράδειγμα:

typedef int16_t q15_t;
q15_t q15_mul(q15_t a, q15_t b) {
 int32_t temp = (int32_t)a * (int32_t)b;
 return (q15_t)(temp >> 15);
}

Όταν συμβαίνουν συσσωρεύσεις (π.χ. σε φίλτρα), τα bits φύλαξης εμποδίζουν την υπερχείλιση. Χρησιμοποιήστε 32-bit ή ακόμα 64-bit συσσωρευτές και κορεσμένα αποτελέσματα. Οι βιβλιοθήκες σταθερών σημείων όπως ARM CMSIS-DSP[ παρέχουν βελτιστοποιημένες λειτουργίες σταθερών σημείων, συμπεριλαμβανομένων των φίλτρων, των μετασχηματισμών και των λειτουργιών μήτρας.

Πότε να χρησιμοποιήσετε το Σταθερό Σημείο vs Floating-Point

Σύγχρονοι επεξεργαστές με FPU (π.χ., Cortex-M4/M7) μπορούν να εκτελούν λειτουργίες κινητής υποδιαστολής τόσο γρήγορα όσο και σταθερό σημείο. Χρησιμοποιήστε το πλωτό σημείο όταν:

  • Η δυναμική γκάμα του αλγόριθμου είναι υψηλή (π.χ. προσαρμοστικά φίλτρα).
  • Η διατηρησιμότητα του κώδικα αποτελεί προτεραιότητα (ανάλυση με λιγότερη κλιμάκωση).
  • Το υλικό FPU είναι παρόν και ο αγωγός μπορεί να επικαλύψει τις προσθήκες και τις πολλαπλασιάσεις.

Σε συσκευές υψηλού όγκου χωρίς FPU, σταθερό σημείο παραμένει το πρότυπο για τις εφαρμογές που είναι ευαίσθητες στο κόστος.

Βελτιστοποίηση πρόσβασης μνήμης για DSP

Οι αλγόριθμοι DSP συχνά επεξεργάζονται μεγάλες σειρές δεδομένων διαδοχικά. Οι λανθάνοντες λανθάνοντες αγωγοί και οι πάγκοι λεωφορείων μπορούν να σκοτώσουν την απόδοση. Ακολουθήστε αυτές τις αρχές:

  • Κοντά πρόσβαση δεδομένων: διατομές σε συνεχόμενη σειρά (σειρά-μείζων σε C). Αποφύγετε τα διασκελισμένα πρότυπα πρόσβασης εκτός εάν απαιτείται από τον αλγόριθμο (π.χ., FFT bit-αντίστροφα).
  • Στοίχιση δεδομένων: εξασφαλίζουν ότι οι συστοιχίες ευθυγραμμίζονται με τα όρια των γραμμών cache. Χρησιμοποιήστε χαρακτηριστικά μεταγλωττιστή όπως ή ειδικές ενότητες μνήμης.
  • Φούσκωμα: χρήση διπλής ενδιάμεσης μνήμης για να επικαλύψει τις μεταφορές DMA με την επεξεργασία ΚΜΕ. Ενώ η ΚΜΕ λειτουργεί σε ένα ρυθμιστικό διάλυμα, το επόμενο μπλοκ δειγμάτων φορτώνεται.
  • Περιορίστε τη λέξη κλειδί: χρησιμοποιούν C99’s ] σε δείκτες για να ενημερώσουν τον μεταγλωττιστή ότι οι δείκτες δεν ψευδώνυμα, επιτρέποντας τη διανυσματοποίηση και τον καλύτερο προγραμματισμό οδηγιών.

Για παράδειγμα, μια απλή συνάρτηση φίλτρου FIR θα πρέπει να γράφεται με `περιορισμό' όταν οι ρυθμιστές εισόδου και εξόδου είναι χωριστές:

void fir_lowpass(const int16_t * restrict x, int16_t * restrict y,
 const int16_t * restrict coeffs, int len, int order) {
 for (int i = 0; i < len; i++) {
 int32_t acc = 0;
 for (int j = 0; j < order; j++) {
 acc += (int32_t)x[i + j] * coeffs[j];
 }
 y[i] = (int16_t)(acc >> 15);
 }
}

Αποτελεσματικός Αλγόριθμος Επιλογή και Εφαρμογή

Η αλγοριθμική πολυπλοκότητα μεταφράζεται άμεσα σε χρόνο εκτέλεσης και ισχύ. Πάντα επιλέξτε τον πιο αποτελεσματικό αλγόριθμο για την εργασία:

  • Fast Fourier Transform (FFT): χρησιμοποιούν Cooley-Tukey radix-2 ή split-radix για δύναμη-από-δύο μήκη. Αποφύγετε αφελή DFT που είναι O(N2). Προυπολογίστε παράγοντες του μέσου και να αποθηκεύσετε σε ROM.
  • Φίλτρα FIR: χρησιμοποιούν πολυφασική αποσύνθεση για αποδεκατισμό/ παρεμβολή· εκμεταλλεύονται συμμετρία για γραμμικά-φασικά φίλτρα για να μειώσουν κατά το ήμισυ τον αριθμό των πολλαπλασιασμών.
  • Φίλτρα IIR: χρησιμοποιούν απευθείας τη μορφή II που μεταφέρεται για καλύτερη αριθμητική σταθερότητα· χρησιμοποιούν κλιμακωτά διπλή τμήματα (δεύτερης τάξης στάδια) για να μειώσουν την ευαισθησία στον συντελεστή ποσοτικοποίησης.
  • Συνέλιξη: για μακρές αλληλουχίες, χρησιμοποιήστε μεθόδους επικάλυψης με βάση το FFT ή μεθόδους αποθήκευσης με επικάλυψη αντί για άμεση συνένωση.

Ανατρέξτε στη βιβλιοθήκη του FFT για αναφορά σε σύγχρονες τεχνικές FFT (αν και όχι στη Γ, οι αρχές του αντιγράφονται ευρέως σε ενσωματωμένες βιβλιοθήκες του DSP).

Χρήση υλικού Χαρακτηριστικά γνωρίσματα: Οδηγίες SIMD και DSP

Σχεδόν όλοι οι σύγχρονοι μικροελεγκτές περιλαμβάνουν SIMD (Μονάδια Πολλαπλά Δεδομένα Οδηγιών) ή DSP-ενισχυμένες οδηγίες. Για παράδειγμα:

  • ARM Cortex-M4/M7: SIMD (SADD, SMUAD, κ.λπ.), κορεσμένη αριθμητική, και κλασματικές λειτουργίες (QADD, QSUB). Χρησιμοποιήστε εγγενείς λειτουργίες CMSIS-DSP.
  • TI C6000 DSP: οκτώ μονάδες πολλαπλασιάζονται, διπλή MAC, και το λογισμικό σωληνώσεων. Ο TI DSP Οδηγός Βελτιστοποίησης παρέχει λεπτομερείς τεχνικές.
  • RISC-V με P-επέκταση: οι μελλοντικοί πυρήνες θα έχουν οδηγίες τύπου DSP.

Για να χρησιμοποιήσετε αυτά τα χαρακτηριστικά στο C, γράψτε τον κώδικα που ο μεταγλωττιστής μπορεί να αυτο-εμποτίσει (π.χ., απλοί βρόχοι χωρίς εξαρτήσεις) ή χρησιμοποιήστε εγγενείς λειτουργίες μεταγλωττιστή. Παράδειγμα χρησιμοποιώντας το ARM CMSIS-DSP για ένα φίλτρο FIR:

#include "arm_math.h"
arm_fir_instance_f32 S;
float32_t firState[128];
arm_fir_init_f32(&S, numTaps, coeffs, firState, blockSize);
arm_fir_f32(&S, input, output, blockSize);

Τέτοιες βιβλιοθήκες είναι χειρόγραφες στη συναρμολόγηση για μέγιστη απόδοση. Πάντα προφίλ πριν και μετά τη μετάβαση από το γενικό C σε λειτουργίες βιβλιοθήκης.

Τεχνικές Βελτιστοποίησης Loop

Επειδή οι αλγόριθμοι DSP είναι βαρείς βρόχοι, οι βελτιστοποιήσεις στο επίπεδο βρόχων πληρώνουν μεγάλα μερίσματα:

  • Λουπ ξετυλίγοντας: χειροκίνητα ή με μεταγλωττιστές pragmas (`#pragma unroll N`) για να μειώσει το βρόχο γενικά και να αυξήσει τον παραλληλισμό σε επίπεδο οδηγιών.
  • Λογισμικό σωληνώσεων: αναδιαρθρώνουν βρόχους ώστε πολλαπλές επαναλήψεις να βρίσκονται ταυτόχρονα σε πτήση. Μερικοί μεταγλωττιστές το κάνουν αυτό αυτόματα, χρησιμοποιούν `-O3 ́ και ειδικές για την αρχιτεκτονική σημαίες.
  • Μείωση της διακλάδωσης: αντικαθιστούν τους όρους με αριθμητική (π.χ., min/max με χρήση τριμηνιαίων), ή χρησιμοποιούν πίνακες αναζήτησης για μη γραμμικές λειτουργίες.
  • Χρησιμοποιήστε τοπικές μεταβλητές: αποθηκεύστε συχνά προσπελασμένα δεδομένα σε μητρώα δηλώνοντας μεταβλητές μέσα στο βρόχο ή χρησιμοποιώντας υπόδειξη `register'.
  • Ελάχιστα τμήματα: αντικαθιστούν το διαχωρισμό με σταθερό με πολλαπλασιασμό με αμοιβαία· χρησιμοποιούν μετατόπιση για εξουσίες δύο.

Προυπολογίζοντας Σταθερές και Αναζήτηση πίνακες

Συναρτήσεις DSP όπως τριγωνομετρικές τιμές, συντελεστές, και συντελεστές του μέσου θα πρέπει να προυπολογίζονται offline και να αποθηκεύονται ως σταθερές συστοιχίες σε ROM. Για την εκκίνηση μη-πραγματικού χρόνου, μπορείτε να τις υπολογίσετε μία φορά και να επαναχρησιμοποιήσετε. Παράδειγμα: για ένα FFT 1024-σημείο, προυπολογίστε τις τιμές ημίτονου/κοσίνης για κάθε στάδιο. Αυτό εξαλείφει την αξιολόγηση χρόνου λειτουργίας και μειώνει την ισχύ.

Οι πίνακες αναζήτησης (LUTs) βοηθούν επίσης για λειτουργίες όπως η τετραγωνική ρίζα, το εκθέτης και το log που χρησιμοποιούνται στο DSP (π.χ. στην επεξεργασία ομιλίας).

Προφίλ και συντονισμός

Δεν έχει ολοκληρωθεί η βελτιστοποίηση χωρίς μέτρηση. Χρησιμοποιήστε αυτές τις τεχνικές για τον προσδιορισμό σημείων συμφόρησης:

  • Κύκλος-ακρίβεια προφίλ:[[LFT:1]] χρήση μετρητών κύκλου επί του σκάφους (π.χ., DWT CYCCNT στο Cortex-M) για τη μέτρηση της διάρκειας λειτουργίας.
  • Στατιστικό προφίλ: μετρητής προγράμματος δειγματοληψίας (PC) για να δούμε ποιες λειτουργίες καταναλώνουν χρόνο ΚΜΕ.
  • Αναμνηστικό προφίλ:[ χρησιμοποιούν εργαλεία για την παρακολούθηση των λανθάνοντων λανθάνοντων λανθάνοντων λανθάνοντων λανθάνον (εάν είναι διαθέσιμο) και των συναλλαγών με λεωφορεία.
  • Ανατροφοδότηση compiler: ενεργοποιήστε τις αναφορές βελτιστοποίησης μεταγλωττιστή (‘-fopt-info-vec-optimized` in GCC) για να δείτε αν οι βρόχοι έχουν διανυθεί.

Συχνά τα μεγαλύτερα κέρδη προέρχονται από τη βελτίωση των προτύπων πρόσβασης στη μνήμη και όχι από την τροποποίηση αριθμητικής.

Πρακτική Περίληψη: Συναθροίζοντάς τα Όλα

Η εγγραφή αποτελεσματικού κώδικα DSP σε C απαιτεί ολιστική προσέγγιση:

  • Επιλέξτε τη σωστή αναπαράσταση δεδομένων (σταθερό σημείο έναντι πλωτό σημείο).
  • Σχεδιασμός δομών δεδομένων για διαδοχική πρόσβαση και ευθυγράμμιση.
  • Επιλέξτε αλγόριθμους με χαμηλή πολυπλοκότητα (FFT, πολυφασική).
  • Χρήση των βιβλιοθηκών DSP του πωλητή όταν είναι διαθέσιμες.
  • Ξετύλιξε βρόχους και μείωσε τη διακλάδωση.
  • Προυπολογίστε σταθερές σε ROM.
  • Προφίλ αμείλικτα και αφήστε τον μεταγλωττιστή να βοηθήσει.

Εφαρμόζοντας αυτές τις αρχές, οι προγραμματιστές μπορούν να επιτύχουν επεξεργασία σήματος μέσω της βάσης συγκρίσιμης με την χειροκίνητη συναρμολόγηση, διατηρώντας τη φορητότητα και τη διατηρησιμότητα του C. Το αποτέλεσμα είναι αξιόπιστα, σε πραγματικό χρόνο συστήματα DSP που ανταποκρίνονται στις απαιτήσεις των σύγχρονων ενσωματωμένων προϊόντων ⁇ από τα ακουστικά βοηθήματα έως 5G σταθμούς βάσης.