Author Topic: ADC processing and CMSIS DSP library  (Read 3461 times)

0 Members and 1 Guest are viewing this topic.

Offline Red_MicroTopic starter

  • Regular Contributor
  • *
  • Posts: 121
  • Country: ca
ADC processing and CMSIS DSP library
« on: September 18, 2020, 03:42:19 pm »
I'm using a STM32 Cortex M0+ to read an AC signal from a CT. I'm sampling at 6kHz and storing 400 samples. The signal has a DC bias equal to Vcc/2 = 1.65V. In the digital domain this is 2048. When there's no input signal, I only read the DC bias which is OK. Have a look at the dc_bias_raw.txt file. As you can see, the readings are not so bad. It varies from 2044 to 2052. The DC bias is very precise in hardware so I think this variation is due to the noise floor. Now if I want to do RMS in that set of data, I need to find a way to deal with this DC bias variation. In the file adc_raw_current.txt you can see the samples when there's an input signal.

I have been thinking the following:

1- Subtract a fixed value of 2048 from each ADC reading. This is no so good as I said above this value may vary slightly. Also, if I want to read zero cross it may cause errors to choose exactly 2048 as reference.
2- Sample the DC bias and average it.
3- Leave it and get the DC value as RMS result when there's no input signal
4- Use a more sophisticated software high pass filter

In the other hand, as the title of the post says, I want to use CMSIS DSP Library.
This library allows you to use floating point calculations, and fixed point in Q15 and Q31 formats. The controller I'm using does not have FPU, so I think I will go with fixed point, but how I convert my set of data to Q15 or Q31? Also I do not need much precision, I'm even thinking of staying in the integer domain.

Any help is appreciated!
 

Offline Renate

  • Super Contributor
  • ***
  • Posts: 1460
  • Country: us
Re: ADC processing and CMSIS DSP library
« Reply #1 on: September 20, 2020, 11:52:06 am »
Looking at your numbers, you've got a 12 bit ADC and you're using a range of about 6 bits.
Are you running this with a tiny load and not the real load?
If that is supposed to be the real load, then:
  • You might not be using the right current transformer for your application
  • You might have the wrong ballast resistor
  • You might need to throw a preamp at this

That CMSIS DSP library won't do you a lot of good because it wants all your data at the same time.

To do a simple RMS just accumulate the square of your samples as you go along.
When you have a bunch of them, divide by count then do the square root.
This means that your ADC ISR just takes in the ADC value, subtracts 2048, squares it for 24 bit fixed (ok, 32 bit if you're not using assembly).
Once a second (or whenever you do the heavy lifting of a divide (might just be a shift or a multiply) and a square root.

If you want to keep a running offset, also accumulate the straight values of your samples as you go along.
You can fix the accumulated squares with that value when you're done.
 
The following users thanked this post: Red_Micro

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8724
  • Country: fi
Re: ADC processing and CMSIS DSP library
« Reply #2 on: September 20, 2020, 12:05:19 pm »
Wanting to use CMSIS DSP library sounds like a typical X-Y problem

CMSIS DSP library is a joke. Completely trivial math operations done in very limited and fixed ways. Sure, if you happen to have all data in buffers, in the right format, at once, anyway, and would just call a processing function once anyway, then you may as well use the library (and save writing the 5 lines of code function yourself). Although it still likely takes 10-100 times more time and commitment to read the library documentation, include the files, and use it.

Otherwise than that, usually you need realtime processing. Just write the math operations you want yourself. I think you were given some good and efficient code examples the last time you asked about the problem, what's wrong using them?

AFAIK this library does not implement complex algorithms (think about computer vision, or similar) and you wouldn't want any complex algorithm there anyway.

If you want to have the DC value of the signal, combining the actual DC existing in the signal, and any errors in your measurement:
Assuming you can decide you have either 50Hz or 60Hz signal, you can simply keep track of the average value over, say, 16 cycles (to reduce offset caused by frequency error by factor of 16), and subtract that. If you cannot sync to the signal, then you need a much longer average to subtract - or a FIR/IIR highpass/bandpass filter but that's going to need a lot of taps, too.

If you only want your measurement error, there is no other way than to model your error sources and do periodical calibrations, for which you need to be able to disconnect the load. (You could disconnect the measurement path, but then you would be calibrating only part of the system. Disconnecting the actual load would also leave the current transformer in the loop, to be compensated.)

And also Renate's right, do maximize the dynamic range of the current transformer and ADC. Try to make your maximum possible load signal to range from, say, 500 to 4096-500.
« Last Edit: September 20, 2020, 12:14:39 pm by Siwastaja »
 
The following users thanked this post: Red_Micro

Online coppice

  • Super Contributor
  • ***
  • Posts: 9330
  • Country: gb
Re: ADC processing and CMSIS DSP library
« Reply #3 on: September 20, 2020, 12:45:57 pm »
CMSIS DSP library is a joke.
I agree. Its like they felt they needed to have a DSP library to help them promote the DSP qualities of some of their architectures, but either didn't understand the problem or didn't want to invest.
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8724
  • Country: fi
Re: ADC processing and CMSIS DSP library
« Reply #4 on: September 20, 2020, 01:23:56 pm »
Decision makers need checkboxes to check in order to produce Powerpoint slides and purchase decisions. This is all OK. CMSIS DSP library exists for this purpose.

Then engineers can use the parts as actually intended, as long as the decision maker doesn't micromanage and prevent work being done by requiring usage of the CMSIS DSP library.

They also need some "standardized" DSP code so they can run benchmarks and publish numbers (clock cycles / operation, and so on).
 

Offline Renate

  • Super Contributor
  • ***
  • Posts: 1460
  • Country: us
Re: ADC processing and CMSIS DSP library
« Reply #5 on: September 20, 2020, 01:24:56 pm »
If you want to keep a running offset, also accumulate the straight values of your samples as you go along.
You can fix the accumulated squares with that value when you're done.
Specifically:
RMS = sqrt(Σ(x^2)/n - Σ(x)^2/n^2)
Looks familiar? It's standard deviation.

Edit: Don't just work with the raw value, subtract 2048 to start to get the mean close to zero for better computations.
« Last Edit: September 20, 2020, 01:31:13 pm by Renate »
 

Offline Red_MicroTopic starter

  • Regular Contributor
  • *
  • Posts: 121
  • Country: ca
Re: ADC processing and CMSIS DSP library
« Reply #6 on: September 20, 2020, 02:12:57 pm »
Looking at your numbers, you've got a 12 bit ADC and you're using a range of about 6 bits.
Are you running this with a tiny load and not the real load?
If that is supposed to be the real load, then:
  • You might not be using the right current transformer for your application
  • You might have the wrong ballast resistor
  • You might need to throw a preamp at this

My load is variable, and the samples in the adc_raw_current.txt file, is for my lowest load. See the attached the plot. Also, my resolution is halved as the signal is riding a 1.65V DC bias. That's why my pre amp has adjustable gain.

 

Offline T3sl4co1l

  • Super Contributor
  • ***
  • Posts: 22307
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: ADC processing and CMSIS DSP library
« Reply #7 on: September 20, 2020, 02:39:25 pm »
Remove the DC with a highpass.  A single pole is easy enough, or you can use as many as you like.  Set the pole somewhat below the CT's frequency response, I suppose -- that will avoid additional phase shift.

Example:

Code: [Select]
int16_t highpass(int16_t samp) {

static int32_t hp = 0;

samp -= hp >> 16;
hp += (int32_t)samp * HIGHPASS_FEEDBACK;

return samp;
}

Obviously with the static local variable, this isn't reentrant or sharable across channels, it's a single use thing.  Example use:

Code: [Select]
samp = adc_result();
samp = highpass(samp);
...

Uses fixed point signed format.  For ARM, the int16s should probably be changed to 32.  Which gets you a ton more dynamic range, pick whatever fixed point you like.  Most immediate benefit being, substantial rounding is deferred until the end (when the result finally hits a DAC, or display or other readout method).

Which, for doing RMS, notice that squaring a 32-bit number gives a 64-bit result; but if it's fully fractional (1.31 signed), it only needs one shift to restore that format, and the low half can be truncated off without much* loss of SNR.  The products are summed in an accumulator, then some time later, you sample the accumulator (then clear it), divide by count (if this is a 2^N decimation, merely a shift is needed) and square-root.  Or heck, you can use a 64-bit accumulator for all that matters, you should have plenty of CPU cycles to spare and another DWORD is hardly a lot of memory.

*Or really, if your input is only 12 bit, and there's no oversampling to tease extra bits out of it, then 12 bits squared is 24 bits, still well within a 32-bit word -- no loss at all.

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Online coppice

  • Super Contributor
  • ***
  • Posts: 9330
  • Country: gb
Re: ADC processing and CMSIS DSP library
« Reply #8 on: September 20, 2020, 03:24:14 pm »
Remove the DC with a highpass.  A single pole is easy enough, or you can use as many as you like.  Set the pole somewhat below the CT's frequency response, I suppose -- that will avoid additional phase shift.

Example:

Code: [Select]
int16_t highpass(int16_t samp) {

static int32_t hp = 0;

samp -= hp >> 16;
hp += (int32_t)samp * HIGHPASS_FEEDBACK;

return samp;
}

Obviously with the static local variable, this isn't reentrant or sharable across channels, it's a single use thing.  Example use:

Code: [Select]
samp = adc_result();
samp = highpass(samp);
...

Uses fixed point signed format.  For ARM, the int16s should probably be changed to 32.  Which gets you a ton more dynamic range, pick whatever fixed point you like.  Most immediate benefit being, substantial rounding is deferred until the end (when the result finally hits a DAC, or display or other readout method).

Which, for doing RMS, notice that squaring a 32-bit number gives a 64-bit result; but if it's fully fractional (1.31 signed), it only needs one shift to restore that format, and the low half can be truncated off without much* loss of SNR.  The products are summed in an accumulator, then some time later, you sample the accumulator (then clear it), divide by count (if this is a 2^N decimation, merely a shift is needed) and square-root.  Or heck, you can use a 64-bit accumulator for all that matters, you should have plenty of CPU cycles to spare and another DWORD is hardly a lot of memory.

*Or really, if your input is only 12 bit, and there's no oversampling to tease extra bits out of it, then 12 bits squared is 24 bits, still well within a 32-bit word -- no loss at all.

Tim
You really want something like:
Code: [Select]
int16_t dc_filter16(int16_t x)
{
    int32_t state;

    *p += ((((int32_t) x << 16) - *p) >> 14);
    x -= (*p >> 16);
    return x;
}
so, you noise shape the result of the pole (i,e. the variable 'state', which is an estimate of the DC), before it gets applied to the signal. There is no need to use a multiply, as the pole's location is not critical. A simple shift is fine. On an ARM this may not matter much, but if you use a MCU with a high cost for multiplies it may. This example shifts by 14, but that's a compromise you can adjust. A bigger shift gives a smoother DC estimation, but it takes longer for the filter to settle. That settling time may be important if you need to start up and get an accurate RMS value quickly. Also, remember that the result of the pole, well above its turnover point, will be about 90 degrees out of phase with the signal. So, the residual ripple on the DC estimate being removed from the signal is in quadrature with the signal, and can nudge its phase. If you are only generating an RMS result, this may not matter. If you are doing other things, like also using a voltage signal so you can measure power, this phase shift must be allowed for.
 

Offline Renate

  • Super Contributor
  • ***
  • Posts: 1460
  • Country: us
Re: ADC processing and CMSIS DSP library
« Reply #9 on: September 20, 2020, 03:44:42 pm »
Remove the DC with a highpass.
Really?
The DC is a very slow long-term drift.
I still like my std. dev.
It's also (minorly) less computation to just deal with it at the end of the sample batch.
 

Online coppice

  • Super Contributor
  • ***
  • Posts: 9330
  • Country: gb
Re: ADC processing and CMSIS DSP library
« Reply #10 on: September 20, 2020, 03:56:33 pm »
Remove the DC with a highpass.
Really?
The DC is a very slow long-term drift.
I still like my std. dev.
It's also (minorly) less computation to just deal with it at the end of the sample batch.
Your approach has the benefit of zero settling time, but it produces a poorer estimate of the DC.
 

Offline snarkysparky

  • Frequent Contributor
  • **
  • Posts: 418
  • Country: us
Re: ADC processing and CMSIS DSP library
« Reply #11 on: September 20, 2020, 04:07:25 pm »
first highpass filter as Ts says.

do
{

highpassfilteredvalue =  highpassfilter(input_sample);

squared = highpassfilteredvalue*highpassfilteredvalue;

// low pass filter the squared value
squaredAverage = squaredAverage +  K*(squared - squaredAverage);   //  K < 1

RMS_average =  sqrt(squaredAverage);

}

 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf