Hallo, Ich möchte auf meinem STM32F429-Discovery Board eine Filterung durchführen. Das Signal wird mit einer konstanten Sampling Rate (realisiert durch einen Timer)folgendermaßen eingelesen: // --------------------------------------------------------------------- #include "system.h" #include <stdlib.h> #include "stm32_ub_usb_cdc.h" #include "stm32_ub_led.h" #include "stm32f4xx_gpio.h" #include "stm32f4xx_rcc.h" #include "stm32f4xx_tim.h" #include "misc.h" #include "stm32_ub_adc1_single.h" #include "stm32_ub_lcd_ili9341.h" #include "stm32_ub_graphic.h" int main(void) { UB_ADC1_SINGLE_Init(); UB_USB_CDC_Init(); SystemInit(); delay_init(); sdram_init(); ltdc_init(); ili9341_init(); UB_Led_Init(); UB_USB_CDC_Init(); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE); // Timer7 konfigurieren TIM_TimeBaseInitTypeDef TIM_TimeBase_InitStructure; TIM_TimeBase_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBase_InitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBase_InitStructure.TIM_Period = 28; TIM_TimeBase_InitStructure.TIM_Prescaler = 1000; TIM_TimeBaseInit(TIM7, &TIM_TimeBase_InitStructure); TIM_ITConfig(TIM7, TIM_IT_Update, ENABLE); // Timer7 einschalten TIM_Cmd(TIM7, ENABLE); // Interruptcontroller konfigurieren NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F; NVIC_Init(&NVIC_InitStructure); while(1) {} } void TIM7_IRQHandler() { int x = 0; char str[4]; x = UB_ADC1_SINGLE_Read_MW(ADC_PC3); sprintf(str, "%d", x); UB_USB_CDC_SendString(str,LFCR); TIM_ClearITPendingBit(TIM7, TIM_IT_Update); } //---------------------------------------------------------------------- Der Interrupt wird mit einer Frequenz von 3kHz aufgerufen und sendet den ADC-Value über USB an die serielle Schnittstelle. Dies klappt einwandfrei. Jetzt möchte ich die eingelesenen Werte in "Echtzeit" filtern. Ich habe mir mit MatLab und dem FDATOOL ein Lowpass FIR Filter designt um die Koeffizienten zu bekommen. Ordnung: 50 Fs: 3000 Fpass: 80 Fstop: 120 Mein Ansatz um das Filter zu implementieren: //--------------------------------------------------------------------- int i = 0; int ntaps = 51; float buffer[51]; float h[] = float h[] = { -0.00091909820848026845, -0.0027176960266135364 , -0.0024869527598547769 , 0.0036614383834879848 , 0.013650925230654689 , 0.017351165901097854 , 0.0076653061904350594 , -0.0065547188696257145 , -0.0076967840370497573 , 0.0061054594214059454 , 0.013873915748642305 , 0.00035086172829532027, -0.01690892543668587 , -0.0089056427491534841 , 0.017441129500858993 , 0.02074504452761099 , -0.012296494251941141 , -0.034240865909579518 , -0.00103452960557321 , 0.047790305520800068 , 0.027363037914845938 , -0.059379518831047785 , -0.082307025929228672 , 0.067186909432870937 , 0.31001517709024967 , 0.43004788034351471 , 0.31001517709024967 , 0.067186909432870937 , -0.082307025929228672 , -0.059379518831047785 , 0.027363037914845938 , 0.047790305520800068 , -0.00103452960557321 , -0.034240865909579518 , -0.012296494251941141 , 0.02074504452761099 , 0.017441129500858993 , -0.0089056427491534841 , -0.01690892543668587 , 0.00035086172829532027, 0.013873915748642305 , 0.0061054594214059454 , -0.0076967840370497573 , -0.0065547188696257145 , 0.0076653061904350594 , 0.017351165901097854 , 0.013650925230654689 , 0.0036614383834879848 , -0.0024869527598547769 , -0.0027176960266135364 , -0.00091909820848026845 } for(i=ntaps-1;i>0;i--) { buffer[i]=buffer[i-1]; //macht Platz für neuen Wert } buffer[0] = UB_ADC1_SINGLE_Read_MW(ADC_PC3); for(i = 0;i<ntaps;i++) { x += buffer[i]*h[i]; //berechnet Ausgangswert } Leider weiß ich nicht wie ich das in das obere Programm richtig einfüge, da ich ja eine konstante Sampling Rate brauche? Mach ich die Filterung in der while? oder alles im Interrupt? Vielen Dank für eure Hilfe! Ist leider mein erstes digitales Filter :/
:
Verschoben durch Admin
In der ISR sollte auf rechenintensive Operationen verzichtet werden, z.B. auch auf das sprintf. Normalerweise wird eine Flag (die volatile sein muss) in der ISR gesetzt und in der main loop überprüft. Sobald ein neues sample da ist, rechnest du den nächsten Schritt deines Filters in der main und setzt dann entweder eine neue flag oder benutzt eine state machine, um anzuzeigen, dass du deinen gefilterten Wert über USB verschicken kannst.
Im Cube von ST in der DSP-Library gibt es FIR-Filter-Implementierungen. Die sind ganz gut optimiert. Hast Du schon einmal ein Multitasking-System ausprobiert? FreeRTOS gibt es angepasst für die STM32F4-Familie. Dann kannst Du Dein Sampling, FIR-Filter und Daten weiterleiten in eine Task packen, die nichts anderes zu tun hat. Alle anderen Aufgaben arbeitest Du in anderen Tasks ab. Gruß, Stefan
Da der OP offensichtlich kein Profi ist und eine relativ simple Aufgabe erledigen möchte (und vor allem nicht zig Sachen gleichzeitig, sonst hätte er uns das möglicherweise verraten), ist ein realtime OS sowas von überflüssig und erschlägt jemanden, der obiges nicht per Hand programmieren kann. Ebenso braucht man für ein einziges FIR mit Sicherheit nicht die DSP Lib, ein Cortex M4 lacht sich schlapp bei 3 kHz, sodass keine hochoptimierten Algos nötig sein sollten. Sollen mehrere Filter implementiert werden stimme ich zu, dass man ein Modul für das Filter verwenden, das man instanziieren kann. Das kann aus der Lib kommen, ist aber auch sehr fix selbst geschrieben. Ich glaube aber soweit sind wir hier noch gar nicht. Schöne Grüße, Jan
:
Bearbeitet durch User
Vor allem möchte ich mal ernsthaft anzweifeln, dass wirklich ein FIR 50ster (sic!) Ordnung benötigt wird... aber ich mag mich ja täuschen.
Michael Reinelt schrieb: > Vor allem möchte ich mal ernsthaft anzweifeln, dass wirklich ein FIR > 50ster (sic!) Ordnung benötigt wird... aber ich mag mich ja täuschen. Kann ich mir auch kaum vorstellen. Was willste den der TO damit erreichen? Und der STM den junkt ein Filter in der ISR net. Sollte man aber trotzdem mit einem Oszi überprüfen. Schau dir auch mal den Code an, was für Assembler-Befehle der Compiler raushaut. Ist die Floating-Point-unit an? Kannst ja auch mal im Debugger dir die Werte anschauen. Wenn du schon Matlab nutzt, hau das Filter in eine Embedded-Matlab-Fkt in Simulink und teste am PC, ob das Filter mit double float richtig arbeitet. Gruß Ert
Vielen Dank für die Antworten! Das TP-Filter 50 Ordnung ist nur mal testweise. Spaeter will ich ein Notchfilter für 50Hz realisieren, wo ich laut dem generierten Bodediagramm eine hohe Ordnung brauche für ein gutes Ergebnis. Ich würde auch gerne mal das Filter einfach realisieren um es zu verstehen. Die Vorschläge schau ich mir natürlich an wenn ich das mal am laufen habe. Der Test mit Simulink ist eine gute Idee und werd ich mir anschaun.
Ich hab jz mal das Tiefpass - Filter am Laufen =) Jedoch möchte ich jetzt noch ein 50Hz Notch Filter zusätzlich einbauen. Wenn ich aber ein FIR-Notch-Filter in Matlab berechnen lasse, komme ich auf Ordnungen >500 für ein akzeptables Filter (Stopband -40dB, Welligkeit <1dB,..) Ist das normal oder gibts dafür bessere Lösungne? (IIR-Filter,..) Vielen Dank!!
Moin moin, anstatt 50. Ordnung FIR zu verwenden, solltest du in der Tat in Erwägung ziehen, ein IIR Filter zu bauen. Die Ordnung wird sofort signifikant sinken. Wichtig ist, dass du das IIR nicht einfach 'straight forward' implementierst, sondern in eine SOS-Form überführst, denn aufgrund von Rundungsfehlern der Koeffizienten kann IIR Instabil werden. Mit SOS kannst du das einigermassen einfach noch überprüfen. Zudem würde ich anstatt double nur einfache Genauigkeit benutzen, denn die M4 FPU kann m.E. kein double. Guck mal hier, ichhab hier was für matlab: http://www.kooltek.net/mikrocontroller/realisierung-digitaler-filter
Ich hab mich jz entschieden die 50Hz-Filterung direkt in MatLab durchzuführen. Ich fülle immer ein Array mit variabler Länge mit den Samples von der seriellen Schnittstelle und plotte diese dann. Vor dem Plotten filtere ich dieses Array noch mit einem Matlab-IIR Filter. Habe 3 Bilder angehängt, welche meines "Problem" schön zeigen: Ein 50Hz Sinussignal wird sehr gut gefiltert, aber hat leichte Überschwinger die je nach Güte des Filters zunehmen. Natürlich sieht man diese Überschwinger dann auch bei z.B 90Hz (siehe Bild). Mir ist klar dass sich das Filter erst einschwingen muss, was man hier halt sehr schön sieht. Da ich die Filterfunktion aber sehr oft Aufrufe (immer nach einer einstellbaren Anzahl von Samples) sieht man dieses Einschwingen leider bei je nachdem wie viele Frames ich darstelle immer sehr deutlich. Habt ihr irgent einen Idee dieses Schwingen zu vermeiden bzw. nicht darzustellen? Würde es funktionieren wenn ich den Anfang meines Arrays mit Dummy-Werten fülle. Bei welchen dann der Einschwingvorgang stattfindet und ich aber nur die dahinterligenden "richtigen" Werte plotte?? Vielen Dank!!
Wie sollen wir die Qualität 'beurteilen', wenn du das Eingangssignal nicht auch darstellst? Wenn da jetzt +- 1000000000 reingeht sind alle Filter unbrauchbar -.- Lade deine .mat Daten hoch, evtl kann hier ja einer helfen...
Das Eingangssignal ist das Bild "50Hz_ohneNotch". Das Bild "50Hz_mitNotch" zeigt das selbe Eingangssignal nur mit aktivem Filter. Das Bild "90Hz_mitNotch" soll zeigen, dass auch bei Signalen außerhalb der Notchfrequenz diese Welligkeit am Anfang auftritt,wenn das Filter eingeschaltet ist =)
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.