Return-path: X-Andrew-Authenticated-as: 7997;andrew.cmu.edu;Ted Anderson Received: from corsica.andrew.cmu.edu via trymail for +dist+/afs/andrew.cmu.edu/usr1/ota/space/space.dl@andrew.cmu.edu (->+dist+/afs/andrew.cmu.edu/usr1/ota/space/space.dl) (->ota+space.digests) ID ; Sat, 1 Jul 89 05:17:34 -0400 (EDT) Message-ID: <8Yf8kaK00UkVMQlU4r@andrew.cmu.edu> Reply-To: space+@Andrew.CMU.EDU From: space-request+@Andrew.CMU.EDU To: space+@Andrew.CMU.EDU Date: Sat, 1 Jul 89 05:17:26 -0400 (EDT) Subject: SPACE Digest V9 #527 SPACE Digest Volume 9 : Issue 527 Today's Topics: Re: Satellite Images - at home! ---------------------------------------------------------------------- Date: 28 Jun 89 20:34:19 GMT From: rochester!rit!cci632!ccicpg!paulm@cu-arpa.cs.cornell.edu (tmp Paul Moreau usenet acct) Subject: Re: Satellite Images - at home! Here is the document, schematic, and code to receive pictures for an Atari ST ------------------------------------------------------------------------------- 2400HZ Crystal phase lock Weather Satellite decoder By Mike Gore April 1988 Part 1 of 3 This posting is broken into 3 parts. Part 1 contains a functional outline of the decoder, software overview and some information of interest on the NOAA and Meteor weather satellites. Part 2 contains the decoder diagram in ascii text format. Part 3 contains some functional test software written for the ATARI ST. The NOAA and Meteor weather satellites transmit images of the Earth using an APT format. This format is a 120 lines (Meteor) or 240 line (Noaa) per minute encoded with a 2400HZ AM audio signal that is transmitted on a FM modulated VHF downlink. Frequencies of interest are 137.5MHZ, 137.620MHZ for NOAA and 137.300MHZ, 137.400MHZ and 137.850MHZ for the soviet Meteor satellites. The receiver bandwidth must be 30KHZ or more for good results. Basically the satellites scan the Earth a right angles to their orbit with a mirror that is directed to a photo detector. The light reaching the detector alters the 2400HZ carrier amplitude which in turn affects the bandwidth or spread of of the FM downlink at a given moment. The NOAA craft transmit both visual and IR images where the Meteor crafts only send visual band images. Since my initial posting on this subject, about 1 month ago, I happened across the 1987 ARRL handbook and found that it has some good references for this subject along with a functional decoder. My decoder is a mix of several ideas all in mixed into one with it's main feature being a rather rather novel demodulator design. Circuit description: The demodulator uses a bandpass network built of 2 high and 2 low pass filters. The stop bands are currently 1200HZ and 3600HZ however this value was somewhat a matter of experiment on my part. The filter feeds a full wave active rectifier that can be balanced with a 10K variable resistor. The rectifier part is similar in form to that found in several National Linear AP Notes yet I liked the version in the 1987 ARRL handbook enough that I used theirs. What follows the full wave rectifier is a resetable integrator followed by a sample hold. The analog switches are made by GE Intersel part number is DG201. The op amps are TL082 dual or TL084 quad op amps however you can use LF353's as well. I chose to use the resetable integrator rather then a low pass filter after the rectifier in order to try to push the overall bandwidth of the system to the limit. The results are very good, the main advantage being that aliasing errors are virtually gone because the integration period is synced with the 2400 AM carrier. The integrator may be be run at half cycle intervals however the circuit described here is wired for 1 cycle samples. In order to phase lock the system clock with the 2400HZ AM carrier I chose a Crystal VXO design. Phase locking is not really required if one is willing to live with sample position aliasing. - This would normally be noticed in a feature in the image that is at right angles to the scan path as a slow drift of one pixel as a function of the phase error of the sample. The Sample error would normally change as a function of doppler shift and or any drifting in the local system clock without phase locking. I found that since NOAA scans at 240 lines per minute with two images interleaved on alternate scans there isn't much bandwidth left over such that one might be tempted to toss some away on sample errors. I should note that the Meteor satellites run their carrier slightly off 2400HZ and my system can not phase lock on their carrier - in fact there doesn't seem to be a strict 1 to 1 relationship between carrier frequency and scan rate as is the case with NOAA. The loss of lock still gives good images - they just are not the best possible. With NOAA the 2400HZ signal is 1 to 1 mapped to the scan rate so it is possible to use it rather then the 7 cycle 1200 HZ burst that is modulated on the 2400 HZ carrier to keep frame sync. Meteor use a 300 HZ 7 cycle burst. I chose not to use the 7 cycle sync markers in favor of a manual software offset adjustment in the display program. The programs are broken into two sections - data collection and data display. The VXO uses a standard XOR phase comparator for locking yet there is no loop filter needed. It works out that the phase jitter is to small to even think about with an 8bit A/D. Basically the XOR gate forces the 2400 divided reference clock to be roughly 90 degrees out of phase with the downlink 2400HZ carrier. The crystal I used is series tuned such that when the analog switch closes the frequency runs too low and when it is open it runs too high. The 20pf cap across the switch adds to the switch capacitance to give a minimal value to keep the oscillator stable. The idea is to weight the two values of frequency with the switch open and then closed such that it averages to 2457600 MHZ and with about +/- 150HZ swing. The swing must at least be in excess of the worst case doppler shift - the higher the value the faster the lock but with a chance of larger phase errors as a function of noise. This circuit works very well at locking on a signal almost hidden in noise much unlike what one would expect with a simple analog PLL. Of course a noisy signal is of no real value but even noise bursts can cause loss of sync with a normal non VXO analog PLL design. The software is very crude and was patched together from odd bit's of code I wrote for other things. It was hacked to test hardware that changed just about every day so little attempt was made to clean it up in however it is actually functional. My only intent for including it here in this form is for testing and feedback on the hardware. I plan to actually write a 'real' display/collection program rather soon. [ That will be of course just to show anyone with doubts that - yes I actually can program dispite my worst efforts here :-)! ] Anyway, the test programs are 'documented' as follows: The data collection program takes 1 argument which is simply the file name to save the collected data with. The display program takes no arguments but is command driven. The programs are run from the Mark Williams shell - I should mention that I used the MW C complier to write this code. The commands are: H min max - Sets the values to be black and white where min and max are number integer values bound by 0 and 255. The program will then attempt to expand the range of these values as a crude form of contrast enhancement. This really should be histograms equalization since all the data is at hand - but hey this is a hack program remember ? :-) D offset direction - Sets the display offset and direction where offset is a value between 0 and 1199 and direction is either 1 for north to south passes or -1 for south to north passes. h - Dumps a histogram of the in memory window selected by the D command d - displays the in memory window set by the D command and some contrast maps and various stuff - Press return to exit this display r file line-skip - reads a file where line-skip is the number of scan lines to skip into the file. Offset is remembered across reads. w file - writes a Dagas format file from the in memory copy A file - writes an old format AIM file W file - writes a raw 8 bit image file q - quit -- The following are symbols used for the diagram in part 2 of 3 Labels: (round braces) Traces: (Corner) +----O (Main signal I/O or control) | (Connection) o Resistor: 100 = 100 ohms 4K7 = 4700 ohms v10K = 10000 ohms variable Capacitor: 3n3 = 3.3 nanofarad Diode: -I<- ->I- (Cathode)(Anode) (Anode)(Cathode) FET: o (Drain) D oG (Gate) S o (Source) Inductor: --44mH-- Crystal: -Y- Op Amp: (-In) o- OPo (Out) (+In) o+ Analog switch: (Control) O (In/Out) oXo (In/Out) NAND gate: (IN 1) o NANDo (OUT) (IN 2) o XOR gate: (IN 1) o XORo (OUT) (IN 2) o 2400HZ Crystal phase lock Weather Satellite decoder By Mike Gore April 1988 Part 2 of 3 See part 1 for a description of the the symbols used in this diagram and a function outline. Analog section: Power in (+12)---100---o---------O (+12 to all OP amps) +| 47uf | (GND)---------o----o----O (AGND and DGND) - AGND is to be tied to DGND here +| | 47uf | | | (-12)---100---o---------O (-12 to all OP amps) ! | 47uf +| (+5)---------------o----O (Logic +5) +----13K------+ | | +-----13K-----+ (IN) O--3n3-o-3n3-o--o- | | | | OPo-o--13K-o-13K-o--o- | | o+ | | OPo-o---+ (AGND) O--+ | | 27K | o+ | | | 13K | | | | 27K | | | +----o 10n | | | | | | | +----o | | | 47K | | | | | | | 47K | | | | | | | +-----o---------o-------o------------o-------o | | | | | | +--------------------------------------------+ | | | | +-----13K-----+ | | | | +-----13K-----+ | +-3n3-o-3n3-o--o- | | | | | OPo-o--13K-o-13K-o--o- | | | o+ | | OPo-o---+ | | | 27K | o+ | | | 13K | | | | 27K | | | +----o 10n | | | | | | | +----o | | | 47K | | | | | | | 47K | | | | | | | o---------------o-------o------------o-------o | | | | | | | | +--------------------------------------------+ | | | | | | +-4K7-o-v10K-o-10K-+ | | | | | | | +-10K-o-I<-+ | | (IN1) | | | | | | | | o-10K-o->I-o o- | O | | | | | OPo--o--oXo----o | | | o----|-------o+ | | | | | | | | +---10K-o- | | | | OPo--|----o- | | o+ | OPo--1K-o----O (PHASE) | | | | o+ | | | 10K 10K | +->I-o->I-O (+5) | | | | | | | o-----------o-----o----o---o | | | | | | -------------------------------------------+ | | | | +-------+ | | (IN4) (IN3) | | | | +-o- | | | O O OPo--o--4K7--O (VID) | | +-oXo-o-oXo-o--o+ | | | | | +-O (AGND) | | o-3n3-o | | | | | | | | | v10K--10K-o- | n15 | | | OPo--o | | | | o+ | | | | | | | o---o-------o-----------o--------------+ | | | 10n | | | o---100---O (+12) | D | +--o---o--oG (MPF102) | | | | S | | | | o | 2.4576MHZ Y | | | | | | n15 | | | | | | | +--o 220K | | | | | | o----o--n47--O (CLOCK) | o | | | | | (IN2) OX 20p | 44mH n15 +-O (AGND) | o | | | | | | | | | | | | o--------o--o--o---o----o-----o Digital Section: (+5) O-------------------o---------------o | | Mc14020 | 74ls164 | ========= | ========= | I VccI16-o--7IClr VccI14-o I I I I | I I 9----8I> QaI 3---------------1o (CLOCK) O--10I> I I QbI 4-----12o NANDo 3---O (IN3) I I I I | XORo11--2o I I14o-o-1IA I +---13o I I | +-2IB I | I I | I QcI 4---------------4o I I | I QdI 5------9o NANDo 6-o-O (IN4) I I | I I | XORo 8--5o | I I | I I +---10o | I I | I I | +-11IClr I | I I +-----------+ o--8IGnd I | +-7IGnd I | | ========= | | ========= o--9o | | | | NANDo 8---O (IN1) | | | o-10o | | | (DGND)---o----------------o | | o------------O (A/D Clock) | +----2o XORo---O (IN2) (PHASE) O----1o A/D Sect|on: ADC0809 =============== +----12IVref+ I | I I 100 I I DB25 Atar| pr|nter port | I I ... set to *|nput* mode (+5)-----o----11IVcc D0I17-----O 2 | 9IOE D1I14-----O 3 | I D2I15-----O 4 (IN1)-------o--6IStart D3I 8-----O 5 | +-22IAle D4I18-----O 6 | I D5I19-----O 7 (VID)---------26IIN0 D6I20-----O 8 | I D7I21-----O 9 + | I I 47uf I I | I EOCI 7-----O 11 | I I o----25IA I o--O 18 o----24IB I o--O 19 o----23IC I o--O 20 | I I o--O 21 | I I o--O 22 o----16IVref- I o--O 23 | I I o--O 24 | I I o--O 25 o----13IGND I | | I I | | =============== | | | (DGND) O-o-------------------------o (AGND) This file includes three files: Makefile, get.c, disp.c ----------------------------------- Makefile CFLAGS= -V OBJS= disp: disp.o $(OBJS) cc $(CFLAGS) disp.o $(OBJS) -o disp.prg disp.o: disp.c cc -c $(CFLAGS) disp.c get: get.o $(OBJS) cc $(CFLAGS) get.o $(OBJS) setrte.s -o get.prg get.o: get.c cc -c $(CFLAGS) get.c ----------------------------------- get.c --- #include "osbind.h" #define EXT #define VSIZE 2400 #define HSIZE 1200 #define VMEM (VSIZE*12) #define setres(a) ( *((char *) 0xff8260L) = (int) (a)) #define getres() ( *((char *) 0xff8260L) & 0xff) #define extsync() ( *((char *) 0xff820aL) = (1) ) #define intsync() ( *((char *) 0xff820aL) = (0) ) #define giport(a) ( *((char *) 0xff8800L) = (a) ) #define giwrite(a) ( *((char *) 0xff8802L) = (a) ) #define giread() ( *((unsigned char *) 0xff8800L) ) #define strobeon() ( giport(14), giwrite(giread() | 0x20) ) #define strobeoff() ( giport(14), giwrite(giread() & ~0x20) ) #define stat() ( *((char *) 0xfffa01L) ) #define setcol(a,b) ( *((int *) (0xff8240L+((int)(a)<<1)) ) = (int) (b) ) long save_ssp; unsigned char *mptr; unsigned int Vsum = 0; unsigned int Vsize = 0L; unsigned int Vhead = 0L; unsigned int Vtail = 0L; int Verror = 0; int Vcnt = 0; unsigned char Vbuff[HSIZE+1]; void extstrobe() { setrte(); if(Vsize < VMEM) { giport(15); mptr[Vhead++] = giread(); if(Vhead >= VMEM) Vhead = 0; Vsize++; } else { Verror = 1; } *((char *) 0xfffa11L) &= ~0x01; } void timetick() { setrte(); if(++Vcnt >= 2) { if(Vsize < VMEM) { mptr[Vhead++] = Vsum>>1; if(Vhead >= VMEM) Vhead = 0; Vsize++; } else { Verror = 1; } Vcnt = 0; Vsum = 0; } giport(15); Vsum += giread(); strobeoff(); strobeon(); *((char *) 0xfffa0fL) &= ~0x20; } main(argc,argv) int argc; char *argv[]; { register unsigned char *ptr1, *ptr2; register int i; long *vecp = (long *) 0x100L; long oldvec = 0L; unsigned int oldmask = 0; int fp; if(argc < 2) { printf("Usage: vmain OUTfile\n"); exit(1); } if((fp=creat(argv[1],1)) < 0) { printf("Can't open: %s\n",argv[1]); exit(1); } init(); save_ssp = Super(0L); #ifdef EXT Jdisint(0); oldvec = vecp[0]; vecp[0] = (long) extstrobe; oldmask = *((char *) 0xfffa03L); *((char *) 0xfffa03L) |= 0x01; Jenabint(0); #else Xbtimer(0,3,32,timetick); #endif Super(save_ssp); while(Verror == 0) { if(Cconis() != 0) { Verror = 1; break; } if(Vsize < VSIZE ) continue; ptr1 = (unsigned char *) &mptr[Vtail]; ptr2 = (unsigned char *) &mptr[Vtail+HSIZE]; for(i=0;i>1; Vsize -= VSIZE; Vtail += VSIZE; if(Vtail >= VMEM) Vtail = 0; if(write(fp,Vbuff,(int)HSIZE) != (int)HSIZE ) { printf("Write error: %s\n", argv[1]); Verror = 1; break; } } save_ssp = Super(0L); #ifdef EXT Jdisint(0); vecp[0] = oldvec; oldmask = *((char *) 0xfffa03L) = oldmask; #else Xbtimer(0,0,0,0L); #endif Super(save_ssp); close(fp); portout(); } init() { register int i; Vsize = 0; Vhead = 0; Vtail = 0; Verror = 0; portin(); mptr = (unsigned char *) Malloc((long)(VMEM)+1L); if(mptr == 0L) { printf("Malloc Failed\n"); exit(1); } for(i=0;i"); gets(line); switch(*line) { case 'r': sscanf(line,"%s %s %d", temp, path, &Vline); vclr(mptr, BSIZE); if((fp=open(path,0)) < 0) { printf("Can't open: %s\n",path); break; } Vskip = VSCAN * (long) Vline; lseek(fp,Vskip,0); for(y=0;y<180; y+=20) { if(read(fp,&mptr[offset(0L,y)], (int)VSCAN*20)<(int)VSCAN*20) break; } close(fp); break; case 'w' : sscanf(line,"%s %s", temp, path); fp = creat(path,0666); if(fp >= 0) { z = 0; if(write(fp,&z,2) != 2) { printf("Write error:%s\n", path); close(fp); break; } if(write(fp,disp,32) != 32) { printf("Write error:%s\n", path); close(fp); break; } if(write(fp,((char *) sptr), 0x4000) != 0x4000) { printf("Write error:%s\n", path); close(fp); break; } if(write(fp,((char *) sptr + 0x4000L), 0x4000) != 0x4000) { printf("Write error:%s\n", path); close(fp); break; } close(fp); } else { printf("Can't open:%s\n", path); } break; case 'W' : sscanf(line,"%s %s", temp, path); fp = creat(path,0666); if(fp >= 0) { for(y=0;y<180;++y) { for(x=0;x<300;++x) { if(Vdir<0) c = (mptr[offset(299-x,179-y)+Voff] & 0xff); else c = (mptr[offset(x,y)+Voff] & 0xff); buff[x] = c; } if(write(fp,buff,300) != 300) { printf("Write error:%s\n", path); break; } } close(fp); } else { printf("Can't open:%s\n", path); } break; case 'A' : sscanf(line,"%s %s", temp, path); fp = creat(path,0666); if(fp >= 0) { for(y=0;y<180;++y) { for(x=0;x<256;++x) { if(Vdir<0) c = (mptr[offset(299-x,179-y)+Voff] & 0xff); else c = (mptr[offset(x,y)+Voff] & 0xff); buff[x] = c; } if(write(fp,buff,256) != 256) { printf("Write error:%s\n", path); break; } } for(x=0;x<256;++x) buff[x] = 0; for(;y<256;++y) { if(write(fp,buff,256) != 256) { printf("Write error:%s\n", path); break; } } close(fp); } else { printf("Can't open:%s\n", path); } break; case 'H': sscanf(line,"%s %d %d", temp, &hmin, &hmax); if((hmin >= 0 && hmin <=255) && (hmax >=0 && hmax <=255) && (hmax > hmin) ) { Vmin = hmin; Vmax = hmax; } else { printf("Must be bound by 0..256 and Max > Min\n"); } break; case 'h': for(i=0;i<256;++i) hist[i] = 0L; for(y=0;y<180;++y) { for(x=0;x<300;++x) { c = mptr[offset(x,y)+Voff] & 0xff; if(c>0) ++hist[c]; } } printf("\n"); for(i=0;i<256;++i) { if((i%12) == 0) printf("%3d: ",i); printf(" %5ld", hist[i]); if((i%12) == 11) printf("\n"); } break; case 'D': Voff = 0; Vdir = 1; sscanf(line,"%s %d %d", temp, &Voff, &Vdir); break; case '?': printf("off:%d, dir:%d, min:%d, max:%d\n", Voff,Vdir,Vmin,Vmax); break; case 'd': if((Vmin < 0 && Vmin > 255) || (Vmax < 0 && Vmax > 255) || (Vmax <= Vmin) ) { printf("Max and Min out of bounds\n"); break; } scrinit(); for(i=0;i<256;++i) hist[i] = 0L; for(i=0;i 14) c = 14; Vmap[i] = c; } while(i<256) Vmap[i++] = 15; for(y=0;y<180;++y) { for(x=0;x<300;++x) { c = (mptr[offset(x,y)+Voff] & 0xff); if(c>0) ++hist[c]; if(Vdir<0) set(299-x,179-y,Vmap[c]); else set(x,y,Vmap[c]); } } Vsize = 0L; for(i=0;i<256;++i) { if(Vsize < hist[i]) Vsize = hist[i]; } for(x=0;x<256;x++) { hoff = (int)((hist[x]*10L)/Vsize); if(hoff < 0) hoff = 0; if(hoff > 9) hoff = 9; set(x,189-hoff,15); if((x % 10) == 0) set(x,190,15); for(y=191;y<195;++y) set(x,y,x >> 4); for(y=196;y<200;++y) set(x,y,Vmap[x]); } vcopy(sptr,(char *)Vbase,DSIZE); gets(temp); screxit(); break; case 'Q': case 'q': Mfree(sptr); Mfree(mptr); exit(0); default: printf("\n?\n"); break; } } } scrinit() { gbase(); Cursconf(0,30); getpal(Smap); Res=gres(); sres(0); setpal(disp); vclr(Vbase, DSIZE>>1); } screxit() { sres(Res); setpal(Smap); Cursconf(1,30); } vclr(ptr,size) unsigned char *ptr; long size; { while(size--) *ptr++ = 0; } vcopy(dest, src, size) unsigned char *dest, *src; long size; { while(size--) *dest++ = *src++; } set(x,y,color) register unsigned int x,y,color; { register unsigned int *ptr; register unsigned int mask; mask = ((unsigned) 0x8000) >> (x & 0xf); ptr = (unsigned int *) (Vbase + (160 * y) + ((x & 0xfff0) >> 1) ); *ptr++ |= ((color & 1) ? mask : 0); *ptr++ |= ((color & 2) ? mask : 0); *ptr++ |= ((color & 4) ? mask : 0); *ptr++ |= ((color & 8) ? mask : 0); } unset(x,y) register unsigned int x,y; { register unsigned int *ptr; register unsigned int mask; mask = ~( ((unsigned) 0x8000) >> (x & 0xf) ); ptr = (unsigned int *) (Vbase + (y * 160) + ((x & 0xfff0) >> 1) ); *ptr++ &= mask; *ptr++ &= mask; *ptr++ &= mask; *ptr++ &= mask; } setpal(v) unsigned int *v; { int i; save_ssp = Super(0L); for(i=0;i<16;++i) { setcol(i,v[i]); } Super(save_ssp); } getpal(v) unsigned int *v; { int i; save_ssp = Super(0L); for(i=0;i<16;++i) { v[i] = getcol(i); } Super(save_ssp); } gres() { int x; save_ssp = Super(0L); x = getres(); Super(save_ssp); return(x); } gbase() { save_ssp = Super(0L); Vbase = *((long *) 0x44e); Super(save_ssp); } sres(a) unsigned int a; { save_ssp = Super(0L); setres(a); Super(save_ssp); } ------ .===========================================================. | ####### ####### ### C O M P U T E R | =----------= | | ### ### ### C O N S O L E S | An STC Company | | ####### ####### ### Incorporated | =----------= | |-----------------------------------------------------------| | UUCP: ...ccicpg!dl2!paulm (Paul L. Moreau) | | or ...ccicpg!dl1!paulm (Diagnostics Software Eng) | | or ...ccicpg!paulm (Irvine, California) | `===========================================================' ------------------------------ End of SPACE Digest V9 #527 *******************