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 #include <string.h>
24 #include "globdef.h"
25 #include "uidef.h"
26 #include "fft1def.h"
27 #include "fft2def.h"
28 #include "llsqdef.h"
29 #include "caldef.h"
30 #include "keyboard_def.h"
31
32 #define IQ_FIT_MINFREQ 500
33 #define CORR_MINLEVEL 0.001
34 #define CORR_MAXLEVEL 20.
35 #define YSH 0.29
36 #define ERF_START -2.2
37 #define ERF_END 2.8
38
39 #define SYMFIT_ERROR -1
40 #define SYMFIT_ACCEPT -2
41 #define SYMFIT_CHANGE_LIMITS -3
42
draw_fitline(void)43 void draw_fitline(void)
44 {
45 int i;
46 i=screen_width*(-1+4*(float)(cal_midlim)/fft1_size);
47 lir_line(i,screen_height*(cal_yzer+YSH),i,screen_height*(cal_yzer-YSH),2);
48 }
49
50
make_symfit(int kk,int even,float * buf,float offset)51 void make_symfit(int kk, int even, float *buf, float offset)
52 {
53 int i, k, m, mm;
54 float t1, t2, t3, fft1_hsize;
55 mm=twice_rxchan;
56 fft1_hsize=0.5*(fft1_size-1);
57 k=0;
58 for(i=cal_lowedge; i<cal_midlim; i++)
59 {
60 t1=cal_buf5[i];
61 t2=1-i/fft1_hsize;
62 if(kk == 1)llsq_derivatives[k]=t1;
63 if(even == 1)
64 {
65 t2=t2*t2;
66 t3=t1*t2;
67 }
68 else
69 {
70 t3=t1*t2;
71 t2=t2*t2;
72 }
73 for(m=kk; m<llsq_npar; m++)
74 {
75 llsq_derivatives[m*llsq_neq+k]=t3;
76 t3*=t2;
77 }
78 llsq_errors[2*k]=t1*(buf[mm*i ]-offset);
79 if(ui.rx_rf_channels == 2)
80 {
81 llsq_errors[2*k+1]=t1*(buf[mm*i+2]-offset);
82 }
83 else
84 {
85 llsq_errors[2*k+1]=0;
86 }
87 k++;
88 }
89 if(llsq2() != 0)
90 {
91 lirerr(1050);
92 return;
93 }
94 // Store the fitted curve in cal_buf
95 for(i=0; i<=fft1_size/2; i++)
96 {
97 t2=1-i/fft1_hsize;
98 cal_buf[mm*i]=offset+kk*llsq_steps[0];
99 if(ui.rx_rf_channels == 2)cal_buf[mm*i+2]=offset+kk*llsq_steps[1];
100 if(even == 1)
101 {
102 t2=t2*t2;
103 t3=t2;
104 }
105 else
106 {
107 t3=t2;
108 t2=t2*t2;
109 }
110 for(m=kk; m<llsq_npar; m++)
111 {
112 cal_buf[mm*i ]+=llsq_steps[2*m]*t3;
113 if(ui.rx_rf_channels == 2)
114 {
115 cal_buf[mm*i+2]+=llsq_steps[2*m+1]*t3;
116 }
117 t3*=t2;
118 }
119 }
120 }
121
symmetry_fit_decide(float * buf,float offset,char * txt)122 int symmetry_fit_decide(float *buf, float offset, char *txt)
123 {
124 char s[80];
125 float t2;
126 int i,j,k,mm;
127 float center_region_ia;
128 int center_region_pix;
129 center_region_ia=0.4;
130 symfit_begin:;
131 cal_type=CAL_TYPE_FIX_CENTER_SYMFIT;
132 cal_initscreen();
133 mm=twice_rxchan;
134 lir_text(0,1,"Curve fitting to response of direct conversion receiver.");
135 lir_text(0,2,txt);
136 for(j=0; j<ui.rx_rf_channels; j++)
137 {
138 sprintf(s,"Ch%d",j);
139 lir_text(0,j+3,s);
140 for(k=0; k<llsq_npar; k++)
141 {
142 if(llsq_steps[j+2*k] < 1000)
143 {
144 sprintf(s,"%.4f",llsq_steps[j+2*k]);
145 }
146 else
147 {
148 sprintf(s,"%.0f",llsq_steps[j+2*k]);
149 }
150 lir_text(4+11*k,j+3,s);
151 }
152 }
153 lir_text(2,6, " +- => Change Y-scale");
154 lir_text(2,7, " 0 => Use raw data without curve fit");
155 lir_text(2,8, "1-9 => Fit with new number of terms");
156 lir_text(2,9, " C => Enter a larger number than 9 and fit");
157 lir_text(50,6," A => Use curve fitted with current no of terms");
158 lir_text(50,8," B => Back, change freq limits");
159 lir_text(50,9,"L,R => Border left, right");
160 settextcolor(14);
161 lir_text(0,10,"Raw data.");
162 settextcolor(12);
163 lir_text(16,10,"Difference raw to fitted.");
164 settextcolor(7);
165 redraw:;
166 center_region_pix=screen_width*(-1+4*center_region_ia);
167 lir_line(center_region_pix,screen_height*(cal_yzer+YSH),
168 center_region_pix,screen_height*(cal_yzer-YSH),1);
169 if(kill_all_flag) return SYMFIT_ERROR;
170 draw_fitline();
171 if(kill_all_flag) return SYMFIT_ERROR;
172 sprintf(s,"Y-gain = %f No of terms = %d ",cal_ygain,llsq_npar);
173 lir_text(0,5,s);
174 lir_hline(0,screen_height*cal_yzer,screen_last_xpixel,1);
175 if(kill_all_flag) return SYMFIT_ERROR;
176 lir_hline(0,screen_height*(cal_yzer+YSH),screen_last_xpixel,1);
177 if(kill_all_flag) return SYMFIT_ERROR;
178 for(i=0; i<screen_width; i++)
179 {
180 k=i*fft1_size/(4*screen_width)+fft1_size/4;
181 for(j=0; j<mm; j+=2)
182 {
183 lir_setpixel(i, cal_graph[screen_width*(2*j )+i], 0);
184 t2=0.1*cal_ygain*(buf[mm*k+j]-offset);
185 if(t2 <-cal_ymax)t2=-cal_ymax;
186 if(t2 >cal_ymax)t2=cal_ymax;
187 if(j > 0)t2-=YSH;
188 cal_graph[screen_width*(2*j )+i]=screen_height*(cal_yzer-t2);
189 lir_setpixel(i, cal_graph[screen_width*(2*j )+i], 14);
190 lir_setpixel(i, cal_graph[screen_width*(2*j+1)+i], 0);
191 t2=0.1*cal_ygain*(cal_buf[mm*k+j]-buf[mm*k+j]);
192 if(t2 <-cal_ymax)t2=-cal_ymax;
193 if(t2 >cal_ymax)t2=cal_ymax;
194 if(j > 0)t2-=YSH;
195 cal_graph[screen_width*(2*j+1)+i]=screen_height*(cal_yzer-t2);
196 lir_setpixel(i, cal_graph[screen_width*(2*j+1)+i], 12);
197 }
198 }
199 await_processed_keyboard();
200 if(kill_all_flag) return SYMFIT_ERROR;
201 if(lir_inkey == 'X')return SYMFIT_ERROR;
202 if(lir_inkey == F1_KEY || lir_inkey == '!')
203 {
204 help_message(300);
205 if(kill_all_flag) return SYMFIT_ERROR;
206 goto symfit_begin;
207 }
208 if(lir_inkey == 'C')
209 {
210 sprintf(s,"Enter number of terms (10 to %d) =>",LLSQ_MAXPAR);
211 lir_text(10,12,s);
212 i=lir_get_integer(11+strlen(s),12,3,10,LLSQ_MAXPAR);
213 clear_lines(12,12);
214 return i;
215 }
216 if(lir_inkey == 'B')return SYMFIT_CHANGE_LIMITS;
217 if(lir_inkey >= '0' && lir_inkey <= '9')return lir_inkey-'0';
218 if(lir_inkey == 'A')
219 {
220 for(i=center_region_ia*fft1_size; i<=fft1_size/2; i++)
221 {
222 for(j=0; j<mm; j+=2)
223 {
224 buf[mm*i+j]=cal_buf[mm*i+j];
225 }
226 }
227 return SYMFIT_ACCEPT;
228 }
229 if(lir_inkey == '+')cal_ygain*=2;
230 if(lir_inkey == '-')cal_ygain/=2;
231 if(lir_inkey == 'L')center_region_ia-=0.003;
232 if(center_region_ia < 0.3)center_region_ia=0.3;
233 if(lir_inkey == 'R')center_region_ia+=0.0025;
234 if(center_region_ia > 0.4975)center_region_ia=0.4975;
235 lir_line(center_region_pix,screen_height*(cal_yzer+YSH),
236 center_region_pix,screen_height*(cal_yzer-YSH),0);
237 if(kill_all_flag) return SYMFIT_ERROR;
238 goto redraw;
239 }
240
make_cal_fft1_filtercorr(void)241 void make_cal_fft1_filtercorr(void)
242 {
243 int i;
244 // We do calibration in fft2_size points (before Linrad-02.28 it
245 // was done in the much larger size fft1_size)
246 // Start by reducing the sizes of fft1_desired and fft1_filtercorr.
247 resize_fft1_desired(fft1_size, fft1_desired, fft2_size, cal_fft1_desired);
248 for(i=0; i<twice_rxchan*fft1_size; i++)cal_fft1_filtercorr[i]=fft1_filtercorr[i];
249 convert_filtercorr_fd_to_td(fft1_n, fft1_size, cal_fft1_filtercorr);
250 resize_filtercorr_td_to_fd(TRUE, fft1_size, cal_fft1_filtercorr,
251 fft2_n, fft2_size, cal_fft1_filtercorr);
252 }
253
cal_update_ram(void)254 int cal_update_ram(void)
255 {
256 int lowp, midp, higp, siz128;
257 int cal_hw_lowp;
258 int cal_hw_higp;
259 char s[80];
260 int mm, falloff_length, step;
261 int ia, ib;
262 int i, j, k, m, ja, jb, ka, kb;
263 float t1,t2,t3;
264 float ygain;
265 float z[MAX_ADCHAN];
266 int desired_shape;
267 char *shape_texts[2]={"erfc(x)","Parabolic"};
268 desired_shape=0;
269 siz128=fft2_size/128;
270 step=10;
271 ygain=1;
272 mm=twice_rxchan;
273 //clear_screen();
274 settextcolor(14);
275 // ******************************************************
276 // Valid spectra:
277 // cal_buf4 = accumulated power and phase (normalised in fft2_size points)
278 // The spectrum in cal_buf4 is what we have while fft1_desired contains
279 // what we have asked for.
280 // To get the desired spectrum we have to add one more filter
281 // to our filter chain.
282 // The new filter should be fft1_desired/cal_buf4.
283 // ******************************************************
284 make_cal_fft1_filtercorr();
285 for(i=0; i<2*MAX_ADCHAN*screen_width; i++)cal_graph[i]=0;
286 for(j=0; j<mm; j++)z[j]=0;
287 for(i=0;i<mm*fft2_size; i++)cal_buf2[i]=0;
288 // Since there may be serious errors in the spectrum of the average
289 // pulse at the spectrum ends, start by locating the passband center.
290 // for this purpose, skip fft2_size/128 points at each end as well
291 // as around the center if we run in I/Q mode.
292 if( (ui.rx_input_mode&IQ_DATA) == 0)
293 {
294 for(i=siz128; i<fft2_size-siz128; i++)
295 {
296 if(cal_fft1_desired[i]>0)
297 {
298 for(j=0; j<mm; j+=2)
299 {
300 t1=pow(cal_fft1_filtercorr[mm*i+j ],2.0)+pow(cal_fft1_filtercorr[mm*i+j+1],2.0);
301 if(t1 > 0 )
302 {
303 t1=cal_buf4[mm*i+j]/sqrt(t1);
304 z[j]+=t1*i;
305 z[j+1]+=t1;
306 cal_buf2[mm*i+j]=t1;
307 }
308 }
309 }
310 }
311 }
312 else
313 {
314 for(i=siz128; i<fft2_size/2-siz128; i++)
315 {
316 if(cal_fft1_desired[i]>0)
317 {
318 for(j=0; j<mm; j+=2)
319 {
320 t1=pow(cal_fft1_filtercorr[mm*i+j ],2.0)+
321 pow(cal_fft1_filtercorr[mm*i+j+1],2.0);
322 if(t1 > 0 )
323 {
324 t1=cal_buf4[mm*i+j]/sqrt(t1);
325 z[j]+=t1*i;
326 z[j+1]+=t1;
327 cal_buf2[mm*i+j]=t1;
328 }
329 }
330 }
331 }
332 for(i=fft2_size/2+siz128; i<fft2_size-siz128; i++)
333 {
334 if(cal_fft1_desired[i]>0)
335 {
336 for(j=0; j<mm; j+=2)
337 {
338 t1=pow(cal_fft1_filtercorr[mm*i+j ],2.0)+pow(cal_fft1_filtercorr[mm*i+j+1],2.0);
339 if(t1 > 0 )
340 {
341 t1=cal_buf4[mm*i+j]/sqrt(t1);
342 z[j]+=t1*i;
343 z[j+1]+=t1;
344 cal_buf2[mm*i+j]=t1;
345 }
346 }
347 }
348 }
349 }
350 midp=0;
351 for(j=0; j<mm; j+=2)
352 {
353 if(z[j+1]==0)
354 {
355 lirerr(1162);
356 return 0;
357 }
358 midp+=z[j]/z[j+1];
359 }
360 midp/=mm>>1;
361 ia=midp-fft2_size/16;
362 ib=midp+fft2_size/16;
363 // Locate the maximum near the midpoint.
364 for(j=0; j<mm; j+=2)
365 {
366 z[j]=0;
367 if( (ui.rx_input_mode&IQ_DATA) == 0)
368 {
369 for(i=ia; i<ib; i++)
370 {
371 if(z[j]<cal_buf2[mm*i+j])z[j]=cal_buf2[mm*i+j];
372 }
373 }
374 else
375 {
376 for(i=ia; i<fft2_size/2-siz128; i++)
377 {
378 if(z[j]<cal_buf2[mm*i+j])z[j]=cal_buf2[mm*i+j];
379 }
380 for(i=fft2_size/2+siz128; i<ib; i++)
381 {
382 if(z[j]<cal_buf2[mm*i+j])z[j]=cal_buf2[mm*i+j];
383 }
384 }
385 z[j]*=.01;
386 z[j+1]=0;
387 }
388 // Locate where the level is -20 dB at the sides relative to the level
389 // at the center.
390 lowp=0;
391 higp=fft2_size-1;
392 k=0;
393 while( lowp < midp && k == 0)
394 {
395 k=1;
396 for(j=0; j<mm; j+=2)
397 {
398 if( z[j]>cal_buf2[mm*lowp+j]) k=0;
399 }
400 lowp++;
401 }
402 m=0;
403 while(higp > midp && m==0)
404 {
405 m=1;
406 for(j=0; j<mm; j+=2)
407 {
408 if( z[j]>cal_buf2[mm*higp+j])m=0;
409 }
410 higp--;
411 }
412 // Get a minimum level for filtercorr power to not divide by zero
413 for(j=0; j<mm; j+=2)
414 {
415 k=higp-lowp-1;
416 if( (ui.rx_input_mode&IQ_DATA) == 0)
417 {
418 for(i=lowp+1; i<higp; i++)
419 {
420 z[j+1]+=pow(cal_fft1_filtercorr[mm*i+j ],2.0)+
421 pow(cal_fft1_filtercorr[mm*i+j+1],2.0);
422 }
423 }
424 else
425 {
426 for(i=lowp+1; i<fft2_size/2-siz128; i++)
427 {
428 z[j+1]+=pow(cal_fft1_filtercorr[mm*i+j ],2.0)+
429 pow(cal_fft1_filtercorr[mm*i+j+1],2.0);
430 }
431 for(i=fft2_size/2+siz128; i<higp; i++)
432 {
433 z[j+1]+=pow(cal_fft1_filtercorr[mm*i+j ],2.0)+
434 pow(cal_fft1_filtercorr[mm*i+j+1],2.0);
435 }
436 k-=2*siz128;
437 }
438 // Set level at -30dB
439 z[j+1]=0.001*z[j+1]/k;
440 }
441 // Store the hardware spectrum in cal_buf2 as amplitude and phase
442 // Get it as the shape before the correction in filcorr was applied i.e.
443 // as cal_buf4/fft1_filtercorr
444 for(i=0; i<fft2_size; i++)
445 {
446 for(j=0; j<mm; j+=2)
447 {
448 t1=pow(cal_fft1_filtercorr[mm*i+j ],2.0)+pow(cal_fft1_filtercorr[mm*i+j+1],2.0);
449 if(t1 > z[j+1] && cal_fft1_desired[i] > 0)
450 {
451 cal_buf2[mm*i+j]=cal_buf4[mm*i+j]/t1;
452 cal_buf2[mm*i+j+1]=cal_buf4[mm*i+j+1]-atan2(cal_fft1_filtercorr[mm*i+j+1],
453 cal_fft1_filtercorr[mm*i+j ]);
454 }
455 else
456 {
457 cal_buf2[mm*i+j ]=0;
458 cal_buf2[mm*i+j+1]=0;
459 }
460 }
461 }
462 for(j=0; j<mm; j+=2)
463 {
464 z[j]=0;
465 if( (ui.rx_input_mode&IQ_DATA) == 0)
466 {
467 for(i=lowp+1; i<fft2_size; i++)
468 {
469 if(z[j] < cal_buf2[mm*i+j])z[j]=cal_buf2[mm*i+j];
470 }
471 }
472 else
473 {
474 for(i=lowp+1; i<fft2_size/2-siz128; i++)
475 {
476 if(z[j] < cal_buf2[mm*i+j])z[j]=cal_buf2[mm*i+j];
477 }
478 for(i=fft2_size/2+siz128; i<higp; i++)
479 {
480 if(z[j] < cal_buf2[mm*i+j])z[j]=cal_buf2[mm*i+j];
481 }
482 }
483 }
484 for(i=0; i<fft2_size; i++)
485 {
486 for(j=0; j<mm; j+=2)
487 {
488 cal_buf2[mm*i+j]/=z[j];
489 }
490 }
491 // ******************************************************
492 // Valid spectra:
493 // cal_buf4 = accumulated pulse spectrum, power and phase (normalised)
494 // cal_buf2 = hardware spectrum, power and phase (normalised)
495 // ******************************************************
496 // Locate the MIN_GAIN points at the low and high frequency sides of cal_buf2
497 #define MIN_GAIN 0.1 //10dB
498 cal_hw_lowp=lowp;
499 cal_hw_higp=higp;
500 k=0;
501 while(k != ui.rx_rf_channels && cal_hw_lowp < cal_hw_higp)
502 {
503 k=0;
504 cal_hw_lowp++;
505 for(j=0; j<mm; j+=2)
506 {
507 if(cal_buf2[mm*cal_hw_lowp+j] > MIN_GAIN)k++;
508 }
509 }
510 k=0;
511 while(k != ui.rx_rf_channels && cal_hw_lowp<=cal_hw_higp)
512 {
513 k=0;
514 cal_hw_higp--;
515 for(j=0; j<mm; j+=2)
516 {
517 if(cal_buf2[mm*cal_hw_higp+j] > MIN_GAIN)k++;
518 }
519 }
520 screen:;
521 cal_type=CAL_TYPE_SET_FILTERSHAPE;
522 cal_initscreen();
523 t1=(0.001*fft1_size)/fft2_size;
524 sprintf(s,"%.1f dB points: %fkHz %fkHz",20*log10(MIN_GAIN),
525 t1*fft1_hz_per_point*cal_hw_lowp,t1*fft1_hz_per_point*cal_hw_higp);
526 lir_text(0,1,s);
527 if( (fft1_calibrate_flag&CALAMP) != CALAMP)
528 {
529 // This is the first time.
530 // Place the 75% point of the corrected spectrum at the MIN_GAIN point of
531 // the hardware. (75% amplitude = -4.4dB)
532 // Make the slope a parabola, start and stop equally many points away
533 // from the 75% point.
534 // Start with a parabola that ends halfway to the farthest end point.
535 // Store the desired filter with parabolic fall offs in cal_buf5.
536 falloff_length=cal_hw_lowp-1;
537 if(fft2_size-cal_hw_higp-2 > falloff_length)
538 falloff_length=fft2_size-cal_hw_higp-2;
539 if(desired_shape ==1)
540 {
541 lowp=cal_hw_lowp;
542 higp=cal_hw_higp;
543 }
544 else
545 {
546 if(fft2_size/(falloff_length+1) > 20)
547 {
548 falloff_length=fft2_size/20;
549 if(cal_hw_lowp <= falloff_length)cal_hw_lowp=falloff_length+1;
550 if(cal_hw_higp > fft2_size-falloff_length-2)
551 cal_hw_higp=fft2_size-falloff_length-2;
552 }
553 t1=(ERF_END-ERF_START)/(ERF_END+0.5);
554 i=falloff_length;
555 falloff_length*=t1;
556 i=falloff_length-i;
557 lowp=cal_hw_lowp+i;
558 higp=cal_hw_higp-i;
559 }
560 }
561 else
562 {
563 i=0;
564 while(cal_fft1_desired[i] == 0 && i<fft2_size)i++;
565 if(i==fft2_size)
566 {
567 lirerr(1054);
568 return 0;
569 }
570 k=fft2_size-1;
571 while(cal_fft1_desired[k] == 0 && k>=i)k--;
572 j=i;
573 while(cal_fft1_desired[j] < 0.99999 && j<fft2_size)j++;
574 falloff_length=(j-i)/2;
575 if(falloff_length >= (k-i)/4)falloff_length=(k-i)/4-1;
576 lowp=i+falloff_length;
577 higp=k-falloff_length;
578 }
579 get_ideal_ampl:;
580 if(falloff_length >=lowp)
581 {
582 i=1+(falloff_length-lowp)/2;
583 lowp+=i;
584 falloff_length-=i;
585 }
586 if(falloff_length >=fft2_size-1-higp)
587 {
588 i=1+(falloff_length-(fft2_size-higp-1))/2;
589 higp-=i;
590 falloff_length-=i;
591 }
592 for(i=0; i<lowp; i++)cal_buf5[i]=0;
593 for(i=higp; i<fft2_size; i++)cal_buf5[i]=0;
594 for(i=lowp+1; i<higp; i++)cal_buf5[i]=1;
595 if(desired_shape ==1)
596 {
597 t1=sqrt(.25)/falloff_length;
598 t2=1;
599 t3=t1;
600 t2=1-t3*t3;
601 t3+=t1;
602 ja=lowp+falloff_length;
603 jb=higp-falloff_length;
604 while(t2 > 0)
605 {
606 cal_buf5[ja]=t2;
607 cal_buf5[jb]=t2;
608 t2=1-t3*t3;
609 t3+=t1;
610 ja--;
611 jb++;
612 }
613 }
614 else
615 {
616 adjust:;
617 ja=lowp+1;
618 jb=higp-1;
619 if(jb-ja < falloff_length/2)
620 {
621 lirerr(9845621);
622 return 0;
623 }
624 t1=(ERF_END-ERF_START)/falloff_length;
625 t2=ERF_START;
626 while(t2 < ERF_END)
627 {
628 t3=0.5*erfc(t2);
629 cal_buf5[ja]=t3;
630 cal_buf5[jb]=t3;
631 t2+=t1;
632 ja--;
633 jb++;
634 if(ja < 0)
635 {
636 lowp++;
637 goto adjust;
638 }
639 if(jb >= fft2_size)
640 {
641 higp--;
642 goto adjust;
643 }
644 }
645 }
646 // ******************************************************
647 // Valid spectra:
648 // cal_buf4 = accumulated pulse spectrum, power and phase (normalised)
649 // cal_buf2 = hardware spectrum, power and phase (normalised)
650 // cal_buf5 = desired spectrum (amplitude only)
651 // ******************************************************
652 // Divide cal_buf5 by sqrt(cal_buf2) to get the total correction function we need
653 // to get the desired frequency response.
654 for(i=0; i<fft2_size; i++)
655 {
656 for(j=0; j<mm; j+=2)
657 {
658 if(cal_buf2[mm*i+j]>0)
659 {
660 cal_buf3[mm*i+j]=cal_buf5[i]/sqrt(cal_buf2[mm*i+j]);
661 }
662 else
663 {
664 cal_buf3[mm*i+j]=0;
665 }
666 }
667 }
668 // Find max of the correction function from both sides.
669 ja=0;
670 jb=fft2_size-1;
671 ka=siz128;
672 kb=siz128;
673 for(j=0; j<mm; j++)z[j]=0;
674 for(i=0; i<fft2_size; i++)
675 {
676 for(j=0; j<mm; j+=2)
677 {
678 if(z[j ]<cal_buf3[mm*ja+j])
679 {
680 z[j ]=cal_buf3[mm*ja+j];
681 ka=fft2_size/128;
682 }
683 if(z[j+1]<cal_buf3[mm*jb+j])
684 {
685 z[j+1]=cal_buf3[mm*jb+j];
686 kb=fft2_size/128;
687 }
688 if(z[j ]==0)ka=fft2_size/128;
689 if(z[j+1]==0)kb=fft2_size/128;
690 }
691 if(ka>0)
692 {
693 ja++;
694 ka--;
695 }
696 if(kb>0)
697 {
698 jb--;
699 kb--;
700 }
701 }
702 for(j=0; j<ui.rx_rf_channels; j++)
703 {
704 sprintf(s,"Max correction Ch %d low=%.2fdB high=%.2fdB ",
705 j,20*log10(z[2*j]), 20*log10(z[2*j+1]));
706 lir_text(0,2+j,s);
707 }
708 clear_lines(5,13);
709 lir_text(0, 5,"| inc | dec | Item |");
710 lir_text(0, 6,"| A | B | Flat region |");
711 lir_text(0, 7,"| C | D | Center freq |");
712 lir_text(0, 8,"| E | F | Steepness |");
713 sprintf(s, "| I | K | Step %4d |",step);
714 lir_text(0, 9,s);
715 lir_text(0,10,"| + | - | Y-Gain |");
716 lir_text(5,13,"Y=>Accept X=Skip");
717 settextcolor(15);
718 lir_text(40,5,"DESIRED AMPLITUDE");
719 settextcolor(14);
720 lir_text(40,6,"CORR. AMPLITUDE");
721 settextcolor(10);
722 lir_text(40,7,"CORR. PHASE");
723 settextcolor(7);
724 sprintf(s,"| M | Shape %s",shape_texts[desired_shape]);
725 lir_text(40,9,s);
726 sprintf(s,"| |");
727 lir_text(40,8,s);
728 lir_text(40,10,s);
729 for(i=0; i<screen_width; i++)
730 {
731 k=i*fft2_size/screen_last_xpixel;
732 if(k>fft2_size-1)k=fft2_size-1;
733 //k=fft2_size/2-screen_width/2+i;
734 for(j=0; j<mm; j+=2)
735 {
736 lir_setpixel(i, cal_graph[screen_width*(2*j )+i], 0);
737 t2=0.1*ygain*cal_buf3[mm*k+j];
738 if(t2 <-cal_ymax)t2=-cal_ymax;
739 if(t2 >cal_ymax)t2=cal_ymax;
740 if(j > 0)t2-=YSH;
741 cal_graph[screen_width*(2*j )+i]=screen_height*(cal_yzer-t2);
742 lir_setpixel(i, cal_graph[screen_width*(2*j )+i], 14);
743 lir_setpixel(i, cal_graph[screen_width*(2*j+1)+i], 0);
744 t2=0.1*ygain*cal_buf5[k];
745 if(t2 <-cal_ymax)t2=-cal_ymax;
746 if(t2 >cal_ymax)t2=cal_ymax;
747 if(j > 0)t2-=YSH;
748 cal_graph[screen_width*(2*j+1)+i]=screen_height*(cal_yzer-t2);
749 lir_setpixel(i, cal_graph[screen_width*(2*j+1)+i], 15);
750 lir_setpixel(i, cal_graph[screen_width*(2*j+2)+i], 0);
751 t2=0.03*ygain*cal_buf2[mm*k+j+1];
752 if(t2 <-cal_ymax)t2=-cal_ymax;
753 if(t2 >cal_ymax)t2=cal_ymax;
754 if(j > 0)t2-=YSH;
755 cal_graph[screen_width*(2*j+2)+i]=screen_height*(cal_yzer-t2);
756 lir_setpixel(i, cal_graph[screen_width*(2*j+2)+i], 10);
757 }
758 if(k==fft2_size-1)goto grx;
759 }
760 grx:;
761 if(ui.rx_rf_channels >1)
762 {
763 if(z[0] > z[2])
764 {
765 t1=z[2]/z[0];
766 }
767 else
768 {
769 t1=z[0]/z[2];
770 }
771 sprintf(s,"Channel amplitudes %f %f Diff %f dB",
772 z[0],z[2],-10*log10(t1));
773 if(t1 < 0.5)
774 {
775 clear_lines(14,15);
776 lir_text(0,14,"Channel unbalance too large.");
777 lir_text(0,15,"Clear old data or adjust hardware!");
778 }
779 }
780 await_processed_keyboard();
781 if(kill_all_flag) return 0;
782 switch (lir_inkey)
783 {
784 case 'X':
785 return 0;
786
787 case '+':
788 ygain*=2;
789 break;
790
791 case '-':
792 ygain/=2;
793 break;
794
795 case 'A':
796 lowp-=step;
797 if(lowp < 2)lowp=2;
798 higp+=step;
799 if(higp > fft2_size-3)higp=fft2_size-3;
800 break;
801
802 case 'B':
803 lowp+=step;
804 higp-=step;
805 if(lowp>higp-2*falloff_length)
806 {
807 higp=(lowp+higp)/2;
808 lowp=higp-falloff_length;
809 higp+=falloff_length;
810 }
811 break;
812
813 case 'C':
814 lowp+=step;
815 higp+=step;
816 if(higp > fft2_size-3)higp=fft2_size-3;
817 break;
818
819 case 'D':
820 lowp-=step;
821 higp-=step;
822 if(lowp<2)lowp=2;
823 break;
824
825 case 'E':
826 falloff_length-=step;
827 if(falloff_length<1)falloff_length=1;
828 break;
829
830 case 'F':
831 falloff_length+=step;
832 if(falloff_length>fft2_size/2.5)falloff_length=fft2_size/2.5;
833 break;
834
835 case 'I':
836 step++;
837 if(step > siz128)step=siz128;
838 break;
839
840 case 'K':
841 step--;
842 if(step < 1)step=1;
843 break;
844
845 case 'M':
846 desired_shape^=1;
847 break;
848
849 case F1_KEY:
850 case '!':
851 help_message(307);
852 goto screen;
853
854 case 'Y':
855 goto update_ram;
856 }
857 goto get_ideal_ampl;
858 update_ram:;
859 // ******************************************************
860 // Valid spectra:
861 // cal_buf4 = accumulated pulse spectrum, power and phase (normalised)
862 // cal_buf2 = hardware spectrum, power and phase (normalised)
863 // cal_buf5 = desired spectrum (amplitude only)
864 // ******************************************************
865 // Renormalise cal_buf4 so the average becomes 1 within the hw limits
866 for(j=0; j<mm; j+=2)z[j]=0;
867 for(i=cal_hw_lowp+1; i<cal_hw_higp; i++)
868 {
869 for(j=0; j<mm; j+=2)
870 {
871 z[j]+=cal_buf4[mm*i+j ];
872 }
873 }
874 for(j=0; j<mm; j+=2)z[j]/=(cal_hw_higp-cal_hw_lowp-1);
875 for(i=0; i<fft2_size; i++)
876 {
877 for(j=0; j<mm; j+=2)
878 {
879 cal_buf4[mm*i+j ]/=z[j];
880 }
881 }
882 // We get the new filter function as cal_fft1_desired/cal_buf4
883 // Get the new correction by multiplication onto the old.
884 fft1_calibrate_flag|=CALAMP;
885 for(i=0; i<fft2_size; i++)
886 {
887 cal_fft1_desired[i]=cal_buf5[i];
888 {
889 for(j=0; j<mm; j+=2)
890 {
891 if(cal_buf4[mm*i+j]>0)
892 {
893 t1=sqrt(pow(cal_fft1_filtercorr[mm*i+j ],2.0)+
894 pow(cal_fft1_filtercorr[mm*i+j+1],2.0));
895 t2=atan2(cal_fft1_filtercorr[mm*i+j+1],
896 cal_fft1_filtercorr[mm*i+j ]);
897 t1*=cal_fft1_desired[i]/sqrt(cal_buf4[mm*i+j]);
898 t2-=cal_buf4[mm*i+j+1];
899 cal_fft1_filtercorr[mm*i+j ]=t1;
900 cal_fft1_filtercorr[mm*i+j+1]=t2;
901 }
902 else
903 {
904 cal_fft1_filtercorr[mm*i+j ]=0;
905 cal_fft1_filtercorr[mm*i+j+1]=0;
906 }
907 }
908 }
909 }
910 for(i=0; i<fft2_size; i++)
911 {
912 if(cal_fft1_desired[i] > 0)
913 {
914 for(j=0; j<mm; j+=2)
915 {
916 t1=cal_fft1_filtercorr[mm*i+j ];
917 t2=cal_fft1_filtercorr[mm*i+j+1];
918 cal_fft1_filtercorr[mm*i+j ]=cos(t2)*t1;
919 cal_fft1_filtercorr[mm*i+j+1]=sin(t2)*t1;
920 }
921 }
922 else
923 {
924 for(j=0; j<mm; j+=2)
925 {
926 cal_fft1_filtercorr[mm*i+j ]=0;
927 cal_fft1_filtercorr[mm*i+j+1]=0;
928 }
929 }
930 }
931 for(i=0; i<mm*fft2_size; i++)cal_tmp[i]=cal_fft1_filtercorr[i];
932 convert_filtercorr_fd_to_td(fft2_n, fft2_size, cal_tmp);
933 resize_filtercorr_td_to_fd(TRUE, fft2_size, cal_tmp,
934 fft1_n, fft1_size, fft1_filtercorr);
935 resize_fft1_desired(fft2_size, cal_fft1_desired, fft1_size, fft1_desired);
936 i=0;
937 while(fft1_desired[i] == 0)
938 {
939 for(j=0; j<mm; j++)
940 {
941 fft1_filtercorr[mm*i+j]=0;
942 }
943 i++;
944 if(i==fft1_size)lirerr(936183);
945 }
946 i=fft1_size-1;
947 while(fft1_desired[i] == 0)
948 {
949 for(j=0; j<mm; j++)
950 {
951 fft1_filtercorr[mm*i+j]=0;
952 }
953 i--;
954 }
955 settextcolor(7);
956 clear_screen();
957 return 1;
958 }
959
show_missing_cal_info(void)960 void show_missing_cal_info(void)
961 {
962 clear_screen();
963 lir_text(5,5,"There is no calibration function.");
964 lir_text(5,7,"Run B first for amplitude and phase calibration");
965 lir_text(8,9,press_any_key);
966 await_processed_keyboard();
967 }
968
969
remove_iq_notch(void)970 int remove_iq_notch(void)
971 {
972 char s[80];
973 int i, j, k, m, n, mm;
974 float t1,t2,t3;
975 int old_end, cal_lowedge_min;
976 float xgain, xmid, ampmax;
977 // In case the native size of the calibration data is smaller
978 // than fft1_size, change fft1_size and remember old values in fft2_size.
979 if(cal_fft1_size == 0)
980 {
981 show_missing_cal_info();
982 return 1;
983 }
984 fft2_size=fft1_size;
985 fft2_n=fft1_n;
986 if(cal_fft1_size < fft1_size)
987 {
988 fft1_size=cal_fft1_size;
989 fft1_n=cal_fft1_n;
990 init_fft1_filtercorr();
991 fft1_hz_per_point*=(float)(fft2_size)/fft1_size;
992 }
993 mm=twice_rxchan;
994 old_end=0;
995 llsq_derivatives=malloc(LLSQ_MAXPAR*fft1_size/2*sizeof(float));
996 if(llsq_derivatives == NULL)
997 {
998 lirerr(1048);
999 return 0;
1000 }
1001 llsq_errors=malloc(fft1_size*sizeof(float));
1002 if(llsq_errors == NULL)
1003 {
1004 lirerr(1048);
1005 err_ex1:;
1006 free(llsq_derivatives);
1007 return 0;
1008 }
1009 xgain=(float)(screen_width)/fft1_size;
1010 xmid=fft1_size/2;
1011 // Do not fit curves closer than IQ_FIT_MINFREQ Hz from the center.
1012 // We assume that the phase and amplitude is entirely unaffected
1013 // by the AC coupling at this relatively high frequency.
1014 // The user may change this limit if he so wishes.
1015 cal_midlim=fft1_size/2-1-IQ_FIT_MINFREQ/fft1_hz_per_point;
1016 // Convert fft1_filtercorr to amplitude and phase.
1017 // Split it into a symmetric and an antisymmetric part.
1018 for(i=0; i<fft1_size/2; i++)
1019 {
1020 k=fft1_size-1-i;
1021 t1=0;
1022 for(j=0; j<mm; j+=2)
1023 {
1024 t2=sqrt(pow(fft1_filtercorr[mm*i+j ],2.0)+
1025 pow(fft1_filtercorr[mm*i+j+1],2.0));
1026 t3=sqrt(pow(fft1_filtercorr[mm*k+j ],2.0)+
1027 pow(fft1_filtercorr[mm*k+j+1],2.0));
1028 if(t2 > 0 && t3 > 0)
1029 {
1030 cal_buf6[mm*i+j ]=t2/t3;
1031 cal_buf3[mm*i+j ]=sqrt(t2*t3);
1032 if( cal_buf3[mm*i+j ] > t1)t1=cal_buf3[mm*i+j ];
1033 t2=atan2(fft1_filtercorr[mm*i+j+1],fft1_filtercorr[mm*i+j ]);
1034 t3=atan2(fft1_filtercorr[mm*k+j+1],fft1_filtercorr[mm*k+j ]);
1035 cal_buf6[mm*i+j+1]=(t2-t3)/2;
1036 cal_buf3[mm*i+j+1]=(t2+t3)/2;
1037 }
1038 else
1039 {
1040 if(t3 > 0)
1041 {
1042 cal_buf6[mm*i+j ]=t2/t3;
1043 cal_buf3[mm*i+j ]=sqrt(t3);
1044 t3=atan2(fft1_filtercorr[mm*k+j+1],fft1_filtercorr[mm*k+j ]);
1045 cal_buf6[mm*i+j+1]=-t3/2;
1046 cal_buf3[mm*i+j+1]=t3/2;
1047 }
1048 else
1049 {
1050 if(t2 > 0)
1051 {
1052 t3=t2*0.00001;
1053 cal_buf6[mm*i+j ]=t2/t3;
1054 cal_buf3[mm*i+j ]=sqrt(t2*t3);
1055 t2=atan2(fft1_filtercorr[mm*i+j+1],fft1_filtercorr[mm*i+j ]);
1056 cal_buf6[mm*i+j+1]=t2/2;
1057 cal_buf3[mm*i+j+1]=t2/2;
1058 }
1059 else
1060 {
1061 cal_buf6[mm*i+j ]=0;
1062 cal_buf6[mm*i+j+1]=0;
1063 cal_buf3[mm*i+j ]=0;
1064 cal_buf3[mm*i+j+1]=0;
1065 }
1066 }
1067 }
1068 }
1069 if(t1 > 0)
1070 {
1071 cal_buf5[i]=1/t1;
1072 }
1073 else
1074 {
1075 cal_buf5[i]=0;
1076 }
1077 }
1078 // cal_buf5 is for use as weight factor in curve fitting.
1079 // We may have incorrect data outside the passband so
1080 // fitting is limited by cal_lowedge
1081 cal_lowedge=0;
1082 while(fft1_desired[cal_lowedge] != 1 &&
1083 cal_lowedge < fft1_size/2)cal_lowedge++;
1084 if(cal_lowedge < fft1_size/4)cal_lowedge=fft1_size/4;
1085 cal_lowedge_min=cal_lowedge;
1086 restart:;
1087 cal_type=CAL_TYPE_FIX_CENTER_SETUP;
1088 cal_initscreen();
1089 lir_text(5,5,"Remove center discontinuity");
1090 i=fft1_hz_per_point*(fft1_size/2-cal_midlim-1);
1091 sprintf(s,"%d Hz is excluded from polynomial fit on both",i);
1092 lir_text(5,6,s);
1093 lir_text(5,7,"sides of the center as indicated by the green line.");
1094 i=fft1_hz_per_point*(fft1_size/2-cal_lowedge-1);
1095 sprintf(s,"%d Hz away from the center is included in the polynomial fit",i);
1096 lir_text(5,8,s);
1097 lir_text(5,10,"L=Change center limit");
1098 lir_text(5,11,"R=Change range to fit");
1099 lir_text(5,13,"C=Continue with current value");
1100 draw_fitline();
1101 to_upper_await_keyboard();
1102 if(kill_all_flag)
1103 {
1104 err_ex2:;
1105 free(llsq_errors);
1106 goto err_ex1;
1107 }
1108 switch (lir_inkey)
1109 {
1110 case 'X':
1111 goto err_ex2;
1112
1113 case 'L':
1114 lir_text(5,15,"New limit (Hz):");
1115 i=lir_get_integer(22,15,6,0,99999);
1116 if(kill_all_flag)goto err_ex2;
1117 if(i != 0)
1118 {
1119 cal_midlim=fft1_size/2-1-i/fft1_hz_per_point;
1120 }
1121 if(cal_midlim < 0.3*fft1_size)
1122 {
1123 cal_midlim=0.31*fft1_size;
1124 }
1125 goto restart;
1126
1127 case 'R':
1128 lir_text(5,15,"New limit (Hz):");
1129 i=lir_get_integer(22,15,7,0,999999);
1130 if(kill_all_flag)goto err_ex2;
1131 if(i != 0)
1132 {
1133 cal_lowedge=fft1_size/2-1-i/fft1_hz_per_point;
1134 }
1135 if(cal_lowedge < cal_lowedge_min)cal_lowedge=cal_lowedge_min;
1136 if(cal_midlim-cal_lowedge < fft1_size/32)
1137 {
1138 cal_lowedge = 1+fft1_size/32-cal_midlim;
1139 }
1140 goto restart;
1141
1142 case F1_KEY:
1143 case '!':
1144 help_message(308);
1145 goto restart;
1146
1147 case 'C':
1148 break;
1149
1150 default:
1151 goto restart;
1152 }
1153
1154 if(kill_all_flag)goto err_ex2;
1155 llsq_neq=cal_midlim-cal_lowedge;
1156 if(llsq_neq < fft1_size/32)
1157 {
1158 lirerr(1137);
1159 goto err_ex2;
1160 }
1161 ampmax=0;
1162 for(i=cal_lowedge; i<cal_midlim; i++)
1163 {
1164 if(ampmax<cal_buf5[i])ampmax=cal_buf5[i];
1165 }
1166 for(i=0; i<fft1_size/2; i++)
1167 {
1168 for(j=0; j<mm; j+=2)
1169 {
1170 cal_buf3[mm*i+j ]*=ampmax;
1171 }
1172 }
1173 // ***********************************************************
1174 // The antisymmetric power component has to be 1.0 at (fft1_size-1)/2
1175 // Fit it to y=c1*x + c2*x*x + c3*x*x*x ........
1176 llsq_npar=3;
1177 cal_ygain=1;
1178 fit_asym_power:;
1179 make_symfit(0, 0, cal_buf6, 1.0);
1180 llsq_npar=symmetry_fit_decide(cal_buf6, 1., "Antisymmetric power (RF)");
1181 if(llsq_npar == SYMFIT_CHANGE_LIMITS)goto restart;
1182 if(llsq_npar == -1)goto err_ex2;
1183 if(llsq_npar > 0)goto fit_asym_power;
1184 // ***********************************************************
1185 // The antisymmetric phase may have a dicontinuity at (fft1_size-1)/2.
1186 // Fit it to y=c1 + c2*x + c3*x*x ........
1187 llsq_npar=5;
1188 fit_asym_phase:;
1189 make_symfit(1,0,&cal_buf6[1],0.);
1190 llsq_npar=symmetry_fit_decide(&cal_buf6[1], 0.,"Antisymmetric phase (AF)");
1191 if(llsq_npar == SYMFIT_CHANGE_LIMITS)goto restart;
1192 if(llsq_npar == -1)goto err_ex2;
1193 if(llsq_npar > 0)goto fit_asym_phase;
1194 // Make the antisymmetric phase cross zero at (fft1_size-1)/2 in
1195 // case the user decides to use the fitted values.
1196 for(i=0; i<=fft1_size/2; i++)
1197 {
1198 for(j=0;j<ui.rx_rf_channels;j++)
1199 {
1200 cal_buf6[mm*i+2*j+1]-=llsq_steps[j];
1201 }
1202 }
1203 // ***********************************************************
1204 // The symmetric power part must be a symmetric function (even).
1205 // Fit it to y=c1 + c2*x*x + c3*x*x*x*x ........
1206 llsq_npar=6;
1207 fit_sym_power:;
1208 make_symfit(1,1,cal_buf3,0.);
1209 llsq_npar=symmetry_fit_decide(cal_buf3, 0.,"Symmetric power (AF)");
1210 if(llsq_npar == SYMFIT_CHANGE_LIMITS)goto restart;
1211 if(llsq_npar == -1)goto err_ex2;
1212 if(llsq_npar > 0)goto fit_sym_power;
1213 // ***********************************************************
1214 // The symmetric phase part must be a symmetric function (even).
1215 // Fit it to y=c1 + c2*x*x + c3*x*x*x*x ........
1216 llsq_npar=3;
1217 fit_sym_phase:;
1218 make_symfit(1,1,&cal_buf3[1],0.);
1219 llsq_npar=symmetry_fit_decide(&cal_buf3[1], 0.,"Symmetric phase (RF)");
1220 if(llsq_npar == SYMFIT_CHANGE_LIMITS)goto restart;
1221 if(llsq_npar == -1)goto err_ex2;
1222 if(llsq_npar > 0)goto fit_sym_phase;
1223 // Combine the symmetric and antisymmetric functions to give back
1224 // the total filter response.
1225 for(i=1; i<fft1_size/2; i++)
1226 {
1227 k=fft1_size-1-i;
1228 for(j=0; j<mm; j+=2)
1229 {
1230 t1=cal_buf3[mm*i+j];
1231 t2=sqrt(cal_buf6[mm*i+j]);
1232 if(t1>0 && t2>0)
1233 {
1234 cal_buf3[mm*k+j]=t1/t2;
1235 cal_buf3[mm*i+j]=t1*t2;
1236 t1=cal_buf3[mm*i+j+1]-cal_buf6[mm*i+j+1];
1237 t2=cal_buf3[mm*i+j+1]+cal_buf6[mm*i+j+1];
1238 cal_buf3[mm*k+j+1]=t1;
1239 cal_buf3[mm*i+j+1]=t2;
1240 }
1241 else
1242 {
1243 cal_buf3[mm*k+j]=0;
1244 cal_buf3[mm*i+j]=0;
1245 cal_buf3[mm*k+j+1]=0;
1246 cal_buf3[mm*i+j+1]=0;
1247 }
1248 }
1249 }
1250 cal_ygain=1;
1251 cal_type=CAL_TYPE_FIX_CENTER_SAVE;
1252 cal_initscreen();
1253 lir_text(4,2,"+/- => Y-scale");
1254 lir_text(4,3,"E,C => Expand,Contract x-scale");
1255 lir_text(4,4,"R,L => Right/Left x-scale");
1256 lir_text(4,5,"X => Exit without saving");
1257 lir_text(4,6,"S => Update RAM and save to disk");
1258 show:;
1259 for(j=0; j<mm; j++)
1260 {
1261 m=screen_width*j;
1262 n=screen_width*mm;
1263 for(i=1; i<=old_end; i++)
1264 {
1265 lir_line(cal_graph[n+i-1], cal_graph[m+i-1],
1266 cal_graph[n+i ], cal_graph[m+i ],0);
1267 if(kill_all_flag)goto err_ex2;
1268 }
1269 }
1270 old_end=-1;
1271 t1=0;
1272 i=-1;
1273 show1:
1274 t1+=xgain;
1275 if(t1<i+1)goto show1;
1276 i=t1;
1277 if(i>screen_last_xpixel)goto showx;
1278 k=(t1-screen_width/2)/xgain+xmid;
1279 while(k<0)k+=fft1_size;
1280 while(k>=fft1_size)k-=fft1_size;
1281 old_end++;
1282 cal_graph[screen_width*mm+old_end]=i;
1283 for(j=0; j<mm; j+=2)
1284 {
1285 t2=0.1*cal_ygain*cal_buf3[mm*k+j ];
1286 if(t2 <-cal_ymax)t2=-cal_ymax;
1287 if(t2 >cal_ymax)t2=cal_ymax;
1288 if(j > 0)t2-=YSH;
1289 cal_graph[screen_width*j+old_end]=screen_height*(cal_yzer-t2);
1290 t2=0.03*cal_ygain*cal_buf3[mm*k+j+1];
1291 if(t2 <-cal_ymax)t2=-cal_ymax;
1292 if(t2 >cal_ymax)t2=cal_ymax;
1293 if(j > 0)t2-=YSH;
1294 cal_graph[screen_width*(j+1)+old_end]=screen_height*(cal_yzer-t2);
1295 if(old_end>0)
1296 {
1297 lir_line(cal_graph[screen_width*mm+old_end-1],
1298 cal_graph[screen_width*j+old_end-1],
1299 i,cal_graph[screen_width*j+old_end],13);
1300 if(kill_all_flag) goto err_ex2;
1301 lir_line(cal_graph[screen_width*mm+old_end-1],
1302 cal_graph[screen_width*(j+1)+old_end-1],
1303 i,cal_graph[screen_width*(j+1)+old_end],10);
1304 if(kill_all_flag) goto err_ex2;
1305 }
1306 }
1307 goto show1;
1308 showx:;
1309 await_processed_keyboard();
1310 if(kill_all_flag) goto err_ex2;
1311 switch (lir_inkey)
1312 {
1313 case 'S':
1314 for(i=0; i<fft1_size; i++)
1315 {
1316 for(j=0; j<mm; j+=2)
1317 {
1318 t1=cal_buf3[mm*i+j ]/ampmax;
1319 t2=cal_buf3[mm*i+j+1];
1320 fft1_filtercorr[mm*i+j ]=t1*cos(t2);
1321 fft1_filtercorr[mm*i+j+1]=t1*sin(t2);
1322 }
1323 }
1324 write_filcorr(0);
1325 free(llsq_derivatives);
1326 free(llsq_errors);
1327 // Restore filtercorr and fft1 desired.
1328 if(fft2_size != fft1_size)
1329 {
1330 fft1_hz_per_point/=(float)(fft2_size)/fft1_size;
1331 fft1_size=fft2_size;
1332 fft1_n=fft2_n;
1333 init_fft1_filtercorr();
1334 }
1335 return 1;
1336
1337 case 'X':
1338 goto err_ex2;
1339
1340 case '+':
1341 cal_ygain*=2;
1342 break;
1343
1344 case '-':
1345 cal_ygain/=2;
1346 break;
1347
1348 case 'C':
1349 xgain/=2;
1350 break;
1351
1352 case 'E':
1353 xgain*=2;
1354 break;
1355
1356 case 'R':
1357 xmid-=0.25*screen_width/xgain;
1358 break;
1359
1360 case 'L':
1361 xmid+=0.25*screen_width/xgain;
1362 break;
1363
1364
1365 case F1_KEY:
1366 case '!':
1367 help_message(309);
1368 break;
1369 }
1370 goto show;
1371 }
1372
1373