Pulse counting

Hi,

I am attempting to read the LPO from the Shinyei Dust Sensor on PIN01 of the APRIL board and then post it to our server - using the code below. However I’m not sure I am using the pulse counter correctly should I be also multiplying it by the milliseconds? Many thanks

const FIELD_COUNT = 1; // Number of fields in the stream
local fieldNames = [“Particles”]; // Exact names of each field

//-----------------------------------------------------------------------------------------

//-------------------
function get_date_string() {
    local d = date(); // the time() function would return seconds since 1970.
    return ( d["year"] + "/" + d["month"] + "/" + d["day"] + "  " +
             d["hour"] + ":" + d["min"] + ":" + d["sec"] + " UTC+1" );
}

//---------------------------------------------------------------
local counter = 0;

count <- hardware.pin1;
local time = 60 // time to log pulses for, double the time seems to be needed…
count.configure(PULSE_COUNTER, time);
local numPulses = 0;

function bigLoop() {
counter = counter +1;

local numPulses = count.read();
//local temp2 = mysensorBMP.read_temp_Celsius();
//local pressure = mysensorBMP.read_pressure_atm();

// Populate fieldData array with respective data values
    local fieldData = [numPulses];

    // Create a data string to send to the agent. Should be of the form:
    //"fieldName0=fieldData0&fieldName1=fieldData1&fieldName2=fieldData2"
    local data = "";
    for (local i=0; i<FIELD_COUNT; i++)
    {
        data += fieldNames[i] + "=" + fieldData[i];
        if (i < FIELD_COUNT - 1)
            data += "&";
    }
   
    server.log("Sending Data!");
    agent.send("postData", data);

server.log( "Particles: " + numPulses);

imp.wakeup(1, bigLoop); // sleep for xx seconds

}

bigLoop();

If you’re using an LPO like this:

This is the sensor used: Shinyei Model PPD42NS Particle Sensor

You would record how many milliseconds the pulse is low during a 30 second sample.
So LPO means “Low Pulse Occupancy”. You don’t count the pulses, but the accumulated time the pulse is low over a 30 second sample.

They have an Arduino example too. Deconstruct the Arduino code to see how they do it.

If it’s based on proportion of time low, I would use the ADC sampler API to sample the line, then threshold the buffers. Looking at this http://aqicn.org/sensor/shinyei/ it seems like you could sample at 1kHz and get good accuracy - processing a 1k buffer every second and windowing the results so you are always taking account of a 30s history window.

Hi both, Thanks very much for the replies. Yes I need something like the arduino pulseIn function. Do you think that ADC sampler API would work in this way?

@dustbox99,
I think what Hugo is saying, is that you use the analog sampler that “logs data” at a 1kHz rate. Normally, you would be logging something like temperature, where the analog signal coming in will fluctuate from 0VDC to something else. In your case, you’re just logging a voltage that goes from around 0VDC to 3.3VDC. Because it samples at 1kHz, you need to read a block of data (30 seconds worth) and find out how many of those samples were below 1VDC. That’s the deal … you don’t care how many pulses there were, but how long the pulses were LOW in a 30 second period.

The key to using the ADC sampler is that it already does the reading and buffering for you, for a specific amount of time, automatically. You just need to process the data.

I think I’m saying that correctly?

That’s what I’m saying yes, but you don’t need to sample 30s at once (that’d be a 30kB buffer - there’s RAM to do that, but you can just have a couple of 1k buffers and swap them over).

If I have a moment then I’ll see if I can write some sample code for this…

Hi both, Thanks so much for this advice - Hugo if you did have time to write sample code for this it would be very useful! I could then test it out and feedback.

Try this.

`
// Two buffers; whilst we are processing one, the sampler is filling the other
buffer1 <- blob(2000);
buffer2 <- blob(2000);

// Count of samples over the threshold
samples_over_count <- 0;

// Filled buffer processing function; this is called every second (2000 byte buffers,
// 1000 samples per second, 2 bytes per sample)
function samplesReady(buffer, length) {
// We’re not really interested in the partial buffer when we stop,
// so let’s only look at full buffers
if (length == 2000) {
// Rewind to the start of the buffer
buffer.seek(0);

    // Local count of number of samples over the threshold in this buffer
    // (it's a local for performance)
    local over=0;
    
    // Each reading as 16 bits, so two bytes per sample
    // Samples range from 0 to 65535, so 32767 is halfway
    for(local a=0; a<length; a+=2) if (buffer.readn('w') > 32767) over++;
    
    // Add to the global total
    samples_over_count += over;
}

}

// This function zeros the count & starts the sampler. In 30s, it’ll stop the sampler
// and call the callback function you passed in with the count of samples over the
// threshold in that period (out of 30,000, ie 15,000 would be 50%)
function samplefor30s(result_callback) {
// Reset total
samples_over_count = 0;

// Sample pin 1 at 1kHz
hardware.sampler.configure(hardware.pin1, 1000, [buffer1, buffer2], samplesReady);
hardware.sampler.start();
imp.wakeup(30, function() {
    hardware.sampler.stop();
    result_callback(samples_over_count);
})

}

// We’ll call this when the 30s is up
function completed(result) {
server.log(“Out of 30000 samples, we saw “+result+” high, a percentage of “+(100.0*(result/30000.0))+”%”)

// Start another period
samplefor30s(completed);

}

// Kick off 30s monitoring; it will keep going in the background
samplefor30s(completed);
`

The nice thing here is that this completely runs in the background; it takes about 50ms every second to process the full buffer (this can be brought down to about 20ms very easily but I kept it simple for clarity).

I didn’t have a dust sensor or anything to try this with, but let me know if it seems to work for you!

Thanks for the sample code Hugo - I’m testing it out today and will let you know how it works.

One other thing - the sensor has to be powered from 5v, and has a 4.5v output. I would put at least a 10k resistor in series with the pin1 input on the imp as the imp is max 3.3v and though this will be clamped by the ESD diodes, you want to reduce the current as much as possible.