| /**************************************************************************** |
| * libs/libdsp/lib_foc.c |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <dsp.h> |
| #include <string.h> |
| |
| /**************************************************************************** |
| * Private Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: foc_current_controller |
| * |
| * Description: |
| * This function implements FOC current controller algorithm. |
| * |
| * Input Parameters: |
| * foc - (in/out) pointer to the FOC data |
| * v_dq_req - (in) pointer to the voltage DQ request frame |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void foc_current_controller(FAR struct foc_data_f32_s *foc, |
| FAR dq_frame_f32_t *v_dq_req) |
| { |
| FAR pid_controller_f32_t *id_pid = &foc->id_pid; |
| FAR pid_controller_f32_t *iq_pid = &foc->iq_pid; |
| |
| LIBDSP_DEBUGASSERT(foc != NULL); |
| LIBDSP_DEBUGASSERT(v_dq_req != NULL); |
| |
| /* Get dq current error */ |
| |
| foc->i_dq_err.d = foc->i_dq_ref.d - foc->i_dq.d; |
| foc->i_dq_err.q = foc->i_dq_ref.q - foc->i_dq.q; |
| |
| /* NOTE: PI controllers saturation is updated in foc_vdq_mag_max_set() */ |
| |
| /* PI controller for d-current (flux loop) */ |
| |
| v_dq_req->d = pi_controller(id_pid, foc->i_dq_err.d); |
| |
| /* PI controller for q-current (torque loop) */ |
| |
| v_dq_req->q = pi_controller(iq_pid, foc->i_dq_err.q); |
| } |
| |
| /**************************************************************************** |
| * Name: foc_vab_mod_scale_set |
| * |
| * Description: |
| * |
| * Input Parameters: |
| * foc - (in/out) pointer to the FOC data |
| * scale - (in) scaling factor for alpha-beta voltage |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void foc_vab_mod_scale_set(FAR struct foc_data_f32_s *foc, |
| float scale) |
| { |
| LIBDSP_DEBUGASSERT(foc != NULL); |
| |
| foc->vab_mod_scale = scale; |
| } |
| |
| /**************************************************************************** |
| * Name: foc_vdq_mag_max_set |
| * |
| * Description: |
| * Set maximum dq voltage vector magnitude |
| * |
| * Input Parameters: |
| * foc - (in/out) pointer to the FOC data |
| * max - (in) maximum dq voltage magnitude |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void foc_vdq_mag_max_set(FAR struct foc_data_f32_s *foc, float max) |
| { |
| LIBDSP_DEBUGASSERT(foc != NULL); |
| |
| foc->vdq_mag_max = max; |
| |
| /* Update regulators saturation */ |
| |
| pi_saturation_set(&foc->id_pid, -foc->vdq_mag_max, foc->vdq_mag_max); |
| pi_saturation_set(&foc->iq_pid, -foc->vdq_mag_max, foc->vdq_mag_max); |
| } |
| |
| /**************************************************************************** |
| * Name: foc_vdq_ref_set |
| * |
| * Description: |
| * Set dq requested voltage vector |
| * |
| * Input Parameters: |
| * foc - (in/out) pointer to the FOC data |
| * vdq_ref - (in) pointer to the requested idq voltage |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void foc_vdq_ref_set(FAR struct foc_data_f32_s *foc, |
| FAR dq_frame_f32_t *vdq_ref) |
| { |
| LIBDSP_DEBUGASSERT(foc != NULL); |
| LIBDSP_DEBUGASSERT(vdq_ref != NULL); |
| |
| foc->v_dq.d = vdq_ref->d; |
| foc->v_dq.q = vdq_ref->q; |
| } |
| |
| /**************************************************************************** |
| * Name: foc_idq_ref_set |
| * |
| * Description: |
| * Set dq reference current vector |
| * |
| * Input Parameters: |
| * foc - (in/out) pointer to the FOC data |
| * idq_ref - (in) pointer to the reference idq current |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| static void foc_idq_ref_set(FAR struct foc_data_f32_s *foc, |
| FAR dq_frame_f32_t *idq_ref) |
| { |
| LIBDSP_DEBUGASSERT(foc != NULL); |
| LIBDSP_DEBUGASSERT(idq_ref != NULL); |
| |
| foc->i_dq_ref.d = idq_ref->d; |
| foc->i_dq_ref.q = idq_ref->q; |
| } |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: foc_init |
| * |
| * Description: |
| * Initialize FOC controller |
| * |
| * Input Parameters: |
| * foc - (in/out) pointer to the FOC data |
| * init - (in) pointer to the FOC initialization data |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| void foc_init(FAR struct foc_data_f32_s *foc, |
| FAR struct foc_initdata_f32_s *init) |
| { |
| /* Reset data */ |
| |
| memset(foc, 0, sizeof(struct foc_data_f32_s)); |
| |
| /* Initialize PI current d component */ |
| |
| pi_controller_init(&foc->id_pid, init->id_kp, init->id_ki); |
| |
| /* Initialize PI current q component */ |
| |
| pi_controller_init(&foc->iq_pid, init->iq_kp, init->iq_ki); |
| |
| /* Disable PI intergral part reset when saturated */ |
| |
| pi_ireset_enable(&foc->iq_pid, false); |
| pi_ireset_enable(&foc->id_pid, false); |
| |
| /* Enable PI anti-windup protection */ |
| |
| pi_antiwindup_enable(&foc->iq_pid, 0.99, true); |
| pi_antiwindup_enable(&foc->id_pid, 0.99, true); |
| } |
| |
| /**************************************************************************** |
| * Name: foc_vbase_update |
| * |
| * Description: |
| * Update base voltage for FOC controller |
| * |
| * Input Parameters: |
| * foc - (in/out) pointer to the FOC data |
| * vbase - (in) base voltage for FOC |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| void foc_vbase_update(FAR struct foc_data_f32_s *foc, float vbase) |
| { |
| float scale = 0.0f; |
| float mag_max = 0.0f; |
| |
| /* Prevent division by zero */ |
| |
| if (vbase < 1e-10f) |
| { |
| vbase = 1e-10f; |
| } |
| |
| /* NOTE: this is base voltage for FOC, not bus voltage! */ |
| |
| scale = (1.0f / vbase); |
| mag_max = vbase; |
| |
| /* Update */ |
| |
| foc_vab_mod_scale_set(foc, scale); |
| foc_vdq_mag_max_set(foc, mag_max); |
| } |
| |
| /**************************************************************************** |
| * Name: foc_angle_update |
| * |
| * Description: |
| * Update FOC data with new motor phase angle. |
| * |
| * Input Parameters: |
| * foc - (in/out) pointer to the FOC data |
| * angle - (in) pointer to the phase angle data |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| void foc_angle_update(FAR struct foc_data_f32_s *foc, |
| FAR phase_angle_f32_t *angle) |
| { |
| LIBDSP_DEBUGASSERT(foc != NULL); |
| LIBDSP_DEBUGASSERT(angle != NULL); |
| |
| /* Copy angle to foc data */ |
| |
| foc->angle.angle = angle->angle; |
| foc->angle.sin = angle->sin; |
| foc->angle.cos = angle->cos; |
| } |
| |
| /**************************************************************************** |
| * Name: foc_iabc_update |
| * |
| * Description: |
| * Update FOC data with new iabc frame. |
| * |
| * To work properly this function requires some additional steps: |
| * 1. phase angle must be set with foc_angle_update() |
| * |
| * Input Parameters: |
| * foc - (in/out) pointer to the FOC data |
| * i_abc - (in) pointer to the ABC current frame |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| void foc_iabc_update(FAR struct foc_data_f32_s *foc, |
| FAR abc_frame_f32_t *i_abc) |
| { |
| dq_frame_f32_t i_dq; |
| |
| LIBDSP_DEBUGASSERT(foc != NULL); |
| LIBDSP_DEBUGASSERT(i_abc != NULL); |
| |
| /* Reset data */ |
| |
| i_dq.d = 0; |
| i_dq.q = 0; |
| |
| /* Copy ABC current to foc data */ |
| |
| foc->i_abc.a = i_abc->a; |
| foc->i_abc.b = i_abc->b; |
| foc->i_abc.c = i_abc->c; |
| |
| /* Convert abc current to alpha-beta current */ |
| |
| clarke_transform(&foc->i_abc, &foc->i_ab); |
| |
| /* Convert alpha-beta current to dq current */ |
| |
| park_transform(&foc->angle, &foc->i_ab, &i_dq); |
| |
| /* Store dq current */ |
| |
| foc->i_dq.d = i_dq.d; |
| foc->i_dq.q = i_dq.q; |
| } |
| |
| /**************************************************************************** |
| * Name: foc_voltage_control |
| * |
| * Description: |
| * Process FOC voltage control. |
| * |
| * Input Parameters: |
| * foc - (in/out) pointer to the FOC data |
| * vdq_ref - (in) voltage dq reference frame |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| void foc_voltage_control(FAR struct foc_data_f32_s *foc, |
| FAR dq_frame_f32_t *vdq_ref) |
| { |
| LIBDSP_DEBUGASSERT(foc != NULL); |
| |
| /* Update VDQ request */ |
| |
| foc_vdq_ref_set(foc, vdq_ref); |
| |
| /* Inverse Park transform (voltage dq -> voltage alpha-beta) */ |
| |
| inv_park_transform(&foc->angle, &foc->v_dq, &foc->v_ab); |
| |
| #ifdef CONFIG_LIBDSP_FOC_VABC |
| /* Inverse Clarke transform (voltage alpha-beta -> voltage abc) */ |
| |
| inv_clarke_transform(&foc->v_ab, &foc->v_abc); |
| #endif |
| |
| /* Normalize the alpha-beta voltage to get the alpha-beta modulation |
| * voltage |
| */ |
| |
| foc->v_ab_mod.a = foc->v_ab.a * foc->vab_mod_scale; |
| foc->v_ab_mod.b = foc->v_ab.b * foc->vab_mod_scale; |
| } |
| |
| /**************************************************************************** |
| * Name: foc_current_control |
| * |
| * Description: |
| * Process FOC current control. |
| * |
| * Input Parameters: |
| * foc - (in/out) pointer to the FOC data |
| * idq_ref - (in) current dq reference frame |
| * vdq_comp - (in) voltage dq compensation frame |
| * vdq_ref - (out) voltage dq reference frame |
| * |
| * Returned Value: |
| * None |
| * |
| * TODO: add some reference and a brief description of the FOC |
| * |
| ****************************************************************************/ |
| |
| void foc_current_control(FAR struct foc_data_f32_s *foc, |
| FAR dq_frame_f32_t *idq_ref, |
| FAR dq_frame_f32_t *vdq_comp, |
| FAR dq_frame_f32_t *vdq_ref) |
| { |
| LIBDSP_DEBUGASSERT(foc != NULL); |
| |
| /* Update IDQ reference */ |
| |
| foc_idq_ref_set(foc, idq_ref); |
| |
| /* Run FOC current controller (current dq -> voltage dq) */ |
| |
| foc_current_controller(foc, vdq_ref); |
| |
| /* DQ voltage compensation */ |
| |
| vdq_ref->d = vdq_ref->d - vdq_comp->d; |
| vdq_ref->q = vdq_ref->q - vdq_comp->q; |
| } |
| |
| /**************************************************************************** |
| * Name: foc_vabmod_get |
| * |
| * Description: |
| * Get result from the FOC controller (foc_current_control or |
| * foc_voltage_control) |
| * |
| * Input Parameters: |
| * foc - (in/out) pointer to the FOC data |
| * v_ab_mod - (out) pointer to the voltage alpha-beta modulation frame |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| void foc_vabmod_get(FAR struct foc_data_f32_s *foc, |
| FAR ab_frame_f32_t *v_ab_mod) |
| { |
| LIBDSP_DEBUGASSERT(foc != NULL); |
| LIBDSP_DEBUGASSERT(v_ab_mod != NULL); |
| |
| v_ab_mod->a = foc->v_ab_mod.a; |
| v_ab_mod->b = foc->v_ab_mod.b; |
| } |
| |
| /**************************************************************************** |
| * Name: foc_vdq_mag_max_get |
| * |
| * Description: |
| * Get maximum dq voltage vector magnitude |
| * |
| * Input Parameters: |
| * foc - (in/out) pointer to the FOC data |
| * max - (out) maximum dq voltage magnitude |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| void foc_vdq_mag_max_get(FAR struct foc_data_f32_s *foc, FAR float *max) |
| { |
| LIBDSP_DEBUGASSERT(foc != NULL); |
| |
| *max = foc->vdq_mag_max; |
| } |