#include #include #include #include "globdef.h" #include "uidef.h" #include "fft1def.h" #include "fft2def.h" #include "fft3def.h" #include "sigdef.h" #include "screendef.h" #include "seldef.h" #include "thrdef.h" #include "txdef.h" #include "vernr.h" #include "hwaredef.h" #include "sdrdef.h" #include "keyboard_def.h" int tx_ssb_step2(float *totpwr) { int i, k; float t1, t2; // ************* Step 2. ************* // Compute the power for each bin within the passband. // Apply muting in the frequency domain by setting bins with too small // signal power to zero. // Collect the sum of the powers from surviving bins and mute the entire // block in case the total power is below threshold. // Here we use the agc factor as determined from the the // previous block and attenuated with the decay factor. // Note that the agc factor is limited to 20 dB at this point. // A big pulse will not kill the signal for a long time!! t1=0; k=0; for(i=tx_filter_ia1; i micfft_bin_minpower) { k++; t1+=t2; } else { micfft[micfft_px+2*i ]=0; micfft[micfft_px+2*i+1]=0; } } for(i=0; i<=tx_filter_ib1; i++) { t2=micfft[micfft_px+2*i ]*micfft[micfft_px+2*i ]+ micfft[micfft_px+2*i+1]*micfft[micfft_px+2*i+1]; if(t2 > micfft_bin_minpower) { k++; t1+=t2; } else { micfft[micfft_px+2*i ]=0; micfft[micfft_px+2*i+1]=0; } } if(k>0 && t1 < micfft_minpower) { for(i=tx_filter_ia1; i TX_AGC_THRESHOLD*(tx_highest_bin-tx_lowest_bin+1)) { tx_agc_factor=TX_AGC_THRESHOLD/(r1*t1); } t2=tx_agc_factor*(tx_highest_bin-tx_lowest_bin+1)*r1; t2*=pow(10.0,0.05*(txssb.mic_out_gain-60)); // Apply the AGC within the current fft block. for(i=tx_filter_ia1; it1[0])t1[0]=t2; if(t2 > 1) { t2=1/sqrt(t2); cliptimf[cliptimf_pa+i ]*=t2; cliptimf[cliptimf_pa+i+1]*=t2; } } if( (tx_filter_ia1&1) != 0)r1*=-1; for(i=0; i=0; i-=2) { r1=micfft_winfac*micfft_win[k]; cliptimf[cliptimf_pa+i ]=tx_ph1*cliptimf[cliptimf_pa+i ]*r1; cliptimf[cliptimf_pa+i+1]=tx_ph1*cliptimf[cliptimf_pa+i+1]*r1; k++; t2=cliptimf[cliptimf_pa+i ]*cliptimf[cliptimf_pa+i ]+ cliptimf[cliptimf_pa+i+1]*cliptimf[cliptimf_pa+i+1]; if(t1[0] < MAX_DYNRANGE && t2 < MAX_DYNRANGE) { cliptimf[cliptimf_pa+i ]=0; cliptimf[cliptimf_pa+i+1]=0; } else { prat[0]+=t2; if(t2>t1[0])t1[0]=t2; if(t2 > 1) { t2=1/sqrt(t2); cliptimf[cliptimf_pa+i ]*=t2; cliptimf[cliptimf_pa+i+1]*=t2; t2=cliptimf[cliptimf_pa+i ]*cliptimf[cliptimf_pa+i ]+ cliptimf[cliptimf_pa+i+1]*cliptimf[cliptimf_pa+i+1]; } } } for(i=0; i>1]; cliptimf[cliptimf_pa+i ]=tx_ph1*r2*micfft[micfft_px+i ]; cliptimf[cliptimf_pa+i+1]=tx_ph1*r2*micfft[micfft_px+i+1]; t2=cliptimf[cliptimf_pa+i ]*cliptimf[cliptimf_pa+i ]+ cliptimf[cliptimf_pa+i+1]*cliptimf[cliptimf_pa+i+1]; if(t1[0] < MAX_DYNRANGE && t2 < MAX_DYNRANGE) { cliptimf[cliptimf_pa+i ]=0; cliptimf[cliptimf_pa+i+1]=0; } else { prat[0]+=t2; if(t2>t1[0])t1[0]=t2; if(t2 > 1) { t2=1/sqrt(t2); cliptimf[cliptimf_pa+i ]*=t2; cliptimf[cliptimf_pa+i+1]*=t2; } } } if( (tx_filter_ia1&1) != 0)r1*=-1; for(i=0; i 2*mic_fftsize) { pb=(cliptimf_px+2*(mic_fftsize-1))&micfft_mask; nx=cliptimf_px/mic_fftsize; nb=((cliptimf_px+mic_fftsize)&micfft_mask)/mic_fftsize; if(cliptimf_mute[nx]==FALSE/* && cliptimf_mute[nb]==FALSE*/) { j=mic_fftsize-1; for(i=0; i=MAX_SCREENCOUNT) { show_txfft(&clipfft[clipfft_pa],0,1,mic_fftsize); } } for(i=tx_filter_ib1+1; ipmax)pmax=t2; tx_forwardpwr*=txpwr_decay; if(tx_forwardpwr>1)+i]=tx_forwardpwr; } } else { for(i=0; ipmax)pmax=t2; tx_forwardpwr*=txpwr_decay; if(tx_forwardpwr>1)+i]=tx_forwardpwr; } } } else { if(mute_previous) { tx_forwardpwr=0; alctimf_mute[alctimf_pa/alc_fftsize]=TRUE; } else { alctimf_mute[alctimf_pa/alc_fftsize]=FALSE; for(i=0; ipmax)pmax=t2; tx_forwardpwr*=txpwr_decay; if(tx_forwardpwr>1)+i]=tx_forwardpwr; } } } if( alctimf_mute[alctimf_pa/alc_fftsize] == FALSE) { // Store an exponential power fall-off with the same time constant, 50 ms, // in the reverse direction. i=alc_sizhalf-1; t1=0; while(i >= 0) { t1*=txpwr_decay; if(t1 < alctimf_pwrf[(alctimf_pa>>1)+i])t1=alctimf_pwrf[(alctimf_pa>>1)+i]; alctimf_pwrd[(alctimf_pa>>1)+i]=t1; i--; } pb=alctimf_pa; t1=alctimf_pwrd[(pb>>1)]; i=0; while( pb != ((int)(alctimf_fx+4+alc_bufsiz)&alc_mask) && i == 0) { t1*=txpwr_decay; pb=(pb+alc_mask)&alc_mask; if(t1 > alctimf_pwrf[(pb>>1)]) { alctimf_pwrd[(pb>>1)]=t1; } else { i=1; } } } alctimf_pa=(alctimf_pa+alc_fftsize)&alc_mask; if(clipfft_mute[clipfft_px/alc_block] == FALSE) { for(i=0; i>1)+i]; if(t1 > 1) { t1=1/sqrt(t1); alctimf[alctimf_pb+2*i ]*=t1; alctimf[alctimf_pb+2*i+1]*=t1; } t2=alctimf[alctimf_pb+2*i ]*alctimf[alctimf_pb+2*i ]+ alctimf[alctimf_pb+2*i+1]*alctimf[alctimf_pb+2*i+1]; // We do not want more than MAX_DYNRANGE dynamic range. // any signal below is just rounding errors in muted periods. if(t2 < MAX_DYNRANGE) { alctimf[alctimf_pb+2*i ]=0; alctimf[alctimf_pb+2*i+1]=0; } if(t2 > pmax)pmax=t2; prat[0]+=t2; } } else { pmax=0; prat[0]=0; for(i=0; i 4*alc_fftsize) { tx_output_flag=1; tx_resamp_pa=0; tx_resamp_px=0; } } if(tx_output_flag == 1) { resample_tx_output(); } } void use_tx_resamp(float ampfac) { int i, j, k, m; float t1, t2, t3, r1, r2; // The latest half block of data resides in tx_resamp[alc_fftsize] // to tx_resamp[2*alc_fftsize-1] // Copy the previous block from resamp_tmp and multiply with // the window function. k=alc_sizhalf; m=k-1; t1=0; for(i=0; i 0) { for(i=alc_sizhalf; i=i && t1 >0) { tx_resamp[2*k]*=t1; tx_resamp[2*k+1]*=t1; tx_resamp[2*i]*=t1; tx_resamp[2*i+1]*=t1; t2+=t3; t1=1-t2*t2; i++; k--; } while(k>=i) { tx_resamp[2*k]=0; tx_resamp[2*k+1]=0; tx_resamp[2*i]=0; tx_resamp[2*i+1]=0; i++; k--; } } if(k < 0) { lirerr(77676); } // //if(screen_count>=MAX_SCREENCOUNT) // { // if(tx_setup_flag == TRUE)show_txfft(tx_resamp,0,2,txout_fftsize); // } // Now we have the output in the frequency domain at the size txout_fftsize // with a sampling rate that fits our D/A converter. Transform it back // to the time domain into txout. fftback(txout_fftsize, txout_fftn, tx_resamp, txout_table, txout_permute); for(i=0; i PI_L)tx_output_phase-=2*PI_L; if(tx_output_phase < -PI_L)tx_output_phase+=2*PI_L; t1=cos(tx_output_phase); t2=sin(tx_output_phase); r1=tx_resamp[i ]+txout_tmp[i ]; r2=tx_resamp[i+1]+txout_tmp[i+1]; txout[i ]=r1*t1+r2*t2; txout[i+1]=-r1*t2+r2*t1; } for(i=0; i 2) { i2=alctimf_fx+(r1+r2)/2; i3=i2+2; i2&=mask2; i3&=mask2; } else { if(i3==i2) { i2=alctimf_fx+r1; i2&=mask2; if(i3==i2) { i3=i2+2; i3&=mask2; } } } i4=(i3+2)&(mask2); i1=(i2+mask2)&(mask2); if( ((alctimf_pb-i4+alc_bufsiz)&alc_mask) > 4) { if(alctimf_mute[i2/alc_fftsize]==FALSE || alctimf_mute[i3/alc_fftsize]==FALSE) { rdiff=r1+alctimf_fx-i2; if(rdiff > alc_bufsiz/2) { rdiff-=alc_bufsiz; } rdiff/=2; // Use Lagrange's interpolation formula to fit a third degree // polynomial to 4 points: // a1=-rdiff * (rdiff-1)*(rdiff-2)*alctimf[i1]/6 // +(rdiff+1)*(rdiff-1)*(rdiff-2)*alctimf[i2]/2 // -(rdiff+1)* rdiff *(rdiff-2)*alctimf[i3]/2 // +(rdiff+1)* rdiff *(rdiff-1)*alctimf[i4]/6; // Rewrite slightly to save a few multiplications - do not // think the compiler is smart enough to do it for us. t1=rdiff-1; t2=rdiff-2; t3=rdiff+1; t4=t1*t2; t5=t3*rdiff; t6=rdiff*t4; t4=t3*t4; t7=t5*t2; t5=t5*t1; a1=((t5*alctimf[i4 ]-t6*alctimf[i1 ])/3+t4*alctimf[i2 ]-t7*alctimf[i3 ])/2; a2=((t5*alctimf[i4+1]-t6*alctimf[i1+1])/3+t4*alctimf[i2+1]-t7*alctimf[i3+1])/2; // The curve fitting is (of course) just an approximation. // Make sure we do not go outside our range! t2=a1*a1+a2*a2; if(t2 > tx_resamp_ampfac1)tx_resamp_ampfac1=t2; tx_resamp[tx_resamp_pa+alc_fftsize ]=a1; tx_resamp[tx_resamp_pa+alc_fftsize+1]=a2; } else { tx_resamp[tx_resamp_pa+alc_fftsize ]=0; tx_resamp[tx_resamp_pa+alc_fftsize+1]=0; } r1=r2; tx_resamp_pa+=2; if(tx_resamp_pa >= alc_fftsize) { alctimf_fx+=r2; if(alctimf_fx>alc_bufsiz)alctimf_fx-=alc_bufsiz; t1=tx_resamp_ampfac1; if(t1 < tx_resamp_ampfac2)t1=tx_resamp_ampfac2; /* {int i; for(i=0; i= 0)return; lir_fillbox(x,y,TX_BAR_SIZE,text_height-2,7); return; } if(val2 > val1) { lir_fillbox(x+val1,y,val2-val1,text_height-2,12); } else { lir_fillbox(x+val2,y,val1-val2,text_height-2,7); } } void show_txfft(float *z, float lim, int type, int siz) { int i, ia, ib, k, m; int pixels_per_bin, bins_per_pixel; float t1,t2; char color; short int *trc; if(type >= MAX_DISPLAY_TYPES) { lirerr(762319); return; } trc=&txtrace[type*tx_show_siz]; ia=0; t2=0; pixels_per_bin=(screen_width-1)/siz; bins_per_pixel=1; while(pixels_per_bin == 0) { siz/=2; pixels_per_bin=(screen_width-1)/siz; bins_per_pixel*=2; } ib=pixels_per_bin; lir_sched_yield(); for(i=1; itxtrace_height)k=txtrace_height; if(k<0)k=0; trc[i]=k+screen_height-txtrace_height-1; if(i>0) { if(type==0) { if(t2 > lim) { color=15; } else { color=12; } } else { color=display_color[type]; } lir_line(ia,trc[i-1],ib,trc[i],color); ia=ib; ib+=pixels_per_bin; } t2=t1; } lir_sched_yield(); }