Digitization of an analog signal

I have an array of CSV values ​​representing a digital output. It was assembled using an analog oscilloscope, so it is not an ideal digital signal. I am trying to filter out the data in order to have the perfect digital signal for calculating periods (which may differ). I would also like to determine the maximum error that I get from this filtering.

Something like that:

enter image description here

Idea

Apply data data. Here is the pseudo code:

for data_point_raw in data_array: if data_point_raw < 0.8: data_point_perfect = LOW if data_point_raw > 2 : data_point_perfect = HIGH else: #area between thresholds if previous_data_point_perfect == Low : data_point_perfect = LOW if previous_data_point_perfect == HIGH: data_point_perfect = HIGH 

I am worried about two problems.

  • This seems like a common problem in digital signal processing, but I did not find a predefined standard function for it. Is this a good way to filter?
  • How to get the maximum error?
+8
python numpy signal-processing
source share
4 answers

Here is some code that might help.

 from __future__ import division import numpy as np def find_transition_times(t, y, threshold): """ Given the input signal `y` with samples at times `t`, find the times where `y` increases through the value `threshold`. `t` and `y` must be 1-D numpy arrays. Linear interpolation is used to estimate the time `t` between samples at which the transitions occur. """ # Find where y crosses the threshold (increasing). lower = y < threshold higher = y >= threshold transition_indices = np.where(lower[:-1] & higher[1:])[0] # Linearly interpolate the time values where the transition occurs. t0 = t[transition_indices] t1 = t[transition_indices + 1] y0 = y[transition_indices] y1 = y[transition_indices + 1] slope = (y1 - y0) / (t1 - t0) transition_times = t0 + (threshold - y0) / slope return transition_times def periods(t, y, threshold): """ Given the input signal `y` with samples at times `t`, find the time periods between the times at which the signal `y` increases through the value `threshold`. `t` and `y` must be 1-D numpy arrays. """ transition_times = find_transition_times(t, y, threshold) deltas = np.diff(transition_times) return deltas if __name__ == "__main__": import matplotlib.pyplot as plt # Time samples t = np.linspace(0, 50, 501) # Use a noisy time to generate a noisy y. tn = t + 0.05 * np.random.rand(t.size) y = 0.6 * ( 1 + np.sin(tn) + (1./3) * np.sin(3*tn) + (1./5) * np.sin(5*tn) + (1./7) * np.sin(7*tn) + (1./9) * np.sin(9*tn)) threshold = 0.5 deltas = periods(t, y, threshold) print "Measured periods at threshold %g:" % threshold print deltas print "Min: %.5g" % deltas.min() print "Max: %.5g" % deltas.max() print "Mean: %.5g" % deltas.mean() print "Std dev: %.5g" % deltas.std() trans_times = find_transition_times(t, y, threshold) plt.plot(t, y) plt.plot(trans_times, threshold * np.ones_like(trans_times), 'ro-') plt.show() 

Exit:

 Measured periods at threshold 0.5: [ 6.29283207 6.29118893 6.27425846 6.29580066 6.28310224 6.30335003] Min: 6.2743 Max: 6.3034 Mean: 6.2901 Std dev: 0.0092793 

Plot

You can use numpy.histogram and / or matplotlib.pyplot.hist to further analyze the array returned by periods(t, y, threshold) .

+6
source share

This is not an answer to your question, just a suggestion that might help. I write it here because I cannot put an image in a comment.

I think you should somehow normalize the data before any processing.

After normalization in the range 0 ... 1 you should apply your filter.

enter image description here

+2
source share

If you are only interested in a period, you can build the Fourier transform, you will have a peak where the frequency of the signals will take place (and therefore you have a period). The wider the peak in the Fourier region, the greater the error in measuring the period

 import numpy as np data = np.asarray(my_data) np.fft.fft(data) 
+1
source share

Your filtering is fine, it is basically the same as the schmitt trigger, but the main problem you may run into is speed. The advantage of using Numpy is that it can be as fast as C, while you have to repeat it once over each element.

You can achieve something similar using the SciPy median filter. The following should achieve a similar result (and does not depend on any values):

 filtered = scipy.signal.medfilt(raw) filtered = numpy.where(filtered > numpy.mean(filtered), 1, 0) 

You can adjust the strength of median filtering with medfilt(raw, n_samples) , n_samples by default to 3.

As for the mistake, it will be very subjective. One way is to sample the signal without filtering, and then compare the differences. For example:

 discrete = numpy.where(raw > numpy.mean(raw), 1, 0) errors = np.count_nonzero(filtered != discrete) error_rate = errors / len(discrete) 
+1
source share

All Articles