Hi, ``` I'm trying to build a device for environmental noise measurement and for this purpose I need to take samples at 48kHz for at least 0.05s to capture the whole frequency range of interest. However, there is something very peculiar about the way the device behaves. If I'm only acquireing samples, i.e. the rest of the code is commented out, everything works fine. If I add the lines of code that convert the ADC output codes to voltages, the program will make three loops and then the device resets. If I then uncomment the part of code to weight the samples (which I've checked and it works fine), the device won't even manage to acquire the samples. I does however enter the main loop. And finally, if I only try to acquire 100 samples, everything works flawlessly.
I thought that it could have something to do with memory limitations, so I tried to get rid of tuplets/lists I don't use as quick as possible in the program. Am I correct now that this is not possible in Zerynth? Whenever I trydel tuple ``` I get:Can't find name [tuple] ``` Anyway, it seems unlikely to be the actual reason.
Here's my code:
import streams import A_weighting2 import rms import SPLmap import adc sampling_freq = 48000 preamp_gain = 125 # voltage gain of the preamp amp_gain = 100 # voltage gain of the amplifier mic_sens = 6.5 # [mV/Pa] sensitivity of the microphone th_sens = 0.00002 # [Pa] threshold of hearing V_th = th_sens*mic_sens*preamp_gain*amp_gain # [V] RMS voltage at threshold of hearing sampling_time = 0.05 # [s] sampling time inputAnalog = A0 # define the analog pin for reading the value ^ conv_const = 3300.0/4095.0 # reload the driver with a custom sampling frequency adc.done(ADC0) adc.init(ADC0, sampling_freq) streams.serial() pinMode(inputAnalog,INPUT_ANALOG) pinMode(LED0,OUTPUT) for i in range(2): sleep(1000) # wait for a second digitalWrite(LED0, HIGH) # turn the LED ON by setting the voltage HIGH sleep(1000) # wait for a second digitalWrite(LED0, LOW) # turn the LED OFF by setting the voltage LOW print("\\rEntering loop") while True: samples = adc.read(ADC0, int(sampling_freq*sampling_time)) # get Raw values (0-4095) print("\\r\\tAcquired samples!") samples_conv =  # list of samples converted to voltage for i in range(len(samples)): samples_conv.append(samples[i]*conv_const) # Convert all raw values to millivolts samples = () print("\\r\\tSamples converted!") MS = A_weighting2.a_weight(samples_conv) # Get the Mean Square of the weighted samples using A-weighting print("\\r\\tWeighted samples!\ \ ") #RMS = rms.rms(samples) # get the RMS value of weighted samples #print("Calculated RMS value!") #SPL = SPLmap.map(MS/V_th) # get a logarithm of the argument from a look-up table #print(SPL, "dBA") sleep(3000)```
Which device are you using? Can you post me all your project file so I can better understand and help you to fix this issue?
At the same time, if you want to check memory usage, you can import the Garbage Collector lib, printing gc.info() and monotoring if the “free memory” (second value of the returned tuple) is not near to 0.
Let me know
I’m using Particle Photon.
I’ve tried monitoring the memory usage and it looks like the problem is something else. This is the output of gc.info() after each step. I got from the device when collecting just 100 samples, before it reset itself:
(120352, 114076, 1, 251, 18, 1500, 0)
(120352, 110968, 0, 328, 1, 25, 1)
(120352, 83388, 0, 794, 1, 25, 6)
(120352, 47964, 92, 3690, 10, 25, 44)
Acquired samples! (120352, 45040, 91, 3763, 10, 25, 3045) Samples converted! (120352, 17432, 77, 4229, 10, 25, 3049) Weighted samples! (120352, 89488, 96, 1541, 116, 25, 16)
<div> When I try to collect full 2400 samples it doesn't even go past the data acquisition phase.</div><br>In the attachment are all the .py files I'm using.<br>
Yes seems like the problem is not the memory usage.
In these days I will study your code and work to find a solution for your issue.
Stay tuned for good news
we succesfully ran tests using a slightly modified firmware.
A good practice to optimize memory usage is to define lists with their final length since the beginning instead of building them up with append.
So I would reccomend you to use this:
samples_conv =  * len(samples)
for i in range(len(samples)):
samples_conv[i] = samples[i] * conv_const
instead of this:<br><pre class="CodeBlock">samples_conv =  # list of samples converted to voltage<br>for i in range(len(samples)):<br> samples_conv.append(samples[i]*conv_const) # Convert all raw values to millivolts<br>
Then, to free the memory used for (what is referred by) samples you can just callsamples = None
In the same way you can call <br><pre class="CodeBlock">samples_conv = None
after using the variable to calculate the rms value.
With these changes, the firmware should go through the loop without problems.
Said this, below is some consideration about the rest of the code.
1) I noted that rms sometimes almost reach the representability limit and MS is printed as “Inf”. This seems to be a bug of the print function and do not affects the rms results.
Currently Zerynth uses 31 and 32 bits for integer and floating point numbers respectively; in the future, 64-bit floats will be supported.
However, the following snippet show how to avoid the print-Inf / overflow condition (on the other hand this workaround worsen the performances a bit)def rms2(samples):
MS = 0
l = len(samples)
for i in range(l):
MS += (samples[i]2) / l
RMS = MS(0.5)
<br>2) The a-weighting algorithm take more or less 3 seconds to complete its work (you can find yourself the actual value importing <a href="https://docs.zerynth.com/latest/official/core.zerynth.stdlib/docs/official_core.zerynth.stdlib_timers.html" title="Link: https://docs.zerynth.com/latest/official/core.zerynth.stdlib/docs/official_core.zerynth.stdlib_timers.html">Zerynth standard library timers</a> and playing with it).<br>We all know that convolution processing is computationally intensive but, in this specific case, you can cut a few tenths of a second really easily with 2 small changes:<br><br>This division is performed at every iteration of the main loop (line 53):<br><pre class="CodeBlock">weighted_sample = weighted_sample / a2
but a2 is equal to 1 so you can simply comment this line.
Another operation that is performed at each iteration is (line 38):for i in range(len(b2)):
but b2 never changes. I would define a new variable before the loop to use some lines later:<br><pre class="CodeBlock">b2_length = len(b2)<br><br>for sample_no in range(len(samples)):<br> for i in range(b2_length):<br> ...
Maybe you can further optimize the algorithm (I guess that some if check can be saved) to decrease the run time.
We look forward to receive an update on your project!
thank you for your expertise, it looks rather promising I’ll let you know in a couple of days how it went.
I’ve implemented everything you’ve suggested and now it runs smoothly. Thank you very much!