498 lines
17 KiB
C
498 lines
17 KiB
C
/****************************************************************************
|
|
* include/dsp.h
|
|
*
|
|
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
|
|
* Author: Mateusz Szafoni <raiden00@railab.me>
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
|
* used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifndef __INCLUDE_DSP_H
|
|
#define __INCLUDE_DSP_H
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/compiler.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
#include <math.h>
|
|
|
|
#include <assert.h>
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
#ifndef CONFIG_BUILD_FLAT
|
|
# error "Only flat build supported for now"
|
|
#endif
|
|
|
|
/* Disable DEBUGASSERT macro if LIBDSP debug is not enabled */
|
|
|
|
#ifdef CONFIG_LIBDSP_DEBUG
|
|
# ifndef CONFIG_DEBUG_ASSERTIONS
|
|
# warning "Need CONFIG_DEBUG_ASSERTIONS to work properly"
|
|
# endif
|
|
#else
|
|
# undef DEBUGASSERT
|
|
# define DEBUGASSERT(x)
|
|
#endif
|
|
|
|
#ifndef CONFIG_LIBDSP_PRECISION
|
|
# define CONFIG_LIBDSP_PRECISION 0
|
|
#endif
|
|
|
|
#if !defined(CONFIG_LIBM) && !defined(CONFIG_ARCH_MATH_H)
|
|
# error math.h not defined!
|
|
#endif
|
|
|
|
/* Phase rotation direction */
|
|
|
|
#define DIR_CW (1.0f)
|
|
#define DIR_CCW (-1.0f)
|
|
|
|
/* Some math constants *********************************************************/
|
|
|
|
#define SQRT3_BY_TWO_F (0.866025f)
|
|
#define SQRT3_BY_THREE_F (0.57735f)
|
|
#define ONE_BY_SQRT3_F (0.57735f)
|
|
#define TWO_BY_SQRT3_F (1.15470f)
|
|
|
|
/* Some lib constants **********************************************************/
|
|
|
|
/* Motor electrical angle is in range 0.0 to 2*PI */
|
|
|
|
#define MOTOR_ANGLE_E_MAX (2.0f*M_PI_F)
|
|
#define MOTOR_ANGLE_E_MIN (0.0f)
|
|
#define MOTOR_ANGLE_E_RANGE (MOTOR_ANGLE_E_MAX - MOTOR_ANGLE_E_MIN)
|
|
|
|
/* Motor mechanical angle is in range 0.0 to 2*PI */
|
|
|
|
#define MOTOR_ANGLE_M_MAX (2.0f*M_PI_F)
|
|
#define MOTOR_ANGLE_M_MIN (0.0f)
|
|
#define MOTOR_ANGLE_M_RANGE (MOTOR_ANGLE_M_MAX - MOTOR_ANGLE_M_MIN)
|
|
|
|
/* Some useful macros ***************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: LP_FILTER
|
|
*
|
|
* Description:
|
|
* Simple single-pole digital low pass filter:
|
|
* Y(n) = (1-beta)*Y(n-1) + beta*X(n) = (beta * (Y(n-1) - X(n)))
|
|
*
|
|
* filter - (0.0 - 1.0) where 1.0 gives unfiltered values
|
|
* filter = T * (2*PI) * f_c
|
|
*
|
|
* phase shift = -arctan(f_in/f_c)
|
|
*
|
|
* T - period at which the digital filter is being calculated
|
|
* f_in - input frequency of the filter
|
|
* f_c - cutoff frequency of the filter
|
|
*
|
|
* REFERENCE: https://www.embeddedrelated.com/showarticle/779.php
|
|
*
|
|
****************************************************************************/
|
|
|
|
#define LP_FILTER(val, sample, filter) val -= (filter * (val - sample))
|
|
|
|
/****************************************************************************
|
|
* Name: SVM3_BASE_VOLTAGE_GET
|
|
*
|
|
* Description:
|
|
* Get maximum voltage for SVM3 without overmodulation
|
|
*
|
|
* Notes:
|
|
* max possible phase voltage for 3-phase power inwerter:
|
|
* Vd = (2/3)*Vdc
|
|
* max phase reference voltage according to SVM modulation diagram:
|
|
* Vrefmax = Vd * cos(30*) = SQRT3_BY_2 * Vd
|
|
* which give us:
|
|
* Vrefmax = SQRT3_BY_3 * Vdc
|
|
*
|
|
* Vdc - bus voltage
|
|
*
|
|
****************************************************************************/
|
|
|
|
#define SVM3_BASE_VOLTAGE_GET(vbus) (vbus * SQRT3_BY_THREE_F)
|
|
|
|
/****************************************************************************
|
|
* Public Types
|
|
****************************************************************************/
|
|
|
|
/* This structure represents phase angle.
|
|
* Besides angle value it also stores sine and cosine values for given angle.
|
|
*/
|
|
|
|
struct phase_angle_s
|
|
{
|
|
float angle; /* Phase angle in radians <0, 2PI> */
|
|
float sin; /* Phase angle sine */
|
|
float cos; /* Phase angle cosine */
|
|
};
|
|
|
|
typedef struct phase_angle_s phase_angle_t;
|
|
|
|
/* This structure stores motor angles and corresponding sin and cos values
|
|
*
|
|
* th_el = th_m * pole_pairs
|
|
* th_m = th_el/pole_pairs
|
|
*
|
|
* where:
|
|
* th_el - motor electrical angle
|
|
* th_m - motor mechanical angle
|
|
* pole_pairs - motor pole pairs
|
|
*
|
|
* NOTE: pole_pairs = poles_total/2
|
|
*/
|
|
|
|
struct motor_angle_s
|
|
{
|
|
phase_angle_t angle_el; /* Electrical angle */
|
|
float anglem; /* Mechanical angle in radians <0, 2PI> */
|
|
float one_by_p; /* Aux variable */
|
|
uint8_t p; /* Number of the motor pole pairs */
|
|
int8_t i; /* Pole counter */
|
|
};
|
|
|
|
/* Float number saturaton */
|
|
|
|
struct float_sat_s
|
|
{
|
|
float min; /* Lower limit */
|
|
float max; /* Upper limit */
|
|
};
|
|
|
|
typedef struct float_sat_s float_sat_t;
|
|
|
|
/* PI/PID controler state structure */
|
|
|
|
struct pid_controller_s
|
|
{
|
|
float out; /* Controller output */
|
|
float_sat_t sat; /* Output saturation */
|
|
float err; /* Current error value */
|
|
float err_prev; /* Previous error value */
|
|
float KP; /* Proportional coefficient */
|
|
float KI; /* Integral coefficient */
|
|
float KD; /* Derivative coefficient */
|
|
float part[3]; /* 0 - proporitonal part
|
|
* 1 - integral part
|
|
* 2 - derivative part
|
|
*/
|
|
};
|
|
|
|
typedef struct pid_controller_s pid_controller_t;
|
|
|
|
/* This structure represents the ABC frame (3 phase vector) */
|
|
|
|
struct abc_frame_s
|
|
{
|
|
float a; /* A component */
|
|
float b; /* B component */
|
|
float c; /* C component */
|
|
};
|
|
|
|
typedef struct abc_frame_s abc_frame_t;
|
|
|
|
/* This structure represents the alpha-beta frame (2 phase vector) */
|
|
|
|
struct ab_frame_s
|
|
{
|
|
float a; /* Alpha component */
|
|
float b; /* Beta component */
|
|
};
|
|
|
|
typedef struct ab_frame_s ab_frame_t;
|
|
|
|
/* This structure represent the direct-quadrature frame */
|
|
|
|
struct dq_frame_s
|
|
{
|
|
float d; /* Driect component */
|
|
float q; /* Quadrature component */
|
|
};
|
|
|
|
typedef struct dq_frame_s dq_frame_t;
|
|
|
|
/* Space Vector Modulation data for 3-phase system */
|
|
|
|
struct svm3_state_s
|
|
{
|
|
uint8_t sector; /* Current space vector sector */
|
|
float d_u; /* Duty cycle for phase U */
|
|
float d_v; /* Duty cycle for phase V */
|
|
float d_w; /* Duty cycle for phase W */
|
|
float d_max; /* Duty cycle max */
|
|
float d_min; /* Duty cycle min */
|
|
};
|
|
|
|
/* Motor open-loop control data */
|
|
|
|
struct openloop_data_s
|
|
{
|
|
float max; /* Open-loop max speed */
|
|
float angle; /* Open-loop current angle normalized to <0.0, 2PI> */
|
|
float per; /* Open-loop control execution period */
|
|
};
|
|
|
|
/* Common motor observer structure */
|
|
|
|
struct motor_observer_s
|
|
{
|
|
float angle; /* Estimated observer angle */
|
|
float speed; /* Estimated observer speed */
|
|
float per; /* Observer execution period */
|
|
|
|
float angle_err; /* Observer angle error.
|
|
* This can be used to gradually eliminate
|
|
* error between openloop angle and observer angle
|
|
*/
|
|
|
|
/* There are different types of motor observers which different
|
|
* sets of private data.
|
|
*/
|
|
|
|
void *so; /* Speed estimation observer data */
|
|
void *ao; /* Angle estimation observer data */
|
|
};
|
|
|
|
/* Speed observer division method data */
|
|
|
|
struct motor_sobserver_div_s
|
|
{
|
|
float angle_diff; /* Mechanical angle difference */
|
|
float angle_acc; /* Accumulated mechanical angle */
|
|
float angle_prev; /* Previous mechanical angle */
|
|
float one_by_dt; /* Frequency of observer execution */
|
|
float cntr; /* Sample counter */
|
|
float samples; /* Number of samples for observer */
|
|
float filter; /* Low-pass filter for final omega */
|
|
};
|
|
|
|
/* Speed observer PLL method data */
|
|
#if 0
|
|
struct motor_sobserver_pll_s
|
|
{
|
|
/* TODO */
|
|
};
|
|
#endif
|
|
|
|
/* Motor Sliding Mode Observer private data */
|
|
|
|
struct motor_observer_smo_s
|
|
{
|
|
float k_slide; /* Bang-bang controller gain */
|
|
float err_max; /* Linear mode threashold */
|
|
float F_gain; /* Current observer F gain (1-Ts*R/L) */
|
|
float G_gain; /* Current observer G gain (Ts/L) */
|
|
float emf_lp_filter1; /* Adaptive first low pass EMF filter */
|
|
float emf_lp_filter2; /* Adaptive second low pass EMF filter */
|
|
ab_frame_t emf; /* Estimated back-EMF */
|
|
ab_frame_t emf_f; /* Fitlered estimated back-EMF */
|
|
ab_frame_t z; /* Correction factor */
|
|
ab_frame_t i_est; /* Estimated idq current */
|
|
ab_frame_t v_err; /* v_err = v_ab - emf */
|
|
ab_frame_t i_err; /* i_err = i_est - i_dq */
|
|
ab_frame_t sign; /* Bang-bang controller sign */
|
|
};
|
|
|
|
/* Motor physical parameters.
|
|
* This data structure was designed to work with BLDC/PMSM motors,
|
|
* but probably can be used to describe different types of motors.
|
|
*/
|
|
|
|
struct motor_phy_params_s
|
|
{
|
|
uint8_t p; /* Number of the motor pole pairs */
|
|
|
|
float res; /* Phase-to-neutral temperature compensated
|
|
* resistance
|
|
*/
|
|
float res_base; /* Phase-to-neutral base resistance */
|
|
float res_alpha; /* Temperature coefficient of resistance */
|
|
float res_temp_ref; /* Reference temperature of alpha */
|
|
float ind; /* Average phase-to-neutral inductance */
|
|
float one_by_ind; /* Inverse phase-to-neutral inductance */
|
|
};
|
|
|
|
/* Field oriented control (FOC) data
|
|
* REVISIT:
|
|
*/
|
|
|
|
struct foc_data_s
|
|
{
|
|
abc_frame_t v_abc; /* Voltage in ABC frame */
|
|
ab_frame_t v_ab; /* Voltage in alpha-beta frame */
|
|
dq_frame_t v_dq; /* Voltage in dq frame */
|
|
ab_frame_t v_ab_mod; /* Modulation voltage normalized to
|
|
* magnitude (0.0, 1.0)
|
|
*/
|
|
|
|
abc_frame_t i_abc; /* Current in ABC frame */
|
|
ab_frame_t i_ab; /* Current in apha-beta frame*/
|
|
dq_frame_t i_dq; /* Current in dq frame */
|
|
dq_frame_t i_dq_err; /* DQ current error */
|
|
|
|
dq_frame_t i_dq_ref; /* Current dq reference frame */
|
|
pid_controller_t id_pid; /* Current d-axis component PI controller */
|
|
pid_controller_t iq_pid; /* Current q-axis component PI controller */
|
|
|
|
float vdq_mag_max; /* Maximum dq voltage magnitude */
|
|
float vab_mod_scale; /* Voltage alpha-beta modulation scale */
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
#undef EXTERN
|
|
#if defined(__cplusplus)
|
|
#define EXTERN extern "C"
|
|
extern "C"
|
|
{
|
|
#else
|
|
#define EXTERN extern
|
|
#endif
|
|
|
|
/* Math functions */
|
|
|
|
float fast_sin(float angle);
|
|
float fast_sin2(float angle);
|
|
float fast_cos(float angle);
|
|
float fast_cos2(float angle);
|
|
float fast_atan2(float y, float x);
|
|
|
|
void f_saturate(FAR float *val, float min, float max);
|
|
|
|
float vector2d_mag(float x, float y);
|
|
void vector2d_saturate(FAR float *x, FAR float *y, float max);
|
|
|
|
void dq_saturate(FAR dq_frame_t *dq, float max);
|
|
float dq_mag(FAR dq_frame_t *dq);
|
|
|
|
/* PID controller functions */
|
|
|
|
void pid_controller_init(FAR pid_controller_t *pid,
|
|
float KP, float KI, float KD);
|
|
void pi_controller_init(FAR pid_controller_t *pid,
|
|
float KP, float KI);
|
|
void pid_saturation_set(FAR pid_controller_t *pid, float min, float max);
|
|
void pi_saturation_set(FAR pid_controller_t *pid, float min, float max);
|
|
void pid_integral_reset(FAR pid_controller_t *pid);
|
|
void pi_integral_reset(FAR pid_controller_t *pid);
|
|
float pi_controller(FAR pid_controller_t *pid, float err);
|
|
float pid_controller(FAR pid_controller_t *pid, float err);
|
|
|
|
/* Transformation functions */
|
|
|
|
void clarke_transform(FAR abc_frame_t *abc, FAR ab_frame_t *ab);
|
|
void inv_clarke_transform(FAR ab_frame_t *ab, FAR abc_frame_t *abc);
|
|
void park_transform(FAR phase_angle_t *angle, FAR ab_frame_t *ab,
|
|
FAR dq_frame_t *dq);
|
|
void inv_park_transform(FAR phase_angle_t *angle, FAR dq_frame_t *dq,
|
|
FAR ab_frame_t *ab);
|
|
|
|
/* Phase angle related functions */
|
|
|
|
void angle_norm(FAR float *angle, float per, float bottom, float top);
|
|
void angle_norm_2pi(FAR float *angle, float bottom, float top);
|
|
void phase_angle_update(FAR struct phase_angle_s *angle, float val);
|
|
|
|
/* 3-phase system space vector modulation*/
|
|
|
|
void svm3_init(FAR struct svm3_state_s *s, float min, float max);
|
|
void svm3(FAR struct svm3_state_s *s, FAR ab_frame_t *ab);
|
|
void svm3_current_correct(FAR struct svm3_state_s *s,
|
|
int32_t *c0, int32_t *c1, int32_t *c2);
|
|
|
|
/* Field Oriented control */
|
|
|
|
void foc_vbase_update(FAR struct foc_data_s *foc, float vbase);
|
|
void foc_idq_ref_set(FAR struct foc_data_s *data, float d, float q);
|
|
|
|
void foc_init(FAR struct foc_data_s *data,
|
|
float id_kp, float id_ki, float iq_kp, float iq_ki);
|
|
void foc_process(FAR struct foc_data_s *foc,
|
|
FAR abc_frame_t *i_abc,
|
|
FAR phase_angle_t *angle);
|
|
|
|
/* BLDC/PMSM motor observers */
|
|
|
|
void motor_observer_init(FAR struct motor_observer_s *observer,
|
|
FAR void *ao, FAR void *so, float per);
|
|
float motor_observer_speed_get(FAR struct motor_observer_s *o);
|
|
float motor_observer_angle_get(FAR struct motor_observer_s *o);
|
|
|
|
void motor_observer_smo_init(FAR struct motor_observer_smo_s *smo,
|
|
float kslide, float err_max);
|
|
void motor_observer_smo(FAR struct motor_observer_s *o,
|
|
FAR ab_frame_t *i_ab, FAR ab_frame_t *v_ab,
|
|
FAR struct motor_phy_params_s *phy, float dir);
|
|
|
|
void motor_sobserver_div_init(FAR struct motor_sobserver_div_s *so,
|
|
uint8_t samples, float filer, float per);
|
|
void motor_sobserver_div(FAR struct motor_observer_s *o,
|
|
float angle, float dir);
|
|
|
|
/* Motor openloop control */
|
|
|
|
void motor_openloop_init(FAR struct openloop_data_s *op,
|
|
float max, float per);
|
|
void motor_openloop(FAR struct openloop_data_s *op, float speed, float dir);
|
|
float motor_openloop_angle_get(FAR struct openloop_data_s *op);
|
|
|
|
/* Motor angle */
|
|
|
|
void motor_angle_init(FAR struct motor_angle_s *angle, uint8_t p);
|
|
void motor_angle_e_update(FAR struct motor_angle_s *angle,
|
|
float angle_new,float dir);
|
|
void motor_angle_m_update(FAR struct motor_angle_s *angle,
|
|
float angle_new,float dir);
|
|
float motor_angle_m_get(FAR struct motor_angle_s *angle);
|
|
float motor_angle_e_get(FAR struct motor_angle_s *angle);
|
|
|
|
/* Motor physical parameters functions */
|
|
|
|
void motor_phy_params_init(FAR struct motor_phy_params_s *phy, uint8_t poles,
|
|
float res, float ind);
|
|
void motor_phy_params_temp_set(FAR struct motor_phy_params_s *phy,
|
|
float res_alpha, float res_temp_ref);
|
|
|
|
#undef EXTERN
|
|
#if defined(__cplusplus)
|
|
}
|
|
#endif
|
|
|
|
#endif /* __INCLUDE_DSP_H */
|