Skip to content

A software-based small signal analysis tool for digital controlled power supplies and more

Notifications You must be signed in to change notification settings

rikka0w0/libsfra

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LibSFRA

A software-based small signal analysis and measurement tool for digital controlled power supplies and more.

  • Platform-independent, this library can run on any hardware, F28379 and STM32F334 have been tested. Theoretically, it will work on the STM32F0 series, even on 8-bit microcontrollers.
  • High performance and minimal negative impact, functions that ISR routines may call contains minimal calculations.
  • FPU is not compulsory, functions that ISR routines may call can be fixed-point only.
  • MODBUS front-end and MATLAB scripts are available, data transfer is much faster than TI's closed-source implementation.
  • Written in C99, works on most compilers.
  • Multiple SFRA instances can co-exist.
  • Utilization of local hardware accelerations is possible, e.g., trigonometric functions can be faster and more accurate on some C2000 platforms (e.g., F28379).

Usage

Add all .c and .h files to the Makefile or your managed project, steps may vary, depend on your IDE, build tools, and toolchains.

The following example shows how to add this library to the Makefile generated by STM32CubeIDE:

C_SOURCES =  \
$(wildcard libsfra/*.c) \
...

C_INCLUDES =  \
-Ilibsfra \
...

Create configuration header

Create a file named "libsfra_config.h":

#ifndef INC_LIBSFRA_CONFIG_H_
#define INC_LIBSFRA_CONFIG_H_

// Use fixed-point
#define SFRA_INT 1

// No tests
#define SFRA_HAS_TEST 0

#endif /* INC_LIBSFRA_CONFIG_H_ */

Declare SFRA struct and prepare buffers

// Size of each SFRA result buffer field
#define SFRA_BUF_SIZE 100

typedef struct {
    float freq[SFRA_BUF_SIZE];  // In Hz, log-spaced
    float mag[SFRA_BUF_SIZE];   // In dB
    float phase[SFRA_BUF_SIZE]; // In degrees
} sfra_results_t;

// Holds measured bode plot
sfra_results_t sfra_results;

// Declare the SFRA instance
sfra_t sfra = {
    .config.isrFreq = 100000,   // Sampling frequency
    .config.freqStart = 10,     // Start frequency
    .config.freqStep = 1.584893192461113,  // Frequency step (log-spaced)
    .config.vecLength = SFRA_BUF_SIZE,     // Number of sweeps
    .results.freqVect = sfra_results.freq, // Points to the frequency vector
    .results.magnitudeVect = sfra_results.mag,	// Points to the magnitude vector
    .results.phaseVect = sfra_results.phase   // Points to the phase vector
};

freqStep is always 10 powers the reciprocal of the sweep number per decade.

The stop frequency can be calculated as freqEnd = freqStart * power(freqStep, vecLength - 1).

Given freqStep and freqStart, one can find the closest vecLength from a given stop frequency (freqEndExpected): floor(log(freqEndExpected/freqStart) / log(freqStep) + 1).

Note that vecLength should never exceed the buffer size (SFRA_BUF_SIZE, in this case).

Add initialization and background task calls

void main(void) {
...
    // Initialize common SFRA infrastructures
    sfra_init_all();
...
    while (1) {   // Main Loop
        ...

        // Run background tasks for each SFRA instance
        sfra_background_task(&sfra);

        ...
    }
}

Setup injection and measurement

The following code demonstrates how to measure the duty cycle to output voltage transfer function in a DC/DC converter.

// Measured output voltage, populated by ADC + DMA
float adc_result_output_voltage;

// Normally this is an ISR routine
void control_law_run(void) {
    // Duty cycle
    float duty = 1.0F;

    // Generate perturbation
    float preturb_magnitude = 1.0F;
    float perturb = sfra_inject_int32(&sfra) / (float) FAST_SIN_TABLE_SCALE;

    // Add perturbation
    duty += preturb_magnitude * perturb;

    // Scale both for a better accuracy
    float mon_in = duty * (float) 256.0F;
    float mon_out = adc_result_output_voltage * (float) 256.0F;

    // Update SFRA state
    sfra_monitor_int32(&sfra, mon_in, mon_out);
}

Alternatively, the digital filter in filter_rc.h can be used to test the SFRA without an actual power stage:

const float dc_gain = 100.0F;

// Normally this is an ISR routine
void control_law_run(void) {
    float filter_input = 1.0F;

    // Generate perturbation
    float preturb_magnitude = 1.0F;
    float perturb = sfra_inject_int32(&sfra) / (float) FAST_SIN_TABLE_SCALE;

    // Add perturbation
    filter_input += preturb_magnitude * perturb;

    // Run the filter
    float filter_output = dc_gain * vFilterRCRun(&test_filter, filter_input);

    // Scale both for a better accuracy
    float mon_in = filter_input * (float) 256.0F;
    float mon_out = filter_output * (float) 256.0F;

    // Update SFRA state
    sfra_monitor_int32(&sfra, mon_in, mon_out);
}

Start SFRA sweeping

Call sfra_start() in a non-ISR context, and poll sfra_is_done(). sfra.internal_state.freqIndex indicates the progress. Once finished, call sfra_clear_done() to clear the done flag.

Acquire the result

Struct sfra_results now holds the bode plot.

MODBUS

Add a light-weight MODBUS serial (Supports RS485) implementation to expose the results (also settings, of course). Sometimes, the application has already implemented MODBUS.

T.B.D

MATLAB provides functions to access MODBUS (supports serial and TCP) and plot the figure. With the help of ESP8266 as a MODBUS RS485-TCP bridge, it is now possible to wirelessly acquire the bode plot from a MCU on the hot-side.

Direct memory access

This approach requires minimal modification to the existing application code. However, it is subjected to certain limitations on certain platforms and IDEs.

This approach works great on TI's C2000 platforms, where Code Composer Studio (CCS) allows you to inspect and edit the memory content without pausing the code execution. One can start the sweeping by setting sfra.internal_state.start to 1 and copy the results directly from the Memory view.

However, this is not true on most other platforms. For instance, GDB cannot read the memory of an STM32 MCU unless the code execution has paused. __ Before pausing the code, make sure to disable the power stage and/or switch off its power. __

TODOs

  • Verify the accuracy on different topologies
  • MODBUS demo project

About

A software-based small signal analysis tool for digital controlled power supplies and more

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages