/* * Measurement.cpp * Measuremnet class implementation * $Id: Measurement.cpp 21615 2015-02-25 09:31:08Z ritt $ */ #include "DRSOscInc.h" void linfit(double *x, double *y, int n, double &a, double &b); Measurement::Measurement(DOFrame *frame, int index) { m_frame = frame; m_index = index; memset(m_param, 0, sizeof(m_param)); m_statIndex = 0; m_nMeasured = 0; m_nStat = 1000; m_statArray = new double[m_nStat]; m_vsum = m_vvsum = 0; m_min = m_max = 0; ResetStat(); } Measurement::~Measurement() { delete m_statArray; } void Measurement::ResetStat() { m_nMeasured = 0; m_statIndex = 0; } void Measurement::SetNStat(int n) { if (n > 1000000) n = 1000000; if (n < 1) n = 1; m_nStat = n; delete m_statArray; m_statArray = new double[n]; ResetStat(); } wxString Measurement::GetName() { switch (m_index) { case 0: return wxT("Level"); break; case 1: return wxT("Pk-Pk"); break; case 2: return wxT("RMS"); break; case 3: return wxT("VSlice"); break; case 4: return wxT("Charge"); break; case 5: return wxT("Freq"); break; case 6: return wxT("Period"); break; case 7: return wxT("Rise"); break; case 8: return wxT("Fall"); break; case 9: return wxT("Pos Width"); break; case 10: return wxT("Neg Width"); break; case 11: return wxT("Chn delay"); break; case 12: return wxT("HSlice"); break; default: return wxT(""); break; } } void Measurement::Measure(double *x1, double *y1, double *x2, double *y2, int n) { Measure(x1, y1, x2, y2, n, true, NULL); } double Measurement::Measure(double *x1, double *y1, double *x2, double *y2, int n, bool update, DOScreen *s) { double v; int i, na; switch (m_index) { case 0: v = MLevel(x1, y1, n, s); break; case 1: v = MPkPk(x1, y1, n, s); break; case 2: v = MRMS(x1, y1, n, s); break; case 3: v = MVSlice(x1, y1, n, s); break; case 4: v = MCharge(x1, y1, n, s); break; case 5: v = MFreq(x1, y1, n, s); break; case 6: v = MPeriod(x1, y1, n, s); break; case 7: v = MRise(x1, y1, n, s); break; case 8: v = MFall(x1, y1, n, s); break; case 9: v = MPosWidth(x1, y1, n, s); break; case 10: v = MNegWidth(x1, y1, n, s); break; case 11: v = MChnDelay(x1, y1, x2, y2, n, s); break; case 12: v = MHSlice(x1, y1, n, s); break; default: v = 0; break; } m_value = v; /* update statistics */ if (update && !ss_isnan(v)) { m_statArray[m_statIndex] = v; m_statIndex = (m_statIndex + 1) % m_nStat; if (m_nMeasured < m_nStat) { m_nMeasured++; na = m_nMeasured; } else { na = m_nStat; } m_vsum = m_vvsum = 0; m_min = m_max = v; for (i=0 ; i m_max) m_max = m_statArray[i]; } } return v; } wxString Measurement::GetString() { wxString str; if (ss_isnan(m_value)) str.Printf(wxT(" N/A")); else { switch (m_index) { case 0: case 1: case 2: case 3: str.Printf(wxT("%6.1lf mV"), m_value); break; case 4: str.Printf(wxT("%6.1lf pC"), m_value); break; case 5: str.Printf(wxT("%6.1lf MHz"), m_value); break; case 6: case 7: case 8: case 9: case 10: case 11: case 12: str.Printf(wxT("%6.3lf ns"), m_value); break; } } return str; } wxString Measurement::GetStat() { double mean, std; if (m_nMeasured == 0) { mean = 0; std = 0; } else { mean = m_vsum / m_nMeasured; std = sqrt(m_vvsum/m_nMeasured - m_vsum*m_vsum/m_nMeasured/m_nMeasured); } wxString str; if (ss_isnan(m_min) || ss_isnan(m_max)) str.Printf(wxT(" N/A N/A N/A N/A %6d"), m_nMeasured); else str.Printf(wxT("%8.3lf %8.3lf %8.3lf %8.4lf %6d"), m_min, m_max, mean, std, m_nMeasured); return str; } double Measurement::MLevel(double *x, double *y, int n, DOScreen *s) { double l = 0; for (int i=0 ; i 0) l /= n; if (s) { s->GetDC()->DrawLine(s->timeToX(x[0]), s->voltToY(l), s->timeToX(x[n-1]), s->voltToY(l)); } return l; } double Measurement::MPkPk(double *x, double *y, int n, DOScreen *s) { double min_x, min_y, max_x, max_y; min_x = max_x = x[0]; min_y = max_y = y[0]; for (int i=0 ; i max_y) { max_x = x[i]; max_y = y[i]; } } if (s) { int x_min = s->timeToX(min_x); int x_max = s->timeToX(max_x); int y_min = s->voltToY(min_y); int y_max = s->voltToY(max_y); int x_center = (x_min + x_max) / 2; if (x_max > x_min) { s->GetDC()->DrawLine(x_min-20, y_min, x_center+20, y_min); s->GetDC()->DrawLine(x_center-20, y_max, x_max+20, y_max); } else { s->GetDC()->DrawLine(x_max-20, y_max, x_center+20, y_max); s->GetDC()->DrawLine(x_center-20, y_min, x_min+20, y_min); } s->GetDC()->DrawLine(x_center, y_max, x_center, y_min); s->GetDC()->DrawLine(x_center, y_max, x_center+2, y_max+6); s->GetDC()->DrawLine(x_center, y_max, x_center-2, y_max+6); s->GetDC()->DrawLine(x_center, y_min, x_center+2, y_min-6); s->GetDC()->DrawLine(x_center, y_min, x_center-2, y_min-6); } return max_y-min_y; } double Measurement::MRMS(double *x, double *y, int n, DOScreen *s) { double mean = 0; double rms = 0; if (n <= 0) return 0; for (int i=0 ; ivoltToY(mean); for (int i=0 ; iGetDC()->DrawLine(s->timeToX(x[i]), ym, s->timeToX(x[i]), s->voltToY(y[i])); } return rms; } double Measurement::MVSlice(double *x, double *y, int n, DOScreen *s) { int i; double u = 0; if (n <= 0) return 0; for (i=0 ; i m_param[0]) break; if (i == n-1) return ss_nan(); if (x[i+1] - x[i] == 0) return ss_nan(); u = y[i] + (y[i+1]-y[i]) * (m_param[0] - x[i]) / (x[i+1] - x[i]); if (s) { s->GetDC()->DrawLine(s->timeToX(m_param[0]), s->GetY1(), s->timeToX(m_param[0]), s->GetY2()); } return u; } double Measurement::MCharge(double *x, double *y, int n, DOScreen *s) { double q = 0; double x1, x2, y1, y2; if (n <= 0) return 0; for (int i=0 ; i= m_param[0] && x[i] <= m_param[2]) { if (x[i] < m_param[0]) { x1 = m_param[0]; y1 = y[i] + (y[i+1]-y[i]) * (m_param[0] - x[i]) / (x[i+1] - x[i]); } else { x1 = x[i]; y1 = y[i]; } if (x[i+1] > m_param[2]) { x2 = m_param[2]; y2 = y[i] + (y[i+1]-y[i]) * (m_param[2] - x[i]) / (x[i+1] - x[i]); } else { x2 = x[i+1]; y2 = y[i+1]; } q += 0.5 * (y1 + y2) * (x2 - x1); if (s) { wxPoint p[4]; p[0] = wxPoint(s->timeToX(x1), s->voltToY(0)); p[1] = wxPoint(s->timeToX(x1), s->voltToY(y1)); p[2] = wxPoint(s->timeToX(x2), s->voltToY(y2)); p[3] = wxPoint(s->timeToX(x2), s->voltToY(0)); s->GetDC()->DrawPolygon(4, p, 0, 0); } } } return q / 50; // signal into 50 Ohm } /*-------------------------------------------------------------------------*/ double Measurement::MFreq(double *x, double *y, int n, DOScreen *s) { double p = MPeriod(x, y, n, s); if (ss_isnan(p) || p == 0) return ss_nan(); return 1000/p; } double Measurement::MPeriod(double *x, double *y, int n, DOScreen *s) { int i, pos_edge, n_pos, n_neg; double miny, maxy, mean, t1, t2; if (n <= 0) return 0; miny = maxy = y[0]; mean = 0; for (i=0 ; i maxy) maxy = y[i]; if (y[i] < miny) miny = y[i]; mean += y[i]; } if (n < 5 || maxy - miny < 10) return ss_nan(); mean = mean/n; /* count zero crossings */ n_pos = n_neg = 0; for (i=1 ; i mean && y[i-1] <= mean) n_pos++; if (y[i] < mean && y[i-1] >= mean) n_neg++; } /* search for zero crossing */ for (i=n/2+2 ; i>1 ; i--) { if (n_pos > 1 && y[i] > mean && y[i-1] <= mean) break; if (n_neg > 1 && y[i] < mean && y[i-1] >= mean) break; } if (i == 1) for (i=n/2 ; i 1 && y[i] > mean && y[i-1] <= mean) break; if (n_neg > 1 && y[i] < mean && y[i-1] >= mean) break; } if (i == n) return ss_nan(); pos_edge = y[i] > mean; t1 = (mean*(x[i]-x[i-1])+x[i-1]*y[i]-x[i]*y[i-1])/(y[i]-y[i-1]); /* search next zero crossing */ for (i++ ; i mean && y[i-1] <= mean) break; if (!pos_edge && y[i] < mean && y[i-1] >= mean) break; } if (i == n) return ss_nan(); t2 = (mean*(x[i]-x[i-1])+x[i-1]*y[i]-x[i]*y[i-1])/(y[i]-y[i-1]); if (s) { int ym = s->voltToY(mean); int x1 = s->timeToX(t1); int x2 = s->timeToX(t2); s->GetDC()->DrawLine(x1, ym-10, x1, ym+10); s->GetDC()->DrawLine(x2, ym-10, x2, ym+10); s->GetDC()->DrawLine(x1, ym, x2, ym); s->GetDC()->DrawLine(x1, ym, x1+6, ym-2); s->GetDC()->DrawLine(x1, ym, x1+6, ym+2); s->GetDC()->DrawLine(x2, ym, x2-6, ym-2); s->GetDC()->DrawLine(x2, ym, x2-6, ym+2); } return t2 - t1; } double Measurement::MRise(double *x, double *y, int n, DOScreen *s) { int i; double miny, maxy, t1, t2, y10, y90; if (n <= 0) return 0; miny = maxy = y[0]; for (i=0 ; i maxy) maxy = y[i]; if (y[i] < miny) miny = y[i]; } if (maxy - miny < 10) return ss_nan(); y10 = miny+0.1*(maxy-miny); y90 = miny+0.9*(maxy-miny); /* search for 10% level crossing */ for (i=n/2+2 ; i>1 ; i--) if (y[i] > y10 && y[i-1] <= y10) break; if (i == 1) for (i=n/2 ; i y10 && y[i-1] <= y10) break; } if (i == n) return ss_nan(); t1 = (y10*(x[i]-x[i-1])+x[i-1]*y[i]-x[i]*y[i-1])/(y[i]-y[i-1]); /* search for 90% level crossing */ for (i++ ; i y90 && y[i-1] <= y90) break; if (i == n) return ss_nan(); t2 = (y90*(x[i]-x[i-1])+x[i-1]*y[i]-x[i]*y[i-1])/(y[i]-y[i-1]); if (s) { int y1 = s->voltToY(y10); int y2 = s->voltToY(y90); int x1 = s->timeToX(t1); int x2 = s->timeToX(t2); int ym = (y1 + y2)/2; s->GetDC()->DrawLine(x1, y1+10, x1, ym-10); s->GetDC()->DrawLine(x2, y2-10, x2, ym+10); s->GetDC()->DrawLine(x1, ym, x2, ym); s->GetDC()->DrawLine(x1, ym, x1+6, ym-2); s->GetDC()->DrawLine(x1, ym, x1+6, ym+2); s->GetDC()->DrawLine(x2, ym, x2-6, ym-2); s->GetDC()->DrawLine(x2, ym, x2-6, ym+2); } return t2 - t1; } double Measurement::MFall(double *x, double *y, int n, DOScreen *s) { int i; double miny, maxy, t1, t2, y10, y90; if (n <= 0) return 0; miny = maxy = y[0]; for (i=0 ; i maxy) maxy = y[i]; if (y[i] < miny) miny = y[i]; } if (maxy - miny < 10) return ss_nan(); y10 = miny+0.1*(maxy-miny); y90 = miny+0.9*(maxy-miny); /* search for 90% level crossing */ for (i=n/2+2 ; i>1 ; i--) if (y[i] < y90 && y[i-1] >= y90) break; if (i == 1) for (i=n/2 ; i= y90) break; } if (i == n) return ss_nan(); t1 = (y90*(x[i]-x[i-1])+x[i-1]*y[i]-x[i]*y[i-1])/(y[i]-y[i-1]); /* search for 10% level crossing */ for (i++ ; i= y10) break; if (i == n) return ss_nan(); t2 = (y10*(x[i]-x[i-1])+x[i-1]*y[i]-x[i]*y[i-1])/(y[i]-y[i-1]); if (s) { int y1 = s->voltToY(y90); int y2 = s->voltToY(y10); int x1 = s->timeToX(t1); int x2 = s->timeToX(t2); int ym = (y1 + y2)/2; s->GetDC()->DrawLine(x1, y1-10, x1, ym+10); s->GetDC()->DrawLine(x2, y2+10, x2, ym-10); s->GetDC()->DrawLine(x1, ym, x2, ym); s->GetDC()->DrawLine(x1, ym, x1+6, ym-2); s->GetDC()->DrawLine(x1, ym, x1+6, ym+2); s->GetDC()->DrawLine(x2, ym, x2-6, ym-2); s->GetDC()->DrawLine(x2, ym, x2-6, ym+2); } return t2 - t1; } double Measurement::MPosWidth(double *x, double *y, int n, DOScreen *s) { int i; double miny, maxy, mean, t1, t2; if (n <= 0) return 0; miny = maxy = y[0]; for (i=0 ; i maxy) maxy = y[i]; if (y[i] < miny) miny = y[i]; } mean = (miny + maxy)/2; if (maxy - miny < 10) return ss_nan(); /* search for first pos zero crossing */ for (i=1 ; i mean && y[i-1] <= mean) break; if (i == n) return ss_nan(); t1 = (mean*(x[i]-x[i-1])+x[i-1]*y[i]-x[i]*y[i-1])/(y[i]-y[i-1]); /* search next neg zero crossing */ for (i++ ; i= mean) break; if (i == n) return ss_nan(); t2 = (mean*(x[i]-x[i-1])+x[i-1]*y[i]-x[i]*y[i-1])/(y[i]-y[i-1]); if (s) { int ym = s->voltToY(mean); int x1 = s->timeToX(t1); int x2 = s->timeToX(t2); s->GetDC()->DrawLine(x1, ym-10, x1, ym+10); s->GetDC()->DrawLine(x2, ym-10, x2, ym+10); s->GetDC()->DrawLine(x1, ym, x2, ym); s->GetDC()->DrawLine(x1, ym, x1+6, ym-2); s->GetDC()->DrawLine(x1, ym, x1+6, ym+2); s->GetDC()->DrawLine(x2, ym, x2-6, ym-2); s->GetDC()->DrawLine(x2, ym, x2-6, ym+2); } return t2 - t1; } double Measurement::MNegWidth(double *x, double *y, int n, DOScreen *s) { int i; double miny, maxy, mean, t1, t2; if (n <= 0) return 0; miny = maxy = y[0]; for (i=0 ; i maxy) maxy = y[i]; if (y[i] < miny) miny = y[i]; } mean = (miny + maxy)/2; if (maxy - miny < 10) return ss_nan(); /* search for first neg zero crossing */ for (i=1 ; i= mean) break; if (i == n) return ss_nan(); t1 = (mean*(x[i]-x[i-1])+x[i-1]*y[i]-x[i]*y[i-1])/(y[i]-y[i-1]); /* search next pos zero crossing */ for (i++ ; i mean && y[i-1] <= mean) break; if (i == n) return ss_nan(); t2 = (mean*(x[i]-x[i-1])+x[i-1]*y[i]-x[i]*y[i-1])/(y[i]-y[i-1]); if (s) { int ym = s->voltToY(mean); int x1 = s->timeToX(t1); int x2 = s->timeToX(t2); s->GetDC()->DrawLine(x1, ym-10, x1, ym+10); s->GetDC()->DrawLine(x2, ym-10, x2, ym+10); s->GetDC()->DrawLine(x1, ym, x2, ym); s->GetDC()->DrawLine(x1, ym, x1+6, ym-2); s->GetDC()->DrawLine(x1, ym, x1+6, ym+2); s->GetDC()->DrawLine(x2, ym, x2-6, ym-2); s->GetDC()->DrawLine(x2, ym, x2-6, ym+2); } return t2 - t1; } #define N_FIT 0 void linfit(double *x, double *y, int n, double &a, double &b) { int i; double sx, sxx, sy, syy, sxy; sx = sxx = sy = syy = sxy = 0; for (i=0 ; iGetTrgLevel(0) * 1000; pol = m_frame->GetTrgPolarity(); for (i=1 ; i= thr) break; if (pol == 0 && y1[i] > thr && y1[i-1] <= thr) break; } if (i == n) return ss_nan(); t1 = (thr*(x1[i]-x1[i-1])+x1[i-1]*y1[i]-x1[i]*y1[i-1])/(y1[i]-y1[i-1]); if (N_FIT > 0 && i>=N_FIT/2) { i1l = i-N_FIT/2; i1r = i1l+N_FIT-1; linfit(&x1[i-N_FIT/2], &y1[i-N_FIT/2], N_FIT, a, b); if (b != 0) t1 = (thr-a)/b; if (s) { int xa = s->timeToX(x1[i1l]); int ya = s->voltToY(s->GetCurChn(), a+b*x1[i1l]); int xb = s->timeToX(x1[i1r]); int yb = s->voltToY(s->GetCurChn(), a+b*x1[i1r]); s->GetDC()->DrawLine(xa, ya, xb, yb); } } for (i=1 ; i= thr) break; if (pol == 0 && y2[i] > thr && y2[i-1] <= thr) break; } if (i == n) return ss_nan(); t2 = (thr*(x2[i]-x2[i-1])+x2[i-1]*y2[i]-x2[i]*y2[i-1])/(y2[i]-y2[i-1]); if (N_FIT > 0 && i>=N_FIT/2) { i2l = i-N_FIT/2; i2r = i2l+N_FIT-1; linfit(&x2[i-N_FIT/2], &y2[i-N_FIT/2], N_FIT, a, b); if (b != 0) t2 = (thr-a)/b; if (s) { int xa = s->timeToX(x2[i2l]); int ya = s->voltToY(s->GetCurChn(), a+b*x2[i2l]); int xb = s->timeToX(x2[i2r]); int yb = s->voltToY(s->GetCurChn(), a+b*x2[i2r]); s->GetDC()->DrawLine(xa, ya, xb, yb); } } if (s) { if (s->GetChnOn(0, (s->GetCurChn()+1)%4)) { /// ### TBG: change board index int ym1 = s->voltToY(s->GetCurChn(), thr); int ym2 = s->voltToY((s->GetCurChn()+1)%4, thr); int xa = s->timeToX(t1); int xb = s->timeToX(t2); int ymm = (ym1+ym2)/2; if (ym1 < ym2) { s->GetDC()->DrawLine(xa, ym1-10, xa, ymm+10); s->GetDC()->DrawLine(xb, ymm-10, xb, ym2+10); } else { s->GetDC()->DrawLine(xa, ym1+10, xa, ymm-10); s->GetDC()->DrawLine(xb, ymm+10, xb, ym2-10); } s->GetDC()->DrawLine(xa, ymm, xb, ymm); s->GetDC()->DrawLine(xa, ymm, xa+6, ymm-2); s->GetDC()->DrawLine(xa, ymm, xa+6, ymm+2); s->GetDC()->DrawLine(xb, ymm, xb-6, ymm-2); s->GetDC()->DrawLine(xb, ymm, xb-6, ymm+2); } } return t2 - t1; } double Measurement::MHSlice(double *x, double *y, int n, DOScreen *s) { int i; double tmin = ss_nan(); double t, dtmin = 1E6;; if (n <= 0) return 0; for (i=0 ; i m_param[1]) || (y[i] >= m_param[1] && y[i+1] < m_param[1])) { if (y[i+1] - y[i] == 0) continue; t = x[i] + (x[i+1]-x[i]) * (m_param[1] - y[i]) / (y[i+1] - y[i]); if (fabs(t - m_param[0]) < dtmin) { dtmin = fabs(t - m_param[0]); tmin = t; } } } if (s) { s->GetDC()->DrawLine(s->GetX1(), s->voltToY(m_param[1]), s->GetX2(), s->voltToY(m_param[1])); } return tmin; }