Phasenschieber 90 Grad

Gast #3318059
Lesenswert?

Hallo,
da ich leider kein DSP Mathematiker bin, such ich mal hier um Hilfe.
Ich will für ein kleines Projekt eine Einseitenbandmodulation mit dem 
IQ-Mischer realisieren. Dazu brauche ich einen Phasenschieber, der das 
oder die Signale um 90 Grad verschiebt. Nun steht mal so im Raum eine 
Hilberttransformation, All-pass, IIR oder Ähnliches.
Ich habe schon einige IIR-Filter realisiert und auf einem ARM7 
umgesetzt. Jetzt steht ein Cortex M4F zur Verfügung, der um einiges 
schneller ist.

Ich habe leider im WEB keine Implementierung dafür gefunden. Nur etliche 
verzettelte Theorien. Ich konnte bis jetzt nichts brauchbares ableiten.

Gerne bin ich dann auch Bereit den Code hier fürs Forum offen zu legen.
Programmieren tu ich in Assembler mit FPU oder Fixpoint, je nach....

Frequenzspektrum ca. 200Hz...5KHz
Samplefrequenz 22,32,44KHz je nach
Quantisierung der ADC-Werte 16Bit


Gruß Sascha
Gast #3318388
Lesenswert?

Hallo Johannes,
ja ganz einfach ich suche nach einem Lösungsweg um einen solchen 
Phasenschieber programmieren zu können.
Gibt es Berechnungsprogramme für die Faktoren?
Welche Art von Filter eignet sich dafür am besten?
Hat jemand Erfahrung damit?

Gruß Sascha
#3318638
Lesenswert?

Sascha schrieb:
> Gibt es Berechnungsprogramme für die Faktoren?

Für eine Hilbert-Transformation braucht man einen FIR-Filter, die 
Filterkoeffizienten kann man z.B. mit Scilab berechnen, die Funktion 
heist "hilb()".

Die Implementierung eines FIR-Filters auf einen Controller/DSP ist im 
Prinzip relativ einfach, wenn man schon mal einen IIR-Filter 
programmiert hat.
Eine fertige Implementierung, die man im Internet herunterladen kann, 
kenne ich allerdings auch nicht.

Hier ist ein Beispiel-Skript für Scilab:
(Koeffizientenberechnung und Simulation)
1
L=500;
2
t=[0:1:L-1];
3
x=sin(2*%pi*0.02*t);
4

5
n=40;
6
c_hilb = hilb(n);
7

8
z=poly(0, 'z');
9
h=poly(c_hilb, 'z', "coeff")/z^(n-1);
10

11
y=flts(x, h);
12
x_delay = [zeros(1,n/2), x(1:L-n/2)];
13
clf();
14
plot([x_delay', y']);

Die Filterkoeffizienten stehen in der Variablen c_hilb.

Das sind Fließkommazahlen, für Festkomma-Rechnung muss man die 
entsprechend normieren und umwandeln.
Gast #3318684
Lesenswert?

Hallo Johannes,
das ist ja super, werde ich morgen ausprobieren.
FIR filter ist kein Problem, kann ich sogar als Fixed Point mit 64 Bit 
durchlaufen lassen. Oder mit der FPU als 32 Bit IEEE754.
Ich habe gerade bei Freescale die AN4265 gefunden, hier gehts zwar um 
Stromzähler, aber es ist auch eine recht intresannte Vorlage dafür.
Habe im Web gesehen das ein FIR Filter mit 64 Taps ausreichend genug 
ist.

Gruß Sascha
Gast #3319264
Lesenswert?

Hilbert Filter treten gerne mal als Paar auf, d.h. man nimmt zwei 
Filter, die zueinander eine Phasenverschiebung von 90° haben. Folgenden 
hack habe ich mir letztens irgendwo aus dem Netz gezogen, funktioniert 
sehr gut.

hth

Cheers
Detlef


#define FAK (32768)

int16_t hilbert_I[32]={ // Inphase Filter Hilbert Transformation
(int16_t)(FAK*0.000210129754790+0.5), // inPhase
(int16_t)(FAK*0.000435686890851+0.5), // inPhase
(int16_t)(FAK*0.001141127330285+0.5), // inPhase
(int16_t)(FAK*-0.000474463384430+0.5), // inPhase
(int16_t)(FAK*0.003228639378579+0.5), // inPhase
(int16_t)(FAK*0.015798773063932+0.5), // inPhase
(int16_t)(FAK*0.016068342201175+0.5), // inPhase
(int16_t)(FAK*-0.008791323992589+0.5), // inPhase
(int16_t)(FAK*-0.023622650882713+0.5), // inPhase
(int16_t)(FAK*-0.002444248072844+0.5), // inPhase
(int16_t)(FAK*-0.003613471987776+0.5), // inPhase
(int16_t)(FAK*-0.082509515298895+0.5), // inPhase
(int16_t)(FAK*-0.141251242309150+0.5), // inPhase
(int16_t)(FAK*-0.022156774160222+0.5), // inPhase
(int16_t)(FAK*0.215723703269164+0.5), // inPhase
(int16_t)(FAK*0.295359239543522+0.5), // inPhase
(int16_t)(FAK*0.089596245788314+0.5), // inPhase
(int16_t)(FAK*-0.177039867952018+0.5), // inPhase
(int16_t)(FAK*-0.224961503288498+0.5), // inPhase
(int16_t)(FAK*-0.075500361981124+0.5), // inPhase
(int16_t)(FAK*0.044102254749162+0.5), // inPhase
(int16_t)(FAK*0.036688196782744+0.5), // inPhase
(int16_t)(FAK*-0.002005942552907+0.5), // inPhase
(int16_t)(FAK*0.007165852803285+0.5), // inPhase
(int16_t)(FAK*0.028981111275206+0.5), // inPhase
(int16_t)(FAK*0.019579331622486+0.5), // inPhase
(int16_t)(FAK*-0.001556043330388+0.5), // inPhase
(int16_t)(FAK*-0.006040359426444+0.5), // inPhase
(int16_t)(FAK*-0.000887658558481+0.5), // inPhase
(int16_t)(FAK*0.000112391232169+0.5), // inPhase
(int16_t)(FAK*-0.000530886012554+0.5), // inPhase
(int16_t)(FAK*0.000692704968094+0.5)};

int16_t hilbert_Q[32]={ // Quadratur Filter Hilbert Transformation
(int16_t)(FAK*0.000692704968094+0.5), // quadraturePhase
(int16_t)(FAK*-0.000530886012554+0.5), // quadraturePhase
(int16_t)(FAK*0.000112391232169+0.5), // quadraturePhase
(int16_t)(FAK*-0.000887658558481+0.5), // quadraturePhase
(int16_t)(FAK*-0.006040359426444+0.5), // quadraturePhase
(int16_t)(FAK*-0.001556043330388+0.5), // quadraturePhase
(int16_t)(FAK*0.019579331622486+0.5), // quadraturePhase
(int16_t)(FAK*0.028981111275206+0.5), // quadraturePhase
(int16_t)(FAK*0.007165852803285+0.5), // quadraturePhase
(int16_t)(FAK*-0.002005942552907+0.5), // quadraturePhase
(int16_t)(FAK*0.036688196782744+0.5), // quadraturePhase
(int16_t)(FAK*0.044102254749162+0.5), // quadraturePhase
(int16_t)(FAK*-0.075500361981124+0.5), // quadraturePhase
(int16_t)(FAK*-0.224961503288498+0.5), // quadraturePhase
(int16_t)(FAK*-0.177039867952018+0.5), // quadraturePhase
(int16_t)(FAK*0.089596245788314+0.5), // quadraturePhase
(int16_t)(FAK*0.295359239543522+0.5), // quadraturePhase
(int16_t)(FAK*0.215723703269164+0.5), // quadraturePhase
(int16_t)(FAK*-0.022156774160222+0.5), // quadraturePhase
(int16_t)(FAK*-0.141251242309150+0.5), // quadraturePhase
(int16_t)(FAK*-0.082509515298895+0.5), // quadraturePhase
(int16_t)(FAK*-0.003613471987776+0.5), // quadraturePhase
(int16_t)(FAK*-0.002444248072844+0.5), // quadraturePhase
(int16_t)(FAK*-0.023622650882713+0.5), // quadraturePhase
(int16_t)(FAK*-0.008791323992589+0.5), // quadraturePhase
(int16_t)(FAK*0.016068342201175+0.5), // quadraturePhase
(int16_t)(FAK*0.015798773063932+0.5), // quadraturePhase
(int16_t)(FAK*0.003228639378579+0.5), // quadraturePhase
(int16_t)(FAK*-0.000474463384430+0.5), // quadraturePhase
(int16_t)(FAK*0.001141127330285+0.5), // quadraturePhase
(int16_t)(FAK*0.000435686890851+0.5), // quadraturePhase
(int16_t)(FAK*0.000210129754790+0.5)};

#undef FAK


for(k=32;k<128;k++){

    x1=0;x2=0;
    //12Bit+16Bit+5Bit
    for(m=0;m<32;m++){
     x1 += ((int32_t)hilbert_I[m]*(trace[k-m-1]-xy))>>3;
     x2 += ((int32_t)hilbert_Q[m]*(trace[k-m-1]-xy))>>3;
    }
    /*
    fx1=0.0;fx2=0.0;
    //12Bit+16Bit*5Bit
    for(m=0;m<32;m++){
     fx1 += ((double)hilbert_I[m]*(trace[k-m-1]-xy));
     fx2 += ((double)hilbert_Q[m]*(trace[k-m-1]-xy));
    }
    */
    dd[k]= (int16_t)((int32_t)(sqrt((double)x2*x2+(double)x1*x1))>>12);
    //fdd[k]= sqrt(fx2*fx2+fx1*fx1);
    //printf("%d %.3f  %d\n",k,fdd[k],dd[k]);
}
Gast #3319359
Lesenswert?

Hallo,
ja sieht auch sehr interessant aus, man kann sich sogar die zweite 
Tabelle einsparen, ist ja nur eine Spiegelung der ersten.
Die Faktoren scheinen sehr intressant aufgebaut zu sein, muss ich mal 
unbedingt testen.

Gruß Sascha
Gast #3327145
Lesenswert?

Ja, der Artikel ist sehr Interessant, nur mit IIR-Filter bin ich noch 
etwas vorsichtig, da wie auch im Artikel zu lesen ist schwingt die 
Sache.
Es ist sicherlich einfacher mit einem IIR-Filter einen wirksamen 
Tiefpassfilder zu bauen, aber Phasenshieber mit IIR sehe ich immer sehr 
kritisch. Aber ich arbeite mich stetig an das Thema heran.

Folgende Anforderungen habe ich jetzt auch ausfindig machen können:
Der Phasenfehler muss (sollte) unter 1 Grad liegen, der Amplitudenfehler 
sollte bei 1dB liegen. Das müsste doch zu schaffen sein.

Gruß Sascha

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren