@@ -9,9 +9,9 @@ aptdec: $(OBJS) | |||||
reg.o: reg.c | reg.o: reg.c | ||||
color.o: color.c | color.o: color.c | ||||
main.o: main.c | |||||
main.o: main.c | |||||
media.o: median.c | media.o: median.c | ||||
dsp.o: dsp.c | |||||
dsp.o: dsp.c | |||||
filter.o: filter.c | filter.o: filter.c | ||||
image.o: image.c | image.o: image.c | ||||
pngio.o: pngio.c | pngio.o: pngio.c | ||||
@@ -30,96 +30,96 @@ rgb_t applyPalette(char *palette, int val){ | |||||
} | } | ||||
rgb_t RGBcomposite(rgb_t top, float top_a, rgb_t bottom, float bottom_a){ | rgb_t RGBcomposite(rgb_t top, float top_a, rgb_t bottom, float bottom_a){ | ||||
return (rgb_t){ | |||||
MCOMPOSITE(top.r, top_a, bottom.r, bottom_a), | |||||
MCOMPOSITE(top.g, top_a, bottom.g, bottom_a), | |||||
MCOMPOSITE(top.b, top_a, bottom.b, bottom_a) | |||||
}; | |||||
return (rgb_t){ | |||||
MCOMPOSITE(top.r, top_a, bottom.r, bottom_a), | |||||
MCOMPOSITE(top.g, top_a, bottom.g, bottom_a), | |||||
MCOMPOSITE(top.b, top_a, bottom.b, bottom_a) | |||||
}; | |||||
} | } | ||||
// The "I totally didn't just steal this from WXtoImg" palette | // The "I totally didn't just steal this from WXtoImg" palette | ||||
char TempPalette[256*3] = { | char TempPalette[256*3] = { | ||||
"\x45\x0\x8f\x46\x0\x91\x47\x0\x92\x48\x0\x94\x49\x0\x96\x4a\x0\x98\x4b\x0\x9b\x4d\x0\x9d" | |||||
"\x4e\x0\xa0\x50\x0\xa2\x51\x0\xa5\x52\x0\xa7\x54\x0\xaa\x56\x0\xae\x57\x0\xb1" | |||||
"\x58\x0\xb4\x5a\x0\xb7\x5c\x0\xba\x5e\x0\xbd\x5f\x0\xc0\x61\x0\xc4\x64\x0\xc8" | |||||
"\x66\x0\xcb\x68\x0\xce\x69\x0\xd1\x68\x0\xd4\x65\x0\xd7\x63\x0\xda\x61\x0\xdd" | |||||
"\x5d\x0\xe1\x5b\x0\xe4\x59\x0\xe6\x56\x0\xe9\x53\x0\xeb\x50\x0\xee\x4d\x0\xf0" | |||||
"\x49\x0\xf3\x47\x0\xfc\x43\x0\xfa\x31\x0\xbf\x20\x0\x89\x20\x0\x92\x1e\x0\x95" | |||||
"\x1b\x0\x97\x19\x0\x9a\x17\x0\x9c\x15\x0\x9e\x12\x0\xa0\xf\x0\xa3\xf\x2\xa5" | |||||
"\xe\x6\xa8\xe\xa\xab\xe\xd\xad\xe\x11\xb1\xd\x15\xb4\xd\x18\xb7\xd\x1c\xba" | |||||
"\xb\x21\xbd\xa\x25\xc0\xa\x29\xc3\x9\x2d\xc6\x8\x33\xca\x7\x36\xcd\x7\x3b\xd0" | |||||
"\x7\x41\xd3\x5\x45\xd6\x4\x4b\xd9\x4\x50\xdc\x3\x55\xde\x2\x5d\xe2\x1\x61\xe5" | |||||
"\x0\x66\xe7\x0\x6c\xea\x0\x72\xec\x0\x78\xee\x0\x7d\xf0\x0\x82\xf3\x0\x8d\xfc" | |||||
"\x0\x90\xfa\x0\x71\xbf\x0\x54\x89\x0\x5c\x91\x0\x61\x94\x0\x64\x96\x0\x68\x97" | |||||
"\x0\x6d\x99\x0\x71\x9b\x0\x75\x9d\x0\x79\x9f\x0\x7e\xa0\x0\x82\xa2\x0\x87\xa4" | |||||
"\x0\x8c\xa6\x0\x92\xaa\x0\x96\xac\x0\x9c\xae\x0\xa2\xb1\x0\xa6\xb3\x0\xaa\xb5" | |||||
"\x0\xad\xb7\x0\xb1\xba\x0\xb6\xbe\x0\xba\xc0\x0\xbe\xc2\x0\xc2\xc5\x0\xc6\xc6" | |||||
"\x0\xca\xc9\x0\xcc\xca\x0\xcf\xcb\x0\xd2\xcc\x0\xd4\xcc\x0\xd6\xcc\x0\xd9\xcb" | |||||
"\x0\xdb\xcb\x0\xde\xcb\x0\xe0\xcb\x0\xe2\xcc\x0\xea\xd2\x0\xea\xcf\x0\xb9\xa4" | |||||
"\x0\x8e\x7a\x1\x94\x7c\x4\x97\x79\x7\x99\x75\x9\x9b\x71\xd\x9d\x6b\x10\x9f\x67" | |||||
"\x12\xa1\x63\x15\xa3\x5f\x17\xa5\x59\x1a\xa8\x55\x1d\xaa\x50\x20\xac\x4b\x24\xaf\x45" | |||||
"\x28\xb2\x41\x2b\xb5\x3b\x2e\xb8\x35\x31\xba\x30\x34\xbd\x2b\x39\xbf\x24\x3f\xc1\x17" | |||||
"\x49\xc5\x8\x4f\xc8\x1\x4f\xca\x0\x4e\xcd\x0\x4e\xcf\x0\x4f\xd2\x0\x54\xd5\x0" | |||||
"\x5d\xd8\x0\x68\xdb\x0\x6e\xdd\x0\x74\xdf\x0\x7a\xe2\x0\x7f\xe4\x0\x85\xe7\x0" | |||||
"\x8b\xe9\x0\x8f\xeb\x0\x9b\xf3\x0\x9e\xf2\x0\x7e\xbb\x0\x60\x8a\x0\x68\x92\x0" | |||||
"\x6d\x95\x0\x71\x96\x0\x75\x98\x0\x7b\x9a\x0\x7f\x9d\x0\x83\x9f\x0\x87\xa1\x0" | |||||
"\x8c\xa2\x0\x8f\xa5\x0\x92\xa7\x0\x96\xa9\x0\x9a\xad\x0\x9d\xb0\x0\xa1\xb2\x0" | |||||
"\xa5\xb5\x0\xa9\xb7\x0\xad\xba\x0\xb2\xbd\x0\xb6\xbf\x0\xbb\xc3\x0\xbf\xc6\x0" | |||||
"\xc3\xc8\x0\xc8\xcb\x0\xcc\xce\x0\xd0\xd1\x0\xd3\xd2\x0\xd5\xd4\x0\xd9\xd4\x0" | |||||
"\xdc\xd4\x0\xde\xd5\x0\xe1\xd5\x0\xe3\xd5\x0\xe6\xd4\x0\xe8\xd1\x0\xea\xce\x0" | |||||
"\xf2\xcf\x0\xf2\xca\x0\xbb\x99\x0\x8a\x6e\x0\x92\x72\x0\x95\x72\x0\x97\x71\x0" | |||||
"\x9a\x70\x0\x9c\x6e\x0\x9e\x6d\x0\xa0\x6b\x0\xa3\x6a\x0\xa5\x68\x0\xa8\x67\x0" | |||||
"\xab\x66\x0\xae\x65\x0\xb2\x63\x0\xb4\x61\x0\xb7\x5f\x0\xba\x5d\x0\xbd\x5c\x0" | |||||
"\xc0\x59\x0\xc3\x57\x0\xc6\x54\x0\xca\x50\x0\xcd\x4d\x0\xd0\x4a\x0\xd3\x47\x0" | |||||
"\xd6\x43\x0\xd9\x40\x0\xdc\x3d\x0\xde\x39\x0\xe2\x33\x0\xe5\x2f\x0\xe7\x2c\x0" | |||||
"\xea\x28\x0\xec\x23\x0\xef\x1f\x0\xf1\x1a\x0\xf3\x14\x0\xfb\xf\x0\xfa\xd\x0" | |||||
"\xc1\x5\x0\x8e\x0\x0\x97\x0\x0\x9b\x0\x0\x9e\x0\x0\xa1\x0\x0\xa5\x0\x0" | |||||
"\xa9\x0\x0\xad\x0\x0\xb1\x0\x0\xb6\x0\x0\xba\x0\x0\xbd\x0\x0\xc2\x0\x0" | |||||
"\xc8\x0\x0\xcc\x0\x0\xcc\x0\x0" | |||||
"\x45\x0\x8f\x46\x0\x91\x47\x0\x92\x48\x0\x94\x49\x0\x96\x4a\x0\x98\x4b\x0\x9b\x4d\x0\x9d" | |||||
"\x4e\x0\xa0\x50\x0\xa2\x51\x0\xa5\x52\x0\xa7\x54\x0\xaa\x56\x0\xae\x57\x0\xb1" | |||||
"\x58\x0\xb4\x5a\x0\xb7\x5c\x0\xba\x5e\x0\xbd\x5f\x0\xc0\x61\x0\xc4\x64\x0\xc8" | |||||
"\x66\x0\xcb\x68\x0\xce\x69\x0\xd1\x68\x0\xd4\x65\x0\xd7\x63\x0\xda\x61\x0\xdd" | |||||
"\x5d\x0\xe1\x5b\x0\xe4\x59\x0\xe6\x56\x0\xe9\x53\x0\xeb\x50\x0\xee\x4d\x0\xf0" | |||||
"\x49\x0\xf3\x47\x0\xfc\x43\x0\xfa\x31\x0\xbf\x20\x0\x89\x20\x0\x92\x1e\x0\x95" | |||||
"\x1b\x0\x97\x19\x0\x9a\x17\x0\x9c\x15\x0\x9e\x12\x0\xa0\xf\x0\xa3\xf\x2\xa5" | |||||
"\xe\x6\xa8\xe\xa\xab\xe\xd\xad\xe\x11\xb1\xd\x15\xb4\xd\x18\xb7\xd\x1c\xba" | |||||
"\xb\x21\xbd\xa\x25\xc0\xa\x29\xc3\x9\x2d\xc6\x8\x33\xca\x7\x36\xcd\x7\x3b\xd0" | |||||
"\x7\x41\xd3\x5\x45\xd6\x4\x4b\xd9\x4\x50\xdc\x3\x55\xde\x2\x5d\xe2\x1\x61\xe5" | |||||
"\x0\x66\xe7\x0\x6c\xea\x0\x72\xec\x0\x78\xee\x0\x7d\xf0\x0\x82\xf3\x0\x8d\xfc" | |||||
"\x0\x90\xfa\x0\x71\xbf\x0\x54\x89\x0\x5c\x91\x0\x61\x94\x0\x64\x96\x0\x68\x97" | |||||
"\x0\x6d\x99\x0\x71\x9b\x0\x75\x9d\x0\x79\x9f\x0\x7e\xa0\x0\x82\xa2\x0\x87\xa4" | |||||
"\x0\x8c\xa6\x0\x92\xaa\x0\x96\xac\x0\x9c\xae\x0\xa2\xb1\x0\xa6\xb3\x0\xaa\xb5" | |||||
"\x0\xad\xb7\x0\xb1\xba\x0\xb6\xbe\x0\xba\xc0\x0\xbe\xc2\x0\xc2\xc5\x0\xc6\xc6" | |||||
"\x0\xca\xc9\x0\xcc\xca\x0\xcf\xcb\x0\xd2\xcc\x0\xd4\xcc\x0\xd6\xcc\x0\xd9\xcb" | |||||
"\x0\xdb\xcb\x0\xde\xcb\x0\xe0\xcb\x0\xe2\xcc\x0\xea\xd2\x0\xea\xcf\x0\xb9\xa4" | |||||
"\x0\x8e\x7a\x1\x94\x7c\x4\x97\x79\x7\x99\x75\x9\x9b\x71\xd\x9d\x6b\x10\x9f\x67" | |||||
"\x12\xa1\x63\x15\xa3\x5f\x17\xa5\x59\x1a\xa8\x55\x1d\xaa\x50\x20\xac\x4b\x24\xaf\x45" | |||||
"\x28\xb2\x41\x2b\xb5\x3b\x2e\xb8\x35\x31\xba\x30\x34\xbd\x2b\x39\xbf\x24\x3f\xc1\x17" | |||||
"\x49\xc5\x8\x4f\xc8\x1\x4f\xca\x0\x4e\xcd\x0\x4e\xcf\x0\x4f\xd2\x0\x54\xd5\x0" | |||||
"\x5d\xd8\x0\x68\xdb\x0\x6e\xdd\x0\x74\xdf\x0\x7a\xe2\x0\x7f\xe4\x0\x85\xe7\x0" | |||||
"\x8b\xe9\x0\x8f\xeb\x0\x9b\xf3\x0\x9e\xf2\x0\x7e\xbb\x0\x60\x8a\x0\x68\x92\x0" | |||||
"\x6d\x95\x0\x71\x96\x0\x75\x98\x0\x7b\x9a\x0\x7f\x9d\x0\x83\x9f\x0\x87\xa1\x0" | |||||
"\x8c\xa2\x0\x8f\xa5\x0\x92\xa7\x0\x96\xa9\x0\x9a\xad\x0\x9d\xb0\x0\xa1\xb2\x0" | |||||
"\xa5\xb5\x0\xa9\xb7\x0\xad\xba\x0\xb2\xbd\x0\xb6\xbf\x0\xbb\xc3\x0\xbf\xc6\x0" | |||||
"\xc3\xc8\x0\xc8\xcb\x0\xcc\xce\x0\xd0\xd1\x0\xd3\xd2\x0\xd5\xd4\x0\xd9\xd4\x0" | |||||
"\xdc\xd4\x0\xde\xd5\x0\xe1\xd5\x0\xe3\xd5\x0\xe6\xd4\x0\xe8\xd1\x0\xea\xce\x0" | |||||
"\xf2\xcf\x0\xf2\xca\x0\xbb\x99\x0\x8a\x6e\x0\x92\x72\x0\x95\x72\x0\x97\x71\x0" | |||||
"\x9a\x70\x0\x9c\x6e\x0\x9e\x6d\x0\xa0\x6b\x0\xa3\x6a\x0\xa5\x68\x0\xa8\x67\x0" | |||||
"\xab\x66\x0\xae\x65\x0\xb2\x63\x0\xb4\x61\x0\xb7\x5f\x0\xba\x5d\x0\xbd\x5c\x0" | |||||
"\xc0\x59\x0\xc3\x57\x0\xc6\x54\x0\xca\x50\x0\xcd\x4d\x0\xd0\x4a\x0\xd3\x47\x0" | |||||
"\xd6\x43\x0\xd9\x40\x0\xdc\x3d\x0\xde\x39\x0\xe2\x33\x0\xe5\x2f\x0\xe7\x2c\x0" | |||||
"\xea\x28\x0\xec\x23\x0\xef\x1f\x0\xf1\x1a\x0\xf3\x14\x0\xfb\xf\x0\xfa\xd\x0" | |||||
"\xc1\x5\x0\x8e\x0\x0\x97\x0\x0\x9b\x0\x0\x9e\x0\x0\xa1\x0\x0\xa5\x0\x0" | |||||
"\xa9\x0\x0\xad\x0\x0\xb1\x0\x0\xb6\x0\x0\xba\x0\x0\xbd\x0\x0\xc2\x0\x0" | |||||
"\xc8\x0\x0\xcc\x0\x0\xcc\x0\x0" | |||||
}; | }; | ||||
char PrecipPalette[256*3] = { | char PrecipPalette[256*3] = { | ||||
"\xe0\x98\x8\xec\x84\x10\xf5\x70\x1b\xfc\x5c\x29\xff\x49\x38\xff\x37\x4a" | |||||
"\xfb\x28\x5d\xf5\x1a\x71\xeb\xf\x85\xdf\x8\x99\xd0\x3\xad\xc0\x1\xbf" | |||||
"\xad\x3\xd0\x9a\x7\xdf\x86\xf\xeb\x72\x1a\xf5\x5e\x27\xfb\x4b\x37\xfe" | |||||
"\x39\x48\xff\x29\x5b\xfc\x1b\x6f\xf5\x10\x83\xec\x8\x98\xe0\x3\xab\xd2" | |||||
"\x1\xbe\xc1\x2\xcf\xaf\x7\xdd\x9c\xe\xea\x88\x19\xf4\x73\x26\xfb\x5f" | |||||
"\x35\xfe\x4c\x47\xff\x3a\x5a\xfc\x2a\x6d\xf6\x1d\x82\xed\x11\x96\xe1\x9" | |||||
"\xa9\xd3\x3\xbc\xc3\x1\xcd\xb1\x2\xdc\x9e\x6\xe9\x89\xe\xf3\x75\x18" | |||||
"\xfa\x61\x25\xfe\x4e\x34\xff\x3c\x45\xfc\x2c\x58\xf7\x1e\x6c\xee\x12\x80" | |||||
"\xe3\x9\x94\xd5\x4\xa8\xc4\x1\xba\xb2\x2\xcc\x9f\x6\xdb\x8b\xd\xe8" | |||||
"\x77\x17\xf2\x63\x23\xfa\x50\x33\xfe\x3d\x44\xff\x2d\x56\xfd\x1f\x6a\xf7" | |||||
"\x13\x7e\xef\xa\x92\xe4\x4\xa6\xd6\x1\xb9\xc6\x2\xca\xb4\x5\xda\xa1" | |||||
"\xc\xe7\x8d\x16\xf1\x79\x22\xf9\x65\x31\xfe\x51\x42\xff\x3f\x54\xfd\x2f" | |||||
"\x68\xf8\x20\x7c\xf0\x14\x90\xe5\xb\xa4\xd7\x4\xb7\xc7\x1\xc9\xb6\x1" | |||||
"\xd8\xa3\x5\xe6\x8f\xb\xf1\x7b\x15\xf9\x66\x21\xfd\x53\x30\xff\x41\x40" | |||||
"\xfd\x30\x53\xf9\x21\x66\xf1\x15\x7a\xe6\xb\x8f\xd9\x5\xa3\xc9\x1\xb6" | |||||
"\xb7\x1\xc7\xa5\x4\xd7\x91\xb\xe5\x7c\x14\xf0\x68\x20\xf8\x55\x2e\xfd" | |||||
"\x42\x3f\xff\x31\x51\xfe\x22\x64\xf9\x16\x78\xf2\xc\x8d\xe7\x5\xa1\xda" | |||||
"\x2\xb4\xca\x1\xc6\xb9\x4\xd6\xa6\xa\xe4\x93\x13\xef\x7e\x1f\xf7\x6a" | |||||
"\x2d\xfd\x56\x3d\xff\x44\x4f\xfe\x33\x63\xfa\x24\x77\xf2\x17\x8b\xe8\xd" | |||||
"\x9f\xdb\x6\xb2\xcc\x2\xc4\xbb\x1\xd4\xa8\x4\xe2\x94\x9\xee\x80\x12" | |||||
"\xf7\x6c\x1d\xfc\x58\x2b\xff\x45\x3c\xfe\x34\x4e\xfa\x25\x61\xf3\x18\x75" | |||||
"\xe9\xe\x89\xdc\x6\x9d\xcd\x2\xb1\xbc\x1\xc3\xaa\x3\xd3\x96\x9\xe1" | |||||
"\x82\x11\xed\x6e\x1c\xf6\x5a\x2a\xfc\x47\x3a\xff\x36\x4c\xfe\x26\x5f\xfb" | |||||
"\x19\x73\xf4\xf\x87\xea\x7\x9b\xde\x2\xaf\xcf\x1\xc1\xbe\x3\xd2\xac" | |||||
"\x8\xe0\x98\x10\xec\x84\x1b\xf5\x6f\x29\xfc\x5c\x39\xff\x49\x4a\xff\x37" | |||||
"\x5d\xfb\x28\x71\xf5\x1a\x85\xeb\xf\x9a\xdf\x7\xad\xd0\x3\xbf\xc0\x1" | |||||
"\xd0\xad\x3\xdf\x9a\x7\xeb\x86\xf\xf5\x71\x1a\xfb\x5d\x27\xff\x4a\x37" | |||||
"\xff\x39\x49\xfc\x29\x5c\xf5\x1b\x6f\xec\x10\x84\xe0\x8\x98\xd2\x3\xab" | |||||
"\xc1\x1\xbe\xaf\x2\xcf\x9c\x7\xde\x87\xe\xea\x73\x19\xf4\x5f\x26\xfb" | |||||
"\x4c\x36\xfe\x3a\x47\xff\x2a\x5a\xfc\x1c\x6e\xf6\x11\x82\xed\x9\x96\xe1" | |||||
"\x3\xaa\xd3\x1\xbc\xc3\x2\xcd\xb1\x6\xdc\x9d\xe\xe9\x89\x18\xf3\x75" | |||||
"\x25\xfa\x61\x34\xfe\x4e\x45\xff\x3c\x58\xfc\x2c\x6c\xf7\x1e\x80\xee\x12" | |||||
"\x94\xe2\x9\xa8\xd4\x4\xbb\xc4\x1\xcc\xb2\x2\xdb\x9f\x6\xe8\x8b\xd" | |||||
"\xf2\x77\x17\xfa\x63\x24\xfe\x4f\x33\xff\x3d\x44\xfd\x2d\x56\xf7\x1f\x6a" | |||||
"\xef\x13\x7e\xe4\xa\x92\xd6\x4\xa6\xc6\x1\xb9\xb4\x2\xca\xa1\x5\xda" | |||||
"\x8d\xc\xe7\x79\x16\xf2\x64\x22\xf9\x51\x31\xfe\x3f\x42\xff\x2e\x55\xfd" | |||||
"\x20\x68\xf8\x14\x7c\xf0\xb\x91\xe5\x4\xa4\xd7\x1\xb7\xc7\x1\xc9\xb6" | |||||
"\x5\xd9\xa3\xb\xe6\x8f\x15\xf1\x7a\x21\xf9\x66\x30\xfd\x53\x41\xff\x40" | |||||
"\x53\xfd\x30\x66\xf9\x21\x7b\xf1\x15\x8f\xe6\xb\xa3\xd8\x5\xb6\xc9\x1" | |||||
"\xc7\xb7\x1\xd7\xa4\x4\xe5\x91\xb\xf0\x7c\x14\xf8\x68\x20\xfd\x54\x2e" | |||||
"\xff\x42\x3f\xfe\x31\x51\xf9\x22\x65\xf1\x16\x79\xe7\xc\x8d\xda\x5\xa1" | |||||
"\xca\x2\xb4\xb9\x1\xc6\xa6\x4\xd6\x92\xa\xe4\x7e\x13\xef\x6a\x1f\xf7" | |||||
"\x56\x2d\xfd\x44\x3d\xff\x33\x4f\xfe\x24\x63\xfa" | |||||
"\xe0\x98\x8\xec\x84\x10\xf5\x70\x1b\xfc\x5c\x29\xff\x49\x38\xff\x37\x4a" | |||||
"\xfb\x28\x5d\xf5\x1a\x71\xeb\xf\x85\xdf\x8\x99\xd0\x3\xad\xc0\x1\xbf" | |||||
"\xad\x3\xd0\x9a\x7\xdf\x86\xf\xeb\x72\x1a\xf5\x5e\x27\xfb\x4b\x37\xfe" | |||||
"\x39\x48\xff\x29\x5b\xfc\x1b\x6f\xf5\x10\x83\xec\x8\x98\xe0\x3\xab\xd2" | |||||
"\x1\xbe\xc1\x2\xcf\xaf\x7\xdd\x9c\xe\xea\x88\x19\xf4\x73\x26\xfb\x5f" | |||||
"\x35\xfe\x4c\x47\xff\x3a\x5a\xfc\x2a\x6d\xf6\x1d\x82\xed\x11\x96\xe1\x9" | |||||
"\xa9\xd3\x3\xbc\xc3\x1\xcd\xb1\x2\xdc\x9e\x6\xe9\x89\xe\xf3\x75\x18" | |||||
"\xfa\x61\x25\xfe\x4e\x34\xff\x3c\x45\xfc\x2c\x58\xf7\x1e\x6c\xee\x12\x80" | |||||
"\xe3\x9\x94\xd5\x4\xa8\xc4\x1\xba\xb2\x2\xcc\x9f\x6\xdb\x8b\xd\xe8" | |||||
"\x77\x17\xf2\x63\x23\xfa\x50\x33\xfe\x3d\x44\xff\x2d\x56\xfd\x1f\x6a\xf7" | |||||
"\x13\x7e\xef\xa\x92\xe4\x4\xa6\xd6\x1\xb9\xc6\x2\xca\xb4\x5\xda\xa1" | |||||
"\xc\xe7\x8d\x16\xf1\x79\x22\xf9\x65\x31\xfe\x51\x42\xff\x3f\x54\xfd\x2f" | |||||
"\x68\xf8\x20\x7c\xf0\x14\x90\xe5\xb\xa4\xd7\x4\xb7\xc7\x1\xc9\xb6\x1" | |||||
"\xd8\xa3\x5\xe6\x8f\xb\xf1\x7b\x15\xf9\x66\x21\xfd\x53\x30\xff\x41\x40" | |||||
"\xfd\x30\x53\xf9\x21\x66\xf1\x15\x7a\xe6\xb\x8f\xd9\x5\xa3\xc9\x1\xb6" | |||||
"\xb7\x1\xc7\xa5\x4\xd7\x91\xb\xe5\x7c\x14\xf0\x68\x20\xf8\x55\x2e\xfd" | |||||
"\x42\x3f\xff\x31\x51\xfe\x22\x64\xf9\x16\x78\xf2\xc\x8d\xe7\x5\xa1\xda" | |||||
"\x2\xb4\xca\x1\xc6\xb9\x4\xd6\xa6\xa\xe4\x93\x13\xef\x7e\x1f\xf7\x6a" | |||||
"\x2d\xfd\x56\x3d\xff\x44\x4f\xfe\x33\x63\xfa\x24\x77\xf2\x17\x8b\xe8\xd" | |||||
"\x9f\xdb\x6\xb2\xcc\x2\xc4\xbb\x1\xd4\xa8\x4\xe2\x94\x9\xee\x80\x12" | |||||
"\xf7\x6c\x1d\xfc\x58\x2b\xff\x45\x3c\xfe\x34\x4e\xfa\x25\x61\xf3\x18\x75" | |||||
"\xe9\xe\x89\xdc\x6\x9d\xcd\x2\xb1\xbc\x1\xc3\xaa\x3\xd3\x96\x9\xe1" | |||||
"\x82\x11\xed\x6e\x1c\xf6\x5a\x2a\xfc\x47\x3a\xff\x36\x4c\xfe\x26\x5f\xfb" | |||||
"\x19\x73\xf4\xf\x87\xea\x7\x9b\xde\x2\xaf\xcf\x1\xc1\xbe\x3\xd2\xac" | |||||
"\x8\xe0\x98\x10\xec\x84\x1b\xf5\x6f\x29\xfc\x5c\x39\xff\x49\x4a\xff\x37" | |||||
"\x5d\xfb\x28\x71\xf5\x1a\x85\xeb\xf\x9a\xdf\x7\xad\xd0\x3\xbf\xc0\x1" | |||||
"\xd0\xad\x3\xdf\x9a\x7\xeb\x86\xf\xf5\x71\x1a\xfb\x5d\x27\xff\x4a\x37" | |||||
"\xff\x39\x49\xfc\x29\x5c\xf5\x1b\x6f\xec\x10\x84\xe0\x8\x98\xd2\x3\xab" | |||||
"\xc1\x1\xbe\xaf\x2\xcf\x9c\x7\xde\x87\xe\xea\x73\x19\xf4\x5f\x26\xfb" | |||||
"\x4c\x36\xfe\x3a\x47\xff\x2a\x5a\xfc\x1c\x6e\xf6\x11\x82\xed\x9\x96\xe1" | |||||
"\x3\xaa\xd3\x1\xbc\xc3\x2\xcd\xb1\x6\xdc\x9d\xe\xe9\x89\x18\xf3\x75" | |||||
"\x25\xfa\x61\x34\xfe\x4e\x45\xff\x3c\x58\xfc\x2c\x6c\xf7\x1e\x80\xee\x12" | |||||
"\x94\xe2\x9\xa8\xd4\x4\xbb\xc4\x1\xcc\xb2\x2\xdb\x9f\x6\xe8\x8b\xd" | |||||
"\xf2\x77\x17\xfa\x63\x24\xfe\x4f\x33\xff\x3d\x44\xfd\x2d\x56\xf7\x1f\x6a" | |||||
"\xef\x13\x7e\xe4\xa\x92\xd6\x4\xa6\xc6\x1\xb9\xb4\x2\xca\xa1\x5\xda" | |||||
"\x8d\xc\xe7\x79\x16\xf2\x64\x22\xf9\x51\x31\xfe\x3f\x42\xff\x2e\x55\xfd" | |||||
"\x20\x68\xf8\x14\x7c\xf0\xb\x91\xe5\x4\xa4\xd7\x1\xb7\xc7\x1\xc9\xb6" | |||||
"\x5\xd9\xa3\xb\xe6\x8f\x15\xf1\x7a\x21\xf9\x66\x30\xfd\x53\x41\xff\x40" | |||||
"\x53\xfd\x30\x66\xf9\x21\x7b\xf1\x15\x8f\xe6\xb\xa3\xd8\x5\xb6\xc9\x1" | |||||
"\xc7\xb7\x1\xd7\xa4\x4\xe5\x91\xb\xf0\x7c\x14\xf8\x68\x20\xfd\x54\x2e" | |||||
"\xff\x42\x3f\xfe\x31\x51\xf9\x22\x65\xf1\x16\x79\xe7\xc\x8d\xda\x5\xa1" | |||||
"\xca\x2\xb4\xb9\x1\xc6\xa6\x4\xd6\x92\xa\xe4\x7e\x13\xef\x6a\x1f\xf7" | |||||
"\x56\x2d\xfd\x44\x3d\xff\x33\x4f\xfe\x24\x63\xfa" | |||||
}; | }; |
@@ -74,25 +74,25 @@ static inline double Phase(double I, double Q) { | |||||
if(I == 0.0 && Q == 0.0) return 0.0; | if(I == 0.0 && Q == 0.0) return 0.0; | ||||
if (Q < 0) { | |||||
if (Q < 0) { | |||||
s = -1; | s = -1; | ||||
Q = -Q; | Q = -Q; | ||||
} else { | |||||
} else { | |||||
s = 1; | s = 1; | ||||
} | |||||
if (I >= 0) { | |||||
r = (I - Q) / (I + Q); | |||||
angle = 0.25 - 0.25 * r; | |||||
} else { | |||||
r = (I + Q) / (Q - I); | |||||
angle = 0.75 - 0.25 * r; | |||||
} | |||||
if(s > 0){ | |||||
return angle; | |||||
}else{ | |||||
return -angle; | |||||
} | |||||
if (I >= 0) { | |||||
r = (I - Q) / (I + Q); | |||||
angle = 0.25 - 0.25 * r; | |||||
} else { | |||||
r = (I + Q) / (Q - I); | |||||
angle = 0.75 - 0.25 * r; | |||||
} | |||||
if(s > 0){ | |||||
return angle; | |||||
}else{ | |||||
return -angle; | |||||
} | } | ||||
} | } | ||||
@@ -102,44 +102,44 @@ static inline double Phase(double I, double Q) { | |||||
*/ | */ | ||||
static double pll(double I, double Q) { | static double pll(double I, double Q) { | ||||
// PLL coefficient | // PLL coefficient | ||||
static double PhaseOsc = 0.0; | |||||
double Io, Qo; | |||||
double Ip, Qp; | |||||
double DPhi; | |||||
static double PhaseOsc = 0.0; | |||||
double Io, Qo; | |||||
double Ip, Qp; | |||||
double DPhi; | |||||
// Quadrature oscillator / reference | // Quadrature oscillator / reference | ||||
Io = cos(PhaseOsc); | |||||
Qo = sin(PhaseOsc); | |||||
Io = cos(PhaseOsc); | |||||
Qo = sin(PhaseOsc); | |||||
// Phase detector | // Phase detector | ||||
Ip = I * Io + Q * Qo; | |||||
Qp = Q * Io - I * Qo; | |||||
DPhi = Phase(Ip, Qp); | |||||
Ip = I * Io + Q * Qo; | |||||
Qp = Q * Io - I * Qo; | |||||
DPhi = Phase(Ip, Qp); | |||||
// Loop filter | // Loop filter | ||||
PhaseOsc += 2.0 * M_PI * (K1 * DPhi + FreqOsc); | |||||
if (PhaseOsc > M_PI) | |||||
PhaseOsc += 2.0 * M_PI * (K1 * DPhi + FreqOsc); | |||||
if (PhaseOsc > M_PI) | |||||
PhaseOsc -= 2.0 * M_PI; | PhaseOsc -= 2.0 * M_PI; | ||||
if (PhaseOsc <= -M_PI) | |||||
if (PhaseOsc <= -M_PI) | |||||
PhaseOsc += 2.0 * M_PI; | PhaseOsc += 2.0 * M_PI; | ||||
FreqOsc += K2 * DPhi; | |||||
if (FreqOsc > ((Fc + DFc) / Fe)) | |||||
FreqOsc += K2 * DPhi; | |||||
if (FreqOsc > ((Fc + DFc) / Fe)) | |||||
FreqOsc = (Fc + DFc) / Fe; | FreqOsc = (Fc + DFc) / Fe; | ||||
if (FreqOsc < ((Fc - DFc) / Fe)) | |||||
if (FreqOsc < ((Fc - DFc) / Fe)) | |||||
FreqOsc = (Fc - DFc) / Fe; | FreqOsc = (Fc - DFc) / Fe; | ||||
return Ip; | |||||
return Ip; | |||||
} | } | ||||
// Convert samples into pixels | // Convert samples into pixels | ||||
static int getamp(double *ampbuff, int count) { | static int getamp(double *ampbuff, int count) { | ||||
static float inbuff[BLKIN]; | |||||
static int idxin = 0; | |||||
static int nin = 0; | |||||
static float inbuff[BLKIN]; | |||||
static int idxin = 0; | |||||
static int nin = 0; | |||||
for (int n = 0; n < count; n++) { | |||||
double I, Q; | |||||
for (int n = 0; n < count; n++) { | |||||
double I, Q; | |||||
// Get some more samples when needed | // Get some more samples when needed | ||||
if (nin < IQFilterLen * 2 + 2) { | if (nin < IQFilterLen * 2 + 2) { | ||||
@@ -147,11 +147,11 @@ static int getamp(double *ampbuff, int count) { | |||||
int res; | int res; | ||||
memmove(inbuff, &(inbuff[idxin]), nin * sizeof(float)); | memmove(inbuff, &(inbuff[idxin]), nin * sizeof(float)); | ||||
idxin = 0; | idxin = 0; | ||||
// Read some samples | // Read some samples | ||||
res = getsample(&(inbuff[nin]), BLKIN - nin); | res = getsample(&(inbuff[nin]), BLKIN - nin); | ||||
nin += res; | nin += res; | ||||
// Make sure there is enough samples to continue | // Make sure there is enough samples to continue | ||||
if (nin < IQFilterLen * 2 + 2) | if (nin < IQFilterLen * 2 + 2) | ||||
return n; | return n; | ||||
@@ -164,25 +164,25 @@ static int getamp(double *ampbuff, int count) { | |||||
// Increment current sample | // Increment current sample | ||||
idxin++; | idxin++; | ||||
nin--; | nin--; | ||||
} | |||||
} | |||||
return count; | |||||
return count; | |||||
} | } | ||||
// Sub-pixel offsetting + FIR compensation | // Sub-pixel offsetting + FIR compensation | ||||
int getpixelv(float *pvbuff, int count) { | int getpixelv(float *pvbuff, int count) { | ||||
// Amplitude buffer | // Amplitude buffer | ||||
static double ampbuff[BLKAMP]; | |||||
static int nam = 0; | |||||
static int idxam = 0; | |||||
static double ampbuff[BLKAMP]; | |||||
static int nam = 0; | |||||
static int idxam = 0; | |||||
double mult; | |||||
double mult; | |||||
// Gaussian resampling factor | // Gaussian resampling factor | ||||
mult = (double) Fi / Fe * FreqLine; | |||||
int m = RSFilterLen / mult + 1; | |||||
mult = (double) Fi / Fe * FreqLine; | |||||
int m = RSFilterLen / mult + 1; | |||||
for (int n = 0; n < count; n++) { | |||||
for (int n = 0; n < count; n++) { | |||||
int shift; | int shift; | ||||
if (nam < m) { | if (nam < m) { | ||||
@@ -203,53 +203,53 @@ int getpixelv(float *pvbuff, int count) { | |||||
idxam += shift; | idxam += shift; | ||||
nam -= shift; | nam -= shift; | ||||
} | |||||
return count; | |||||
} | |||||
return count; | |||||
} | } | ||||
// Get an entire row of pixels, aligned with sync markers | // Get an entire row of pixels, aligned with sync markers | ||||
// FIXME: skips noisy lines with no findable sync marker | // FIXME: skips noisy lines with no findable sync marker | ||||
int getpixelrow(float *pixelv, int nrow, int *zenith) { | int getpixelrow(float *pixelv, int nrow, int *zenith) { | ||||
static float pixels[PixelLine + SyncFilterLen]; | |||||
static int npv; | |||||
static int synced = 0; | |||||
static double max = 0.0; | |||||
static float pixels[PixelLine + SyncFilterLen]; | |||||
static int npv; | |||||
static int synced = 0; | |||||
static double max = 0.0; | |||||
static double minDoppler = 100; | static double minDoppler = 100; | ||||
double corr, ecorr, lcorr; | |||||
int res; | |||||
double corr, ecorr, lcorr; | |||||
int res; | |||||
// Move the row buffer into the the image buffer | // Move the row buffer into the the image buffer | ||||
if (npv > 0) | |||||
if (npv > 0) | |||||
memmove(pixelv, pixels, npv * sizeof(float)); | memmove(pixelv, pixels, npv * sizeof(float)); | ||||
// Get the sync line | // Get the sync line | ||||
if (npv < SyncFilterLen + 2) { | |||||
if (npv < SyncFilterLen + 2) { | |||||
res = getpixelv(&(pixelv[npv]), SyncFilterLen + 2 - npv); | res = getpixelv(&(pixelv[npv]), SyncFilterLen + 2 - npv); | ||||
npv += res; | npv += res; | ||||
if (npv < SyncFilterLen + 2) | if (npv < SyncFilterLen + 2) | ||||
return 0; | return 0; | ||||
} | |||||
} | |||||
// Calculate the frequency offset | |||||
ecorr = fir(pixelv, Sync, SyncFilterLen); | |||||
corr = fir(&pixelv[1], Sync, SyncFilterLen - 1); | |||||
lcorr = fir(&pixelv[2], Sync, SyncFilterLen - 2); | |||||
FreqLine = 1.0+((ecorr-lcorr) / corr / PixelLine / 4.0); | |||||
// Calculate the frequency offset | |||||
ecorr = fir(pixelv, Sync, SyncFilterLen); | |||||
corr = fir(&pixelv[1], Sync, SyncFilterLen - 1); | |||||
lcorr = fir(&pixelv[2], Sync, SyncFilterLen - 2); | |||||
FreqLine = 1.0+((ecorr-lcorr) / corr / PixelLine / 4.0); | |||||
// Find the point in which ecorr and lcorr intercept | // Find the point in which ecorr and lcorr intercept | ||||
if(fabs(lcorr - ecorr) < minDoppler && fabs(lcorr - ecorr) > 2){ | if(fabs(lcorr - ecorr) < minDoppler && fabs(lcorr - ecorr) > 2){ | ||||
minDoppler = fabs(lcorr - ecorr); | minDoppler = fabs(lcorr - ecorr); | ||||
*zenith = nrow; | *zenith = nrow; | ||||
} | } | ||||
// The point in which the pixel offset is recalculated | // The point in which the pixel offset is recalculated | ||||
if (corr < 0.75 * max) { | |||||
if (corr < 0.75 * max) { | |||||
synced = 0; | synced = 0; | ||||
FreqLine = 1.0; | FreqLine = 1.0; | ||||
} | |||||
max = corr; | |||||
} | |||||
max = corr; | |||||
if (synced < 8) { | if (synced < 8) { | ||||
int mshift; | int mshift; | ||||
@@ -285,20 +285,20 @@ int getpixelrow(float *pixelv, int nrow, int *zenith) { | |||||
} | } | ||||
// Get the rest of this row | // Get the rest of this row | ||||
if (npv < PixelLine) { | |||||
if (npv < PixelLine) { | |||||
res = getpixelv(&(pixelv[npv]), PixelLine - npv); | res = getpixelv(&(pixelv[npv]), PixelLine - npv); | ||||
npv += res; | npv += res; | ||||
if (npv < PixelLine) | if (npv < PixelLine) | ||||
return 0; | return 0; | ||||
} | |||||
} | |||||
// Move the sync lines into the output buffer with the calculated offset | // Move the sync lines into the output buffer with the calculated offset | ||||
if (npv == PixelLine) { | |||||
if (npv == PixelLine) { | |||||
npv = 0; | npv = 0; | ||||
} else { | |||||
} else { | |||||
memmove(pixels, &(pixelv[PixelLine]), (npv - PixelLine) * sizeof(float)); | memmove(pixels, &(pixelv[PixelLine]), (npv - PixelLine) * sizeof(float)); | ||||
npv -= PixelLine; | npv -= PixelLine; | ||||
} | |||||
} | |||||
return 1; | |||||
return 1; | |||||
} | } |
@@ -23,45 +23,45 @@ | |||||
// Finite impulse response | // Finite impulse response | ||||
float fir(float *buff, const float *coeff, const int len) { | float fir(float *buff, const float *coeff, const int len) { | ||||
double r; | |||||
double r; | |||||
r = 0.0; | |||||
for (int i = 0; i < len; i++) { | |||||
r += buff[i] * coeff[i]; | |||||
} | |||||
return r; | |||||
r = 0.0; | |||||
for (int i = 0; i < len; i++) { | |||||
r += buff[i] * coeff[i]; | |||||
} | |||||
return r; | |||||
} | } | ||||
/* IQ finite impulse response | /* IQ finite impulse response | ||||
* Turn samples into a single IQ sample | * Turn samples into a single IQ sample | ||||
*/ | */ | ||||
void iqfir(float *buff, const float *coeff, const int len, double *I, double *Q) { | void iqfir(float *buff, const float *coeff, const int len, double *I, double *Q) { | ||||
double i = 0.0, q = 0.0; | |||||
double i = 0.0, q = 0.0; | |||||
for (int k = 0; k < len; k++) { | |||||
q += buff[2*k] * coeff[k]; | |||||
i += buff[2*k]; | |||||
} | |||||
for (int k = 0; k < len; k++) { | |||||
q += buff[2*k] * coeff[k]; | |||||
i += buff[2*k]; | |||||
} | |||||
i = buff[len-1] - (i / len); | |||||
*I = i, *Q = q; | |||||
i = buff[len-1] - (i / len); | |||||
*I = i, *Q = q; | |||||
} | } | ||||
/* Gaussian finite impulse responce compensation | /* Gaussian finite impulse responce compensation | ||||
* https://www.recordingblogs.com/wiki/gaussian-window | * https://www.recordingblogs.com/wiki/gaussian-window | ||||
*/ | */ | ||||
float rsfir(double *buff, const float *coeff, const int len, const double offset, const double delta) { | float rsfir(double *buff, const float *coeff, const int len, const double offset, const double delta) { | ||||
double out; | |||||
double out; | |||||
out = 0.0; | |||||
double n = offset; | |||||
for (int i = 0; i < (len-1)/delta-1; n += delta, i++) { | |||||
int k; | |||||
double alpha; | |||||
out = 0.0; | |||||
double n = offset; | |||||
for (int i = 0; i < (len-1)/delta-1; n += delta, i++) { | |||||
int k; | |||||
double alpha; | |||||
k = (int)floor(n); | |||||
alpha = n - k; | |||||
out += buff[i] * (coeff[k] * (1.0 - alpha) + coeff[k + 1] * alpha); | |||||
} | |||||
return out; | |||||
k = (int)floor(n); | |||||
alpha = n - k; | |||||
out += buff[i] * (coeff[k] * (1.0 - alpha) + coeff[k + 1] * alpha); | |||||
} | |||||
return out; | |||||
} | } |
@@ -35,22 +35,22 @@ extern void polyreg(const int m, const int n, const double x[], const double y[] | |||||
// Compute regression | // Compute regression | ||||
static void rgcomp(double x[16], rgparam_t * rgpr) { | static void rgcomp(double x[16], rgparam_t * rgpr) { | ||||
// { 0.106, 0.215, 0.324, 0.433, 0.542, 0.652, 0.78, 0.87, 0.0 } | |||||
const double y[9] = { 31.07, 63.02, 94.96, 126.9, 158.86, 191.1, 228.62, 255.0, 0.0 }; | |||||
// { 0.106, 0.215, 0.324, 0.433, 0.542, 0.652, 0.78, 0.87, 0.0 } | |||||
const double y[9] = { 31.07, 63.02, 94.96, 126.9, 158.86, 191.1, 228.62, 255.0, 0.0 }; | |||||
polyreg(REGORDER, 9, x, y, rgpr->cf); | |||||
polyreg(REGORDER, 9, x, y, rgpr->cf); | |||||
} | } | ||||
// Convert a value to 0-255 based off the provided regression curve | // Convert a value to 0-255 based off the provided regression curve | ||||
static double rgcal(float x, rgparam_t *rgpr) { | static double rgcal(float x, rgparam_t *rgpr) { | ||||
double y, p; | |||||
double y, p; | |||||
int i; | int i; | ||||
for (i = 0, y = 0.0, p = 1.0; i < REGORDER + 1; i++) { | |||||
for (i = 0, y = 0.0, p = 1.0; i < REGORDER + 1; i++) { | |||||
y += rgpr->cf[i] * p; | y += rgpr->cf[i] * p; | ||||
p = p * x; | p = p * x; | ||||
} | |||||
return y; | |||||
} | |||||
return y; | |||||
} | } | ||||
static double tele[16]; | static double tele[16]; | ||||
@@ -119,38 +119,38 @@ double teleNoise(double wedges[16]){ | |||||
double noise = 0; | double noise = 0; | ||||
for(int i = 0; i < 9; i++) | for(int i = 0; i < 9; i++) | ||||
noise += fabs(wedges[i] - pattern[i]); | noise += fabs(wedges[i] - pattern[i]); | ||||
return noise; | return noise; | ||||
} | } | ||||
// Get telemetry data for thermal calibration/equalization | // Get telemetry data for thermal calibration/equalization | ||||
int calibrate(float **prow, int nrow, int offset, int width) { | int calibrate(float **prow, int nrow, int offset, int width) { | ||||
double teleline[MAX_HEIGHT] = { 0.0 }; | double teleline[MAX_HEIGHT] = { 0.0 }; | ||||
double wedge[16]; | |||||
rgparam_t regr[MAX_HEIGHT/FRAME_LEN + 1]; | |||||
int telestart, mtelestart = 0; | |||||
double wedge[16]; | |||||
rgparam_t regr[MAX_HEIGHT/FRAME_LEN + 1]; | |||||
int telestart, mtelestart = 0; | |||||
int channel = -1; | int channel = -1; | ||||
// The minimum rows required to decode a full frame | // The minimum rows required to decode a full frame | ||||
if (nrow < 192) { | |||||
if (nrow < 192) { | |||||
fprintf(stderr, "Telemetry decoding error, not enough rows\n"); | fprintf(stderr, "Telemetry decoding error, not enough rows\n"); | ||||
return 0; | return 0; | ||||
} | |||||
} | |||||
// Calculate average of a row of telemetry | // Calculate average of a row of telemetry | ||||
for (int y = 0; y < nrow; y++) { | |||||
for (int y = 0; y < nrow; y++) { | |||||
for (int x = 3; x < 43; x++) | for (int x = 3; x < 43; x++) | ||||
teleline[y] += prow[y][x + offset + width]; | teleline[y] += prow[y][x + offset + width]; | ||||
teleline[y] /= 40.0; | teleline[y] /= 40.0; | ||||
} | |||||
} | |||||
/* Wedge 7 is white and 8 is black, this will have the largest | /* Wedge 7 is white and 8 is black, this will have the largest | ||||
* difference in brightness, this can be used to find the current | * difference in brightness, this can be used to find the current | ||||
* position within the telemetry. | * position within the telemetry. | ||||
*/ | */ | ||||
float max = 0.0f; | float max = 0.0f; | ||||
for (int n = nrow / 3 - 64; n < 2 * nrow / 3 - 64; n++) { | |||||
for (int n = nrow / 3 - 64; n < 2 * nrow / 3 - 64; n++) { | |||||
float df; | float df; | ||||
// (sum 4px below) / (sum 4px above) | // (sum 4px below) / (sum 4px above) | ||||
@@ -162,20 +162,20 @@ int calibrate(float **prow, int nrow, int offset, int width) { | |||||
mtelestart = n; | mtelestart = n; | ||||
max = df; | max = df; | ||||
} | } | ||||
} | |||||
} | |||||
telestart = (mtelestart - 64) % FRAME_LEN; | |||||
telestart = (mtelestart - 64) % FRAME_LEN; | |||||
// Make sure that theres at least one full frame in the image | |||||
if (nrow < telestart + FRAME_LEN) { | |||||
// Make sure that theres at least one full frame in the image | |||||
if (nrow < telestart + FRAME_LEN) { | |||||
fprintf(stderr, "Telemetry decoding error, not enough rows\n"); | fprintf(stderr, "Telemetry decoding error, not enough rows\n"); | ||||
return 0; | return 0; | ||||
} | |||||
} | |||||
// Find the least noisy frame | // Find the least noisy frame | ||||
double minNoise = -1; | double minNoise = -1; | ||||
int bestFrame = -1; | int bestFrame = -1; | ||||
for (int n = telestart, k = 0; n < nrow - FRAME_LEN; n += FRAME_LEN, k++) { | |||||
for (int n = telestart, k = 0; n < nrow - FRAME_LEN; n += FRAME_LEN, k++) { | |||||
int j; | int j; | ||||
for (j = 0; j < 16; j++) { | for (j = 0; j < 16; j++) { | ||||
@@ -228,7 +228,7 @@ int calibrate(float **prow, int nrow, int offset, int width) { | |||||
} | } | ||||
Cs = rgcal(Cs / i, ®r[k]); | Cs = rgcal(Cs / i, ®r[k]); | ||||
} | } | ||||
} | |||||
} | |||||
if(bestFrame == -1){ | if(bestFrame == -1){ | ||||
fprintf(stderr, "Something has gone very wrong, please file a bug report."); | fprintf(stderr, "Something has gone very wrong, please file a bug report."); | ||||
@@ -237,8 +237,8 @@ int calibrate(float **prow, int nrow, int offset, int width) { | |||||
calibrateImage(prow, nrow, offset, width, regr[bestFrame]); | calibrateImage(prow, nrow, offset, width, regr[bestFrame]); | ||||
return channel + 1; | |||||
return channel + 1; | |||||
} | } | ||||
void distrib(options_t *opts, image_t *img, char *chid) { | void distrib(options_t *opts, image_t *img, char *chid) { | ||||
@@ -261,7 +261,7 @@ void distrib(options_t *opts, image_t *img, char *chid) { | |||||
for(int n = 0; n < img->nrow; n++) { | for(int n = 0; n < img->nrow; n++) { | ||||
float *pixelv = img->prow[n]; | float *pixelv = img->prow[n]; | ||||
for(int i = 0; i < CH_WIDTH; i++) { | for(int i = 0; i < CH_WIDTH; i++) { | ||||
int y = CLIP((int)pixelv[i + CHA_OFFSET], 0, 255); | int y = CLIP((int)pixelv[i + CHA_OFFSET], 0, 255); | ||||
int x = CLIP((int)pixelv[i + CHB_OFFSET], 0, 255); | int x = CLIP((int)pixelv[i + CHB_OFFSET], 0, 255); | ||||
@@ -275,7 +275,7 @@ void distrib(options_t *opts, image_t *img, char *chid) { | |||||
for(int x = 0; x < 256; x++) | for(int x = 0; x < 256; x++) | ||||
for(int y = 0; y < 256; y++) | for(int y = 0; y < 256; y++) | ||||
distrib.prow[y][x] = distrib.prow[y][x] / max * 255.0; | distrib.prow[y][x] = distrib.prow[y][x] / max * 255.0; | ||||
extern int ImageOut(options_t *opts, image_t *img, int offset, int width, char *desc, char *chid, char *palette); | extern int ImageOut(options_t *opts, image_t *img, int offset, int width, char *desc, char *chid, char *palette); | ||||
ImageOut(&options, &distrib, 0, 256, "Distribution", chid, NULL); | ImageOut(&options, &distrib, 0, 256, "Distribution", chid, NULL); | ||||
} | } | ||||
@@ -319,21 +319,21 @@ void flipImage(image_t *img, int width, int offset){ | |||||
#include "satcal.h" | #include "satcal.h" | ||||
typedef struct { | typedef struct { | ||||
double Nbb; | |||||
double Cs; | |||||
double Cb; | |||||
int ch; | |||||
double Nbb; | |||||
double Cs; | |||||
double Cb; | |||||
int ch; | |||||
} tempparam_t; | } tempparam_t; | ||||
// IR channel temperature compensation | // IR channel temperature compensation | ||||
static void tempcomp(double t[16], int ch, int satnum, tempparam_t *tpr) { | static void tempcomp(double t[16], int ch, int satnum, tempparam_t *tpr) { | ||||
double Tbb, T[4]; | |||||
double C; | |||||
double Tbb, T[4]; | |||||
double C; | |||||
tpr->ch = ch - 4; | |||||
tpr->ch = ch - 4; | |||||
// Compute equivalent T blackbody temperature | |||||
for (int n = 0; n < 4; n++) { | |||||
// Compute equivalent T blackbody temperature | |||||
for (int n = 0; n < 4; n++) { | |||||
float d0, d1, d2; | float d0, d1, d2; | ||||
C = t[9 + n] * 4.0; | C = t[9 + n] * 4.0; | ||||
@@ -344,57 +344,57 @@ static void tempcomp(double t[16], int ch, int satnum, tempparam_t *tpr) { | |||||
T[n] += d1 * C; | T[n] += d1 * C; | ||||
C *= C; | C *= C; | ||||
T[n] += d2 * C; | T[n] += d2 * C; | ||||
} | |||||
Tbb = (T[0] + T[1] + T[2] + T[3]) / 4.0; | |||||
Tbb = satcal[satnum].rad[tpr->ch].A + satcal[satnum].rad[tpr->ch].B * Tbb; | |||||
} | |||||
Tbb = (T[0] + T[1] + T[2] + T[3]) / 4.0; | |||||
Tbb = satcal[satnum].rad[tpr->ch].A + satcal[satnum].rad[tpr->ch].B * Tbb; | |||||
// Compute blackbody radiance temperature | |||||
C = satcal[satnum].rad[tpr->ch].vc; | |||||
tpr->Nbb = c1 * C * C * C / (expm1(c2 * C / Tbb)); | |||||
// Compute blackbody radiance temperature | |||||
C = satcal[satnum].rad[tpr->ch].vc; | |||||
tpr->Nbb = c1 * C * C * C / (expm1(c2 * C / Tbb)); | |||||
// Store blackbody count and space | |||||
tpr->Cs = Cs * 4.0; | |||||
tpr->Cb = t[14] * 4.0; | |||||
// Store blackbody count and space | |||||
tpr->Cs = Cs * 4.0; | |||||
tpr->Cb = t[14] * 4.0; | |||||
} | } | ||||
// IR channel temperature calibration | // IR channel temperature calibration | ||||
static double tempcal(float Ce, int satnum, tempparam_t * rgpr) { | static double tempcal(float Ce, int satnum, tempparam_t * rgpr) { | ||||
double Nl, Nc, Ns, Ne; | |||||
double T, vc; | |||||
double Nl, Nc, Ns, Ne; | |||||
double T, vc; | |||||
Ns = satcal[satnum].cor[rgpr->ch].Ns; | |||||
Nl = Ns + (rgpr->Nbb - Ns) * (rgpr->Cs - Ce * 4.0) / (rgpr->Cs - rgpr->Cb); | |||||
Nc = satcal[satnum].cor[rgpr->ch].b[0] + | |||||
Ns = satcal[satnum].cor[rgpr->ch].Ns; | |||||
Nl = Ns + (rgpr->Nbb - Ns) * (rgpr->Cs - Ce * 4.0) / (rgpr->Cs - rgpr->Cb); | |||||
Nc = satcal[satnum].cor[rgpr->ch].b[0] + | |||||
satcal[satnum].cor[rgpr->ch].b[1] * Nl + | satcal[satnum].cor[rgpr->ch].b[1] * Nl + | ||||
satcal[satnum].cor[rgpr->ch].b[2] * Nl * Nl; | satcal[satnum].cor[rgpr->ch].b[2] * Nl * Nl; | ||||
Ne = Nl + Nc; | |||||
Ne = Nl + Nc; | |||||
vc = satcal[satnum].rad[rgpr->ch].vc; | |||||
T = c2 * vc / log(c1 * vc * vc * vc / Ne + 1.0); | |||||
T = (T - satcal[satnum].rad[rgpr->ch].A) / satcal[satnum].rad[rgpr->ch].B; | |||||
vc = satcal[satnum].rad[rgpr->ch].vc; | |||||
T = c2 * vc / log(c1 * vc * vc * vc / Ne + 1.0); | |||||
T = (T - satcal[satnum].rad[rgpr->ch].A) / satcal[satnum].rad[rgpr->ch].B; | |||||
// Convert to celsius | // Convert to celsius | ||||
T -= 273.15; | T -= 273.15; | ||||
// Rescale to 0-255 for -100°C to +60°C | |||||
T = (T + 100.0) / 160.0 * 255.0; | |||||
// Rescale to 0-255 for -100°C to +60°C | |||||
T = (T + 100.0) / 160.0 * 255.0; | |||||
return T; | return T; | ||||
} | } | ||||
// Temperature calibration wrapper | // Temperature calibration wrapper | ||||
void temperature(options_t *opts, image_t *img, int offset, int width){ | void temperature(options_t *opts, image_t *img, int offset, int width){ | ||||
tempparam_t temp; | |||||
tempparam_t temp; | |||||
printf("Temperature... "); | |||||
fflush(stdout); | |||||
printf("Temperature... "); | |||||
fflush(stdout); | |||||
tempcomp(tele, img->chB, opts->satnum - 15, &temp); | |||||
tempcomp(tele, img->chB, opts->satnum - 15, &temp); | |||||
for (int y = 0; y < img->nrow; y++) { | |||||
for (int x = 0; x < width; x++) { | |||||
for (int y = 0; y < img->nrow; y++) { | |||||
for (int x = 0; x < width; x++) { | |||||
img->prow[y][x + offset] = tempcal(img->prow[y][x + offset], opts->satnum - 15, &temp); | img->prow[y][x + offset] = tempcal(img->prow[y][x + offset], opts->satnum - 15, &temp); | ||||
} | } | ||||
} | |||||
printf("Done\n"); | |||||
} | |||||
printf("Done\n"); | |||||
} | } |
@@ -66,7 +66,7 @@ static int processAudio(char *filename, options_t *opts); | |||||
static void usage(void); | static void usage(void); | ||||
int main(int argc, char **argv) { | int main(int argc, char **argv) { | ||||
fprintf(stderr, VERSION"\n"); | |||||
fprintf(stderr, VERSION"\n"); | |||||
// Check if there are actually any input files | // Check if there are actually any input files | ||||
if(argc == optind || argc == 1){ | if(argc == optind || argc == 1){ | ||||
@@ -78,7 +78,7 @@ int main(int argc, char **argv) { | |||||
// Parse arguments | // Parse arguments | ||||
int opt; | int opt; | ||||
while ((opt = getopt(argc, argv, "m:d:i:s:e:r")) != EOF) { | |||||
while ((opt = getopt(argc, argv, "m:d:i:s:e:r")) != EOF) { | |||||
switch (opt) { | switch (opt) { | ||||
case 'd': | case 'd': | ||||
opts.path = optarg; | opts.path = optarg; | ||||
@@ -105,14 +105,14 @@ int main(int argc, char **argv) { | |||||
default: | default: | ||||
usage(); | usage(); | ||||
} | } | ||||
} | |||||
} | |||||
// Process the files | // Process the files | ||||
for (; optind < argc; optind++) { | for (; optind < argc; optind++) { | ||||
processAudio(argv[optind], &opts); | processAudio(argv[optind], &opts); | ||||
} | } | ||||
exit(0); | |||||
exit(0); | |||||
} | } | ||||
static int processAudio(char *filename, options_t *opts){ | static int processAudio(char *filename, options_t *opts){ | ||||
@@ -124,7 +124,7 @@ static int processAudio(char *filename, options_t *opts){ | |||||
char *id[7]; | char *id[7]; | ||||
char *name[7]; | char *name[7]; | ||||
} ch = { | } ch = { | ||||
{ "?", "1", "2", "3A", "4", "5", "3B" }, | |||||
{ "?", "1", "2", "3A", "4", "5", "3B" }, | |||||
{ "unknown", "visble", "near-infrared", "mid-infrared", "thermal-infrared", "thermal-infrared", "mid-infrared" } | { "unknown", "visble", "near-infrared", "mid-infrared", "thermal-infrared", "thermal-infrared", "mid-infrared" } | ||||
}; | }; | ||||
@@ -163,7 +163,7 @@ static int processAudio(char *filename, options_t *opts){ | |||||
for (img.nrow = 0; img.nrow < MAX_HEIGHT; img.nrow++) { | for (img.nrow = 0; img.nrow < MAX_HEIGHT; img.nrow++) { | ||||
// Allocate memory for this row | // Allocate memory for this row | ||||
img.prow[img.nrow] = (float *) malloc(sizeof(float) * 2150); | img.prow[img.nrow] = (float *) malloc(sizeof(float) * 2150); | ||||
// Write into memory and break the loop when there are no more samples to read | // Write into memory and break the loop when there are no more samples to read | ||||
if (getpixelrow(img.prow[img.nrow], img.nrow, &zenith) == 0) | if (getpixelrow(img.prow[img.nrow], img.nrow, &zenith) == 0) | ||||
break; | break; | ||||
@@ -259,40 +259,40 @@ static int processAudio(char *filename, options_t *opts){ | |||||
// Distribution image | // Distribution image | ||||
if (CONTAINS(opts->type, 'd')) | if (CONTAINS(opts->type, 'd')) | ||||
distrib(opts, &img, "d"); | distrib(opts, &img, "d"); | ||||
return 1; | return 1; | ||||
} | } | ||||
static int initsnd(char *filename) { | static int initsnd(char *filename) { | ||||
SF_INFO infwav; | |||||
int res; | |||||
SF_INFO infwav; | |||||
int res; | |||||
// Open audio file | // Open audio file | ||||
infwav.format = 0; | |||||
audioFile = sf_open(filename, SFM_READ, &infwav); | |||||
if (audioFile == NULL) { | |||||
infwav.format = 0; | |||||
audioFile = sf_open(filename, SFM_READ, &infwav); | |||||
if (audioFile == NULL) { | |||||
fprintf(stderr, "Could not open %s for reading\n", filename); | fprintf(stderr, "Could not open %s for reading\n", filename); | ||||
return 0; | return 0; | ||||
} | |||||
} | |||||
res = init_dsp(infwav.samplerate); | |||||
res = init_dsp(infwav.samplerate); | |||||
printf("Input file: %s\n", filename); | printf("Input file: %s\n", filename); | ||||
if(res < 0) { | |||||
if(res < 0) { | |||||
fprintf(stderr, "Input sample rate too low: %d\n", infwav.samplerate); | fprintf(stderr, "Input sample rate too low: %d\n", infwav.samplerate); | ||||
return 0; | return 0; | ||||
}else if(res > 0) { | |||||
}else if(res > 0) { | |||||
fprintf(stderr, "Input sample rate too high: %d\n", infwav.samplerate); | fprintf(stderr, "Input sample rate too high: %d\n", infwav.samplerate); | ||||
return 0; | return 0; | ||||
} | |||||
printf("Input sample rate: %d\n", infwav.samplerate); | |||||
} | |||||
printf("Input sample rate: %d\n", infwav.samplerate); | |||||
// TODO: accept stereo audio | // TODO: accept stereo audio | ||||
if (infwav.channels != 1) { | |||||
if (infwav.channels != 1) { | |||||
fprintf(stderr, "Too many channels in input file: %d\n", infwav.channels); | fprintf(stderr, "Too many channels in input file: %d\n", infwav.channels); | ||||
return 0; | return 0; | ||||
} | |||||
} | |||||
return 1; | |||||
return 1; | |||||
} | } | ||||
// Read samples from the wave file | // Read samples from the wave file | ||||
@@ -301,28 +301,28 @@ int getsample(float *sample, int nb) { | |||||
} | } | ||||
static void usage(void) { | static void usage(void) { | ||||
fprintf(stderr, | |||||
fprintf(stderr, | |||||
"Aptdec [options] audio files ...\n" | "Aptdec [options] audio files ...\n" | ||||
"Options:\n" | "Options:\n" | ||||
" -e [t|h|d|p|f|l] Effects\n" | " -e [t|h|d|p|f|l] Effects\n" | ||||
" t: Crop telemetry\n" | |||||
" h: Histogram equalise\n" | |||||
" d: Denoise\n" | |||||
" p: Precipitation\n" | |||||
" f: Flip image\n" | |||||
" l: Linear equalise\n" | |||||
" t: Crop telemetry\n" | |||||
" h: Histogram equalise\n" | |||||
" d: Denoise\n" | |||||
" p: Precipitation\n" | |||||
" f: Flip image\n" | |||||
" l: Linear equalise\n" | |||||
" -i [r|a|b|c|t|m] Output image\n" | " -i [r|a|b|c|t|m] Output image\n" | ||||
" r: Raw\n" | |||||
" a: Channel A\n" | |||||
" b: Channel B\n" | |||||
" c: False color\n" | |||||
" t: Temperature\n" | |||||
" m: MCIR\n" | |||||
" -d <dir> Image destination directory.\n" | |||||
" -s [15-19] Satellite number\n" | |||||
" -m <file> Map file\n" | |||||
" -r Realtime decode\n" | |||||
" r: Raw\n" | |||||
" a: Channel A\n" | |||||
" b: Channel B\n" | |||||
" c: False color\n" | |||||
" t: Temperature\n" | |||||
" m: MCIR\n" | |||||
" -d <dir> Image destination directory.\n" | |||||
" -s [15-19] Satellite number\n" | |||||
" -m <file> Map file\n" | |||||
" -r Realtime decode\n" | |||||
"\nRefer to the README for more infomation\n"); | "\nRefer to the README for more infomation\n"); | ||||
exit(EINVAL); | |||||
exit(EINVAL); | |||||
} | } |
@@ -7,24 +7,24 @@ | |||||
#define ELEM_SWAP(a, b) { register float t = (a); (a) = (b); (b) = t; } | #define ELEM_SWAP(a, b) { register float t = (a); (a) = (b); (b) = t; } | ||||
float quick_select(float arr[], int n) { | float quick_select(float arr[], int n) { | ||||
int low, median, high; | |||||
int middle, ll, hh; | |||||
low = 0; high = n-1; median = (low + high) / 2; | |||||
for (;;) { | |||||
if (high <= low) /* One element only */ | |||||
return arr[median] ; | |||||
if (high == low + 1) { /* Two elements only */ | |||||
if (arr[low] > arr[high]) | |||||
ELEM_SWAP(arr[low], arr[high]); | |||||
return arr[median]; | |||||
} | |||||
int low, median, high; | |||||
int middle, ll, hh; | |||||
low = 0; high = n-1; median = (low + high) / 2; | |||||
for (;;) { | |||||
if (high <= low) /* One element only */ | |||||
return arr[median] ; | |||||
if (high == low + 1) { /* Two elements only */ | |||||
if (arr[low] > arr[high]) | |||||
ELEM_SWAP(arr[low], arr[high]); | |||||
return arr[median]; | |||||
} | |||||
/* Find median of low, middle and high items; swap into position low */ | /* Find median of low, middle and high items; swap into position low */ | ||||
middle = (low + high) / 2; | middle = (low + high) / 2; | ||||
if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]); | if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]); | ||||
if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]); | |||||
if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]); | |||||
if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]); | if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]); | ||||
/* Swap low item (now in position middle) into position (low+1) */ | /* Swap low item (now in position middle) into position (low+1) */ | ||||
@@ -51,6 +51,6 @@ float quick_select(float arr[], int n) { | |||||
low = ll; | low = ll; | ||||
if (hh >= median) | if (hh >= median) | ||||
high = hh - 1; | high = hh - 1; | ||||
} | |||||
} | |||||
} | } | ||||
#undef ELEM_SWAP | #undef ELEM_SWAP |
@@ -191,8 +191,8 @@ png_text meta[] = { | |||||
int ImageOut(options_t *opts, image_t *img, int offset, int width, char *desc, char *chid, char *palette){ | int ImageOut(options_t *opts, image_t *img, int offset, int width, char *desc, char *chid, char *palette){ | ||||
char outName[384]; | char outName[384]; | ||||
sprintf(outName, "%s/%s-%s.png", opts->path, img->name, chid); | |||||
sprintf(outName, "%s/%s-%s.png", opts->path, img->name, chid); | |||||
meta[1].text = desc; | meta[1].text = desc; | ||||
meta[1].text_length = sizeof(desc); | meta[1].text_length = sizeof(desc); | ||||
@@ -208,24 +208,24 @@ int ImageOut(options_t *opts, image_t *img, int offset, int width, char *desc, c | |||||
} | } | ||||
// Create writer | // Create writer | ||||
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | |||||
if (!png_ptr) { | |||||
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | |||||
if (!png_ptr) { | |||||
png_destroy_write_struct(&png_ptr, (png_infopp) NULL); | png_destroy_write_struct(&png_ptr, (png_infopp) NULL); | ||||
fprintf(stderr, "Could not create a PNG writer\n"); | fprintf(stderr, "Could not create a PNG writer\n"); | ||||
return 0; | return 0; | ||||
} | |||||
png_infop info_ptr = png_create_info_struct(png_ptr); | |||||
if (!info_ptr) { | |||||
} | |||||
png_infop info_ptr = png_create_info_struct(png_ptr); | |||||
if (!info_ptr) { | |||||
png_destroy_write_struct(&png_ptr, (png_infopp) NULL); | png_destroy_write_struct(&png_ptr, (png_infopp) NULL); | ||||
fprintf(stderr, "Could not create a PNG writer\n"); | fprintf(stderr, "Could not create a PNG writer\n"); | ||||
return 0; | return 0; | ||||
} | |||||
} | |||||
if(palette == NULL && !CONTAINS(opts->effects, 'p') && !fc && opts->map[0] == '\0' && strcmp(chid, "MCIR") != 0){ | if(palette == NULL && !CONTAINS(opts->effects, 'p') && !fc && opts->map[0] == '\0' && strcmp(chid, "MCIR") != 0){ | ||||
greyscale = 1; | greyscale = 1; | ||||
// Greyscale image | // Greyscale image | ||||
png_set_IHDR(png_ptr, info_ptr, width, img->nrow, | |||||
png_set_IHDR(png_ptr, info_ptr, width, img->nrow, | |||||
8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, | 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, | ||||
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); | PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); | ||||
}else{ | }else{ | ||||
@@ -235,17 +235,17 @@ int ImageOut(options_t *opts, image_t *img, int offset, int width, char *desc, c | |||||
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); | PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); | ||||
} | } | ||||
png_set_text(png_ptr, info_ptr, meta, 3); | |||||
png_set_pHYs(png_ptr, info_ptr, 3636, 3636, PNG_RESOLUTION_METER); | |||||
png_set_text(png_ptr, info_ptr, meta, 3); | |||||
png_set_pHYs(png_ptr, info_ptr, 3636, 3636, PNG_RESOLUTION_METER); | |||||
// Init I/O | // Init I/O | ||||
pngfile = fopen(outName, "wb"); | |||||
if (!pngfile) { | |||||
pngfile = fopen(outName, "wb"); | |||||
if (!pngfile) { | |||||
fprintf(stderr, "Could not open %s for writing\n", outName); | fprintf(stderr, "Could not open %s for writing\n", outName); | ||||
return 1; | return 1; | ||||
} | |||||
png_init_io(png_ptr, pngfile); | |||||
png_write_info(png_ptr, info_ptr); | |||||
} | |||||
png_init_io(png_ptr, pngfile); | |||||
png_write_info(png_ptr, info_ptr); | |||||
// Move prow into crow, crow ~ color rows | // Move prow into crow, crow ~ color rows | ||||
rgb_t *crow[img->nrow]; | rgb_t *crow[img->nrow]; | ||||
@@ -287,10 +287,10 @@ int ImageOut(options_t *opts, image_t *img, int offset, int width, char *desc, c | |||||
printf("Writing %s", outName); | printf("Writing %s", outName); | ||||
// Build image | // Build image | ||||
for (int y = 0; y < img->nrow; y++) { | |||||
for (int y = 0; y < img->nrow; y++) { | |||||
png_color pix[width]; // Color | png_color pix[width]; // Color | ||||
png_byte mpix[width]; // Mono | png_byte mpix[width]; // Mono | ||||
int skip = 0; | int skip = 0; | ||||
for (int x = 0; x < width; x++) { | for (int x = 0; x < width; x++) { | ||||
if(skiptele){ | if(skiptele){ | ||||
@@ -320,21 +320,21 @@ int ImageOut(options_t *opts, image_t *img, int offset, int width, char *desc, c | |||||
}; | }; | ||||
} | } | ||||
} | } | ||||
if(greyscale){ | if(greyscale){ | ||||
png_write_row(png_ptr, (png_bytep) mpix); | png_write_row(png_ptr, (png_bytep) mpix); | ||||
}else{ | }else{ | ||||
png_write_row(png_ptr, (png_bytep) pix); | png_write_row(png_ptr, (png_bytep) pix); | ||||
} | } | ||||
} | |||||
} | |||||
// Tidy up | // Tidy up | ||||
png_write_end(png_ptr, info_ptr); | |||||
fclose(pngfile); | |||||
printf("\nDone\n"); | |||||
png_destroy_write_struct(&png_ptr, &info_ptr); | |||||
png_write_end(png_ptr, info_ptr); | |||||
fclose(pngfile); | |||||
printf("\nDone\n"); | |||||
png_destroy_write_struct(&png_ptr, &info_ptr); | |||||
return 1; | |||||
return 1; | |||||
} | } | ||||
// TODO: clean up everthing below this comment | // TODO: clean up everthing below this comment | ||||
@@ -344,44 +344,44 @@ FILE *rt_pngfile; | |||||
int initWriter(options_t *opts, image_t *img, int width, int height, char *desc, char *chid){ | int initWriter(options_t *opts, image_t *img, int width, int height, char *desc, char *chid){ | ||||
char outName[384]; | char outName[384]; | ||||
sprintf(outName, "%s/%s-%s.png", opts->path, img->name, chid); | |||||
sprintf(outName, "%s/%s-%s.png", opts->path, img->name, chid); | |||||
meta[1].text = desc; | meta[1].text = desc; | ||||
meta[1].text_length = sizeof(desc); | meta[1].text_length = sizeof(desc); | ||||
// Create writer | // Create writer | ||||
rt_png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | |||||
if (!rt_png_ptr) { | |||||
rt_png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | |||||
if (!rt_png_ptr) { | |||||
png_destroy_write_struct(&rt_png_ptr, (png_infopp) NULL); | png_destroy_write_struct(&rt_png_ptr, (png_infopp) NULL); | ||||
fprintf(stderr, "Could not create a PNG writer\n"); | fprintf(stderr, "Could not create a PNG writer\n"); | ||||
return 0; | return 0; | ||||
} | |||||
rt_info_ptr = png_create_info_struct(rt_png_ptr); | |||||
if (!rt_info_ptr) { | |||||
} | |||||
rt_info_ptr = png_create_info_struct(rt_png_ptr); | |||||
if (!rt_info_ptr) { | |||||
png_destroy_write_struct(&rt_png_ptr, (png_infopp) NULL); | png_destroy_write_struct(&rt_png_ptr, (png_infopp) NULL); | ||||
fprintf(stderr, "Could not create a PNG writer\n"); | fprintf(stderr, "Could not create a PNG writer\n"); | ||||
return 0; | return 0; | ||||
} | |||||
} | |||||
// Greyscale image | // Greyscale image | ||||
png_set_IHDR(rt_png_ptr, rt_info_ptr, width, height, | |||||
png_set_IHDR(rt_png_ptr, rt_info_ptr, width, height, | |||||
8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, | 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, | ||||
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); | PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); | ||||
png_set_text(rt_png_ptr, rt_info_ptr, meta, 3); | png_set_text(rt_png_ptr, rt_info_ptr, meta, 3); | ||||
// Channel = 25cm wide | // Channel = 25cm wide | ||||
png_set_pHYs(rt_png_ptr, rt_info_ptr, 3636, 3636, PNG_RESOLUTION_METER); | |||||
png_set_pHYs(rt_png_ptr, rt_info_ptr, 3636, 3636, PNG_RESOLUTION_METER); | |||||
// Init I/O | // Init I/O | ||||
rt_pngfile = fopen(outName, "wb"); | |||||
if (!rt_pngfile) { | |||||
rt_pngfile = fopen(outName, "wb"); | |||||
if (!rt_pngfile) { | |||||
fprintf(stderr, "Could not open %s for writing\n", outName); | fprintf(stderr, "Could not open %s for writing\n", outName); | ||||
return 0; | return 0; | ||||
} | |||||
png_init_io(rt_png_ptr, rt_pngfile); | |||||
png_write_info(rt_png_ptr, rt_info_ptr); | |||||
} | |||||
png_init_io(rt_png_ptr, rt_pngfile); | |||||
png_write_info(rt_png_ptr, rt_info_ptr); | |||||
return 1; | return 1; | ||||
} | } | ||||
@@ -389,12 +389,12 @@ void pushRow(float *row, int width){ | |||||
png_byte pix[width]; | png_byte pix[width]; | ||||
for(int i = 0; i < width; i++) | for(int i = 0; i < width; i++) | ||||
pix[i] = row[i]; | pix[i] = row[i]; | ||||
png_write_row(rt_png_ptr, (png_bytep) pix); | png_write_row(rt_png_ptr, (png_bytep) pix); | ||||
} | } | ||||
void closeWriter(){ | void closeWriter(){ | ||||
png_write_end(rt_png_ptr, rt_info_ptr); | png_write_end(rt_png_ptr, rt_info_ptr); | ||||
fclose(rt_pngfile); | |||||
png_destroy_write_struct(&rt_png_ptr, &rt_info_ptr); | |||||
fclose(rt_pngfile); | |||||
png_destroy_write_struct(&rt_png_ptr, &rt_info_ptr); | |||||
} | } |
@@ -18,18 +18,18 @@ | |||||
static void FactPiv(int N, double A[DMAX][DMAX], double B[], double Cf[]); | static void FactPiv(int N, double A[DMAX][DMAX], double B[], double Cf[]); | ||||
void polyreg(const int M, const int N, const double X[], const double Y[], double C[]) { | void polyreg(const int M, const int N, const double X[], const double Y[], double C[]) { | ||||
int R, K, J; /* Loop counters */ | |||||
double A[DMAX][DMAX]; /* A */ | |||||
double B[DMAX]; | |||||
double P[2 * DMAX + 1]; | |||||
double x, y; | |||||
double p; | |||||
/* Zero the array */ | |||||
for (R = 0; R < M + 1; R++) | |||||
int R, K, J; /* Loop counters */ | |||||
double A[DMAX][DMAX]; /* A */ | |||||
double B[DMAX]; | |||||
double P[2 * DMAX + 1]; | |||||
double x, y; | |||||
double p; | |||||
/* Zero the array */ | |||||
for (R = 0; R < M + 1; R++) | |||||
B[R] = 0; | B[R] = 0; | ||||
/* Compute the column vector */ | |||||
/* Compute the column vector */ | |||||
for (K = 0; K < N; K++) { | for (K = 0; K < N; K++) { | ||||
y = Y[K]; | y = Y[K]; | ||||
x = X[K]; | x = X[K]; | ||||
@@ -38,50 +38,50 @@ void polyreg(const int M, const int N, const double X[], const double Y[], doubl | |||||
B[R] += y * p; | B[R] += y * p; | ||||
p = p * x; | p = p * x; | ||||
} | } | ||||
} | |||||
} | |||||
/* Zero the array */ | |||||
for (J = 1; J <= 2 * M; J++) | |||||
/* Zero the array */ | |||||
for (J = 1; J <= 2 * M; J++) | |||||
P[J] = 0; | P[J] = 0; | ||||
P[0] = N; | |||||
/* Compute the sum of powers of x_(K-1) */ | |||||
for (K = 0; K < N; K++) { | |||||
P[0] = N; | |||||
/* Compute the sum of powers of x_(K-1) */ | |||||
for (K = 0; K < N; K++) { | |||||
x = X[K]; | x = X[K]; | ||||
p = X[K]; | p = X[K]; | ||||
for (J = 1; J <= 2 * M; J++) { | for (J = 1; J <= 2 * M; J++) { | ||||
P[J] += p; | P[J] += p; | ||||
p = p * x; | p = p * x; | ||||
} | } | ||||
} | |||||
} | |||||
/* Determine the matrix entries */ | |||||
for (R = 0; R < M + 1; R++) { | |||||
/* Determine the matrix entries */ | |||||
for (R = 0; R < M + 1; R++) { | |||||
for (K = 0; K < M + 1; K++) | for (K = 0; K < M + 1; K++) | ||||
A[R][K] = P[R + K]; | A[R][K] = P[R + K]; | ||||
} | |||||
} | |||||
/* Solve the linear system of M + 1 equations: A*C = B | |||||
for the coefficient vector C = (c_1,c_2,..,c_M,c_(M+1)) */ | |||||
FactPiv(M + 1, A, B, C); | |||||
/* Solve the linear system of M + 1 equations: A*C = B | |||||
for the coefficient vector C = (c_1,c_2,..,c_M,c_(M+1)) */ | |||||
FactPiv(M + 1, A, B, C); | |||||
} /* end main */ | } /* end main */ | ||||
/*--------------------------------------------------------*/ | /*--------------------------------------------------------*/ | ||||
static void FactPiv(int N, double A[DMAX][DMAX], double B[], double Cf[]) { | static void FactPiv(int N, double A[DMAX][DMAX], double B[], double Cf[]) { | ||||
int K, P, C, J; /* Loop counters */ | |||||
int Row[NMAX]; /* Field with row-number */ | |||||
double X[DMAX], Y[DMAX]; | |||||
double SUM, DET = 1.0; | |||||
int T; | |||||
/* Initialize the pointer vector */ | |||||
for (J = 0; J < NMAX; J++) | |||||
int K, P, C, J; /* Loop counters */ | |||||
int Row[NMAX]; /* Field with row-number */ | |||||
double X[DMAX], Y[DMAX]; | |||||
double SUM, DET = 1.0; | |||||
int T; | |||||
/* Initialize the pointer vector */ | |||||
for (J = 0; J < NMAX; J++) | |||||
Row[J] = J; | Row[J] = J; | ||||
/* Start LU factorization */ | |||||
for (P = 0; P < N - 1; P++) { | |||||
/* Start LU factorization */ | |||||
for (P = 0; P < N - 1; P++) { | |||||
/* Find pivot element */ | /* Find pivot element */ | ||||
for (K = P + 1; K < N; K++) { | for (K = P + 1; K < N; K++) { | ||||
if (fabs(A[Row[K]][P]) > fabs(A[Row[P]][P])) { | if (fabs(A[Row[K]][P]) > fabs(A[Row[P]][P])) { | ||||
@@ -109,34 +109,34 @@ static void FactPiv(int N, double A[DMAX][DMAX], double B[], double Cf[]) { | |||||
A[Row[K]][C] -= A[Row[K]][P] * A[Row[P]][C]; | A[Row[K]][C] -= A[Row[K]][P] * A[Row[P]][C]; | ||||
} | } | ||||
} | } | ||||
} | |||||
} | |||||
/* End of L*U factorization routine */ | /* End of L*U factorization routine */ | ||||
DET = DET * A[Row[N - 1]][N - 1]; | |||||
DET = DET * A[Row[N - 1]][N - 1]; | |||||
/* Start the forward substitution */ | |||||
for (K = 0; K < N; K++) | |||||
/* Start the forward substitution */ | |||||
for (K = 0; K < N; K++) | |||||
Y[K] = B[K]; | Y[K] = B[K]; | ||||
Y[0] = B[Row[0]]; | Y[0] = B[Row[0]]; | ||||
for (K = 1; K < N; K++) { | |||||
for (K = 1; K < N; K++) { | |||||
SUM = 0; | SUM = 0; | ||||
for (C = 0; C <= K - 1; C++) | for (C = 0; C <= K - 1; C++) | ||||
SUM += A[Row[K]][C] * Y[C]; | SUM += A[Row[K]][C] * Y[C]; | ||||
Y[K] = B[Row[K]] - SUM; | Y[K] = B[Row[K]] - SUM; | ||||
} | |||||
} | |||||
/* Start the back substitution */ | |||||
X[N - 1] = Y[N - 1] / A[Row[N - 1]][N - 1]; | |||||
for (K = N - 2; K >= 0; K--) { | |||||
/* Start the back substitution */ | |||||
X[N - 1] = Y[N - 1] / A[Row[N - 1]][N - 1]; | |||||
for (K = N - 2; K >= 0; K--) { | |||||
SUM = 0; | SUM = 0; | ||||
for (C = K + 1; C < N; C++) { | for (C = K + 1; C < N; C++) { | ||||
SUM += A[Row[K]][C] * X[C]; | SUM += A[Row[K]][C] * X[C]; | ||||
} | } | ||||
X[K] = (Y[K] - SUM) / A[Row[K]][K]; | X[K] = (Y[K] - SUM) / A[Row[K]][K]; | ||||
} /* End of back substitution */ | |||||
} /* End of back substitution */ | |||||
/* Output */ | |||||
for (K = 0; K < N; K++) | |||||
/* Output */ | |||||
for (K = 0; K < N; K++) | |||||
Cf[K] = X[K]; | Cf[K] = X[K]; | ||||
} | } |
@@ -18,107 +18,107 @@ | |||||
*/ | */ | ||||
const struct { | const struct { | ||||
float d[4][3]; | |||||
struct { | |||||
float vc, A, B; | |||||
} rad[3]; | |||||
struct { | |||||
float Ns; | |||||
float b[3]; | |||||
} cor[3]; | |||||
float d[4][3]; | |||||
struct { | |||||
float vc, A, B; | |||||
} rad[3]; | |||||
struct { | |||||
float Ns; | |||||
float b[3]; | |||||
} cor[3]; | |||||
/* Calibration corficcients taken from the NOAA KLM satellite user guide | /* Calibration corficcients taken from the NOAA KLM satellite user guide | ||||
* https://web.archive.org/web/20141220021557/https://www.ncdc.noaa.gov/oa/pod-guide/ncdc/docs/klm/tables.htm | * https://web.archive.org/web/20141220021557/https://www.ncdc.noaa.gov/oa/pod-guide/ncdc/docs/klm/tables.htm | ||||
*/ | */ | ||||
} satcal[] = { | } satcal[] = { | ||||
{ // NOAA 15 | { // NOAA 15 | ||||
{ // PRT coefficient d0, d1, d2 | |||||
{276.60157, 0.051045, 1.36328E-06}, | |||||
{276.62531, 0.050909, 1.47266E-06}, | |||||
{276.67413, 0.050907, 1.47656E-06}, | |||||
{276.59258, 0.050966, 1.47656E-06} | |||||
}, | |||||
{ // Channel radiance coefficient vc, A, B | |||||
{925.4075, 0.337810, 0.998719}, // Channel 4 | |||||
{839.8979, 0.304558, 0.999024}, // Channel 5 | |||||
{2695.9743, 1.621256, 0.998015} // Channel 3B | |||||
}, | |||||
{ // Nonlinear radiance correction Ns, b0, b1, b2 | |||||
{-4.50, {4.76, -0.0932, 0.0004524}}, // Channel 4 | |||||
{-3.61, {3.83, -0.0659, 0.0002811}}, // Channel 5 | |||||
{0.0, {0.0, 0.0, 0.0}} // Channel 3B | |||||
} | |||||
{ // PRT coefficient d0, d1, d2 | |||||
{276.60157, 0.051045, 1.36328E-06}, | |||||
{276.62531, 0.050909, 1.47266E-06}, | |||||
{276.67413, 0.050907, 1.47656E-06}, | |||||
{276.59258, 0.050966, 1.47656E-06} | |||||
}, | |||||
{ // Channel radiance coefficient vc, A, B | |||||
{925.4075, 0.337810, 0.998719}, // Channel 4 | |||||
{839.8979, 0.304558, 0.999024}, // Channel 5 | |||||
{2695.9743, 1.621256, 0.998015} // Channel 3B | |||||
}, | |||||
{ // Nonlinear radiance correction Ns, b0, b1, b2 | |||||
{-4.50, {4.76, -0.0932, 0.0004524}}, // Channel 4 | |||||
{-3.61, {3.83, -0.0659, 0.0002811}}, // Channel 5 | |||||
{0.0, {0.0, 0.0, 0.0}} // Channel 3B | |||||
} | |||||
}, | }, | ||||
{ // NOAA 16 | { // NOAA 16 | ||||
{ // PRT coeff d0, d1, d2 | |||||
{276.355, 5.562E-02, -1.590E-05}, | |||||
{276.142, 5.605E-02, -1.707E-05}, | |||||
{275.996, 5.486E-02, -1.223E-05}, | |||||
{276.132, 5.494E-02, -1.344E-05} | |||||
}, | |||||
{ // Channel radiance coefficient vc, A, B | |||||
{917.2289, 0.332380, 0.998522}, // Channel 4 | |||||
{838.1255, 0.674623, 0.998363}, // Channel 5 | |||||
{2700.1148, 1.592459, 0.998147} // Channel 3B | |||||
}, | |||||
{ // Nonlinear radiance correction Ns, b0, b1, b2 | |||||
{-2.467, {2.96, -0.05411, 0.00024532}}, // Channel 4 | |||||
{-2.009, {2.25, -0.03665, 0.00014854}}, // Channel 5 | |||||
{0.0, {0.0, 0.0, 0.0}} // Channel 3B | |||||
} | |||||
{ // PRT coeff d0, d1, d2 | |||||
{276.355, 5.562E-02, -1.590E-05}, | |||||
{276.142, 5.605E-02, -1.707E-05}, | |||||
{275.996, 5.486E-02, -1.223E-05}, | |||||
{276.132, 5.494E-02, -1.344E-05} | |||||
}, | |||||
{ // Channel radiance coefficient vc, A, B | |||||
{917.2289, 0.332380, 0.998522}, // Channel 4 | |||||
{838.1255, 0.674623, 0.998363}, // Channel 5 | |||||
{2700.1148, 1.592459, 0.998147} // Channel 3B | |||||
}, | |||||
{ // Nonlinear radiance correction Ns, b0, b1, b2 | |||||
{-2.467, {2.96, -0.05411, 0.00024532}}, // Channel 4 | |||||
{-2.009, {2.25, -0.03665, 0.00014854}}, // Channel 5 | |||||
{0.0, {0.0, 0.0, 0.0}} // Channel 3B | |||||
} | |||||
}, | }, | ||||
{ // NOAA 17 | { // NOAA 17 | ||||
{ // PRT coefficient d0, d1, d2 | |||||
{276.628, 0.05098, 1.371e-06}, | |||||
{276.538, 0.05098, 1.371e-06}, | |||||
{276.761, 0.05097, 1.369e-06}, | |||||
{276.660, 0.05100, 1.348e-06} | |||||
}, | |||||
{ // Channel radiance coefficient vc, A, B | |||||
{926.2947, 0.271683, 0.998794}, // Channel 4 | |||||
{839.8246, 0.309180, 0.999012}, // Channel 5 | |||||
{2669.3554, 1.702380, 0.997378} // Channel 3B | |||||
}, | |||||
{ // Nonlinear radiance correction Ns, b0, b1, b2 | |||||
{-8.55, {8.22, -0.15795, 0.00075579}}, // Channel 4 | |||||
{-3.97, {4.31, -0.07318, 0.00030976}}, // Channel 5 | |||||
{0.0, {0.0, 0.0, 0.0}} // Channel 3B | |||||
} | |||||
{ // PRT coefficient d0, d1, d2 | |||||
{276.628, 0.05098, 1.371e-06}, | |||||
{276.538, 0.05098, 1.371e-06}, | |||||
{276.761, 0.05097, 1.369e-06}, | |||||
{276.660, 0.05100, 1.348e-06} | |||||
}, | |||||
{ // Channel radiance coefficient vc, A, B | |||||
{926.2947, 0.271683, 0.998794}, // Channel 4 | |||||
{839.8246, 0.309180, 0.999012}, // Channel 5 | |||||
{2669.3554, 1.702380, 0.997378} // Channel 3B | |||||
}, | |||||
{ // Nonlinear radiance correction Ns, b0, b1, b2 | |||||
{-8.55, {8.22, -0.15795, 0.00075579}}, // Channel 4 | |||||
{-3.97, {4.31, -0.07318, 0.00030976}}, // Channel 5 | |||||
{0.0, {0.0, 0.0, 0.0}} // Channel 3B | |||||
} | |||||
}, | }, | ||||
{ // NOAA 18 | { // NOAA 18 | ||||
{ // PRT coefficient d0, d1, d2 | |||||
{276.601, 0.05090, 1.657e-06}, | |||||
{276.683, 0.05101, 1.482e-06}, | |||||
{276.565, 0.05117, 1.313e-06}, | |||||
{276.615, 0.05103, 1.484e-06} | |||||
}, | |||||
{ // Channel radiance coefficient vc, A, B | |||||
{928.1460, 0.436645, 0.998607}, // Channel 4 | |||||
{833.2532, 0.253179, 0.999057}, // Channel 5 | |||||
{2659.7952, 1.698704, 0.996960} // Channel 3B | |||||
}, | |||||
{ // Nonlinear radiance correction Ns, b0, b1, b2 | |||||
{-5.53, {5.82, -0.11069, 0.00052337}}, // Channel 4 | |||||
{-2.22, {2.67, -0.04360, 0.00017715}}, // Channel 5 | |||||
{0.0, {0.0, 0.0, 0.0}} // Channel 3B | |||||
} | |||||
{ // PRT coefficient d0, d1, d2 | |||||
{276.601, 0.05090, 1.657e-06}, | |||||
{276.683, 0.05101, 1.482e-06}, | |||||
{276.565, 0.05117, 1.313e-06}, | |||||
{276.615, 0.05103, 1.484e-06} | |||||
}, | |||||
{ // Channel radiance coefficient vc, A, B | |||||
{928.1460, 0.436645, 0.998607}, // Channel 4 | |||||
{833.2532, 0.253179, 0.999057}, // Channel 5 | |||||
{2659.7952, 1.698704, 0.996960} // Channel 3B | |||||
}, | |||||
{ // Nonlinear radiance correction Ns, b0, b1, b2 | |||||
{-5.53, {5.82, -0.11069, 0.00052337}}, // Channel 4 | |||||
{-2.22, {2.67, -0.04360, 0.00017715}}, // Channel 5 | |||||
{0.0, {0.0, 0.0, 0.0}} // Channel 3B | |||||
} | |||||
}, | }, | ||||
{ // NOAA 19 | { // NOAA 19 | ||||
{ // PRT coefficient d0, d1, d2 | |||||
{276.6067, 0.051111, 1.405783E-06}, | |||||
{276.6119, 0.051090, 1.496037E-06}, | |||||
{276.6311, 0.051033, 1.496990E-06}, | |||||
{276.6268, 0.051058, 1.493110E-06} | |||||
}, | |||||
{ // Channel radiance coefficient vc, A, B | |||||
{928.9, 0.53959, 0.998534}, // Channel 4 | |||||
{831.9, 0.36064, 0.998913}, // Channel 5 | |||||
{2670.0, 1.67396, 0.997364} // Channel 3B | |||||
}, | |||||
{ // Nonlinear radiance correction Ns, b0, b1, b2 | |||||
{-5.49, {5.70 -0.11187, 0.00054668}}, // Channel 4 | |||||
{-3.39, {3.58 -0.05991, 0.00024985}}, // Channel 5 | |||||
{0.0, {0.0, 0.0, 0.0}} // Channel 3B | |||||
} | |||||
{ // PRT coefficient d0, d1, d2 | |||||
{276.6067, 0.051111, 1.405783E-06}, | |||||
{276.6119, 0.051090, 1.496037E-06}, | |||||
{276.6311, 0.051033, 1.496990E-06}, | |||||
{276.6268, 0.051058, 1.493110E-06} | |||||
}, | |||||
{ // Channel radiance coefficient vc, A, B | |||||
{928.9, 0.53959, 0.998534}, // Channel 4 | |||||
{831.9, 0.36064, 0.998913}, // Channel 5 | |||||
{2670.0, 1.67396, 0.997364} // Channel 3B | |||||
}, | |||||
{ // Nonlinear radiance correction Ns, b0, b1, b2 | |||||
{-5.49, {5.70 -0.11187, 0.00054668}}, // Channel 4 | |||||
{-3.39, {3.58 -0.05991, 0.00024985}}, // Channel 5 | |||||
{0.0, {0.0, 0.0, 0.0}} // Channel 3B | |||||
} | |||||
}}; | }}; | ||||
const float c1 = 1.1910427e-5; | const float c1 = 1.1910427e-5; |