#+TITLE: Piezoelectric Force Sensor - Test Bench :DRAWER: #+LANGUAGE: en #+EMAIL: dehaeze.thomas@gmail.com #+AUTHOR: Dehaeze Thomas #+HTML_LINK_HOME: ../index.html #+HTML_LINK_UP: ../index.html #+HTML_HEAD: #+HTML_HEAD: #+HTML_HEAD: #+HTML_HEAD: #+HTML_HEAD: #+HTML_HEAD: #+PROPERTY: header-args:latex :headers '("\\usepackage{tikz}" "\\usepackage{import}" "\\import{$HOME/Cloud/tikz/org/}{config.tex}") #+PROPERTY: header-args:latex+ :imagemagick t :fit yes #+PROPERTY: header-args:latex+ :iminoptions -scale 100% -density 150 #+PROPERTY: header-args:latex+ :imoutoptions -quality 100 #+PROPERTY: header-args:latex+ :results raw replace :buffer no #+PROPERTY: header-args:latex+ :eval no-export #+PROPERTY: header-args:latex+ :exports both #+PROPERTY: header-args:latex+ :mkdirp yes #+PROPERTY: header-args:latex+ :output-dir figs #+PROPERTY: header-args:latex+ :post pdf2svg(file=*this*, ext="png") #+PROPERTY: header-args:matlab :session *MATLAB* #+PROPERTY: header-args:matlab+ :comments org #+PROPERTY: header-args:matlab+ :exports both #+PROPERTY: header-args:matlab+ :results none #+PROPERTY: header-args:matlab+ :eval no-export #+PROPERTY: header-args:matlab+ :noweb yes #+PROPERTY: header-args:matlab+ :mkdirp yes #+PROPERTY: header-args:matlab+ :output-dir figs :END: * Introduction :ignore: In this document is studied how a piezoelectric stack can be used to measured the force. - Section [[sec:open_closed_circuit]]: the effect of the input impedance of the electronics connected to the force sensor stack on the stiffness of the stack is studied - Section [[sec:charge_voltage_estimation]]: * Change of Stiffness due to Sensors stack being open/closed circuit :PROPERTIES: :header-args:matlab+: :tangle matlab/open_closed_circuit.m :END: <> ** Introduction :ignore: ** Matlab Init :noexport:ignore: #+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name) <> #+end_src #+begin_src matlab :exports none :results silent :noweb yes <> #+end_src #+begin_src matlab :tangle no addpath('./matlab/mat/'); #+end_src #+begin_src matlab :eval no addpath('./mat/'); #+end_src ** Load Data #+begin_src matlab oc = load('identification_open_circuit.mat', 't', 'encoder', 'u'); sc = load('identification_short_circuit.mat', 't', 'encoder', 'u'); #+end_src ** Transfer Functions #+begin_src matlab Ts = 1e-4; % Sampling Time [s] win = hann(ceil(10/Ts)); #+end_src #+begin_src matlab [tf_oc_est, f] = tfestimate(oc.u, oc.encoder, win, [], [], 1/Ts); [co_oc_est, ~] = mscohere( oc.u, oc.encoder, win, [], [], 1/Ts); [tf_sc_est, ~] = tfestimate(sc.u, sc.encoder, win, [], [], 1/Ts); [co_sc_est, ~] = mscohere( sc.u, sc.encoder, win, [], [], 1/Ts); #+end_src #+begin_src matlab :exports none figure; hold on; plot(f, co_oc_est, '-') plot(f, co_sc_est, '-') set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'lin'); ylabel('Coherence'); xlabel('Frequency [Hz]'); hold off; xlim([0.5, 5e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/stiffness_force_sensor_coherence.pdf', 'width', 'wide', 'height', 'normal'); #+end_src #+name: fig:stiffness_force_sensor_coherence #+caption: #+RESULTS: [[file:figs/stiffness_force_sensor_coherence.png]] #+begin_src matlab :exports none figure; tiledlayout(2, 1, 'TileSpacing', 'None', 'Padding', 'None'); ax1 = nexttile; hold on; plot(f, abs(tf_oc_est), '-', 'DisplayName', 'Open-Circuit') plot(f, abs(tf_sc_est), '-', 'DisplayName', 'Short-Circuit') set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log'); ylabel('Amplitude'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-7, 3e-4]); legend('location', 'southwest'); ax2 = nexttile; hold on; plot(f, 180/pi*angle(tf_oc_est), '-') plot(f, 180/pi*angle(tf_sc_est), '-') set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'lin'); ylabel('Phase'); xlabel('Frequency [Hz]'); hold off; yticks(-360:90:360); axis padded 'auto x' linkaxes([ax1,ax2], 'x'); xlim([0.5, 5e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/stiffness_force_sensor_bode.pdf', 'width', 'wide', 'height', 'tall'); #+end_src #+name: fig:stiffness_force_sensor_bode #+caption: #+RESULTS: [[file:figs/stiffness_force_sensor_bode.png]] #+begin_src matlab :tangle no :exports results :results file replace xlim([180, 280]); exportFig('figs/stiffness_force_sensor_bode_zoom.pdf', 'width', 'small', 'height', 'tall'); #+end_src #+name: fig:stiffness_force_sensor_bode_zoom #+caption: Zoom on the change of resonance #+RESULTS: [[file:figs/stiffness_force_sensor_bode_zoom.png]] #+begin_important The change of resonance frequency / stiffness is very small and is not important here. #+end_important * Generated Number of Charge / Voltage :PROPERTIES: :header-args:matlab+: :tangle matlab/charge_voltage_estimation.m :END: <> ** Introduction :ignore: Two stacks are used as actuator (in parallel) and one stack is used as sensor. The amplifier gain is 20V/V (Cedrat LA75B). ** Matlab Init :noexport:ignore: #+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name) <> #+end_src #+begin_src matlab :exports none :results silent :noweb yes <> #+end_src #+begin_src matlab :tangle no addpath('./matlab/mat/'); #+end_src #+begin_src matlab :eval no addpath('./mat/'); #+end_src ** Steps #+begin_src matlab load('force_sensor_steps.mat', 't', 'encoder', 'u', 'v'); #+end_src #+begin_src matlab figure; tiledlayout(2, 1, 'TileSpacing', 'None', 'Padding', 'None'); nexttile; plot(t, v); xlabel('Time [s]'); ylabel('Measured voltage [V]'); nexttile; plot(t, u); xlabel('Time [s]'); ylabel('Actuator Voltage [V]'); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/force_sen_steps_time_domain.pdf', 'width', 'wide', 'height', 'tall'); #+end_src #+name: fig:force_sen_steps_time_domain #+caption: Time domain signal during the 3 actuator voltage steps #+RESULTS: [[file:figs/force_sen_steps_time_domain.png]] Three steps are performed at the following time intervals: #+begin_src matlab t_s = [ 2.5, 23; 23.8, 35; 35.8, 50]; #+end_src Fit function: #+begin_src matlab f = @(b,x) b(1).*exp(b(2).*x) + b(3); #+end_src We are interested by the =b(2)= term, which is the time constant of the exponential. #+begin_src matlab tau = zeros(size(t_s, 1),1); V0 = zeros(size(t_s, 1),1); #+end_src #+begin_src matlab for t_i = 1:size(t_s, 1) t_cur = t(t_s(t_i, 1) < t & t < t_s(t_i, 2)); t_cur = t_cur - t_cur(1); y_cur = v(t_s(t_i, 1) < t & t < t_s(t_i, 2)); nrmrsd = @(b) norm(y_cur - f(b,t_cur)); % Residual Norm Cost Function B0 = [0.5, -0.15, 2.2]; % Choose Appropriate Initial Estimates [B,rnrm] = fminsearch(nrmrsd, B0); % Estimate Parameters ‘B’ tau(t_i) = 1/B(2); V0(t_i) = B(3); end #+end_src #+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*) data2orgtable([abs(tau), V0], {}, {'$tau$ [s]', '$V_0$ [V]'}, ' %.2f '); #+end_src #+RESULTS: | $tau$ [s] | $V_0$ [V] | |-----------+-----------| | 6.47 | 2.26 | | 6.76 | 2.26 | | 6.49 | 2.25 | With the capacitance being $C = 4.4 \mu F$, the internal impedance of the Speedgoat ADC can be computed as follows: #+begin_src matlab Cp = 4.4e-6; % [F] Rin = abs(mean(tau))/Cp; #+end_src #+begin_src matlab :results value replace :exports results ans = Rin #+end_src #+RESULTS: : 1494100.0 The input impedance of the Speedgoat's ADC should then be close to $1.5\,M\Omega$ (specified at $1\,M\Omega$). #+begin_important How can we explain the voltage offset? #+end_important As shown in Figure [[fig:force_sensor_model_electronics_without_R]] (taken from cite:reza06_piezoel_trans_vibrat_contr_dampin), an input voltage offset is due to the input bias current $i_n$. #+name: fig:force_sensor_model_electronics_without_R #+caption: Model of a piezoelectric transducer (left) and instrumentation amplifier (right) [[file:figs/force_sensor_model_electronics_without_R.png]] The estimated input bias current is then: #+begin_src matlab in = mean(V0)/Rin; #+end_src #+begin_src matlab :results value replace :exports results ans = in #+end_src #+RESULTS: : 1.5119e-06 An additional resistor in parallel with $R_{in}$ would have two effects: - reduce the input voltage offset \[ V_{off} = \frac{R_a R_{in}}{R_a + R_{in}} i_n \] - increase the high pass corner frequency $f_c$ \[ C_p \frac{R_{in}R_a}{R_{in} + R_a} = \tau_c = \frac{1}{f_c} \] \[ R_a = \frac{R_i}{f_c C_p R_i - 1} \] If we allow the high pass corner frequency to be equals to 3Hz: #+begin_src matlab fc = 3; Ra = Rin/(fc*Cp*Rin - 1); #+end_src #+begin_src matlab :results value replace :exports results ans = Ra #+end_src #+RESULTS: : 79804 With this parallel resistance value, the voltage offset would be: #+begin_src matlab V_offset = Ra*Rin/(Ra + Rin) * in; #+end_src #+begin_src matlab :results value replace :exports results ans = V_offset #+end_src #+RESULTS: : 0.11454 Which is much more acceptable. ** Add Parallel Resistor A resistor $R_p \approx 100\,k\Omega$ is added in parallel with the force sensor as shown in Figure [[fig:force_sensor_model_electronics]]. #+name: fig:force_sensor_model_electronics #+caption: Model of a piezoelectric transducer (left) and instrumentation amplifier (right) with the additional resistor $R_p$ [[file:figs/force_sensor_model_electronics.png]] #+begin_src matlab load('force_sensor_steps_R_82k7.mat', 't', 'encoder', 'u', 'v'); #+end_src #+begin_src matlab figure; tiledlayout(2, 1, 'TileSpacing', 'None', 'Padding', 'None'); nexttile; plot(t, v); xlabel('Time [s]'); ylabel('Measured voltage [V]'); nexttile; plot(t, u); xlabel('Time [s]'); ylabel('Actuator Voltage [V]'); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/force_sen_steps_time_domain_par_R.pdf', 'width', 'wide', 'height', 'tall'); #+end_src #+name: fig:force_sen_steps_time_domain_par_R #+caption: Time domain signal during the actuator voltage steps #+RESULTS: [[file:figs/force_sen_steps_time_domain_par_R.png]] Three steps are performed at the following time intervals: #+begin_src matlab t_s = [1.9, 6; 8.5, 13; 15.5, 21; 22.6, 26; 30.0, 36; 37.5, 41; 46.2, 49.5] #+end_src Fit function: #+begin_src matlab f = @(b,x) b(1).*exp(b(2).*x) + b(3); #+end_src We are interested by the =b(2)= term, which is the time constant of the exponential. #+begin_src matlab tau = zeros(size(t_s, 1),1); V0 = zeros(size(t_s, 1),1); #+end_src #+begin_src matlab for t_i = 1:size(t_s, 1) t_cur = t(t_s(t_i, 1) < t & t < t_s(t_i, 2)); t_cur = t_cur - t_cur(1); y_cur = v(t_s(t_i, 1) < t & t < t_s(t_i, 2)); nrmrsd = @(b) norm(y_cur - f(b,t_cur)); % Residual Norm Cost Function B0 = [0.5, -0.2, 0.2]; % Choose Appropriate Initial Estimates [B,rnrm] = fminsearch(nrmrsd, B0); % Estimate Parameters ‘B’ tau(t_i) = 1/B(2); V0(t_i) = B(3); end #+end_src And indeed, we obtain a much smaller offset voltage and a much faster time constant. #+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*) data2orgtable([abs(tau), V0], {}, {'$tau$ [s]', '$V_0$ [V]'}, ' %.2f '); #+end_src #+RESULTS: | $tau$ [s] | $V_0$ [V] | |-----------+-----------| | 0.43 | 0.15 | | 0.45 | 0.16 | | 0.43 | 0.15 | | 0.43 | 0.15 | | 0.45 | 0.15 | | 0.46 | 0.16 | | 0.48 | 0.16 | Knowing the capacitance value, we can estimate the value of the added resistor (neglecting the input impedance of $\approx 1\,M\Omega$): #+begin_src matlab Cp = 4.4e-6; % [F] Rin = abs(mean(tau))/Cp; #+end_src #+begin_src matlab :results value replace :exports results ans = Rin #+end_src #+RESULTS: : 101200.0 And we can verify that the bias current estimation stays the same: #+begin_src matlab in = mean(V0)/Rin; #+end_src #+begin_src matlab :results value replace :exports results ans = in #+end_src #+RESULTS: : 1.5305e-06 This validates the model of the ADC and the effectiveness of the added resistor. ** Sinus #+begin_src matlab load('force_sensor_sin.mat', 't', 'encoder', 'u', 'v'); u = u(t>25); v = v(t>25); encoder = encoder(t>25) - mean(encoder(t>25)); t = t(t>25); #+end_src The driving voltage is a sinus at 0.5Hz centered on 3V and with an amplitude of 3V (Figure [[fig:force_sensor_sin_u]]). #+begin_src matlab :exports none figure; plot(t, u) xlabel('Time [s]'); ylabel('Control Voltage [V]'); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/force_sensor_sin_u.pdf', 'width', 'normal', 'height', 'small'); #+end_src #+name: fig:force_sensor_sin_u #+caption: Driving Voltage #+RESULTS: [[file:figs/force_sensor_sin_u.png]] The full stroke as measured by the encoder is: #+begin_src matlab :results value replace max(encoder)-min(encoder) #+end_src #+RESULTS: : 5.005e-05 Its signal is shown in Figure [[fig:force_sensor_sin_encoder]]. #+begin_src matlab :exports none figure; plot(t, encoder) xlabel('Time [s]'); ylabel('Encoder [m]'); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/force_sensor_sin_encoder.pdf', 'width', 'normal', 'height', 'small'); #+end_src #+name: fig:force_sensor_sin_encoder #+caption: Encoder measurement #+RESULTS: [[file:figs/force_sensor_sin_encoder.png]] The generated voltage by the stack is shown in Figure #+begin_src matlab :exports none figure; plot(t, v) xlabel('Time [s]'); ylabel('Force Sensor Output [V]'); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/force_sensor_sin_stack.pdf', 'width', 'normal', 'height', 'small'); #+end_src #+name: fig:force_sensor_sin_stack #+caption: Voltage measured on the stack used as a sensor #+RESULTS: [[file:figs/force_sensor_sin_stack.png]] The capacitance of the stack is #+begin_src matlab Cp = 4.4e-6; % [F] #+end_src The corresponding generated charge is then shown in Figure [[fig:force_sensor_sin_charge]]. #+begin_src matlab :exports none figure; plot(t, 1e6*Cp*(v-mean(v))) xlabel('Time [s]'); ylabel('Generated Charge [$\mu C$]'); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/force_sensor_sin_charge.pdf', 'width', 'normal', 'height', 'small'); #+end_src #+name: fig:force_sensor_sin_charge #+caption: Generated Charge #+RESULTS: [[file:figs/force_sensor_sin_charge.png]] The relation between the generated voltage and the measured displacement is almost linear as shown in Figure [[fig:force_sensor_linear_relation]]. #+begin_src matlab b1 = encoder\(v-mean(v)); #+end_src #+begin_src matlab :exports none figure; hold on; plot(encoder, v-mean(v), 'DisplayName', 'Measured Voltage'); plot(encoder, encoder*b1, 'DisplayName', sprintf('Linear Fit: $U_s \\approx %.3f [V/\\mu m] \\cdot d$', 1e-6*abs(b1))); hold off; xlabel('Measured Displacement [m]'); ylabel('Generated Voltage [V]'); legend(); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/force_sensor_linear_relation.pdf', 'width', 'normal', 'height', 'small'); #+end_src #+name: fig:force_sensor_linear_relation #+caption: Almost linear relation between the relative displacement and the generated voltage #+RESULTS: [[file:figs/force_sensor_linear_relation.png]] With a 16bits ADC, the resolution will then be equals to (in [nm]): #+begin_src matlab :results value replace abs((20/2^16)/(b1/1e9)) #+end_src #+RESULTS: : 3.9838