Es soll ein I/Q Modulator entstehen mit dem man auf einfache Art und Weise HF erzeugen und modulieren kann. Einzig ein Lokaler Oszillator(LO) und eine Soundkarte wird benötigt.
Die Signale einer handelsüblichen (preiswerten) Soundkarte sind massebezogen(single-ended). Die Basisbandsignale(I/Q) aus der Soundkarte werden in differentielle Signale umgewandelt. Für die Verwendung der Schaltung mit einem Rechtecksignal als LO dient das Filter am LO-Eingang. Danach wird der LO einem Puffer zugeführt, der differentielle Signale für den Modulator bereitstellt. Zusätzlich kann das LO-Signal per Dämpfungsglied im Pegel angepasst werden
Zu erreichbare Daten:
Das Design des Filters ist schon erprobt, es macht sich gut im 2m-LNA vom SDR. Initial bekam ich damals ™ eine 1cmx2cm große Leiterplatte von Winni DL2AWT mit genau dieser Filtertopologie. Folglich simulierte ich das Ding mal und fand passende Werte, die es auch bei Reichelt gibt. C2 und C3 sind dabei Trimmkondensatoren(3-10pF) mit 47pF Keramikkondensator parrallel geschalten.
Erreichbare Daten:
<spoiler> Überblick Spektrum bei Sollfrequenz 144,6MHz:
Spektrum mit 2m-Filter:
Spektrum mit 70cm-Filter:
</spoiler>
<spoiler> Überblick Spektrum bei Sollfrequenz 144,6MHz:
Spektrum mit 2m-Filter:
Überblick Spektrum bei Sollfrequenz 433,8MHz:
Spektrum mit 70cm-Filter:
</spoiler>
<spoiler> Spektrum APRS(144,800MHz) links direkt, rechts mit 2m-Filter:
Spektrum 145,450MHz links direkt, rechts mit 2m-Filter:
C-Code zur Ansteuerung: <spoiler>
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <ctype.h> #include <dirent.h> #include <math.h> #include <fcntl.h> #include <assert.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <signal.h> #include <malloc.h> #include <time.h> #define BCM2708_PERI_BASE 0x20000000 #define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */ #define PAGE_SIZE (4*1024) #define BLOCK_SIZE (4*1024) int mem_fd; char *gpio_mem, *gpio_map; char *spi0_mem, *spi0_map; // I/O access volatile unsigned *gpio = NULL; volatile unsigned *allof7e = NULL; // GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y) #define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3)) #define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3)) #define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3)) #define GPIO_SET *(gpio+7) // sets bits which are 1 ignores bits which are 0 #define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0 #define GPIO_GET *(gpio+13) // sets bits which are 1 ignores bits which are 0 #define ACCESS(base) *(volatile int*)((int)allof7e+base-0x7e000000) #define SETBIT(base, bit) ACCESS(base) |= 1<<bit #define CLRBIT(base, bit) ACCESS(base) &= ~(1<<bit) #define CM_GP0CTL (0x7e101070) #define GPFSEL0 (0x7E200000) #define PADS_GPIO_0_27 (0x7e10002c) #define CM_GP0DIV (0x7e101074) #define CLKBASE (0x7E101000) struct GPCTL { char SRC : 4; char ENAB : 1; char KILL : 1; char : 1; char BUSY : 1; char FLIP : 1; char MASH : 2; unsigned int : 13; char PASSWD : 8; }; void txon() { if(allof7e == NULL){ allof7e = (unsigned *)mmap( NULL, 0x01000000, //len PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, 0x20000000 //base ); if ((int)allof7e==-1) exit(-1); } SETBIT(GPFSEL0 , 14); CLRBIT(GPFSEL0 , 13); CLRBIT(GPFSEL0 , 12); // Set GPIO drive strength, more info: http://www.scribd.com/doc/101830961/GPIO-Pads-Control2 //ACCESS(PADS_GPIO_0_27) = 0x5a000018 + 0; //2mA -3.4dBm //ACCESS(PADS_GPIO_0_27) = 0x5a000018 + 1; //4mA +2.1dBm //ACCESS(PADS_GPIO_0_27) = 0x5a000018 + 2; //6mA +4.9dBm ACCESS(PADS_GPIO_0_27) = 0x5a000018 + 3; //8mA +6.6dBm(default) //ACCESS(PADS_GPIO_0_27) = 0x5a000018 + 4; //10mA +8.2dBm //ACCESS(PADS_GPIO_0_27) = 0x5a000018 + 5; //12mA +9.2dBm //ACCESS(PADS_GPIO_0_27) = 0x5a000018 + 6; //14mA +10.0dBm //ACCESS(PADS_GPIO_0_27) = 0x5a000018 + 7; //16mA +10.6dBm struct GPCTL setupword = {5/*SRC*/, 1, 0, 0, 0, 1,0x5a}; ACCESS(CM_GP0CTL) = *((int*)&setupword); } void txoff() { struct GPCTL setupword = {5/*SRC*/, 0, 0, 0, 0, 1,0x5a}; ACCESS(CM_GP0CTL) = *((int*)&setupword); } void handSig() { exit(0); } // Set up a memory regions to access GPIO void setup_io() { /* open /dev/mem */ if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) { printf("can't open /dev/mem \n"); exit (-1); } /* mmap GPIO */ // Allocate MAP block if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) { printf("allocation error \n"); exit (-1); } // Make sure pointer is on 4K boundary if ((unsigned long)gpio_mem % PAGE_SIZE) gpio_mem += PAGE_SIZE - ((unsigned long)gpio_mem % PAGE_SIZE); // Now map it gpio_map = (unsigned char *)mmap( gpio_mem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, mem_fd, GPIO_BASE ); if ((long)gpio_map < 0) { printf("mmap error %d\n", (int)gpio_map); exit (-1); } // Always use volatile pointer! gpio = (volatile unsigned *)gpio_map; } int main(int argc, char *argv[]) { setup_io(); txon(); ACCESS(CM_GP0DIV) = (0x5a << 24) | (6 << 12) | (896<<2); // 6, 928 für aprs 144,796; 6, 912 für 145,125; 6, 896 für 145,450 return 0; }
</spoiler> </spoiler>
LO | Frequenz | Leistung |
---|---|---|
Si570 | 144,6MHz | 6,3dBm |
Si570 | 433,8MHz | -1dBm |
VNWA | 144,6MHz | -19,2dBm |
VNWA | 433,8MHz | -24,6dBm |
Der I/Q-Modulator will -10dBm..0dBm am LO-Eingang. Der LO-Buffer verstärkt das LO-Signal wie folgt:
Somit muss der LO mindestens -26dBm liefern.
TODO:
Revision: 3
Vorberechnung des Dämpfungsglieds
Dämpfung | R15,R16 | R14,R17 | R18 |
---|---|---|---|
0dB | - | 100Ω | - |
-20dB | 120Ω | 56Ω | 237Ω |
-25dB | 120Ω | 56Ω | 475Ω |
Links zu den verwendeten Schaltkreisen:
Inspiriert durch: Khaled Al Rifai
Sebastian Weiß 2014/01/31 22:53
Sebastian Weiß 2014/02/01 15:54
— Sebastian Weiß 2014/02/03 06:52
Um normale Audio-Dateien FM-moduliert als I/Q-Signale mit einer Soundkarte ausgeben zu können, gibt es folgendes kleines Tool: fmmod. Dieses ist im Xplorer-Github zu finden.