source: BAORadio/libindi/libindi/drivers/ccd/ccd_simulator.cpp @ 642

Last change on this file since 642 was 642, checked in by frichard, 12 years ago

-Alignement des antennes
-Version 0.0.9 de libindi

File size: 28.1 KB
Line 
1/*******************************************************************************
2  Copyright(c) 2010 Gerry Rozema. All rights reserved.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License version 2 as published by the Free Software Foundation.
7 .
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 Library General Public License for more details.
12 .
13 You should have received a copy of the GNU Library General Public License
14 along with this library; see the file COPYING.LIB.  If not, write to
15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 Boston, MA 02110-1301, USA.
17*******************************************************************************/
18#include "ccd_simulator.h"
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <unistd.h>
23#include <math.h>
24#include <string.h>
25
26
27// We declare an auto pointer to ccdsim.
28std::auto_ptr<CCDSim> ccdsim(0);
29
30void ISPoll(void *p);
31
32
33void ISInit()
34{
35   static int isInit =0;
36
37   if (isInit == 1)
38       return;
39
40    isInit = 1;
41    if(ccdsim.get() == 0) ccdsim.reset(new CCDSim());
42    //IEAddTimer(POLLMS, ISPoll, NULL);
43
44}
45
46void ISGetProperties(const char *dev)
47{
48        ISInit();
49        ccdsim->ISGetProperties(dev);
50}
51
52void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int num)
53{
54        ISInit();
55        ccdsim->ISNewSwitch(dev, name, states, names, num);
56}
57
58void ISNewText( const char *dev, const char *name, char *texts[], char *names[], int num)
59{
60        ISInit();
61        ccdsim->ISNewText(dev, name, texts, names, num);
62}
63
64void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int num)
65{
66        ISInit();
67        ccdsim->ISNewNumber(dev, name, values, names, num);
68}
69
70void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n)
71{
72  INDI_UNUSED(dev);
73  INDI_UNUSED(name);
74  INDI_UNUSED(sizes);
75  INDI_UNUSED(blobsizes);
76  INDI_UNUSED(blobs);
77  INDI_UNUSED(formats);
78  INDI_UNUSED(names);
79  INDI_UNUSED(n);
80}
81void ISSnoopDevice (XMLEle *root)
82{
83    ISInit();
84    ccdsim->ISSnoopDevice(root);
85}
86
87
88CCDSim::CCDSim()
89{
90    //ctor
91    testvalue=0;
92    AbortGuideFrame=false;
93    ShowStarField=true;
94
95    HasSt4Port=true;
96    HasGuideHead=false;
97
98
99    RA=9.95;
100    Dec=68.9;
101
102    //  sxvh9
103    bias=1500;
104    maxnoise=20;
105    maxval=65000;
106    limitingmag=11.5;
107    saturationmag=2;
108    focallength=1280;   //  focal length of the telescope in millimeters
109    OAGoffset=0;    //  An oag is offset this much from center of scope position (arcminutes);
110    skyglow=40;
111
112    seeing=3.5;         //  fwhm of our stars
113    ImageScalex=1.0;    //  preset with a valid non-zero
114    ImageScaley=1.0;
115    //focallength=175;   //  focal length of the telescope in millimeters
116    time(&RunStart);
117
118    //  Our PEPeriod is 8 minutes
119    //  and we have a 22 arcsecond swing
120    PEPeriod=8*60;
121    PEMax=11;
122    GuideRate=7;    //  guide rate is 7 arcseconds per second
123    TimeFactor=1;
124
125    SimulatorSettingsNV = new INumberVectorProperty;
126    TimeFactorSV = new ISwitchVectorProperty;
127
128}
129
130bool CCDSim::SetupParms()
131{
132    int nbuf;
133    SetCCDParams(SimulatorSettingsN[0].value,SimulatorSettingsN[1].value,16,SimulatorSettingsN[2].value,SimulatorSettingsN[3].value);
134    //  Kwiq
135    maxnoise=SimulatorSettingsN[10].value;
136    skyglow=SimulatorSettingsN[11].value;
137    maxval=SimulatorSettingsN[4].value;
138    bias=SimulatorSettingsN[5].value;
139    limitingmag=SimulatorSettingsN[7].value;
140    saturationmag=SimulatorSettingsN[6].value;
141    focallength=SimulatorSettingsN[8].value;   //  focal length of the telescope in millimeters
142    OAGoffset=SimulatorSettingsN[12].value;    //  An oag is offset this much from center of scope position (arcminutes);
143    seeing=SimulatorSettingsN[9].value;        //  we get real fat stars in this one
144
145    nbuf = PrimaryCCD.getXRes() * PrimaryCCD.getYRes() * PrimaryCCD.getBPP();
146    nbuf += 512;
147    PrimaryCCD.setFrameBufferSize(nbuf);
148
149    return true;
150}
151
152bool CCDSim::Connect()
153{
154
155    int nbuf;
156    SetupParms();
157
158    if(HasGuideHead)
159    {
160        SetGuidHeadParams(500,290,8,9.8,12.6);
161        nbuf = GuideCCD.getXRes() * GuideCCD.getYRes();
162        GuideCCD.setFrameBufferSize(nbuf);
163    }
164
165    SetTimer(1000);     //  start the timer
166    return true;
167}
168
169CCDSim::~CCDSim()
170{
171    //dtor
172}
173
174const char * CCDSim::getDefaultName()
175{
176        return (char *)"CCD Simulator";
177}
178
179bool CCDSim::initProperties()
180{
181    //  Most hardware layers wont actually have indi properties defined
182    //  but the simulators are a special case
183    INDI::CCD::initProperties();
184
185    IUFillNumber(&SimulatorSettingsN[0],"SIM_PrimarCCD.getXRes()","CCD X resolution","%4.0f",0,2048,0,1280);
186    IUFillNumber(&SimulatorSettingsN[1],"SIM_PrimarCCD.getYRes()","CCD Y resolution","%4.0f",0,2048,0,1024);
187    IUFillNumber(&SimulatorSettingsN[2],"SIM_XSIZE","CCD X Pixel Size","%4.2f",0,60,0,5.2);
188    IUFillNumber(&SimulatorSettingsN[3],"SIM_YSIZE","CCD Y Pixel Size","%4.2f",0,60,0,5.2);
189    IUFillNumber(&SimulatorSettingsN[4],"SIM_MAXVAL","CCD Maximum ADU","%4.0f",0,65000,0,65000);
190    IUFillNumber(&SimulatorSettingsN[5],"SIM_BIAS","CCD Bias","%4.0f",0,6000,0,1500);
191    IUFillNumber(&SimulatorSettingsN[6],"SIM_SATURATION","Saturation Mag","%4.1f",0,20,0,1.0);
192    IUFillNumber(&SimulatorSettingsN[7],"SIM_LIMITINGMAG","Limiting Mag","%4.1f",0,20,0,20);
193    IUFillNumber(&SimulatorSettingsN[8],"SIM_FOCALLENGTH","Focal Length","%4.0f",0,60000,0,1000);
194    IUFillNumber(&SimulatorSettingsN[9],"SIM_FWHM","FWHM (arcseconds)","%4.2f",0,60,0,3.5);
195    IUFillNumber(&SimulatorSettingsN[10],"SIM_NOISE","CCD Noise","%4.0f",0,6000,0,50);
196    IUFillNumber(&SimulatorSettingsN[11],"SIM_SKYGLOW","Sky Glow (magnitudes)","%4.1f",0,6000,0,19.5);
197    IUFillNumber(&SimulatorSettingsN[12],"SIM_OAGOFFSET","Oag Offset (arminutes)","%4.1f",0,6000,0,0);
198    IUFillNumberVector(SimulatorSettingsNV,SimulatorSettingsN,13,deviceName(),"SIMULATOR_SETTINGS","Simulator Settings","Simulator Config",IP_RW,60,IPS_IDLE);
199
200
201    IUFillSwitch(&TimeFactorS[0],"1X","Actual Time",ISS_ON);
202    IUFillSwitch(&TimeFactorS[1],"10X","10x",ISS_OFF);
203    IUFillSwitch(&TimeFactorS[2],"100X","100x",ISS_OFF);
204    IUFillSwitchVector(TimeFactorSV,TimeFactorS,3,deviceName(),"ON_TIME_FACTOR","Time Factor","Simulator Config",IP_RW,ISR_1OFMANY,60,IPS_IDLE);
205
206
207    //loadConfig();
208
209    return true;
210}
211
212void CCDSim::ISGetProperties (const char *dev)
213{
214    //  First we let our parent populate
215
216    //IDLog("CCDSim IsGetProperties with %s\n",dev);
217    INDI::CCD::ISGetProperties(dev);
218
219    defineNumber(SimulatorSettingsNV);
220    defineSwitch(TimeFactorSV);
221    //IDDefText(&ConfigFileTV, NULL);
222    //IDDefSwitch(&ConfigSaveRestoreSV, NULL);
223
224
225    return;
226}
227
228bool CCDSim::updateProperties()
229{
230    IDDefNumber(SimulatorSettingsNV, NULL);
231
232    INDI::CCD::updateProperties();
233    return true;
234}
235
236
237bool CCDSim::Disconnect()
238{
239    return true;
240}
241
242int CCDSim::StartExposure(float duration)
243{
244    //  for the simulator, we can just draw the frame now
245    //  and it will get returned at the right time
246    //  by the timer routines
247    ExposureRequest=duration;
248
249    if(InExposure)
250    {
251        //  We are already in an exposure, just change the time
252        //  and be done with it.
253        return 0;
254    }
255
256    gettimeofday(&ExpStart,NULL);
257    //  Leave the proper time showing for the draw routines
258    DrawCcdFrame();
259    //  Now compress the actual wait time
260    ExposureRequest=duration*TimeFactor;
261
262    InExposure=true;
263    return 0;
264}
265
266int CCDSim::StartGuideExposure(float n)
267{
268    GuideExposureRequest=n;
269    if(InGuideExposure) return 0;
270    DrawGuiderFrame();
271    gettimeofday(&GuideExpStart,NULL);
272    InGuideExposure=true;
273    return 0;
274}
275
276bool CCDSim::AbortGuideExposure()
277{
278    //IDLog("Enter AbortGuideExposure\n");
279    if(!InGuideExposure) return true;   //  no need to abort if we aren't doing one
280    AbortGuideFrame=true;
281    return true;
282}
283
284float CCDSim::CalcTimeLeft(timeval start,float req)
285{
286    double timesince;
287    double timeleft;
288    struct timeval now;
289    gettimeofday(&now,NULL);
290
291    timesince=(double)(now.tv_sec * 1000.0 + now.tv_usec/1000) - (double)(start.tv_sec * 1000.0 + start.tv_usec/1000);
292    timesince=timesince/1000;
293    timeleft=req-timesince;
294    return timeleft;
295}
296
297void CCDSim::TimerHit()
298{
299    int nexttimer=1000;
300
301    if(isConnected() == false) return;  //  No need to reset timer if we are not connected anymore
302
303    if(InExposure)
304    {
305        float timeleft;
306        timeleft=CalcTimeLeft(ExpStart,ExposureRequest);
307
308        if (timeleft < 0)
309             timeleft = 0;
310
311        PrimaryCCD.setExposure(timeleft);
312        //ImageExposureN[0].value = timeleft;
313        //IDSetNumber(ImageExposureNP, NULL);
314
315        if(timeleft < 1.0)
316        {
317            if(timeleft <= 0.001)
318            {
319                InExposure=false;
320                ExposureComplete();
321            } else
322            {
323                nexttimer=timeleft*1000;    //  set a shorter timer
324            }
325        }
326    }
327
328    if(InGuideExposure)
329    {
330        float timeleft;
331        timeleft=CalcTimeLeft(GuideExpStart,GuideExposureRequest);
332
333
334        if (timeleft < 0)
335             timeleft = 0;
336
337        //ImageExposureN[0].value = timeleft;
338        //IDSetNumber(ImageExposureNP, NULL);
339        GuideCCD.setExposure(timeleft);
340
341        if(timeleft < 1.0)
342        {
343            if(timeleft <= 0.001)
344            {
345                InGuideExposure=false;
346                if(!AbortGuideFrame)
347                {
348                    //IDLog("Sending guider frame\n");
349                    GuideExposureComplete();
350                    if(InGuideExposure)
351                    {    //  the call to complete triggered another exposure
352                        timeleft=CalcTimeLeft(GuideExpStart,GuideExposureRequest);
353                        if(timeleft <1.0)
354                        {
355                            nexttimer=timeleft*1000;
356                        }
357                    }
358                } else
359                {
360                    IDLog("Not sending guide frame cuz of abort\n");
361                }
362                AbortGuideFrame=false;
363            } else
364            {
365                nexttimer=timeleft*1000;    //  set a shorter timer
366            }
367        }
368    }
369    SetTimer(nexttimer);
370    return;
371}
372
373int CCDSim::DrawCcdFrame()
374{
375    //  Ok, lets just put a silly pattern into this
376    //  CCd frame is 16 bit data
377    unsigned short int *ptr;
378    unsigned short int val;
379
380    ptr=(unsigned short int *) PrimaryCCD.getFrameBuffer();
381
382    if(ShowStarField)
383    {
384        char gsccmd[250];
385        FILE *pp;
386        int stars=0;
387        int lines=0;
388        int drawn=0;
389        int x,y;
390        float PEOffset;
391        float PESpot;
392        double rad;  //  telescope ra in degrees
393        double rar;  //  telescope ra in radians
394        double decr; //  telescope dec in radians;
395
396
397        double timesince;
398        time_t now;
399        time(&now);
400
401        //  Lets figure out where we are on the pe curve
402        timesince=difftime(now,RunStart);
403        //  This is our spot in the curve
404        PESpot=timesince/PEPeriod;
405        //  Now convert to radians
406        PESpot=PESpot*2.0*3.14159;
407
408        PEOffset=PEMax*sin(PESpot);
409        //fprintf(stderr,"PEOffset = %4.2f arcseconds timesince %4.2f\n",PEOffset,timesince);
410        PEOffset=PEOffset/3600;     //  convert to degrees
411        //PeOffset=PeOffset/15;       //  ra is in h:mm
412
413        //  Start by clearing the frame buffer
414        memset(PrimaryCCD.getFrameBuffer(),0,PrimaryCCD.getFrameBufferSize());
415
416
417        //  Spin up a set of plate constants that will relate
418        //  ra/dec of stars, to our fictitious ccd layout
419
420        //  to account for various rotations etc
421        //  we should spin up some plate constants here
422        //  then we can use these constants to rotate and offset
423        //  the standard co-ordinates on each star for drawing
424        //  a ccd frame;
425        double pa,pb,pc,pd,pe,pf;
426        //  Since this is a simple ccd, correctly aligned
427        //  for now we cheat
428        //  no offset or rotation for and y axis means
429        pb=0.0;
430        pc=PrimaryCCD.getXRes()/2/PrimaryCCD.getBinX();
431        pd=0.0;
432        pf=PrimaryCCD.getYRes()/2/PrimaryCCD.getBinY();
433        //  and we do a simple scale for x and y locations
434        //  based on the focal length and pixel size
435        //  focal length in mm, pixels in microns
436        pa=focallength/PrimaryCCD.getPixelSizeX()*1000/PrimaryCCD.getBinX();
437        pe=focallength/PrimaryCCD.getPixelSizeY()*1000/PrimaryCCD.getBinY();
438
439        //IDLog("Pixels are %4.2f %4.2f  pa %6.4f  pe %6.4f\n",PixelSizex,PixelSizey,pa,pe);
440
441        //  these numbers are now pixels per radian
442        float Scalex;
443        float Scaley;
444        Scalex=pa*0.0174532925;    //  pixels per degree
445        Scalex=Scalex/3600.0;           // pixels per arcsecond
446        Scalex=1.0/Scalex;  //  arcseconds per pixel
447
448        Scaley=pe*0.0174532925;    //  pixels per degree
449        Scaley=Scaley/3600.0;           // pixels per arcsecond
450        Scaley=1.0/Scaley;  //  arcseconds per pixel
451        //qq=qq/3600; //  arcseconds per pixel
452
453        //IDLog("Pixel scale is %4.2f x %4.2f\n",Scalex,Scaley);
454        ImageScalex=Scalex;
455        ImageScaley=Scaley;
456
457        //  calc this now, we will use it a lot later
458        rad=RA*15.0;
459        rar=rad*0.0174532925;
460        //  offsetting the dec by the guide head offset
461        float cameradec;
462        cameradec=Dec+OAGoffset/60;
463        decr=cameradec*0.0174532925;
464
465        //fprintf(stderr,"Dec %7.5f  cameradec %7.5f  CenterOffsetDec %4.4f\n",Dec,cameradec,CenterOffsetDec);
466        //  now lets calculate the radius we need to fetch
467        float radius;
468
469        radius=sqrt((Scalex*Scalex*PrimaryCCD.getXRes()/2.0*PrimaryCCD.getXRes()/2.0)+(Scaley*Scaley*PrimaryCCD.getYRes()/2.0*PrimaryCCD.getYRes()/2.0));
470        //  we have radius in arcseconds now
471        radius=radius/60;   //  convert to arcminutes
472        //fprintf(stderr,"Lookup radius %4.2f\n",radius);
473        //radius=radius*2;
474
475        //  A saturationmag star saturates in one second
476        //  and a limitingmag produces a one adu level in one second
477        //  solve for zero point and system gain
478
479        k=(saturationmag-limitingmag)/((-2.5*log(maxval))-(-2.5*log(1.0/2.0)));
480        z=saturationmag-k*(-2.5*log(maxval));
481        //z=z+saturationmag;
482
483        //IDLog("K=%4.2f  Z=%4.2f\n",k,z);
484
485        //  Should probably do some math here to figure out the dimmest
486        //  star we can see on this exposure
487        //  and only fetch to that magnitude
488        //  for now, just use the limiting mag number with some room to spare
489        float lookuplimit;
490
491        lookuplimit=limitingmag;
492        lookuplimit=lookuplimit;
493        if(radius > 60) lookuplimit=11;
494
495        //  if this is a light frame, we need a star field drawn
496        if(PrimaryCCD.getFrameType()==CCDChip::LIGHT_FRAME)
497        {
498            //sprintf(gsccmd,"gsc -c %8.6f %+8.6f -r 120 -m 0 9.1",rad+PEOffset,Dec);
499            sprintf(gsccmd,"gsc -c %8.6f %+8.6f -r %4.1f -m 0 %4.2f -n 3000",rad+PEOffset,cameradec,radius,lookuplimit);
500            //fprintf(stderr,"gsccmd %s\n",gsccmd);
501            pp=popen(gsccmd,"r");
502            if(pp != NULL) {
503                char line[256];
504                while(fgets(line,256,pp)!=NULL)
505                {
506                    //fprintf(stderr,"%s",line);
507
508                    //  ok, lets parse this line for specifcs we want
509                    char id[20];
510                    char plate[6];
511                    char ob[6];
512                    float mag;
513                    float mage;
514                    float ra;
515                    float dec;
516                    float pose;
517                    int band;
518                    float dist;
519                    int dir;
520                    int c;
521                    int rc;
522
523                    rc=sscanf(line,"%10s %f %f %f %f %f %d %d %4s %2s %f %d",
524                            id,&ra,&dec,&pose,&mag,&mage,&band,&c,plate,ob,&dist,&dir);
525                    //fprintf(stderr,"Parsed %d items\n",rc);
526                    if(rc==12) {
527                        lines++;
528                        //if(c==0) {
529                        stars++;
530                        //fprintf(stderr,"%s %8.4f %8.4f %5.2f %5.2f %d\n",id,ra,dec,mag,dist,dir);
531
532                        //  Convert the ra/dec to standard co-ordinates
533                        double sx;   //  standard co-ords
534                        double sy;   //
535                        double srar;        //  star ra in radians
536                        double sdecr;       //  star dec in radians;
537                        double ccdx;
538                        double ccdy;
539
540                        //fprintf(stderr,"line %s",line);
541                        //fprintf(stderr,"parsed %6.5f %6.5f\n",ra,dec);
542
543                        srar=ra*0.0174532925;
544                        sdecr=dec*0.0174532925;
545                        //  Handbook of astronomical image processing
546                        //  page 253
547                        //  equations 9.1 and 9.2
548                        //  convert ra/dec to standard co-ordinates
549
550                        sx=cos(decr)*sin(srar-rar)/( cos(decr)*cos(sdecr)*cos(srar-rar)+sin(decr)*sin(sdecr) );
551                        sy=(sin(decr)*cos(sdecr)*cos(srar-rar)-cos(decr)*sin(sdecr))/( cos(decr)*cos(sdecr)*cos(srar-rar)+sin(decr)*sin(sdecr) );
552
553                        //  now convert to microns
554                        ccdx=pa*sx+pb*sy+pc;
555                        ccdy=pd*sx+pe*sy+pf;
556
557
558                        rc=DrawImageStar(mag,ccdx,ccdy);
559                        drawn+=rc;
560                        if(rc==1) {
561                            //fprintf(stderr,"star %s scope %6.4f %6.4f star %6.4f %6.4f  ccd %6.2f %6.2f\n",id,rad,Dec,ra,dec,ccdx,ccdy);
562                            //fprintf(stderr,"star %s ccd %6.2f %6.2f\n",id,ccdx,ccdy);
563                        }
564                    }
565                }
566                pclose(pp);
567            } else
568            {
569                IDMessage(deviceName(),"Error looking up stars, is gsc installed with appropriate environment variables set ??");
570                //fprintf(stderr,"Error doing gsc lookup\n");
571            }
572            if(drawn==0)
573            {
574                IDMessage(deviceName(),"Got no stars, is gsc installed with appropriate environment variables set ??");
575
576            }
577        }
578        //fprintf(stderr,"Got %d stars from %d lines drew %d\n",stars,lines,drawn);
579
580        //  now we need to add background sky glow, with vignetting
581        //  this is essentially the same math as drawing a dim star with
582        //  fwhm equivalent to the full field of view
583
584        CCDChip::CCD_FRAME ftype = PrimaryCCD.getFrameType();
585
586        if((ftype==CCDChip::LIGHT_FRAME)||(ftype==CCDChip::FLAT_FRAME))
587        {
588            float skyflux;
589            float glow;
590            //  calculate flux from our zero point and gain values
591            glow=skyglow;
592            if(ftype==CCDChip::FLAT_FRAME)
593            {
594                //  Assume flats are done with a diffuser
595                //  in broad daylight, so, the sky magnitude
596                //  is much brighter than at night
597                glow=skyglow/10;
598            }
599            //fprintf(stderr,"Using glow %4.2f\n",glow);
600            skyflux=pow(10,((glow-z)*k/-2.5));
601            //  ok, flux represents one second now
602            //  scale up linearly for exposure time
603            skyflux=skyflux*ExposureRequest*PrimaryCCD.getBinX()*PrimaryCCD.getBinY();
604            //IDLog("SkyFlux = %4.2f ExposureRequest %4.2f\n",skyflux,ExposureRequest);
605
606            unsigned short *pt;
607
608            int nwidth  = PrimaryCCD.getXRes()/PrimaryCCD.getBinX();
609            int nheight = PrimaryCCD.getYRes()/PrimaryCCD.getBinY();
610            pt=(unsigned short int *)PrimaryCCD.getFrameBuffer();
611            for(int y=0; y< nheight; y++) {
612                for(int x=0; x< nwidth; x++) {
613                    float dc;   //  distance from center
614                    float fp;   //  flux this pixel;
615                    float sx,sy;
616                    float vig;
617
618                    sx=PrimaryCCD.getXRes()/2/PrimaryCCD.getBinX();
619                    sx=sx-x;
620                    sy=PrimaryCCD.getYRes()/2/PrimaryCCD.getBinY();
621                    sy=sy-y;
622
623                    vig=PrimaryCCD.getXRes()/PrimaryCCD.getBinX();
624                    vig=vig*ImageScalex;
625                    //  need to make this account for actual pixel size
626                    dc=sqrt(sx*sx*ImageScalex*ImageScalex+sy*sy*ImageScaley*ImageScaley);
627                    //  now we have the distance from center, in arcseconds
628                    //  now lets plot a gaussian falloff to the edges
629                    //
630                    float fa;
631                    fa=exp(-2.0*0.7*(dc*dc)/vig/vig);
632                    //  get the current value
633                    fp=pt[0];
634                    //  Add the sky glow
635                    fp+=skyflux;
636                    //  now scale it for the vignetting
637                    fp=fa*fp;
638                    //  clamp to limits
639                    if(fp > maxval) fp=maxval;
640                    //  and put it back
641                    pt[0]=fp;
642                    pt++;
643
644                }
645            }
646        }
647
648
649        //  Now we add some bias and read noise
650        for(x=0; x<PrimaryCCD.getXRes(); x++) {
651            for(y=0; y<PrimaryCCD.getYRes(); y++) {
652                int noise;
653
654                noise=random();
655                noise=noise%maxnoise; //
656
657                AddToPixel(x,y,bias+noise);
658            }
659        }
660
661
662    } else {
663        testvalue++;
664        if(testvalue > 255) testvalue=0;
665        val=testvalue;
666
667        int nbuf    = PrimaryCCD.getXRes()*PrimaryCCD.getYRes();
668
669        for(int x=0; x<nbuf; x++)
670        {
671            *ptr=val++;
672            ptr++;
673        }
674
675    }
676    return 0;
677}
678
679int CCDSim::DrawGuiderFrame()
680{
681    unsigned char *ptr;
682    unsigned char val;
683
684    ptr=(unsigned char *) GuideCCD.getFrameBuffer();
685    testvalue++;
686    if(testvalue > 255) testvalue=0;
687    val=testvalue;
688
689    int nbuf = GuideCCD.getXRes()*GuideCCD.getYRes();
690    for(int x=0; x< nbuf; x++)
691    {
692        *ptr=val++;
693        ptr++;
694    }
695    return 0;
696}
697
698int CCDSim::DrawImageStar(float mag,float x,float y)
699{
700    //float d;
701    //float r;
702    int sx,sy;
703    int drew=0;
704    int boxsizex=5;
705    int boxsizey=5;
706    float flux;
707
708    if((x<0)||(x>PrimaryCCD.getXRes()/PrimaryCCD.getBinX())||(y<0)||(y>PrimaryCCD.getYRes()/PrimaryCCD.getBinY()))
709    {
710        //  this star is not on the ccd frame anyways
711        return 0;
712    }
713
714
715
716    //  calculate flux from our zero point and gain values
717    flux=pow(10,((mag-z)*k/-2.5));
718    //  ok, flux represents one second now
719    //  scale up linearly for exposure time
720    flux=flux*ExposureRequest;
721
722
723    float qx;
724    //  we need a box size that gives a radius at least 3 times fwhm
725    qx=seeing/ImageScalex;
726    qx=qx*3;
727    boxsizex=(int)qx;
728    boxsizex++;
729    qx=seeing/ImageScaley;
730    qx=qx*3;
731    boxsizey=(int)qx;
732    boxsizey++;
733
734    //IDLog("BoxSize %d %d\n",boxsizex,boxsizey);
735
736
737    for(sy=-boxsizey; sy<=boxsizey; sy++) {
738        for(sx=-boxsizey; sx<=boxsizey; sx++) {
739            int rc;
740            float dc;   //  distance from center
741            float fp;   //  flux this pixel;
742
743            //  need to make this account for actual pixel size
744            dc=sqrt(sx*sx*ImageScalex*ImageScalex+sy*sy*ImageScaley*ImageScaley);
745            //  now we have the distance from center, in arcseconds
746            //  This should be gaussian, but, for now we'll just go with
747            //  a simple linear function
748            float fa;
749            fa=exp(-2.0*0.7*(dc*dc)/seeing/seeing);
750            fp=fa*flux*PrimaryCCD.getBinX()*PrimaryCCD.getBinY();
751            if(fp < 0) fp=0;
752
753            /*
754            if(dc < boxsize) {
755                dc=boxsize-dc;
756                dc=dc/boxsize;
757                fp=dc*flux;
758            } else {
759                fp=0;
760            }
761            */
762            rc=AddToPixel(x+sx,y+sy,fp);
763            if(rc != 0) drew=1;
764        }
765    }
766    return drew;
767}
768
769int CCDSim::AddToPixel(int x,int y,int val)
770{
771    int drew=0;
772    if(x >= 0) {
773        if(x < PrimaryCCD.getXRes()/PrimaryCCD.getBinX()) {
774            if(y >= 0) {
775                if(y < PrimaryCCD.getYRes()/PrimaryCCD.getBinY()) {
776                    unsigned short *pt;
777                    int newval;
778                    drew++;
779                    pt=(unsigned short int *)PrimaryCCD.getFrameBuffer();
780                    pt+=(y*PrimaryCCD.getXRes()/PrimaryCCD.getBinX());
781                    pt+=x;
782                    newval=pt[0];
783                    newval+=val;
784                    if(newval > maxval) newval=maxval;
785                    pt[0]=newval;
786                }
787            }
788        }
789    }
790    return drew;
791}
792
793bool CCDSim::GuideNorth(float v)
794{
795    float c;
796
797    c=v*GuideRate;  //
798    c=c/3600;
799    Dec=Dec+c;
800
801    return true;
802}
803bool CCDSim::GuideSouth(float v)
804{
805    float c;
806
807    c=v*GuideRate;  //
808    c=c/3600;
809    Dec=Dec-c;
810
811    return true;
812}
813
814bool CCDSim::GuideEast(float v)
815{
816    float c;
817
818    c=v*GuideRate;
819    c=c/3600.0/15.0;
820    c=c/(cos(Dec*0.0174532925));
821    RA=RA-c;
822
823    return true;
824}
825bool CCDSim::GuideWest(float v)
826{
827    float c;
828
829    c=v*GuideRate;  //
830    c=c/3600.0/15.0;
831    c=c/(cos(Dec*0.0174532925));
832    RA=RA+c;
833
834    return true;
835}
836
837bool CCDSim::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
838{
839    //  first check if it's for our device
840    //IDLog("INDI::CCD::ISNewNumber %s\n",name);
841    if(strcmp(dev,deviceName())==0)
842    {
843        //  This is for our device
844        //  Now lets see if it's something we process here
845
846        //IDLog("CCDSim::ISNewNumber %s\n",name);
847        if(strcmp(name,"SIMULATOR_SETTINGS")==0) {
848            //  We are being asked to set camera binning
849            SimulatorSettingsNV->s=IPS_OK;
850
851            for(int x=0; x<n; x++) {
852                //fprintf(stderr,"name %s value %4.2f\n",names[x],values[x]);
853                if(values[x] != 0) {
854                    SimulatorSettingsN[x].value=values[x];
855                } else {
856                    //  We ignore zeros on most of our items
857                    //  because they likely mean it was just a field not
858                    //  actually filled in, but, for the dec offset it is
859                    //  important to keep a zero value
860                    if(strcmp(names[x],"SIM_OAGOFFSET")==0) {
861                        SimulatorSettingsN[x].value=values[x];
862                    }
863                }
864            }
865
866            //  Reset our parameters now
867            SetupParms();
868            IDSetNumber(SimulatorSettingsNV,NULL);
869            saveConfig();
870
871            //IDLog("Frame set to %4.0f,%4.0f %4.0f x %4.0f\n",CcdFrameN[0].value,CcdFrameN[1].value,CcdFrameN[2].value,CcdFrameN[3].value);
872            //seeing=SimulatorSettingsN[0].value;
873            return true;
874        }
875
876
877    }
878    //  if we didn't process it, continue up the chain, let somebody else
879    //  give it a shot
880    return INDI::CCD::ISNewNumber(dev,name,values,names,n);
881}
882
883
884bool CCDSim::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
885{
886    //IDLog("Enter IsNewSwitch for %s\n",name);
887    //for(int x=0; x<n; x++) {
888    //    IDLog("Switch %s %d\n",names[x],states[x]);
889    //}
890
891    if(strcmp(dev,deviceName())==0) {
892        //  This one is for us
893
894
895        if(strcmp(name,"ON_TIME_FACTOR")==0) {
896
897            //  client is telling us what to do with co-ordinate requests
898            TimeFactorSV->s=IPS_OK;
899            IUUpdateSwitch(TimeFactorSV,states,names,n);
900            //  Update client display
901            IDSetSwitch(TimeFactorSV,NULL);
902
903            saveConfig();
904            if(TimeFactorS[0].s==ISS_ON    ) {
905                //IDLog("CCDSim:: Time Factor 1\n");
906                TimeFactor=1;
907            }
908            if(TimeFactorS[1].s==ISS_ON    ) {
909                //IDLog("CCDSim:: Time Factor 0.1\n");
910                TimeFactor=0.1;
911            }
912            if(TimeFactorS[2].s==ISS_ON    ) {
913                //IDLog("CCDSim:: Time Factor 0.01\n");
914                TimeFactor=0.01;
915            }
916
917            return true;
918        }
919
920    }
921
922    //  Nobody has claimed this, so, ignore it
923    return INDI::CCD::ISNewSwitch(dev,name,states,names,n);
924}
925
Note: See TracBrowser for help on using the repository browser.