1 // Copyright (c) <2012> <Leif Asbrink>
2 //
3 // Permission is hereby granted, free of charge, to any person
4 // obtaining a copy of this software and associated documentation
5 // files (the "Software"), to deal in the Software without restriction,
6 // including without limitation the rights to use, copy, modify,
7 // merge, publish, distribute, sublicense, and/or sell copies of
8 // the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be
12 // included in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
21 // OR OTHER DEALINGS IN THE SOFTWARE.
22
23
24
25 #include <ctype.h>
26 #include <unistd.h>
27 #include "globdef.h"
28 #include "uidef.h"
29 #include "fft1def.h"
30 #include "fft2def.h"
31 #include "caldef.h"
32 #include "rusage.h"
33 #include "thrdef.h"
34
35 #define INFOLINE 3
36
cal_initscreen(void)37 void cal_initscreen(void)
38 {
39 int i;
40 char s[256];
41 clear_screen();
42 sprintf(s,"%s for %s. Press F1 or '!' for info.",cal_type_text[cal_type],
43 rxmodes[rx_mode]);
44 for(i=0; i<screen_width*(2*MAX_ADCHAN); i++)cal_graph[i]=screen_height-1;
45 settextcolor(14);
46 lir_text(10,0,s);
47 settextcolor(7);
48 lir_refresh_screen();
49 }
50
normalise_fft1_filtercorr(float * out)51 void normalise_fft1_filtercorr(float *out)
52 {
53 int i, j, k;
54 int mm;
55 float t1, t2, sum[2];
56 mm=2*ui.rx_rf_channels;
57 for(i=0; i<mm*fft1_size; i++)out[i]=1000000000*fft1_filtercorr[i];
58 //Make the average gain equal to one (weighted by desired spectrum)
59 t1=0;
60 sum[0]=0;
61 sum[1]=0;
62 for(i=0; i<fft1_size; i++)
63 {
64 t2=pow(fft1_desired[i],2.0);
65 t1+=t2;
66 k=0;
67 for(j=0; j<mm; j+=2)
68 {
69 sum[k]+=t2*(pow(out[mm*i+j ],2.0)+
70 pow(out[mm*i+j+1],2.0));
71 k++;
72 }
73 }
74 sum[0]=sqrt(sum[0]/t1);
75 sum[1]=sqrt(sum[1]/t1);
76 for(i=0; i<fft1_size; i++)
77 {
78 k=0;
79 for(j=0; j<mm; j+=2)
80 {
81 out[mm*i+j ]/=sum[k];
82 out[mm*i+j+1]/=sum[k];
83 k++;
84 }
85 }
86 }
87
write_filcorr(int siz)88 void write_filcorr(int siz)
89 {
90 FILE *file;
91 int i;
92 int wrbuf[10];
93 char s[80];
94 make_filfunc_filename(s);
95 file = fopen(s, "wb");
96 if (file == NULL)
97 {
98 DEB"\nCould not open file %s\n",s);
99 lirerr(1144);
100 return;
101 }
102 wrbuf[2]=rx_mode;
103 wrbuf[3]=ui.rx_input_mode;
104 wrbuf[4]=genparm[FIRST_FFT_VERNR];
105 wrbuf[5]=ui.rx_ad_speed;
106 wrbuf[6]=ui.rx_rf_channels;
107 if(siz >= 0)
108 {
109 wrbuf[0]=fft1_n;
110 wrbuf[1]=fft1_size;
111 wrbuf[7]=siz;
112 }
113 else
114 {
115 wrbuf[0]=fft2_n;
116 wrbuf[1]=fft2_size;
117 wrbuf[7]=0;
118 }
119 for(i=8; i<10; i++)wrbuf[i]=0;
120 i=fwrite(wrbuf, sizeof(int),10,file);
121 if(i != 10)
122 {
123 errx:
124 fclose(file);
125 lirerr(1145);
126 return;
127 }
128 if(siz < 0)
129 {
130 i=fwrite(cal_fft1_filtercorr, 2*ui.rx_rf_channels*sizeof(float),fft2_size, file);
131 if(i != fft2_size)goto errx;
132 i=fwrite(cal_fft1_desired,sizeof(float),fft2_size,file);
133 if(i != fft2_size)goto errx;
134 }
135 else
136 {
137 if(siz == 0)
138 {
139 normalise_fft1_filtercorr(cal_tmp);
140 i=fwrite(cal_tmp, twice_rxchan*sizeof(float),fft1_size, file);
141 if(i != fft1_size)goto errx;
142 i=fwrite(fft1_desired,sizeof(float),fft1_size,file);
143 if(i != fft1_size)goto errx;
144 }
145 else
146 {
147 i=fwrite(cal_buf, 2*ui.rx_rf_channels*sizeof(float),siz, file);
148 if(i != siz)goto errx;
149 // Store fft1_desired in siz points in cal_buf2
150 resize_fft1_desired(fft1_size, fft1_desired, siz, cal_buf2);
151 i=fwrite(cal_buf2,sizeof(float),siz,file);
152 if(i != siz)goto errx;
153 }
154 }
155 i=fwrite(wrbuf, sizeof(int),10,file);
156 if(i != 10)goto errx;
157 fclose(file);
158 }
159
160
do_cal_interval(void)161 void do_cal_interval(void)
162 {
163 int i, j, k, l, m, n, color,wid,first_pulse;
164 int p0, ia, ib, ic, ja, jb;
165 int imode, lim;
166 int rawbytes;
167 int maxval[MAX_ADCHAN],minval[MAX_ADCHAN];
168 int old_end;
169 int points, mask;
170 int textend,ysiz,ytop;
171 char s[80];
172 float *filpwr;
173 float pwr_l, pwr_h;
174 float old_trig_power,trig_power,dc[MAX_ADCHAN],ampmax;
175 float noise_floor;
176 float t1,t2,t3;
177 // Collect 0.5 seconds of raw data.
178 rawbytes=ui.rx_ad_speed*snd[RXAD].framesize;
179 if(rawbytes > timf1_bytes-3*timf1_blockbytes)
180 rawbytes=timf1_bytes-3*timf1_blockbytes;
181 if(rawbytes < 0.25*ui.rx_ad_speed*snd[RXAD].framesize && fft1_size < 32768)
182 {
183 lirerr(1241);
184 goto calint_error_exit;
185 }
186 points=rawbytes/snd[RXAD].framesize;
187 make_power_of_two(&points);
188 points >>= 1;
189 rawbytes=points*snd[RXAD].framesize;
190 if(rawbytes > fft1_bytes/2)
191 {
192 rawbytes=fft1_bytes/2;
193 points=rawbytes/snd[RXAD].framesize;
194 }
195 filpwr=&fft1_float[points];
196 old_trig_power=1;
197 old_end=-1;
198 cal_ygain=1;
199 cal_xgain=1;
200 cal_interval=0;
201 imode=ui.rx_input_mode&(DWORD_INPUT+TWO_CHANNELS+IQ_DATA);
202 restart:;
203 cal_signal_level=0;
204 cal_type=CAL_TYPE_PULSE_INTERVAL;
205 cal_initscreen();
206 lir_text(3, 1,"Connect pulse generator to all antenna inputs");
207 lir_text(3, 2,"Press ENTER when OK. (+),(-) for y-scale E,C for x-scale");
208 lir_text(0,INFOLINE,"DC offset");
209 lir_text(5,INFOLINE+1,"Min");
210 lir_text(5,INFOLINE+2,"Max");
211 lir_text(3,INFOLINE+3,"Level");
212 lir_refresh_screen();
213 timf1p_px=timf1p_pa;
214 thread_status_flag[THREAD_CAL_INTERVAL]=THRFLAG_ACTIVE;
215 while(thread_command_flag[THREAD_CAL_INTERVAL] == THRFLAG_ACTIVE)
216 {
217 // Get power as a function of time.
218 // The A/D converters are AC coupled so we remove DC components.
219 for(i=0; i<MAX_ADCHAN; i++)
220 {
221 maxval[i]=0x80000000;
222 minval[i]=0x7fffffff;
223 dc[i]=0;
224 }
225 while( ((timf1p_pa-timf1p_px+timf1_bytes)&timf1_bytemask) < rawbytes &&
226 thread_command_flag[THREAD_CAL_INTERVAL] == THRFLAG_ACTIVE)
227 {
228 lir_await_event(EVENT_TIMF1);
229 }
230 timf1p_px=(timf1p_pa-rawbytes+timf1_bytes)&timf1_bytemask;
231 if( (ui.rx_input_mode & DWORD_INPUT) == 0)
232 {
233 p0=timf1p_px/sizeof(short int);
234 mask=timf1_bytemask/sizeof(short int);
235 }
236 else
237 {
238 p0=timf1p_px/sizeof(int);
239 mask=timf1_bytemask/sizeof(int);
240 }
241 switch ( imode )
242 {
243 case 0:
244 // One channel 16 bit real data
245 for(i=0; i<points; i++)
246 {
247 k=(p0+i)&mask;
248 dc[0]+=timf1_short_int[k];
249 if(minval[0]>timf1_short_int[k])minval[0]=timf1_short_int[k];
250 if(maxval[0]<timf1_short_int[k])maxval[0]=timf1_short_int[k];
251 }
252 dc[0]/=points;
253 for(i=0; i<points; i++)
254 {
255 k=(p0+i)&mask;
256 fft1_float[i]=pow( 65536.0*(timf1_short_int[k]-dc[0]), 2.);
257 }
258 break;
259
260 case 1:
261 // One channel 32 bit real data.
262 for(i=0; i<points; i++)
263 {
264 k=(p0+i)&mask;
265 dc[0]+=timf1_int[k];
266 if(minval[0]>timf1_int[k])minval[0]=timf1_int[k];
267 if(maxval[0]<timf1_int[k])maxval[0]=timf1_int[k];
268 }
269 dc[0]/=points;
270 for(i=0; i<points; i++)
271 {
272 k=(p0+i)&mask;
273 fft1_float[i]=pow( timf1_int[k]-dc[0], 2.);
274 }
275 break;
276
277 case 2:
278 // Two channels 16 bit real data
279 for(i=0; i<points; i++)
280 {
281 k=(p0+2*i)&mask;
282 for(j=0; j<2; j++)
283 {
284 dc[j]+=timf1_short_int[k+j];
285 if(minval[j]>timf1_short_int[k+j])minval[j]=timf1_short_int[k+j];
286 if(maxval[j]<timf1_short_int[k+j])maxval[j]=timf1_short_int[k+j];
287 }
288 }
289 for(j=0; j<2; j++)dc[j]/=points;
290 for(i=0; i<points; i++)
291 {
292 t1=0;
293 k=(p0+2*i)&mask;
294 for(j=0; j<2; j++)
295 {
296 t2=timf1_short_int[k+j]-dc[j];
297 t1+=t2*t2;
298 }
299 fft1_float[i]=t1*65536.0*65536.0;
300 }
301 break;
302
303 case 3:
304 // Two channels 32 bit real data
305 for(i=0; i<points; i++)
306 {
307 k=(p0+2*i)&mask;
308 for(j=0; j<2; j++)
309 {
310 dc[j]+=timf1_int[k+j];
311 if(minval[j]>timf1_int[k+j])minval[j]=timf1_int[k+j];
312 if(maxval[j]<timf1_int[k+j])maxval[j]=timf1_int[k+j];
313 }
314 }
315 for(j=0; j<2; j++)dc[j]/=points;
316 for(i=0; i<points; i++)
317 {
318 k=(p0+2*i)&mask;
319 t1=0;
320 for(j=0; j<2; j++)
321 {
322 t2=timf1_int[k+j]-dc[j];
323 t1+=t2*t2;
324 }
325 fft1_float[i]=t1;
326 }
327 break;
328
329
330 case 4:
331 // One channel 16 bit IQ data
332 for(i=0; i<points; i++)
333 {
334 k=(p0+2*i)&mask;
335 for(j=0; j<2; j++)
336 {
337 dc[j]+=timf1_short_int[k+j];
338 if(minval[j]>timf1_short_int[k+j])minval[j]=timf1_short_int[k+j];
339 if(maxval[j]<timf1_short_int[k+j])maxval[j]=timf1_short_int[k+j];
340 }
341 }
342 for(j=0; j<2; j++)dc[j]/=points;
343 for(i=0; i<points; i++)
344 {
345 k=(p0+2*i)&mask;
346 t1=0;
347 for(j=0; j<2; j++)
348 {
349 t2=timf1_short_int[k+j]-dc[j];
350 t1+=t2*t2;
351 }
352 fft1_float[i]=t1*65536.0*65536.0;
353 }
354 break;
355
356 case 5:
357 // One channel 32 bit IQ data
358 for(i=0; i<points; i++)
359 {
360 k=(p0+2*i)&mask;
361 for(j=0; j<2; j++)
362 {
363 dc[j]+=timf1_int[k+j];
364 if(minval[j]>timf1_int[k+j])minval[j]=timf1_int[k+j];
365 if(maxval[j]<timf1_int[k+j])maxval[j]=timf1_int[k+j];
366 }
367 }
368 for(j=0; j<2; j++)dc[j]/=points;
369 for(i=0; i<points; i++)
370 {
371 k=(p0+2*i)&mask;
372 t1=0;
373 for(j=0; j<2; j++)
374 {
375 t2=timf1_int[k+j]-dc[j];
376 t1+=t2*t2;
377 }
378 fft1_float[i]=t1;
379 }
380 break;
381
382 case 6:
383 // Two channels 16 bit IQ data
384 for(i=0; i<points; i++)
385 {
386 k=(p0+4*i)&mask;
387 for(j=0; j<4; j++)
388 {
389 dc[j]+=timf1_short_int[k+j];
390 if(minval[j]>timf1_short_int[k+j])minval[j]=timf1_short_int[k+j];
391 if(maxval[j]<timf1_short_int[k+j])maxval[j]=timf1_short_int[k+j];
392 }
393 }
394 for(j=0; j<4; j++)dc[j]/=points;
395 for(i=0; i<points; i++)
396 {
397 k=(p0+4*i)&mask;
398 t1=0;
399 for(j=0; j<4; j++)
400 {
401 t2=timf1_short_int[k+j]-dc[j];
402 t1+=t2*t2;
403 }
404 fft1_float[i]=t1*65536.0*65536.0;
405 }
406 break;
407
408 case 7:
409 // Two channels 32 bit IQ data
410 for(i=0; i<points; i++)
411 {
412 k=(p0+4*i)&mask;
413 for(j=0; j<4; j++)
414 {
415 dc[j]+=timf1_int[k+j];
416 if(minval[j]>timf1_int[k+j])minval[j]=timf1_int[k+j];
417 if(maxval[j]<timf1_int[k+j])maxval[j]=timf1_int[k+j];
418 }
419 }
420 for(j=0; j<4; j++)dc[j]/=points;
421 for(i=0; i<points; i++)
422 {
423 k=(p0+4*i)&mask;
424 t1=0;
425 for(j=0; j<4; j++)
426 {
427 t2=timf1_int[k+j]-dc[j];
428 t1+=t2*t2;
429 }
430 fft1_float[i]=t1;
431 }
432 break;
433 }
434 lir_sched_yield();
435 cal_signal_level=BIG;
436 if( (ui.rx_input_mode&(DWORD_INPUT)) == 0)lim=0x7ff0; else lim=0x7ff00000;
437 for(j=0; j<ui.rx_ad_channels; j++)
438 {
439 sprintf(s," %4.2f ",dc[j]);
440 lir_text(10+15*j,INFOLINE,s);
441 sprintf(s," %d ",minval[j]);
442 lir_text(10+15*j,INFOLINE+1,s);
443 sprintf(s," %d ",maxval[j]);
444 lir_text(10+15*j,INFOLINE+2,s);
445 t1=-minval[j];
446 if(t1<maxval[j])t1=maxval[j];
447 if(t1 < cal_signal_level)cal_signal_level=t1;
448 if(minval[j] <= -lim || maxval[j] >= lim)
449 {
450 lir_text(10+15*j,INFOLINE+3,"OVERFLOW");
451 t1=1;
452 }
453 else
454 {
455 t1/=lim;
456 sprintf(s," %1.6f%% ",100*t1);
457 lir_text(10+15*j,INFOLINE+3,s);
458 }
459 }
460 cal_signal_level/=lim;
461 // Find the largest power value and point wid to it.
462 trig_power=0;
463 wid=0;
464 for(i=0; i<points; i++)
465 {
466 if(trig_power < fft1_float[i])
467 {
468 trig_power=fft1_float[i];
469 wid=i;
470 }
471 }
472 lir_sched_yield();
473 // Get an approximate width of the pulse (remember it may have a
474 // very ugly shape!)
475 i=wid;
476 while( i<points-3 && (fft1_float[i] >= trig_power/20 ||
477 fft1_float[i+1] >= trig_power/20 ||
478 fft1_float[i+2] >= trig_power/20 ||
479 fft1_float[i+3] >= trig_power/20 ))
480 {
481 i++;
482 if(i-wid >100)goto skip;
483 }
484 while( wid>2 && (fft1_float[wid] >= trig_power/20 ||
485 fft1_float[wid-1] >= trig_power/20 ||
486 fft1_float[wid-2] >= trig_power/20 ||
487 fft1_float[wid-3] >= trig_power/20 ))
488 {
489 wid--;
490 if(i-wid > 100)goto skip;
491 }
492 wid=(i-wid);
493 wid=wid/2+1;
494 // Low pass filter the power function and store in filpwr
495 for(i=wid; i<points; i++)
496 {
497 t1=0;
498 for(j=i-wid; j<=i; j++)
499 {
500 t1+=fft1_float[j];
501 }
502 filpwr[i-wid/2]=t1/wid;
503 }
504 // Save the maximum amplitude and make trig power 31.6 times smaller
505 // than the maximum value (-15dB)
506 ampmax=sqrt(trig_power);
507 if(trig_power > old_trig_power)old_trig_power=trig_power;
508 trig_power=old_trig_power/31.6;
509 // Remember trig_power for the next set of data.
510 old_trig_power/=2;
511 ia=0;
512 i=wid;
513 if(wid < points/16)
514 {
515 // find the position of the first pulse
516 interval_init:;
517 while( i<points-3*wid && filpwr[i] <= trig_power)i++;
518 ja=i;
519 while( i<points-wid && filpwr[i] >= trig_power/20)i++;
520 if(ja==wid)goto interval_init;
521 jb=i;
522 t1=0;
523 for(k=ja; k<jb; k++)
524 {
525 if(fft1_float[k] > t1)
526 {
527 t1=fft1_float[k];
528 ia=k;
529 }
530 }
531 first_pulse=ia;
532 // Find sucessive pulses and store the intervals in cal_tmp
533 k=0;
534 cal_interval=0;
535 j=0;
536 find_interval:;
537 while( i<points-wid && filpwr[i] <= trig_power)i++;
538 ja=i;
539 while( i<points-wid && filpwr[i] >= trig_power/20)i++;
540 jb=i;
541 t1=0;
542 ib=i;
543 for(k=ja; k<jb; k++)
544 {
545 if(fft1_float[k] > t1)
546 {
547 t1=fft1_float[k];
548 ib=k;
549 }
550 }
551 if(i<points-wid)
552 {
553 if(ib-ia<4*wid)goto find_interval;
554 cal_tmp[j]=ib-ia;
555 j++;
556 ia=ib;
557 if(j<fft1_size)goto find_interval;
558 }
559 // Since the pulses may vary in amplitude by more than we allow for in
560 // the setting of the trigger level we sort the intervals in ascending order
561 // and take desicions if the interval is 1,2 or 3 pulses.
562 if(j>0)
563 {
564 for(i=0; i<j-1; i++)
565 {
566 for(k=i+1; k<j; k++)
567 {
568 if(cal_tmp[k]<cal_tmp[i])
569 {
570 t1=cal_tmp[k];
571 cal_tmp[k]=cal_tmp[i];
572 cal_tmp[i]=t1;
573 }
574 }
575 }
576 i=j/4+1;
577 t1=0;
578 while(i<j && cal_tmp[i-1]>0.7*cal_tmp[i])
579 {
580 t1+=cal_tmp[i];
581 i++;
582 }
583 i-=(j/4+1);
584 if(i != 0)
585 {
586 t1/=i;
587 k=0;
588 for(i=0; i<j; i++)
589 {
590 if(cal_tmp[i]>0.8*t1 && cal_tmp[i]<1.2*t1)
591 {
592 cal_interval+=cal_tmp[i];
593 k++;
594 }
595 else
596 {
597 if(cal_tmp[i]>1.8*t1 && cal_tmp[i]<2.2*t1)
598 {
599 cal_interval+=cal_tmp[i];
600 k+=2;
601 }
602 else
603 {
604 if(cal_tmp[i]>2.7*t1 && cal_tmp[i]<3.3*t1)
605 {
606 cal_interval+=cal_tmp[i];
607 k+=3;
608 }
609 }
610 }
611 }
612 cal_interval/=k;
613 // Get the noise floor.
614 // First locate the smallest power value in the filtered power vs time curve.
615 pwr_l=BIG;
616 pwr_h=0;
617 for(i=wid; i<points-wid; i++)
618 {
619 if(pwr_l>filpwr[i])pwr_l=filpwr[i];
620 if(pwr_h<filpwr[i])pwr_h=filpwr[i];
621 }
622 // Assume the noise floor is 10dB above this level
623 pwr_l*=10;
624 // Limit our guess to the range -10dB to -60 dB
625 if(pwr_l < 0.000001*pwr_h)pwr_l=0.000001*pwr_h;
626 if(pwr_l > 0.1*pwr_h)pwr_l=0.1*pwr_h;
627 // Count the number of points above the noise floor and
628 // get the average value of the points below the noise floor.
629 j=0;
630 get_floor:;
631 t2=0;
632 k=0;
633 j++;
634 if(j < 10)
635 {
636 for(i=wid; i<points-wid; i++)
637 {
638 if(filpwr[i]<pwr_l)
639 {
640 k++;
641 t2+=fft1_float[i];
642 }
643 }
644 t2/=k;
645 if(k < 0.4*(points-2*wid))
646 {
647 pwr_l*=3.333;
648 goto get_floor;
649 }
650 if(k > 0.6*(points-2*wid))
651 {
652 if(pwr_l > 4*t2)
653 {
654 pwr_l=3*t2;
655 goto get_floor;
656 }
657 else
658 {
659 if(pwr_l < 2*t2)
660 {
661 pwr_l/=2;
662 goto get_floor;
663 }
664 }
665 }
666 }
667 else
668 {
669 t2=pwr_h;
670 }
671 noise_floor=pwr_h/t2;
672 // Show one of the pulses.
673 while(first_pulse+7*(screen_width>>3) > points)
674 first_pulse -= cal_interval;
675 while(first_pulse < (screen_width>>3))
676 first_pulse += cal_interval;
677 if(first_pulse+7*(screen_width>>3) <= points)
678 {
679 ic=first_pulse+7*(screen_width>>3);
680 ia=first_pulse-(screen_width>>3);
681 for(j=0; j<=ui.rx_ad_channels; j++)
682 {
683 m=screen_width*j;
684 n=screen_width*(ui.rx_ad_channels+1);
685 for(i=1; i<=old_end; i++)
686 {
687 lir_line(cal_graph[n+i-1], cal_graph[m+i-1],
688 cal_graph[n+i ], cal_graph[m+i ],0);
689 if(kill_all_flag) goto calint_error_exit;
690 }
691 }
692 textend=(INFOLINE+4)*text_height;
693 ytop=textend+screen_height*0.3;
694 ysiz=screen_height-ytop;
695 n=-1;
696 for(j=ia; j<ic; j++)
697 {
698 i=(screen_width>>3)+cal_xgain*(j-first_pulse);
699 if(i>=0 && i<screen_width)
700 {
701 n++;
702 if( (n&0x7f)==0) lir_sched_yield();
703 old_end=n;
704 cal_graph[screen_width*(ui.rx_ad_channels+1)+n]=i;
705 cal_graph[n]=textend+screen_height*(0.4-0.008*log(fft1_float[j]));
706 switch ( imode )
707 {
708 // One channel 16 bit
709 case 0:
710 k=(p0+j)&mask;
711 t2=4*6553.6*cal_ygain*timf1_short_int[k]/ampmax;
712 if(t2 <-0.45)t2=-0.45;
713 if(t2 >0.45)t2=0.45;
714 cal_graph[screen_width+n]=ytop+ysiz*(0.5-t2);
715 m=1;
716 break;
717
718 // One channel 32 bit
719 case 1:
720 k=(p0+j)&mask;
721 t2=0.4*cal_ygain*timf1_int[k]/ampmax;
722 if(t2 <-0.45)t2=-0.45;
723 if(t2 >0.45)t2=0.45;
724 cal_graph[screen_width+n]=ytop+ysiz*(0.5-t2);
725 m=1;
726 break;
727
728 // Two channels 16 bit real data
729 case 2:
730 k=(p0+2*j)&mask;
731 for(m=0; m<2; m++)
732 {
733 t2=2*6553.6*cal_ygain*timf1_short_int[k+m]/ampmax;
734 if(t2 <-0.22)t2=-0.22;
735 if(t2 >0.22)t2=0.22;
736 if(m == 1)t2-=0.5;
737 cal_graph[screen_width*(m+1)+n]=ytop+ysiz*(0.25-t2);
738 }
739 m=2;
740 break;
741
742 // Two channels 32 bit real data
743 case 3:
744 k=(p0+2*j)&mask;
745 for(m=0; m<2; m++)
746 {
747 t2=0.4*cal_ygain*timf1_int[k+m]/ampmax;
748 if(t2 <-0.22)t2=-0.22;
749 if(t2 >0.22)t2=0.22;
750 if(m == 1)t2-=0.5;
751 cal_graph[screen_width*(m+1)+n]=ytop+ysiz*(0.25-t2);
752 }
753 m=2;
754 break;
755
756 // One channel 16 bit IQ data
757 case 4:
758 k=(p0+2*j)&mask;
759 for(m=0; m<2; m++)
760 {
761 t2=4*6553.6*cal_ygain*timf1_short_int[k+m]/ampmax;
762 if(t2 <-0.45)t2=-0.45;
763 if(t2 >0.45)t2=0.45;
764 cal_graph[screen_width*(m+1)+n]=ytop+ysiz*(0.5-t2);
765 }
766 m=2;
767 break;
768
769 // One channel 32 bit IQ data
770 case 5:
771 k=(p0+2*j)&mask;
772 for(m=0; m<2; m++)
773 {
774 t2=0.4*cal_ygain*timf1_int[k+m]/ampmax;
775 if(t2 <-0.45)t2=-0.45;
776 if(t2 >0.45)t2=0.45;
777 cal_graph[screen_width*(m+1)+n]=ytop+ysiz*(0.5-t2);
778 }
779 m=2;
780 break;
781
782 // Two channels 16 bit IQ data
783 case 6:
784 k=(p0+4*j)&mask;
785 t3=4*6553.6*cal_ygain/ampmax;
786 for(m=0; m<4; m++)
787 {
788 t2=t3*timf1_short_int[k+m];
789 if(t2 <-0.22)t2=-0.22;
790 if(t2 >0.22)t2=0.22;
791 if(m > 1)t2-=0.5;
792 cal_graph[screen_width*(m+1)+n]=ytop+ysiz*(0.25-t2);
793 }
794 m=4;
795 break;
796
797 // Two channels 32 bit IQ data
798 case 7:
799 k=(p0+4*j)&mask;
800 for(m=0; m<4; m++)
801 {
802 t2=0.4*cal_ygain*timf1_int[k+m]/ampmax;
803 if(t2 <-0.22)t2=-0.22;
804 if(t2 >0.22)t2=0.22;
805 if(m > 1)t2-=0.5;
806 cal_graph[screen_width*(m+1)+n]=ytop+ysiz*(0.25-t2);
807 }
808 m=4;
809 break;
810
811 default:
812 m=0;
813 }
814 if(n>0)
815 {
816 lir_line(cal_graph[screen_width*(ui.rx_ad_channels+1)+n-1],
817 cal_graph[n-1],i,cal_graph[n],15);
818 if(kill_all_flag) goto calint_error_exit;
819 for(l=0; l<m; l++)
820 {
821 color=10+3*(l&1);
822 if( (ui.rx_input_mode&IQ_DATA) == 0)color=14;
823 lir_line(cal_graph[screen_width*(ui.rx_ad_channels +1)+n-1],
824 cal_graph[(l+1)*screen_width+n-1],
825 i,cal_graph[(l+1)*screen_width+n],color);
826 if(kill_all_flag) goto calint_error_exit;
827 }
828 }
829 }
830 sprintf(s,"Scale x=%f y=%f S/N=%f dB PRF %.1f Hz ",
831 cal_xgain,cal_ygain,10*log10(noise_floor),
832 ui.rx_ad_speed/cal_interval);
833 lir_text(1,INFOLINE+4,s);
834 }
835 }
836 }
837 }
838 }
839 skip:;
840 timf1p_px=(timf1p_px+rawbytes)&timf1_bytemask;
841 lir_refresh_screen();
842 }
843 if(thread_command_flag[THREAD_CAL_INTERVAL]==THRFLAG_IDLE)
844 {
845 thread_status_flag[THREAD_CAL_INTERVAL]=THRFLAG_IDLE;
846 while(thread_command_flag[THREAD_CAL_INTERVAL]==THRFLAG_IDLE)
847 {
848 lir_await_event(EVENT_TIMF1);
849 timf1p_px=(timf1p_px+rawbytes)&timf1_bytemask;
850 }
851 if(thread_command_flag[THREAD_CAL_INTERVAL]==THRFLAG_ACTIVE)goto restart;
852 }
853 calint_error_exit:;
854 thread_status_flag[THREAD_CAL_INTERVAL]=THRFLAG_RETURNED;
855 while(thread_command_flag[THREAD_CAL_INTERVAL] != THRFLAG_NOT_ACTIVE)
856 {
857 lir_sleep(1000);
858 }
859 }
860
861