GIT repositories

Index page of all the GIT repositories that are clonable form this server via HTTPS. Übersichtsseite aller GIT-Repositories, die von diesem Server aus über git clone (HTTPS) erreichbar sind.

Services

A bunch of service scripts to convert, analyse and generate data. Ein paar Services zum Konvertieren, Analysieren und Generieren von Daten.

GNU octave web interface

A web interface for GNU Octave, which allows to run scientific calculations from netbooks, tables or smartphones. The interface provides a web form generator for Octave script parameters with pre-validation, automatic script list generation, as well presenting of output text, figures and files in a output HTML page. Ein Webinterface für GNU-Octave, mit dem wissenschaftliche Berechnungen von Netbooks, Tablets oder Smartphones aus durchgeführt werden können. Die Schnittstelle beinhaltet einen Formulargenerator für Octave-Scriptparameter, mit Einheiten und Einfabevalidierung. Textausgabe, Abbildungen und generierte Dateien werden abgefangen und in einer HTML-Seite dem Nutzer als Ergebnis zur Verfügung gestellt.

Filter in C zum Vermeiden von Jittern bei digitalen Eingabeports bei Embedded-Programmen

Filter in C to prevent jitter problems on digital input ports in embedded applications

The header you see below contains a filter macro for C/C++, which allows to prevent input signal level detection problems if your input has some jitters. Latter can occur if a digital input of your controller is connected to a relay or if the controller input has no internal Schmitt-Trigger, or simply if the signal is noisy and has slowly rising/falling edges. In this case you might want to filter this digital input signal and wait until it is stable enough. On the other hand it is often not acceptable to spend much memory or CPU power for a filter function. The little piece of code below is a comprimise of these requirements. You normally need a 8-bit character sized variable for this macro, as the macro is inline it leaves the compiler a good opportunity to optimise, and it does not use any other variables than the one you use as buffer.

The way how it works and how to use it is annotated in the header file below.

Notes:

  • Before using this macro check if your controller hardware has already configurable input filters - some do.

  • Often used and applicable filter length values are in range between 2 and 5. If you have a high sample rate compared to the time that your application needs to react you use define 16 bit buffers as well. The macro does not care about the size, as long as the data type you choose is somehow integer numeric.

  • It is not wise to choose large filter lengths if you don't need to. This filter is in the very end a sliding-window low pass filter with output threshold. That means it delays the detection of edes by length sample cycles.

Die weiter unten stehende Headerdatei enthält ein Filter-Makro in C/C++, mit dem Signalschwankungen von digitalen I/Os ausgeglichen werden können. Solche Signalschwankungen treten z.B. auf wenn der Port an einem Relay angeschlossen ist (Prellen), wenn der Port keinen (guten) Schmitt-Trigger hat, oder einfach wenn das Signal verrauscht ist und keine steilen Flanken hat. In diesen Fällen macht es Sinn, das Eingabesignal zu filtern bzw. "auf ein stabiles Signal zu warten". Andererseits spendiert nimand gerne Speicher und Rechenleistung für aufwendige Filter. Die sieben Zeilen Quellcode in der Headerdatei stellen einen Kompromiss dar. Normalerweise wird eine 8-Bit-Variable benötigt, um über bis zu 6 Takte zu filtern. Als Makro ist die Funktion "inline" und arbeitet nur mit der angegebenen Puffervariablen (ohne weiteren Stackverbrauch). Der Compiler kann dies gut optimieren, so dass die meisten Operationen direkt mit einem Register und dem Konstantenspeicher arbeiten.

Wie es genau funktionniert und zu verwenden ist habe ich im Kommentarbereich der Headerdatei angegeben. Ein Beispielprogramm mit Makefile gibt's ebenfalls weiter unten (mit Ausgabe).

Anmerkungen:

  • Bevor dieses Makro verwendet wird bitte nochmals checken ob die Controllerhardware einen konfigurierbaren Filter hat - manche Controller/DSPs haben das.

  • Oft genutzte Standardwerte für die Filterlänge bewegen sich zeischen 2 und

    1. Wenn die Samplerate des Controllers viel höher ist als die benötigte Reaktionszeit des Programms, so kann auch eine 16- oder 32-bit Variable als Puffer verwendet werden. Dem Makro ist dies reichlich egal, so lange der Datentyp ganzzahlig ist.
  • Es macht oft keinen Sinn große Filterlängen zu definieren wenn man sie nicht braucht. Letztendlich ist dieser Bitfilter ein "Sliding-Window"-Tiefpass mit Schwellenwerterkennung. D.h. er verzögert die Erkennung von Signaländerungen für soviele Takte wie der Filter groß ist.

Header file containing the filter macro

Header-Datei mit dem Filter-Makro

/**
 * @file bitfilter.h
 * @author stfwi
 * @date 2007-05-12
 *
 * ---
 *
 * 2013-06-03 Added extended documentation for publishing.
 *
 * ---
 *
 * Bit filter macro for use to prevent digital input jitter problems in embedded
 * applications.
 *
 * Usage:
 *
 *  bool_t is_io_set = bitfilter(buffer_variable, filter_length, new_io_bit);
 *
 *  E.g. in a program where the io bit is memory mapped and defined in a
 *  structured variable gpio.port0.bit0 you like to filter over 4 samples and
 *  use an 8 bit filter buffer (unsigned char == uint8_t):
 *
 *  uint8_t gpio0_0_buffer = 0;
 *  [...]
 *  if(bitfilter(gpio0_0_buffer, 4, gpio.port0.bit0)) {
 *    // Input is 1
 *  } else {
 *    // Input is 0
 *  }
 *
 *  BUF is your buffer variable that the "function" needs.
 *  L is the length of the buffer. It must be at least 2 bits smaller than
 *  the size of yout buffer variable data type. E.g. if you use uint8, then
 *  the maximum length of the filter is 6. This is because the two MSBs are
 *  reserved to save the state of the filter output. NB is the new input value
 *  you like to add to the filter (e.g. read from io).
 *
 * How it works:
 *
 *  The code below looks a bit complex, but in the very end this is the
 *  how it works. The buffer is used to save the last L bits, beginning form
 *  the LSB. Every time the macro is "called" the buffer will be shifted one
 *  bit left and the new bit will be set to the LSB. If all L bits are 1, then
 *  the output will change to 1. If all L buffer bits are 0 it will change to 0.
 *  Otherwise it will return the last state, which is written in bit L+1.
 *  Because of the left shift at the beginning, this result bit will be shifted
 *  to L+2 (this is why 2 bits are reserved). Everything is done in nested
 *  assignments, so that no other variables are needed to run this filter, and
 *  the compiler has plenty of possibilities to optimise this inline code
 *  fragment. E.g. for a 4 bit filter length this would be the buffer of a
 *  8 bit variable:
 *
 *      Unused bits
 *     /
 *     |  Last return (shifted one up at the beginning)
 *     | /
 *     | | / Return value, saved for next cycle
 *     | ||  buffer (4 bits)
 *     | || /
 *    00|LR|3210
 *
 *  The macro line by line:
 *
 *  1. This is the start of the assignment of the result bit
 *  2. We shift one up, set the new bit at position 1 and save the buffer back
 *  3. We set the result bit if all buffer bits are set. Here 1<<L is bit 4
 *     (00010000), which is one higher the buffer bits [0-3] == 00001111.
 *     The "all bit check" is done using (1<<L)-1, which expands to 00001111.
 *  4. !(BUF & ((1<<L)-1) is the boolean check if the buffer bits are all 0.
 *  5. ((BUF & ((1<<L)<<1)) is the bit 6 00100000, which is the last result.
 *     if this is set we set bit 5 as well for the next time.
 *  6. Line 5 was not true, so we reset the bit 5 as well.
 *  7. We return TRUE if the bit 5 is now set, which is the actual result.
 *
 * @param BUF Your filter buffer variable
 * @param L   The length of the filter 1 to (sizeof(BUF)-1)>>2
 * @param NB  The new bit to add. Must be 0x0 or 0x1 (other bits ignored)
 * @return BOOL
 */
 
#ifndef bitfilter
 
#define bitfilter(BUF, L, NB) (                                                  \
  ((BUF=(                                   /* 1. Framing assignment of result */\
  ((BUF=((BUF<<1)|(NB&0x01)))               /* 2. Add new value                */\
  & (1<<L)-1) == ((1<<L)-1) ? (BUF|(1<<L)) :/* 3. All bits 1 -> set result bit */\
  (!(BUF & ((1<<L)-1)) ? (BUF&~(1<<L))      /* 4. All bits 0 -> clear result   */\
  : ((BUF & ((1<<L)<<1)) ? (BUF|(1<<L)) :   /* 5. Set result (last result == 1 */\
    (BUF&~(1<<L))) ))                       /* 6. Clear result                 */\
  ) & (1<<L)) != 0                          /* 7. Return bool                  */\
)                                                                                \

#endif

Beispielprogramm

Example program

/**
 * Example for bit filter macro.
 *
 * @file bitfilter.c
 * @author stfwi
 */
 
#include "bitfilter.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
/**
 * Test main function
 *
 * @param int argc
 * @param char **argv
 * @return int
 */
int main(int argc, char** argv)
{
  unsigned short buffer = 0;
  int i, j, r, filter_length;
  const char *input = NULL;
 
  // Input and usage
  if(argc != 3) {
    fprintf(stderr, "Usage: bitfilter <filter length> <input sequence>\n");
    fprintf(stderr, "\n");
    fprintf(stderr, "      filter: number from 2 to 14\n");
    fprintf(stderr, "      input : text containing only '1' and '0'\n");
    fprintf(stderr, "              e.g. '011010010001110011'\n");
    fprintf(stderr, "\n");
    fprintf(stderr, "Bit filter example for filtering of digital I/O levels.\n");
    fprintf(stderr, "The program uses a 16 bit buffer variable. 2 bits are\n");
    fprintf(stderr, "reserved, so the maximum filter length is 14.\n");
    fprintf(stderr, "\n");
    exit(1);
  }
 
  filter_length = atoi(argv[1]);
  if(filter_length <= 0 || filter_length >= 14) {
    fprintf(stderr, "Filter length must be 1 to 14 bits.\n");
    exit(2);
  }
  input = argv[2];
  if(!input) {
    fprintf(stderr, "You did not set an input sequence of '1' and '0'.\n");
    exit(3);
  }
 
  // Print header
  printf(
    "\n\n"
    " new bit that was added\n"
    "/\n"
    "|     filter return value\n"
    "|    /\n"
    "|    |     buffer: last result bit\n"
    "|    |    /\n"
    "|    |    | buffer: result bit\n"
    "|    |    |/\n"
    "|    |    ||  buffer: buffered bits\n"
    "|    |    || /\n"
    "|    |    || |\n"
  );
 
  printf("N -> R  ( LR|");
  for(j=filter_length-1; j>=0; j--) printf("%1d", (int)j);
  printf(" )\n--------------------------\n");
 
  // Process input, filter and print the states
  for(i=0; i < (int)strlen(input); i++) {
    r = bitfilter(buffer, filter_length, input[i] == '1' ? 1 : 0);
    printf("%c -> %d  ( ", input[i], r);
    for(j = filter_length+1; j>=0; j--) {
      printf("%c", buffer & (1<<j) ? '1' : '0');
      if(j == filter_length) printf("|");
    }
    printf(" )\n");
  }
  printf("\n");
  return 0;
}

Makefile

CC=g++
CFLAGS=-c -Wall -O3
LDFLAGS=
 
all: bitfilter run
 
clean:
    @rm -f *.o
 
bitfilter: main.o
    @$(CC) $(LDFLAGS) main.o -o bitfilter
    @rm -f *.o
 
main.o:
    @$(CC) $(CFLAGS) main.c -o $@
 
run: bitfilter
    ./bitfilter 4 0000110111011110100100010000101010

Beispiel-Ausgabe

Example program output

stfwi$ make

./bitfilter 4 0000110111011110100100010000101010

 new bit that was added
/
|     filter return value
|    /
|    |     buffer: last result bit
|    |    /
|    |    | buffer: result bit
|    |    |/
|    |    ||  buffer: buffered bits
|    |    || /
|    |    || |
N -> R  ( LR|3210 )
--------------------------
0 -> 0  ( 00|0000 )
0 -> 0  ( 00|0000 )
0 -> 0  ( 00|0000 )
0 -> 0  ( 00|0000 )
1 -> 0  ( 00|0001 )
1 -> 0  ( 00|0011 )
0 -> 0  ( 00|0110 )
1 -> 0  ( 00|1101 )
1 -> 0  ( 00|1011 )
1 -> 0  ( 00|0111 )
0 -> 0  ( 00|1110 )
1 -> 0  ( 00|1101 )
1 -> 0  ( 00|1011 )
1 -> 0  ( 00|0111 )
1 -> 1  ( 01|1111 )
0 -> 1  ( 11|1110 )
1 -> 1  ( 11|1101 )
0 -> 1  ( 11|1010 )
0 -> 1  ( 11|0100 )
1 -> 1  ( 11|1001 )
0 -> 1  ( 11|0010 )
0 -> 1  ( 11|0100 )
0 -> 1  ( 11|1000 )
1 -> 1  ( 11|0001 )
0 -> 1  ( 11|0010 )
0 -> 1  ( 11|0100 )
0 -> 1  ( 11|1000 )
0 -> 0  ( 10|0000 )
1 -> 0  ( 00|0001 )
0 -> 0  ( 00|0010 )
1 -> 0  ( 00|0101 )
0 -> 0  ( 00|1010 )
1 -> 0  ( 00|0101 )
0 -> 0  ( 00|1010 )

Disassembly

AVR-GCC (r, buffer, i are declared volatile):

stfwi$ avr-gcc -c -g -Wa,-a,-ad -O3 main.c -o main.o

[...]

10:main.c        ****   r = bitfilter(buffer, 4, i);
49 0008 8091 0000       lds r24,buffer
50 000c 9091 0000       lds r25,i
51 0010 880F            lsl r24
52 0012 9170            andi r25,lo8(1)
53 0014 892B            or r24,r25
54 0016 8093 0000       sts buffer,r24
55 001a 8091 0000       lds r24,buffer
56 001e 8F70            andi r24,lo8(15)
57 0020 8F30            cpi r24,lo8(15)
58 0022 01F0            breq .L7
61 0024 8091 0000       lds r24,buffer
62 0028 90E0            ldi r25,lo8(0)
63 002a 8F70            andi r24,lo8(15)
64 002c 9070            andi r25,hi8(15)
65 002e 0097            sbiw r24,0
66 0030 01F4            brne .L4
70 0032 8091 0000       lds r24,buffer
71 0036 8F7E            andi r24,lo8(-17)
75 0038 8093 0000       sts buffer,r24
76 003c 9091 0000       lds r25,buffer
77 0040 81E0            ldi r24,lo8(1)
78 0042 94FF            sbrs r25,4
79 0044 80E0            ldi r24,lo8(0)
81 0046 8093 0000       sts r,r24

[...]

GCC (Intel, 64bit, all variables defined volatile):

stfwi$ gcc -c -g -Wa,-a,-ad -O3 main.c -o main.o

[...]

10:main.c        ****   r = bitfilter(buffer, 4, i);
24 0014 0FB60500        movzbl  buffer(%rip), %eax
25 001b 0FB61500        movzbl  i(%rip), %edx
26 0022 01C0            addl    %eax, %eax
27 0024 83E201          andl    $1, %edx
28 0027 09D0            orl %edx, %eax
29 0029 88050000        movb    %al, buffer(%rip)
30 002f 83E00F          andl    $15, %eax
31 0032 83F80F          cmpl    $15, %eax
32 0035 0FB60500        movzbl  buffer(%rip), %eax
33 003c 7439            je  .L6
35 003e A80F            testb   $15, %al
36 0040 0FB60500        movzbl  buffer(%rip), %eax
37 0047 7523            jne .L4
40 0049 83E0EF          andl    $-17, %eax
43 004c A810            testb   $16, %al
44 004e 88050000        movb    %al, buffer(%rip)
45 0054 0F95C0          setne   %al
46 0057 88050000        movb    %al, r(%rip)
12:main.c        ****   return r;

[...]

AVR-GCC (r, buffer, i not volatile --> all done in registers):

stfwi$ avr-gcc -c -g -Wa,-a,-ad -O3 main.c -o main.o

[...]

11:main.c        ****     r = bitfilter(buffer, 4, i);
59 0012 2C2F            mov r18,r28
60 0014 3D2F            mov r19,r29
61 0016 220F            lsl r18
62 0018 331F            rol r19
63 001a 8170            andi r24,lo8(1)
64 001c 822B            or r24,r18
65 001e 482F            mov r20,r24
66 0020 50E0            ldi r21,lo8(0)
67 0022 242F            mov r18,r20
68 0024 352F            mov r19,r21
69 0026 2F70            andi r18,lo8(15)
70 0028 3070            andi r19,hi8(15)
71 002a 2F30            cpi r18,15
72 002c 3105            cpc r19,__zero_reg__
73 002e 01F0            breq .L9
76 0030 2115            cp r18,__zero_reg__
77 0032 3105            cpc r19,__zero_reg__
78 0034 01F0            breq .L5
81 0036 85FD            sbrc r24,5
82 0038 00C0            rjmp .L9
86 003a 8F7E            andi r24,lo8(-17)
90 003c C82F            mov r28,r24
91 003e D0E0            ldi r29,lo8(0)
92 0040 81E0            ldi r24,lo8(1)
93 0042 2C2F            mov r18,r28
94 0044 3D2F            mov r19,r29
95 0046 24FF            sbrs r18,4
96 0048 80E0            ldi r24,lo8(0)
98 004a 8093 0000       sts r,r24

[...]