/* * ISDM.c R06 */ //#include // for abs() function //#include // for printf() function //#include "ISDM.h" #include "app_common.h" #include "app_core.h" #include "app_EWO.h" #include "dpu_api_proto.h" #ifndef _APP_RDN_ /* extern void read_eeprom_ref(byte * ref); // read RefSpect values from eeprom extern void read_eeprom_conf(configstr * conf); // read G14_ISDM_Config values from eeprom */ // read G14_ISDM_RefSpect values from eeprom // (Implemented by T.Imachi) void read_eeprom_ref(byte * ref){ byte *p1, *p2; int i; // p1 = &Guc_EWO_ISDM_tbl[42]; p1 = &G14uc_ISDM_table[42]; p2 = ref; for( i=0; i<32; i++ ){ *p2++ = *p1++; } } // read Config values from eeprom // (Implemented by T.Imachi) void read_eeprom_conf(G14_ISDM_configstr * conf){ byte *p; int i, j; // p = &Guc_EWO_ISDM_tbl[0]; p = &G14uc_ISDM_table[0]; conf->E_Bgnd = 0; for( i=0; i<4; i++ ) conf->E_Bgnd |= ( (int)*p++ << ( i * 8 ) ); conf->E_Proc = 0; for( i=0; i<4; i++ ) conf->E_Proc |= ( (int)*p++ << ( i * 8 ) ); conf->NB_SNR = 0; for( i=0; i<2; i++ ) conf->NB_SNR |= ( (int)*p++ << ( i * 8 ) ); conf->NB_Pw_SN = 0; for( i=0; i<2; i++ ) conf->NB_Pw_SN |= ( (int)*p++ << ( i * 8 ) ); conf->NB_Pw_Lines = *p++; conf->Mid_SNR = 0; for( i=0; i<2; i++ ) conf->Mid_SNR |= ( (int)*p++ << ( i * 8 ) ); conf->Mid_Pw_SN = 0; for( i=0; i<2; i++ ) conf->Mid_Pw_SN |= ( (int)*p++ << ( i * 8 ) ); conf->Mid_Pw_Lines = *p++; conf->WB_SNR = 0; for( i=0; i<2; i++ ) conf->WB_SNR |= ( (int)*p++ << ( i * 8 ) ); conf->WB_Pw_SN = 0; for( i=0; i<2; i++ ) conf->WB_Pw_SN |= ( (int)*p++ << ( i * 8 ) ); conf->WB_Pw_Lines = *p++; conf->Multi_SNR = 0; for( i=0; i<2; i++ ) conf->Multi_SNR |= ( (int)*p++ << ( i * 8 ) ); conf->Multi_Pw_SN = 0; for( i=0; i<2; i++ ) conf->Multi_Pw_SN |= ( (int)*p++ << ( i * 8 ) ); conf->Multi_Pw_Lines = *p++; for( j=0; j<7; j++ ){ conf->Init[j] = 0; for( i=0; i<2; i++ ) conf->Init[j] |= ( (int)*p++ << ( i * 8 ) ); } } /* configstr Config; // config values word RefSpect[256]; // reference spectrum int sm_points=5; // number of points to average int sm_pointsd2=2; // number of points left or right from middle point unsigned int noiseback_cnt[256]; // summ of last 16 spectra line unsigned short noiseback[256]; // averaged noise background byte noiseback_ptr = 16; // pointer for last unsigned short in_spect[17][256]; // last 16 incoming spectra line int energy_ns = 0; // energy of noise bacground byte event_on = 0; // 1: inside event, 0: no event byte event_fcnt = 0; // counting frames during event struct peak_buffer peak_b[17][4]; // buffer for storage 4 largest peaks for every frame in in_spect buffer byte pb_cnt[17] = {0}; // buffer peak_cnt byte avg_lock = 0; // when 16 noise background contains valid spectra byte isdm_stat = 0; // 3,2,1: still counting, 0: calculation done byte isdm_avg_done = 0; // 0: background calculation is going not allowed to kill process // 1: background calculation done process kill is allowed */ byte app14_ISDM_abs( byte a ){ if( (char)a < 0 ) a = (unsigned char)( (char)a * -1 ); return a; } /* * Reset variables and read config and reference spectrum values for the sensor * This is called when sensor Init is set to 1 during f_isdm call */ void app14_ISDM_reset_var(byte Init){ int i,k; byte read_spect[32]; byte l; if (Init == 1){ read_eeprom_ref(&read_spect[0]); // read the RefSpect for Sensor from eeprom read_eeprom_conf(&G14_ISDM_Config); // read the Config for Sensor from eeprom l=0x01; k=0; for (i=0;i<256;i++){ if ((read_spect[k]&l)==0){ G14_ISDM_RefSpect[i]=0; }else{ G14_ISDM_RefSpect[i]=1; } if (l==0x80){ l=0x01; k++; } else { l=l<<1; } } G14_ISDM_sm_points = (G14_ISDM_Config.Init[6]&0xff00)>>8; G14_ISDM_sm_pointsd2 = G14_ISDM_sm_points>>1; G14_ISDM_Config.Init[6] = G14_ISDM_Config.Init[6]&0x00ff; if ((G14_ISDM_sm_points<3) || (G14_ISDM_sm_points > 21)) { G14_ISDM_sm_points = 5; G14_ISDM_sm_pointsd2 = 2; } } G14_ISDM_energy_ns = 0; G14_ISDM_noiseback_ptr = 16; G14_ISDM_avg_lock = 0; for (i=0;i<256;i++){ G14_ISDM_noiseback[i] = 0; G14_ISDM_noiseback_cnt[i] = 0; for (k=0;k<17;k++){ G14_ISDM_in_spect[k][i] = 0; } } } /* * Insert new peak into the peak buffer * Called when new peak is found by the peak detector */ void app14_ISDM_insert_peak(unsigned char peak_pos, unsigned char peak_wide, int peak_peak){ int i; unsigned short comp; int pos; if (G14_ISDM_pb_cnt[G14_ISDM_noiseback_ptr]<4){ // there is empty place G14_ISDM_peak_b[G14_ISDM_noiseback_ptr][G14_ISDM_pb_cnt[G14_ISDM_noiseback_ptr]].pos = peak_pos; G14_ISDM_peak_b[G14_ISDM_noiseback_ptr][G14_ISDM_pb_cnt[G14_ISDM_noiseback_ptr]].wide = peak_wide; G14_ISDM_peak_b[G14_ISDM_noiseback_ptr][G14_ISDM_pb_cnt[G14_ISDM_noiseback_ptr]].h = peak_peak; G14_ISDM_pb_cnt[G14_ISDM_noiseback_ptr]++; } else { // no empty place, check for smaller than actual comp = G14_ISDM_peak_b[G14_ISDM_noiseback_ptr][0].h; pos = 0; for (i=0;i<4;i++){ // looking for smaller if (G14_ISDM_peak_b[G14_ISDM_noiseback_ptr][i].h>4; // calc. noisebackground line G14_ISDM_energy_ns += G14_ISDM_noiseback[i]; // calc. energy } } for (i=0;i<4;i++){ G14_ISDM_peak_b[G14_ISDM_noiseback_ptr][i].h = 0; G14_ISDM_peak_b[G14_ISDM_noiseback_ptr][i].pos = 0; G14_ISDM_peak_b[G14_ISDM_noiseback_ptr][i].wide = 0; } G14_ISDM_pb_cnt[G14_ISDM_noiseback_ptr]=0; if (G14_ISDM_avg_lock<17) G14_ISDM_avg_lock++; } /* * Smooth the incoming spectrum to remove small noise spikes * Average sm_points number of points */ void app14_ISDM_smooth_in(unsigned short * in, unsigned short * out){ int k,i; int add; for(k=(G14_ISDM_sm_pointsd2);k<(256-(G14_ISDM_sm_pointsd2));k++){ add = 0; for (i=-(G14_ISDM_sm_pointsd2);i<=((G14_ISDM_sm_pointsd2));i++){ add += in[k+i]; } out[k] = add / G14_ISDM_sm_points; if(out[k]<3) out[k]=3; } for (k=0;k<(G14_ISDM_sm_pointsd2);k++) { out[k] = out[G14_ISDM_sm_pointsd2]; } for (k=(256-(G14_ISDM_sm_pointsd2));k<256;k++) { out[k] = out[255-G14_ISDM_sm_pointsd2]; } } /* * Check the width of a peak against config values */ int app14_ISDM_calc_width(struct G14_ISDM_peak_buffer * peak, unsigned short * spect, word hlimit, byte wlimit){ int i; int pos; int end; int cnt; int ret; int l; ret = -1; cnt = 0; pos = peak->pos - (wlimit>>1); end = pos + wlimit; if (pos<0) { pos = 0; } if (end>255){ end = 256; } l = (spect[peak->pos]*hlimit)>>8; // printf("b:%d, e:%d, l:%d, SP:%d, pos:%d\n", pos, end, l, spect[peak->pos], peak->pos); for (i=pos;i width is below limit ret = 1; break; } else // width is greater or equal limit ret = -1; } // printf("ret:%d\n", ret); return ret; } /* * Check the peak is inside peak definition */ int app14_ISDM_chk_peak(struct G14_ISDM_peak_buffer * pb, byte pb_c, unsigned short * spect, word snr, word pw_sn, word pw_line){ int i,n; int cnt; int rh; cnt = 0; for (i=0;i>8); if (pb[i].h > rh){ n = app14_ISDM_calc_width(&pb[i], spect, pw_sn, pw_line); if (n>0) { // peak is inside width parameter cnt++; } } } if (cnt>0) return cnt; return -1; } /* * Check previous peaks for long discrete signal */ int app14_ISDM_chk_discrete(int ev_fcnt, byte pos){ int i,k; int bptr; int f_cnt; f_cnt = 0; bptr = G14_ISDM_noiseback_ptr; if (ev_fcnt>15) ev_fcnt = 15; // printf("chk_d: c%d, p%d \n", ev_fcnt, pos); for (i=0;i=ev_fcnt) return 1; return -1; } /* * Main funciton of isdm. */ struct G14_ISDM_event_str app14_ISDM(int Time, unsigned short* Spect, byte Init, byte GainChanged){ struct G14_ISDM_event_str ret; // return variable int energy_c; // energy of incoming spectrum int i,n; // loop counters unsigned short sm_Spect[256]; // smoothed spectrum int peak_energy; // the absolute energy of a "hill" int peak_n_energy; // the noisebackground energy under a "hill" unsigned char peak_wide = 0; // width of the actual processed peak int peak_peak = 0; // the absolute value of a peak int peak_n_peak = 0; // the averaged noise background frequency bins under the peak's hill unsigned char peak_pos = 0; // the position of the peak int peak_cnt = 0; // the number of peaks int peak_max = 0; // the heigth of the biggest detected peak in the spectrum int peak_n_max = 0; // the averaged backround heigth under the peak G14_ISDM_isdm_avg_done = 0; // 0: average calculation started // 1: average calculation finished G14_ISDM_isdm_stat = 3; // 3-1: isdm function is running // 0: isdm function finished ret.Event = 0; ret.e_time = Time; if ((Init == 1)||(GainChanged == 1)){ // if initialization requested or gain changed reset all variables // If initialization than also load the configuration from EEPROM app14_ISDM_reset_var(Init); } app14_ISDM_smooth_in((unsigned short *)Spect, &sm_Spect[0]); // smooth the incoming FFT app14_ISDM_average(Time,&sm_Spect[0]); // calc. background spectra and energy G14_ISDM_isdm_avg_done = 1; // average calculation done if (G14_ISDM_avg_lock == 17){ // noise background is valid // energy calc. on incoming FFT and check for peaks which may have low energy energy_c = 0; for (i=0;i<256;i++){ if(G14_ISDM_RefSpect[i]!=0){ energy_c += sm_Spect[i]; if (sm_Spect[i]>((G14_ISDM_Config.Init[2]*G14_ISDM_noiseback[i])>>8)){ G14_ISDM_event_on=1; } } } // if no peaks found check the energy difference if (G14_ISDM_event_on==0){ if (energy_c > ((G14_ISDM_Config.E_Bgnd*G14_ISDM_energy_ns)>>8)){ // if energy is higher than limit we look for peaks G14_ISDM_event_on = 1; } else { // if below than previous signal ended, length count is set to 0 G14_ISDM_event_on = 0; G14_ISDM_event_fcnt = 0; } } if (G14_ISDM_event_on == 1){ // signal above limit or there are peak like data look for peaks in detail G14_ISDM_event_on = 1; peak_energy = 0; // zero energy of the peak peak_n_energy = 0; // zero energy of the noisebackground under peak peak_wide = 0; // zero the width of the peak peak_peak = 0; // zero the heigth of the peak peak_n_peak = 0; // zero the heigth of the noise backround average frequency bin level peak_cnt = 0; // zero the number of peaks peak_pos = 0; // zero the position of the peak for (i=0;i<256;i++){ if (G14_ISDM_RefSpect[i] != 0){ // where mask is 0 we dont look for peak // printf("pd:[%d]%d : ed:%d, nb:%d\n", i, sm_Spect[i], e_deltawide, noiseback[i]); if (((G14_ISDM_noiseback[i]*G14_ISDM_Config.E_Bgnd)>>8) < sm_Spect[i]){ // if line is above the background * limit // start peak peak_energy += sm_Spect[i]; peak_n_energy += G14_ISDM_noiseback[i]; peak_wide++; if (peak_peak < sm_Spect[i]){ peak_pos = i; peak_peak = sm_Spect[i]; } } else { if (peak_energy != 0){ // peak end peak_n_peak = peak_n_energy / ((int)peak_wide); if ((peak_energy>((G14_ISDM_Config.Init[0]*peak_n_energy)>>8)) && ((peak_peak) > ((G14_ISDM_Config.Init[2]*peak_n_peak)>>8))){ // peak energy and heigth is big enough app14_ISDM_insert_peak(peak_pos, peak_wide, peak_peak); if (peak_cnt<7)peak_cnt++; if (peak_peak>peak_max){ // store maximum peak for quality decision peak_max = peak_peak; peak_n_max = peak_n_peak; } } peak_wide = 0; peak_energy = 0; peak_n_energy = 0; peak_peak = 0; peak_n_peak = 0; } else { // no peak before } } } } // ==== ISDM-R07 ==== if (peak_energy != 0){ // there was no peak end before FFT end peak_n_peak = peak_n_energy / ((int)peak_wide); if ((peak_energy>((G14_ISDM_Config.Init[0]*peak_n_energy)>>8)) && ((peak_peak) > ((G14_ISDM_Config.Init[2]*peak_n_peak)>>8))){ // peak energy and heigth is big enough app14_ISDM_insert_peak(peak_pos, peak_wide, peak_peak); if (peak_cnt<7)peak_cnt++; if (peak_peak>peak_max){ // store maximum peak for quality decision peak_max = peak_peak; peak_n_max = peak_n_peak; } } } // ==== ISDM-R07 ==== // decide frame type // printf("ISDM: pc:%d\n", peak_cnt); switch (peak_cnt){ case 0: // no peak if (energy_c > ((G14_ISDM_Config.E_Bgnd*G14_ISDM_energy_ns)>>8)){ if ( energy_c < ((G14_ISDM_Config.E_Proc*G14_ISDM_energy_ns)>>8) ){ // check signal is below reference // type 5 (weak signal) ret.Event |= 0xA0; ret.e_time = Time; } else { // type 4 diffuse signal ret.Event |= 0x80; ret.e_time = Time; } } else { // type 0 no signal ret.Event |= 0x00; ret.e_time = Time; G14_ISDM_event_fcnt = 0; G14_ISDM_event_on=0; } break; case 1: // 1 peak n = app14_ISDM_chk_peak(&G14_ISDM_peak_b[G14_ISDM_noiseback_ptr][0], G14_ISDM_pb_cnt[G14_ISDM_noiseback_ptr], &sm_Spect[0], G14_ISDM_Config.NB_SNR, G14_ISDM_Config.NB_Pw_SN, G14_ISDM_Config.NB_Pw_Lines); if (n<0) { // wider than narrow n = app14_ISDM_chk_peak(&G14_ISDM_peak_b[G14_ISDM_noiseback_ptr][0], G14_ISDM_pb_cnt[G14_ISDM_noiseback_ptr], &sm_Spect[0], G14_ISDM_Config.Mid_SNR, G14_ISDM_Config.Mid_Pw_SN, G14_ISDM_Config.Mid_Pw_Lines); if (n<0){ // wider than mid n = app14_ISDM_chk_peak(&G14_ISDM_peak_b[G14_ISDM_noiseback_ptr][0], G14_ISDM_pb_cnt[G14_ISDM_noiseback_ptr], &sm_Spect[0],G14_ISDM_Config.WB_SNR, G14_ISDM_Config.WB_Pw_SN, G14_ISDM_Config.WB_Pw_Lines); if (n<0){ // wider than wide if (energy_c > ((G14_ISDM_Config.E_Bgnd*G14_ISDM_energy_ns)>>8)){ if ( energy_c < ((G14_ISDM_Config.E_Proc*G14_ISDM_energy_ns)>>8) ){ // type 5 (weak signal) ret.Event |= 0xA0; ret.e_time = Time; } else { // type 4 diffuse signal ret.Event |= 0x80; ret.e_time = Time; } } else { // type 0 no signal ret.Event |= 0x00; ret.e_time = Time; G14_ISDM_event_fcnt = 0; G14_ISDM_event_on=0; } } else { // wide ret.Event |= 0x22; ret.e_time = Time; } } else { // mid ret.Event |= 0x21; ret.e_time = Time; } } else { // narrow ret.Event |= 0x20; ret.e_time = Time; } break; default: // multiple peaks n = app14_ISDM_chk_peak(&G14_ISDM_peak_b[G14_ISDM_noiseback_ptr][0], G14_ISDM_pb_cnt[G14_ISDM_noiseback_ptr], &sm_Spect[0], G14_ISDM_Config.Multi_SNR, G14_ISDM_Config.Multi_Pw_SN, G14_ISDM_Config.Multi_Pw_Lines); if (n<2){ // not multi n = app14_ISDM_chk_peak(&G14_ISDM_peak_b[G14_ISDM_noiseback_ptr][0], G14_ISDM_pb_cnt[G14_ISDM_noiseback_ptr], &sm_Spect[0], G14_ISDM_Config.NB_SNR, G14_ISDM_Config.NB_Pw_SN, G14_ISDM_Config.NB_Pw_Lines); if (n<0){ // not narrow -> wider n = app14_ISDM_chk_peak(&G14_ISDM_peak_b[G14_ISDM_noiseback_ptr][0], G14_ISDM_pb_cnt[G14_ISDM_noiseback_ptr], &sm_Spect[0], G14_ISDM_Config.Mid_SNR, G14_ISDM_Config.Mid_Pw_SN, G14_ISDM_Config.Mid_Pw_Lines); if (n<0){ // not mid -> wider n = app14_ISDM_chk_peak(&G14_ISDM_peak_b[G14_ISDM_noiseback_ptr][0], G14_ISDM_pb_cnt[G14_ISDM_noiseback_ptr], &sm_Spect[0],G14_ISDM_Config.WB_SNR, G14_ISDM_Config.WB_Pw_SN, G14_ISDM_Config.WB_Pw_Lines); if (n<0){ // not wide -> wider if (energy_c > ((G14_ISDM_Config.E_Bgnd*G14_ISDM_energy_ns)>>8)){ if ( energy_c < ((G14_ISDM_Config.E_Proc*G14_ISDM_energy_ns)>>8) ){ // type 5 (weak signal) ret.Event |= 0xA0; ret.e_time = Time; } else { // type 4 diffuse signal ret.Event |= 0x80; ret.e_time = Time; } } else { // type 0 no signal ret.Event |= 0x00; ret.e_time = Time; G14_ISDM_event_fcnt = 0; G14_ISDM_event_on=0; } } else { // wide ret.Event |= 0x22; ret.e_time = Time; } } else { // mid ret.Event |= 0x21; ret.e_time = Time; } } else { // narrow ret.Event |= 0x20; ret.e_time = Time; } } else { // multi ret.Event |= 0x40; ret.Event |= (n&0x07); ret.e_time = Time; } break; } ret.Event &= ~0x18; // decide frame quality if (((ret.Event&0xE0)==0x20) || ((ret.Event&0xE0)==0x40)){ // there was peak if (peak_max<((G14_ISDM_Config.Init[3]*peak_n_max)>>8)){ ret.Event |= 0x00; // Q = 0 } else { if (peak_max<((G14_ISDM_Config.Init[4]*peak_n_max)>>8)){ ret.Event |= 0x08; // Q = 1 } else { if (peak_max<((G14_ISDM_Config.Init[5]*peak_n_max)>>8)){ ret.Event |= 0x10; // Q = 2 } else { ret.Event |= 0x18; // Q = 3 } } } } else { // no peak if ( energy_c < ((G14_ISDM_Config.Init[3]*G14_ISDM_energy_ns)>>8) ){ ret.Event |= 0x00; // Q = 0 } else { if ( energy_c < ((G14_ISDM_Config.Init[4]*G14_ISDM_energy_ns)>>8) ){ ret.Event |= 0x08; // Q = 1 } else { if ( energy_c < ((G14_ISDM_Config.Init[5]*G14_ISDM_energy_ns)>>8) ){ ret.Event |= 0x10; // Q = 2 } else { ret.Event |= 0x18; // Q = 3 } } } } // printf("ev_fcnt %d\n",event_fcnt); if (G14_ISDM_event_fcnt<255) G14_ISDM_event_fcnt++; if (G14_ISDM_event_fcnt > G14_ISDM_Config.Init[1]){ if ((ret.Event&0xE0) == 0x20){ // when current find is short single check previous peaks for long discrete n = app14_ISDM_chk_discrete(G14_ISDM_event_fcnt, G14_ISDM_peak_b[G14_ISDM_noiseback_ptr][0].pos); if (n>0){ // all peak buffer has peak at similar position -> long discrete ret.Event &= ~0xE0; ret.Event |= 0x60; } } } } else { // signal is below E_Bgnd and no peak like structures return no event ret.Event = 0; ret.e_time = Time; } } else { // noise background is not valid yet return no event ret.Event = 0; ret.e_time = Time; } G14_ISDM_isdm_stat = 0; return ret; } #endif // _APP_RDN_