diff --git a/matlab/+mom/run.m b/matlab/+mom/run.m
index 93f5e2335f432b92331d6772e5961719f49adaf0..01aa83c182fcd0116cf05d074b858a95fb2506fd 100644
--- a/matlab/+mom/run.m
+++ b/matlab/+mom/run.m
@@ -62,7 +62,7 @@ function [oo_, options_mom_, M_] = run(bayestopt_, options_, oo_, estim_params_,
 %  o check_mode_file
 %  o check_posterior_sampler_options
 %  o check_prior_bounds
-%  o check_prior_stderr_corr
+%  o check_prior_stderr_corr_skew
 %  o check_steady_state_changes_parameters
 %  o check_varobs_are_endo_and_declared_once
 %  o check_hessian_at_the_mode
@@ -404,7 +404,7 @@ if do_bayesian_estimation_mcmc
 end
 % warning if prior allows that stderr parameters are negative or corr parameters are outside the unit circle
 if do_bayesian_estimation
-    check_prior_stderr_corr(estim_params_,bayestopt_);
+    check_prior_stderr_corr_skew(estim_params_,bayestopt_);
     % check value of prior density
     [~,~,~,info] = priordens(xparam0,bayestopt_.pshape,bayestopt_.p6,bayestopt_.p7,bayestopt_.p3,bayestopt_.p4);
     if any(info)
diff --git a/matlab/check_model.m b/matlab/check_model.m
index 7dc297109915cfc12379554d479e6df690885276..2e940c2a41507016f86453bf0382b795ca6631a9 100644
--- a/matlab/check_model.m
+++ b/matlab/check_model.m
@@ -36,4 +36,9 @@ if ~isequal(M_.H,0)
     if ~check_consistency_covariances(M_.H)
         error('The specified covariances for the measurement errors are not consistent with the variances as they imply a correlation larger than +-1')
     end
+end
+
+idxSkewOutOfBounds = (abs(M_.Skew_e) > 0.995);
+if any(idxSkewOutOfBounds)
+    error('Skewness parameters for %s are larger than theoretical bound of ±0.995.',strjoin(M_.exo_names(idxSkewOutOfBounds),','))
 end
\ No newline at end of file
diff --git a/matlab/default_option_values.m b/matlab/default_option_values.m
index 300b4c6114fdac8e970ca01769904bd75ffda4bd..20587b6794f17fddee05e72da096b0e8f84b250f 100644
--- a/matlab/default_option_values.m
+++ b/matlab/default_option_values.m
@@ -394,6 +394,8 @@ options_.kalman_algo = 0;
 options_.kalman_filter_mex = false;
 options_.fast_kalman_filter = false;
 options_.kalman_tol = 1e-10;
+options_.kalman.pskf.prune_tol = 0.01;
+options_.kalman.pskf.use_in_gaussian_case = false;
 options_.kalman.keep_kalman_algo_if_singularity_is_detected = false;
 options_.diffuse_kalman_tol = 1e-6;
 options_.use_univariate_filters_if_singularity_is_detected = 1;
@@ -555,6 +557,7 @@ options_.homotopy_force_continue = false;
 
 % numerical hessian
 hessian.use_penalized_objective = false;
+hessian.use_onesided = false;
 
 % Robust prediction error covariance (kalman filter)
 options_.rescale_prediction_error_covariance = false;
diff --git a/matlab/distributions/csnMean.m b/matlab/distributions/csnMean.m
new file mode 100644
index 0000000000000000000000000000000000000000..afef403ebb6788100c247a451713a13d82458127
--- /dev/null
+++ b/matlab/distributions/csnMean.m
@@ -0,0 +1,126 @@
+function [E_csn] = csnMean(mu, Sigma, Gamma, nu, Delta, cdfmvna_fct)
+% function [E_csn] = csnMean(mu, Sigma, Gamma, nu, Delta, cdfmvna_fct)
+% -------------------------------------------------------------------------
+% Evaluates the unconditional expectation vector of a CSN(mu,Sigma,Gamma,nu,Delta)
+% distributed random variable based on expressions derived in
+% - Dominguez-Molina, Gonzalez-Farias, Gupta (2003, sec. 2.4) - The multivariate closed skew normal distribution
+% - Rodenburger (2015) - On Approximations of Normal Integrals in the Context of Probit based Discrete Choice Modeling (2015)
+% -------------------------------------------------------------------------
+% INPUTS
+% - mu            [p by 1]   1st parameter of the CSN distribution (location)
+% - Sigma         [p by p]   2nd parameter of the CSN distribution (scale)
+% - Gamma         [q by p]   3rd parameter of the CSN distribution (regulates skewness from Gaussian (Gamma=0) to half normal)
+% - nu            [q by 1]   4th parameter of the CSN distribution (enables closure of CSN distribution under conditioning)
+% - Delta         [q by q]   5th parameter of the CSN distribution (enables closure of CSN distribution und marginalization)
+% - cdfmvna_fct   [string]   name of function to compute log Gaussian cdf, possible values: 'logmvncdf_ME', 'mvncdf', 'qsilatmvnv', 'qsimvnv'
+% -------------------------------------------------------------------------
+% OUTPUTS
+% - E_csn         [p by 1]   expectation vector of the CSN(mu,Sigma,Gamma,nu,Delta) distribution
+% =========================================================================
+% Copyright (C) 2022-2023 Gaygysyz Guljanov
+%
+% This is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% This is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+% -------------------------------------------------------------------------
+% This file is part of the replication files for the paper "Pruned Skewed
+% Kalman Filter and Smoother: Pruned Skewed Kalman Filter and Smoother:
+% With Applications to the Yield Curve and Asymmetric Monetary Policy Shocks"
+% by Gaygysyz Guljanov, Willi Mutschler, Mark Trede
+% =========================================================================
+
+if nargin < 6
+    cdfmvna_fct = 'logmvncdf_ME';
+end
+q       = size(Delta, 1); % skewness dimension
+derVect = nan(q, 1);      % initialize gradient vector
+Delta1  = Delta + Gamma * Sigma * Gamma'; % var-cov matrix inside the expression "psi" of equation (1) of Dominguez-Molina, Gonzalez-Farias, Gupta (2003, p. 10)
+
+% differentiate the normal cdf, steps are given in Rodenburger (2015, p.28-29)
+for jj = 1:q
+    % permutation of var-cov matrix
+    logi   = true(q, 1); logi(jj, 1)=false;
+    nu2    = nan(q, 1); nu2(1:q-1)=nu(logi); nu2(q)=nu(jj);
+    Delta2 = nan(size(Delta1));
+    Delta2(1:q-1, :) = Delta1(logi, :);
+    Delta2(q, :) = Delta1(jj, :);
+    Delta2 = [Delta2(:, logi), Delta2(:, jj)];
+
+    % conditional mean and var-cov matrix
+    nu2      = -nu2;
+    condMean = (Delta2(1:q-1, q)*nu2(q))/Delta2(q, q);
+    condVar  = Delta2(1:q-1, 1:q-1) - (Delta2(1:q-1, q)/Delta2(q, q))*Delta2(q, 1:q-1);
+
+    % evaluate the gradient vector
+    term1 = normpdf(nu2(q), 0, sqrt(Delta2(q, q)));
+    if isempty(condVar)
+        term2 = 1;
+    else
+        % different functions to evaluate log Gaussian cdf
+        if cdfmvna_fct == "logmvncdf_ME"
+            % requires zero mean and correlation matrix as inputs
+            normalization2 = diag(1./sqrt(diag(condVar)));
+            eval_point2 = normalization2*(nu2(1:q-1) - condMean);
+            Corr_mat2 = normalization2*condVar*normalization2; 
+            Corr_mat2 = 0.5*(Corr_mat2 + Corr_mat2');
+            term2 = exp(logmvncdf_ME(eval_point2, Corr_mat2));
+        elseif cdfmvna_fct == "mvncdf"
+            term2 = mvncdf(nu2(1:q-1)', condMean', condVar);
+        elseif cdfmvna_fct == "qsilatmvnv"
+            if (q-1) > 1
+                term2 = qsilatmvnv( 1000*(q-1), condVar, repmat(-Inf,q-1,1)-condMean, nu2(1:q-1)-condMean );
+            else
+                term2 = normcdf(nu2, condMean, condVar);
+            end
+        elseif cdfmvna_fct == "qsimvnv"
+            if (q-1) > 1
+                term2 = qsimvnv( 1000*(q-1), condVar, repmat(-Inf,q-1,1)-condMean, nu2(1:q-1)-condMean );
+            else
+                term2 = normcdf(nu2, condMean, condVar);
+            end
+        end
+    end
+    derVect(jj) = term1*term2;
+end
+
+% evaluate end result using equation (1) of Dominguez-Molina, Gonzalez-Farias, Gupta (2003, p. 10)
+Delta1 = 0.5*(Delta1+Delta1');
+if isempty(Gamma) || isempty(nu) || isempty(Delta1)
+    if isempty(Gamma) && isempty(nu) && isempty(Delta1)
+        term3 = 1;
+    else
+        error("Problem with Gamma, nu, Delta being empty / not empty")
+    end
+else
+    if cdfmvna_fct == "logmvncdf_ME"
+        % requires zero mean and correlation matrix as inputs
+        normalization3 = diag(1./sqrt(diag(Delta1)));
+        eval_point3 = normalization3*(zeros(q, 1) - nu);
+        Corr_mat3 = normalization3*Delta1*normalization3;
+        Corr_mat3 = 0.5*(Corr_mat3 + Corr_mat3');
+        term3 = exp(logmvncdf_ME(eval_point3, Corr_mat3));
+    elseif cdfmvna_fct == "mvncdf"
+        term3 = mvncdf(zeros(1, q), nu', Delta1);
+    elseif cdfmvna_fct == "qsilatmvnv"
+        if q > 1
+            term3 = qsilatmvnv( 1000*q, Delta1, repmat(-Inf,q,1)-nu, zeros(q, 1)-nu );
+        else
+            term3 = normcdf(0, nu, Delta1);
+        end
+    elseif cdfmvna_fct == "qsimvnv"
+        if q > 1
+            term3 = qsimvnv( 1000*q, Delta1, repmat(-Inf,q,1)-nu, zeros(q, 1)-nu );
+        else
+            term3 = normcdf(0, nu, Delta1);
+        end    
+    end
+end
+E_csn = mu + Sigma * Gamma' * (derVect/term3); % equation (1) of Dominguez-Molina, Gonzalez-Farias, Gupta (2003, p. 10)
+
+end
\ No newline at end of file
diff --git a/matlab/distributions/csnQuantile.m b/matlab/distributions/csnQuantile.m
new file mode 100644
index 0000000000000000000000000000000000000000..330b42df4107440ff00f4a9f2968d5af72b884a6
--- /dev/null
+++ b/matlab/distributions/csnQuantile.m
@@ -0,0 +1,126 @@
+function [q_alph] = csnQuantile(alph, mu, Sigma, Gamma, nu, Delta, cdfmvna_fct, optim_fct)
+% function [q_alph] = csnQuantile(alph, mu, Sigma, Gamma, nu, Delta, cdfmvna_fct, optim_fct)
+% -------------------------------------------------------------------------
+% Evaluates the quantile of a CSN(mu,Sigma,Gamma,nu,Delta) distributed random variable
+% for the cumulative probability alph in the interval [0,1]
+% Idea:
+% - q_alph = min{x: F(x) >= alph}
+% - Lemma 2.2.1 of chapter 2 of Genton (2004) - "Skew-elliptical distributions
+%   and their applications: a journey beyond normality" gives the cdf, F_X(x)
+%   of a CSN distributed random variable X
+% - We need to solve F_X(q_alpha) = alpha, to find alpha quantile q_alpha
+% - Minimization problem: q_alpha = argmin(log(F_X(q_alpha)) - log(alpha))
+% -------------------------------------------------------------------------
+% INPUTS
+% - alph          [0<alph<1] cumulative probability alph in the interval [0,1]
+% - mu            [p by 1]   1st parameter of the CSN distribution (location)
+% - Sigma         [p by p]   2nd parameter of the CSN distribution (scale)
+% - Gamma         [q by p]   3rd parameter of the CSN distribution (regulates skewness from Gaussian (Gamma=0) to half normal)
+% - nu            [q by 1]   4th parameter of the CSN distribution (enables closure of CSN distribution under conditioning)
+% - Delta         [q by q]   5th parameter of the CSN distribution (enables closure of CSN distribution und marginalization)
+% - cdfmvna_fct   [string]   name of function to compute log Gaussian cdf, possible values: 'logmvncdf_ME', 'mvncdf', 'qsilatmvnv', 'qsimvnv'
+% - optim_fct     [string]   name of minimization function, possible values: 'fminunc', 'lsqnonlin'
+% -------------------------------------------------------------------------
+% OUTPUTS
+% - q_alph        [p by 1]   alpha quantile vector of the CSN(mu,Sigma,Gamma,nu,Delta) distribution
+% =========================================================================
+% Copyright (C) 2022-2023 Gaygysyz Guljanov, Willi Mutschler
+%
+% This is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% This is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+% -------------------------------------------------------------------------
+% This file is part of the replication files for the paper "Pruned Skewed
+% Kalman Filter and Smoother: Pruned Skewed Kalman Filter and Smoother:
+% With Applications to the Yield Curve and Asymmetric Monetary Policy Shocks"
+% by Gaygysyz Guljanov, Willi Mutschler, Mark Trede
+% =========================================================================
+
+if nargin < 7 || (nargin >= 7 && isempty(cdfmvna_fct))
+    cdfmvna_fct = 'logmvncdf_ME';
+end
+if strcmp(cdfmvna_fct,'qsilatmvnv')
+    warning('csnQuantile: qsilatmvnv not yet working, switching to ''logmvncdf_ME'' to compute the quantile');
+    cdfmvna_fct = 'logmvncdf_ME';
+end
+if strcmp(cdfmvna_fct,'qsimvnv')
+    warning('csnQuantile: qsimvnv not yet working, switching to ''logmvncdf_ME'' to compute the quantile');
+    cdfmvna_fct = 'logmvncdf_ME';
+end
+if nargin < 8
+    optim_fct = 'lsqnonlin';
+end
+
+q = size(Delta, 1);
+Cov_mat = -Sigma * Gamma';
+
+% evaluate the first log-CDF
+Var_Cov1 = Delta - Gamma * Cov_mat;        
+if cdfmvna_fct == "logmvncdf_ME"
+    normalization1 = diag(1 ./ sqrt(diag(Var_Cov1)));
+    eval_point1    = normalization1 * (zeros(q, 1) - nu);
+    Corr_mat1      = normalization1 * Var_Cov1 * normalization1; 
+    Corr_mat1      = 0.5*(Corr_mat1 + Corr_mat1');
+    cdf1           = logmvncdf_ME(eval_point1, Corr_mat1);
+elseif cdfmvna_fct == "mvncdf"
+    cdf1 = log(mvncdf(zeros(1, q), nu', Var_Cov1));
+elseif cdfmvna_fct == "qsilatmvnv"
+    if q > 1
+        cdf1 = log(qsilatmvnv( 1000*q, Var_Cov1, repmat(-Inf,q,1)-nu, zeros(q, 1)-nu ));
+    else
+        cdf1 = log(normcdf(0, nu, Var_Cov1));
+    end
+elseif cdfmvna_fct == "qsimvnv"
+    if q > 1
+        cdf1 = log(qsimvnv( 1000*q, Var_Cov1, repmat(-Inf,q,1)-nu, zeros(q, 1)-nu ));
+    else
+        cdf1 = log(normcdf(0, nu, Var_Cov1));
+    end
+end
+
+% prepare helper function to get quantile
+Var_Cov2 = [Sigma, Cov_mat; Cov_mat', Var_Cov1];
+
+if cdfmvna_fct == "logmvncdf_ME"
+    % requires zero mean and correlation matrix as inputs
+    normalization2 = diag(1 ./ sqrt(diag(Var_Cov2)));
+    Corr_mat2      = normalization2 * Var_Cov2 * normalization2;
+    Corr_mat2      = 0.5 * (Corr_mat2 + Corr_mat2');
+    if strcmp(optim_fct,'lsqnonlin')
+        fun = @(x) logmvncdf_ME( (normalization2 * ([x; zeros(q, 1)] - [mu; nu])), Corr_mat2 ) - cdf1 - log(alph);
+    elseif strcmp(optim_fct,'fminunc')
+        fun = @(x) ( logmvncdf_ME( (normalization2 * ([x; zeros(q, 1)] - [mu; nu])), Corr_mat2 ) - cdf1 - log(alph))^2;
+    end
+elseif cdfmvna_fct == "mvncdf"
+    if strcmp(optim_fct,'lsqnonlin')
+        fun = @(x) log(mvncdf([x', zeros(1, q)], [mu', nu'], Var_Cov2)) - cdf1 - log(alph);
+    elseif strcmp(optim_fct,'fminunc')
+        fun = @(x) (log(mvncdf([x', zeros(1, q)], [mu', nu'], Var_Cov2)) - cdf1 - log(alph))^2;
+    end
+elseif cdfmvna_fct == "qsilatmvnv"
+    error('csnQuantile: qsilatmvnv not yet working')
+    fun = @(pp_quant) (log(qsilatmvnv(1000*(size(pp_quant,1)+q),Var_Cov2,repmat(-Inf,size(pp_quant,1)+q,1)-[mu', nu']', [pp_quant', zeros(1, q)]' - [mu', nu']')) ...
+                       - cdf1 ...
+                       - log(alph))^2;
+elseif cdfmvna_fct == "qsimvnv"
+    error('csnQuantile: qsimvnv not yet working')
+    fun = @(pp_quant) (log(qsimvnv(1000*(size(pp_quant,1)+q),Var_Cov2,repmat(-Inf,size(pp_quant,1)+q,1)-[pp_quant', zeros(1, q)],[pp_quant', zeros(1, q)] - [mu', nu'])) ...
+                       - cdf1 ...
+                       - log(alph))^2;
+end
+
+% run minimization
+optim_opt = optimset('MaxIter', 10000, 'MaxFunEvals', 10000, 'Display', 'off');
+if strcmp(optim_fct,'lsqnonlin')
+    q_alph = lsqnonlin(fun, mu, [], [], optim_opt);
+elseif strcmp(optim_fct,'fminunc')
+    q_alph = fminunc(fun, mu, optim_opt);
+end
+
+end % csnQuantile
\ No newline at end of file
diff --git a/matlab/distributions/csnRandDirect.m b/matlab/distributions/csnRandDirect.m
new file mode 100644
index 0000000000000000000000000000000000000000..44e0761329bdd6910bd27925661a343c052dcba4
--- /dev/null
+++ b/matlab/distributions/csnRandDirect.m
@@ -0,0 +1,55 @@
+function [csn_draws] = csnRandDirect(n, mu, Sigma, Gamma, nu, Delta)
+% function [res] = csnRandDirect(n, mu, Sigma, D, nu, Delta)
+% -------------------------------------------------------------------------
+% Draws random numbers from CSN distribution using accept-reject method
+% adapted from the "rcsn" command in the "csn" package of the R language
+% -------------------------------------------------------------------------
+% INPUTS
+% - n          [scalar]   number of desired random draws
+% - mu         [p by 1]   1st parameter of the CSN distribution (location)
+% - Sigma      [p by p]   2nd parameter of the CSN distribution (scale)
+% - Gamma      [q by p]   3rd parameter of the CSN distribution (regulates skewness from Gaussian (Gamma=0) to half normal)
+% - nu         [q by 1]   4th parameter of the CSN distribution (enables closure of CSN distribution under conditioning)
+% - Delta      [q by q]   5th parameter of the CSN distribution (enables closure of CSN distribution und marginalization)
+% -------------------------------------------------------------------------
+% OUTPUTS
+% - csn_draws  [p by n]   random draws of the CSN(mu,Sigma,Gamma,nu,Delta) distribution
+% =========================================================================
+% Copyright (C) 2015 GPL v2 Dmitry Pavlyuk, Eugene Girtcius (rcsn.R function in the "csn" R package)
+% Copyright (C) 2022-2023 Gaygysyz Guljanov
+%
+% This is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% This is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+% -------------------------------------------------------------------------
+% This file is part of the replication files for the paper "Pruned Skewed
+% Kalman Filter and Smoother: Pruned Skewed Kalman Filter and Smoother:
+% With Applications to the Yield Curve and Asymmetric Monetary Policy Shocks"
+% by Gaygysyz Guljanov, Willi Mutschler, Mark Trede
+% =========================================================================
+
+q      = length(nu);
+v      = nan(q, n);
+Sigma2 = Delta + Gamma * Sigma * Gamma';
+L      = chol(Sigma2, 'lower');
+for i = 1:n
+    draws = -1;
+    while sum(draws >= 0) ~= q
+        draws = -nu + L * randn(q, 1);
+    end
+    v(:, i) = draws;
+end
+
+tmp = Sigma * Gamma' / Sigma2;
+Exp = mu + tmp * (v + nu);
+Var = Sigma - tmp * Gamma * Sigma;
+L   = chol(Var, 'lower');
+csn_draws = Exp + L * randn(length(mu), n);
+
+end % csnRandDirect
\ No newline at end of file
diff --git a/matlab/distributions/csnSkewness_univariate.m b/matlab/distributions/csnSkewness_univariate.m
new file mode 100644
index 0000000000000000000000000000000000000000..30d412abdbbfc3a9fa22ae06876ca5743f7d6315
--- /dev/null
+++ b/matlab/distributions/csnSkewness_univariate.m
@@ -0,0 +1,38 @@
+function Skew = csnSkewness_univariate(Sigma, Gamma)
+% function Skew = csnSkewness_univariate(Sigma, Gamma)
+% -------------------------------------------------------------------------
+% computes the skewness coefficient of a univariate CSN distributed random
+% variable X ~ CSN(mu,Sigma,Gamma,nu,Delta) with nu=0 and Delta=1
+% according to equation 3.6 of Grabek, Klos, and Koloch (2011) - Skew-Normal
+% shocks in the linear state space form DSGE model
+% -------------------------------------------------------------------------
+% INPUTS
+% - Sigma      [double]   scale parameter of CSN distribution
+% - Gamma      [double]   skewness parameter of CSN distribution
+% -------------------------------------------------------------------------
+% OUTPUTS
+% - Skew       [double]   theoretical skewness coefficient of X
+% =========================================================================
+% Copyright (C) 2023 Gaygysyz Guljanov
+%
+% This is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% This is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+% -------------------------------------------------------------------------
+% This file is part of the replication files for the paper "Pruned Skewed
+% Kalman Filter and Smoother: Pruned Skewed Kalman Filter and Smoother:
+% With Applications to the Yield Curve and Asymmetric Monetary Policy Shocks"
+% by Gaygysyz Guljanov, Willi Mutschler, Mark Trede
+% =========================================================================
+term1 = (4 - pi) / 2;
+term2 = (sqrt(2/pi) * Gamma * Sigma / sqrt(1 + Gamma^2 * Sigma))^3;
+term3 = (Sigma - (2/pi) * (Gamma^2 * Sigma^2) / (1 + Gamma^2 * Sigma))^(3/2);
+Skew  = term1 * term2 / term3;
+
+end
\ No newline at end of file
diff --git a/matlab/distributions/csnVar.m b/matlab/distributions/csnVar.m
new file mode 100644
index 0000000000000000000000000000000000000000..2e0949b0492b271f37785c3c7cb4a246ab0f8244
--- /dev/null
+++ b/matlab/distributions/csnVar.m
@@ -0,0 +1,99 @@
+function V_csn = csnVar(Sigma, Gamma, nu, Delta, cdfmvna_fct)
+% function V_csn = csnVar(Sigma, Gamma, nu, Delta, cdfmvna_fct)
+% -------------------------------------------------------------------------
+% Evaluates the unconditional covariance matrix of a CSN(mu,Sigma,Gamma,nu,Delta)
+% distributed random variable based on expressions derived in
+% - Dominguez-Molina, Gonzalez-Farias, Gupta (2003, sec. 2.4) - The multivariate closed skew normal distribution
+% -------------------------------------------------------------------------
+% INPUTS
+% - Sigma         [p by p]   2nd parameter of the CSN distribution (scale)
+% - Gamma         [q by p]   3rd parameter of the CSN distribution (regulates skewness from Gaussian (Gamma=0) to half normal)
+% - nu            [q by 1]   4th parameter of the CSN distribution (enables closure of CSN distribution under conditioning)
+% - Delta         [q by q]   5th parameter of the CSN distribution (enables closure of CSN distribution und marginalization)
+% - cdfmvna_fct   [string]   name of function to compute log Gaussian cdf, possible values: 'logmvncdf_ME', 'mvncdf', 'qsilatmvnv', 'qsimvnv'
+% -------------------------------------------------------------------------
+% OUTPUTS
+% - V_csn         [p by p]   covariance matrix of the CSN(mu,Sigma,Gamma,nu,Delta) distribution
+% =========================================================================
+% Copyright (C) 2022-2023 Gaygysyz Guljanov
+%
+% This is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% This is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+% -------------------------------------------------------------------------
+% This file is part of the replication files for the paper "Pruned Skewed
+% Kalman Filter and Smoother: Pruned Skewed Kalman Filter and Smoother:
+% With Applications to the Yield Curve and Asymmetric Monetary Policy Shocks"
+% by Gaygysyz Guljanov, Willi Mutschler, Mark Trede
+% =========================================================================
+
+if nargin < 5
+    cdfmvna_fct = 'logmvncdf_ME';
+end
+q = size(Delta, 1); % skewness dimension
+
+% Eq. (1) and (3) of Dominguez-Molina, Gonzalez-Farias, Gupta (2003, p. 10-11)
+Delta2 = Delta + Gamma * Sigma * Gamma';
+Delta2 = 0.5 * (Delta2 + Delta2'); %ensure symmetry
+% Evaluate first and second derivatives
+first_der  = zeros(q, 1); % first derivatives
+second_der = zeros(q, q); % second derivatives
+for ii = 1:q
+    [term1, term2, evalp_t1, covar_t1, evalp_t2, covar_t2, mult_matr] = derivative_gaussian_cdf(nu, Delta2, ii, cdfmvna_fct);
+    first_der(ii) = term1 * term2;    
+    for jj = 1:q
+        if ii ~= jj
+            which_element = jj - (ii < jj);
+            [expr1, expr2] = derivative_gaussian_cdf(-evalp_t2, covar_t2, which_element, cdfmvna_fct);
+            second_der(ii, jj) = term1 * expr1 * expr2;
+        else
+            expr3 = -evalp_t1 / covar_t1 * term1 * term2;            
+            expr4 = zeros(1, q-1);
+            for kk = 1:q-1
+                [first_term, second_term] = derivative_gaussian_cdf(-evalp_t2, covar_t2, kk, cdfmvna_fct);
+                expr4(kk) = first_term * second_term;
+            end            
+            expr5 = term1 * expr4 * (-mult_matr);
+            second_der(jj, jj) = expr3 + expr5;
+        end
+    end
+end
+
+% denominator in psi and Lambda of eq. (1) and (3) of Dominguez-Molina, Gonzalez-Farias, Gupta (2003, p. 10-11)
+if cdfmvna_fct == "logmvncdf_ME"
+    % requires zero mean and correlation matrix as inputs
+    normalization3 = diag(1 ./ sqrt(diag(Delta2)));
+    eval_point3 = normalization3 * (zeros(q, 1) - nu);
+    Corr_mat3 = normalization3 * Delta2 * normalization3;
+    Corr_mat3 = 0.5 * (Corr_mat3 + Corr_mat3');
+    term3 = exp(logmvncdf_ME(eval_point3, Corr_mat3));
+elseif cdfmvna_fct == "mvncdf"
+    term3 = mvncdf(zeros(1, q), nu', Delta2);
+elseif cdfmvna_fct == "qsilatmvnv"
+    if q > 1
+        term3 = qsilatmvnv( 1000*q, Delta2, repmat(-Inf,q,1)-nu, zeros(q,1)-nu );
+    else
+        term3 = normcdf(0, nu, Delta2);
+    end
+elseif cdfmvna_fct == "qsimvnv"
+    if q > 1
+        term3 = qsimvnv( 1000*q, Delta2, repmat(-Inf,q,1)-nu, zeros(q,1)-nu );
+    else
+        term3 = normcdf(0, nu, Delta2);
+    end
+end
+
+% definition of psi in eq (1) of Dominguez-Molina, Gonzalez-Farias, Gupta (2003, p. 10)
+psi = first_der / term3;
+% definition of Lambda in eq (3) of Dominguez-Molina, Gonzalez-Farias, Gupta (2003, p. 11)
+Lambda = second_der / term3; Lambda = 0.5 * (Lambda + Lambda');
+% eq (3) of Dominguez-Molina, Gonzalez-Farias, Gupta (2003, p. 11)
+V_csn = Sigma + Sigma * Gamma' * Lambda * Gamma * Sigma - Sigma * Gamma' * (psi * psi') * Gamma * Sigma;
+
+end %csnVar
\ No newline at end of file
diff --git a/matlab/distributions/csnVarSkew_To_SigmaGamma_univariate.m b/matlab/distributions/csnVarSkew_To_SigmaGamma_univariate.m
new file mode 100644
index 0000000000000000000000000000000000000000..ee53f1f04eaf694b52e68174e92944eec27ac1c5
--- /dev/null
+++ b/matlab/distributions/csnVarSkew_To_SigmaGamma_univariate.m
@@ -0,0 +1,55 @@
+function [Sigma, Gamma, error_indicator] = csnVarSkew_To_SigmaGamma_univariate(Var, Skew, verbose)
+% function [Sigma, Gamma, error_indicator] = csnVarSkew_To_SigmaGamma_univariate(Var, Skew, verbose)
+% -------------------------------------------------------------------------
+% recovers the Sigma and Gamma parameters from the Variance and Skewness of
+% a univariate CSN distributed random variable X ~ CSN(mu,Sigma,Gamma,nu,Delta)
+% where Var=V[X], Skew=skewness[X], nu=0, and Delta=1
+% this basically inverts the formulas provided in equation 3.6 of Grabek,
+% Klos, and Koloch (2011) - Skew-Normal shocks in the linear state space form DSGE model
+% -------------------------------------------------------------------------
+% INPUTS
+% - Var      [double]   unconditional variance of X
+% - Skew     [double]   theoretical skewness coefficient of X
+% - verbose  [boolean]  display details if transformation did not work
+% -------------------------------------------------------------------------
+% OUTPUTS
+% - Sigma             [double]    scale parameter of CSN distribution
+% - Gamma             [double]    skewness parameter of CSN distribution
+% - error_indicator   [boolean]   1: if transformation failed (mostly if Gamma is extremely large and/or Sigma is extremely small)
+% =========================================================================
+% Copyright (C) 2023 Willi Mutschler
+%
+% This is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% This is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+% -------------------------------------------------------------------------
+% This file is part of the replication files for the paper "Pruned Skewed
+% Kalman Filter and Smoother: Pruned Skewed Kalman Filter and Smoother:
+% With Applications to the Yield Curve and Asymmetric Monetary Policy Shocks"
+% by Gaygysyz Guljanov, Willi Mutschler, Mark Trede
+% =========================================================================
+if nargin < 3
+    verbose = false;
+end
+error_indicator = 0;
+Sigma = (-2^(2/3) * (4-pi)^(1/3) * abs(Skew)^(2/3) + pi - 4) * Var / (pi - 4);
+Gamma = sign(Skew) * ( 2^(1/3) * (4-pi)^(2/3)*sqrt(pi)*sqrt( abs(Skew)^(2/3) / ( ( -2 * 2^(1/3) * (4-pi)^(2/3) * (pi-2) * abs(Skew)^(4/3) + 2^(2/3) * (4-pi)^(7/3) * abs(Skew)^(2/3) + 2 * (pi - 4)^2 ) * Var ) ) );
+
+if (abs(csnVar(Sigma,Gamma,0,1) - Var)>1e-13) || (abs(csnSkewness_univariate(Sigma,Gamma) - Skew) > 1e-7)
+    if verbose
+        fprintf('Sigma: %f\n',Sigma);
+        fprintf('Gamma: %f\n',Gamma);
+        fprintf('Var: %f\n',csnVar(Sigma,Gamma,0,1));
+        fprintf('Skew: %f\n',csnSkewness_univariate(Sigma,Gamma));
+        fprintf('abs(csnVar(Sigma,Gamma,0,1) - Var): %f\n',abs(csnVar(Sigma,Gamma,0,1) - Var));
+        fprintf('abs(csnSkewness_univariate(Sigma,Gamma) - Skew): %f\n',abs(csnSkewness_univariate(Sigma,Gamma) - Skew));        
+        warning('could not transform the parameters')
+    end
+    error_indicator = 1;
+end
\ No newline at end of file
diff --git a/matlab/distributions/derivative_gaussian_cdf.m b/matlab/distributions/derivative_gaussian_cdf.m
new file mode 100644
index 0000000000000000000000000000000000000000..6df52464e069ab83db14a7199678488ed0390f26
--- /dev/null
+++ b/matlab/distributions/derivative_gaussian_cdf.m
@@ -0,0 +1,104 @@
+function [term1, term2, evalp_t1, covar_t1, evalp_t2, covar_t2, mult_matr] = derivative_gaussian_cdf(mu, Sigma, which_element, cdfmvna_fct)
+% function [term1, term2, evalp_t1, covar_t1, evalp_t2, covar_t2, mult_matr] = derivative_gaussian_cdf(mu, Sigma, which_element, cdfmvna_fct)
+% -------------------------------------------------------------------------
+% Differentiates the multivariate normal cdf according to steps given in
+% Rodenburger (2015, p.28-29) - On Approximations of Normal Integrals in the Context of Probit based Discrete Choice Modeling (2015)
+% - First derivative is equal to term1 * term2
+% - Output variables "evalp_t1, covar_t1, evalp_t2, covar_t2, mult_matr"
+%   are used for differentiating the first derivative for the second time,
+%   for details look at the double loop in the code of csnVar() function above
+% -------------------------------------------------------------------------
+% INPUTS
+% - mu              [p by 1]   mean of normal distribution
+% - Sigma           [p by p]   covariance matrix of normal distribution
+% - which_element   [scalar]   indicator (1,...,p) for which variable in multivariate normal cdf the derivative is computed for
+% - cdfmvna_fct     [string]   name of function to compute log Gaussian cdf, possible values: 'logmvncdf_ME', 'mvncdf', 'qsilatmvnv', 'qsimvnv'
+% -------------------------------------------------------------------------
+% OUTPUTS
+% - term1           [double]           evaluated normal PDF, see the first part of the derivative
+% - term2           [double]           evaluated normal CDF, see the second part of the derivative
+% - evalp_t1        [1 by 1]           evaluation point of normal PDF in term1
+% - covar_t1        [1 by 1]           variance term of normal PDF in term1
+% - evalp_t2        [(p-1) by 1]       evaluation point of normal CDF in term2
+% - covar_t2        [(p-1) by (p-1)]   covariance matrix of normal CDF in term2
+% - mult_matr       [(p-1) by 1]       auxiliary expression Sigma_12/Sigma_22, this expression shows up when evaluating conditional mean and conditional Variance out of partitions of mean and Variance of joint distribution
+% =========================================================================
+% Copyright (C) 2022-2023 Gaygysyz Guljanov
+%
+% This is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% This is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+% -------------------------------------------------------------------------
+% This file is part of the replication files for the paper "Pruned Skewed
+% Kalman Filter and Smoother: Pruned Skewed Kalman Filter and Smoother:
+% With Applications to the Yield Curve and Asymmetric Monetary Policy Shocks"
+% by Gaygysyz Guljanov, Willi Mutschler, Mark Trede
+% =========================================================================
+
+if nargin < 4
+    cdfmvna_fct = 'logmvncdf_ME';
+end
+
+p = length(mu);
+logic_vec = true(p, 1);
+logic_vec(which_element, 1) = false;
+
+% permute the matrices
+mu2        = zeros(p, 1); 
+mu2(1:p-1) = mu(logic_vec);
+mu2(p)     = mu(which_element);
+
+Sigma2           = zeros(size(Sigma));
+Sigma2(1:p-1, :) = Sigma(logic_vec, :);
+Sigma2(p, :)     = Sigma(which_element, :);
+Sigma2           = [Sigma2(:, logic_vec), Sigma2(:, which_element)];
+
+% Conditional mean and conditional var-cov matrix
+eval_point = -mu2;
+mult_matr  = Sigma2(1:p-1, p) / Sigma2(p, p);
+cond_mean  = mult_matr * eval_point(p);
+cond_var   = Sigma2(1:p-1, 1:p-1) - mult_matr * Sigma2(p, 1:p-1);
+
+evalp_t1 = eval_point(p);
+covar_t1 = Sigma2(p, p);
+
+evalp_t2 = eval_point(1:p-1) - cond_mean;
+covar_t2 = cond_var;
+
+% Evaluate the first term in the derivative
+term1 = normpdf(evalp_t1, 0, sqrt(covar_t1));
+
+% Evaluate the second term in the derivative
+if isempty(cond_var)
+    term2 = 1;
+else
+    if cdfmvna_fct == "logmvncdf_ME"
+        stdnrd   = diag(1./sqrt(diag(cond_var)));
+        haspl    = stdnrd * evalp_t2;
+        Uytgesme = stdnrd * cond_var * stdnrd; 
+        Uytgesme = 0.5 * (Uytgesme + Uytgesme');
+        term2    = exp(logmvncdf_ME(haspl, Uytgesme));
+    elseif cdfmvna_fct == "mvncdf"
+        term2 = mvncdf(eval_point(1:p-1)', cond_mean', cond_var);
+    elseif cdfmvna_fct == "qsilatmvnv"
+        if (p-1) > 1
+            term2 = qsilatmvnv( 1000*(p-1), cond_var, repmat(-Inf,p-1,1)-cond_mean, eval_point(1:p-1)-cond_mean );
+        else
+            term2 = normcdf(eval_point(1:p-1), cond_mean, cond_var);
+        end
+    elseif cdfmvna_fct == "qsimvnv"
+        if (p-1) > 1
+            term2 = qsimvnv( 1000*(p-1), cond_var, repmat(-Inf,p-1,1)-cond_mean, eval_point(1:p-1)-cond_mean );
+        else
+            term2 = normcdf(eval_point(1:p-1), cond_mean, cond_var);
+        end
+    end
+end
+
+end % derivative_gaussian_cdf
\ No newline at end of file
diff --git a/matlab/distributions/logmvncdf_ME.m b/matlab/distributions/logmvncdf_ME.m
new file mode 100644
index 0000000000000000000000000000000000000000..86550738205309b84e1c266fb38452ba19202333
--- /dev/null
+++ b/matlab/distributions/logmvncdf_ME.m
@@ -0,0 +1,93 @@
+function log_cdf = logmvncdf_ME(Zj, R, cutoff)
+% log_cdf = logmvncdf_ME(Zj, R, cutoff)
+% -------------------------------------------------------------------------
+% Approximates Gaussian log(CDF) function according to Mendell and Elston (1974)
+% -------------------------------------------------------------------------
+% INPUTS
+% - Zj       [n by 1]   column vector of points where Gaussian CDF is evaluated at
+% - R        [n by n]   correlation matrix
+% - cutoff   [2 by 1]   optional threshold points at which values in Zj are too low/high to be evaluated, defaults to [6 38]
+% -------------------------------------------------------------------------
+% OUTPUTS
+% log_cdf    [double]   approximate value of Gaussian log(CDF)
+% =========================================================================
+% Copyright (C) 2015 Dietmar Bauer (original implementation)
+% Copyright (C) 2022-2023 Gaygysyz Guljanov
+%
+% This is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% This is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+% -------------------------------------------------------------------------
+% This file is part of the replication files for the paper "Pruned Skewed
+% Kalman Filter and Smoother: Pruned Skewed Kalman Filter and Smoother:
+% With Applications to the Yield Curve and Asymmetric Monetary Policy Shocks"
+% by Gaygysyz Guljanov, Willi Mutschler, Mark Trede
+% =========================================================================
+
+if nargin < 3
+    cutoff = [6 38]; % default values
+end
+% cutoff tails as these are too low to be evaluated
+Zj(Zj>cutoff(1))  = cutoff(1);
+Zj(Zj<-cutoff(1)) = -cutoff(1);
+n = length(Zj); % remaining dimension of Z
+
+% first element
+cdf_val = phid(Zj(1));
+pdf_val = phip(Zj(1));
+log_cdf = log(cdf_val); % perform all calculations in logs
+
+for jj = 1:(n-1)
+    ajjm1 = pdf_val / cdf_val;
+
+    % Update Zj and Rij
+    tZ = Zj + ajjm1 * R(:, 1); % update Zj
+    R_jj = R(:, 1) * R(1, :);
+    tRij = R - R_jj * ( ajjm1 + Zj(1) ) * ajjm1; % update Rij
+
+    % Convert Rij (i.e. Covariance matrix) to Correlation matrix
+    COV_TO_CORR = sqrt( diag(tRij) );
+    Zj = tZ ./ COV_TO_CORR;
+    R = tRij ./ (COV_TO_CORR * COV_TO_CORR');
+
+    % Cutoff those dimensions if they are too low to be evaluated
+    Zj(Zj>cutoff(2))  = cutoff(2);  % use larger cutoff
+    Zj(Zj<-cutoff(2)) = -cutoff(2); % use larger cutoff
+
+    % Evaluate jj's probability
+    cdf_val = phid(Zj(2));
+    pdf_val = phip(Zj(2));
+
+    % Delete unnecessary parts of updated Zj and Corr_mat
+    last_el = n - jj + 1;
+    Zj = Zj(2:last_el);
+    R = R(2:last_el, 2:last_el);
+
+    % Overall probability
+    log_cdf = log_cdf + log(cdf_val);
+
+end
+
+end % logmvncdf_ME
+
+
+%%%%%%%%%%%%%%
+% Normal PDF %
+%%%%%%%%%%%%%%
+function p = phip(z)
+    p = exp(-z.^2/2)/sqrt(2*pi);
+end
+
+
+%%%%%%%%%%%%%%
+% Normal CDF %
+%%%%%%%%%%%%%%
+function p = phid(z)
+    p = erfc( -z/sqrt(2) )/2;
+end
diff --git a/matlab/distributions/singular_skew_normal_2_closed_skew_normal.m b/matlab/distributions/singular_skew_normal_2_closed_skew_normal.m
new file mode 100644
index 0000000000000000000000000000000000000000..0573dea017e5822107882e4cd8a9a86b17ef8a05
--- /dev/null
+++ b/matlab/distributions/singular_skew_normal_2_closed_skew_normal.m
@@ -0,0 +1,70 @@
+function [S_hat, mu_hat, Lambda_hat, Gamma_hat] = singular_skew_normal_2_closed_skew_normal(mu_bar, Sigma_bar, Gamma_bar, tol, hmdel)
+% function [S_hat, mu_hat, Lambda_hat, Gamma_hat] = singular_skew_normal_2_closed_skew_normal(mu_bar, Sigma_bar, Gamma_bar, tol, hmdel)
+% -------------------------------------------------------------------------
+% write Singular Skew Normal (SSN) distribution as a linear transformation
+% of proper Closed Skew Normal (CSN) distribution
+% -----------------------------------------------------------------------
+% INPUTS
+% mu_bar:      first parameter of the SSN distribution
+% Sigma_bar:   second parameter of the SSN distribution
+% Gamma_bar:   third parameter of the SSN distribution
+% tol:         tolerance level showing which values should be assumed to be  numerically zero
+% hmdel:       minimum how many dimensions should be deleted, if known already
+% -----------------------------------------------------------------------
+% OUTPUT
+% parameters of transformed SSN distribution that is CSN
+% S_hat:        multiplying matrix, which has more rows than columns
+% mu_hat    :   first parameter of the proper CSN
+% Lambda_hat:   second parameter of the proper CSN
+% Gamma_hat :   third parameter of the proper CSN
+% =========================================================================
+% Copyright (C) 2023 Gaygysyz Guljanov
+%
+% This is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% This is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+% -------------------------------------------------------------------------
+% This file is part of the replication files for the paper "Pruned Skewed
+% Kalman Filter and Smoother: Pruned Skewed Kalman Filter and Smoother:
+% With Applications to the Yield Curve and Asymmetric Monetary Policy Shocks"
+% by Gaygysyz Guljanov, Willi Mutschler, Mark Trede
+% =========================================================================
+if sum(mu_bar ~= 0)
+    error("mu_bar should be a zero vector")
+end
+[S_mat, Lambda_mat] = schur(Sigma_bar); % get Schur decomposition
+% Create a hold_vec, which tells which dimensions to hold
+if hmdel > 0
+    % Reorder the diagonal elements of Lambda, in an increasing order
+    len = length(Lambda_mat);
+    diag_el = diag(Lambda_mat);
+    [~, min_indices] = mink(diag_el, len);
+    % Should we delete more than hmdel
+    hmdel_tmp = hmdel;
+    ii = 1;
+    while diag_el(min_indices(hmdel_tmp + ii)) / diag_el(min_indices(len)) <= tol
+        ii = ii + 1;
+    end
+    hmdel_tmp = hmdel_tmp + ii - 1;
+    if hmdel_tmp >= len
+        error("Sigma matrix should at least have rank one");
+    end
+    % Which vector to hold, i.e. to not cut
+    hold_vec = true(len, 1);
+    hold_vec(min_indices(1:hmdel_tmp)) = false;
+else
+    hold_vec = diag(Lambda_mat) > tol;
+end
+% Hold the relevant dimensions, i.e. delete the unnecessary ones
+S_hat = S_mat(:, hold_vec);    
+mu_hat = zeros(sum(hold_vec), 1);
+Lambda_hat = Lambda_mat(hold_vec, hold_vec);
+Gamma_hat = Gamma_bar * S_hat;
+
+end % singular_skew_normal_2_closed_skew_normal
diff --git a/matlab/estimation/GetPosteriorParametersStatistics.m b/matlab/estimation/GetPosteriorParametersStatistics.m
index ebaf93666523353a3a2df5c5d54f5f594743395d..a5b3102ff9a01420ca605407879bce44c96f27ff 100644
--- a/matlab/estimation/GetPosteriorParametersStatistics.m
+++ b/matlab/estimation/GetPosteriorParametersStatistics.m
@@ -39,6 +39,7 @@ nvx     = estim_params_.nvx;
 nvn     = estim_params_.nvn;
 ncx     = estim_params_.ncx;
 ncn     = estim_params_.ncn;
+nsx     = estim_params_.nsx;
 np      = estim_params_.np ;
 
 latexFolder = CheckPath('latex',M_.dname);
@@ -87,7 +88,7 @@ if np
     skipline()
     disp(type)
     disp(tit2)
-    ip = nvx+nvn+ncx+ncn+1;
+    ip = nvx+nvn+ncx+ncn+nsx+1;
     for i=1:np
         if options_.mh_replic || (options_.load_mh_file && ~options_.load_results_after_load_mh) || ishssmc(options_) || isonline(options_)
             draws = getalldraws(ip);
@@ -302,6 +303,48 @@ if ncn
     end
 end
 
+if nsx
+    type = 'shocks_skew';
+    if TeX
+        fid = TeXBegin(latexFolder, FileName,6, 'skewness of structural shocks');
+    end
+    skipline()
+    disp('skewness of shocks')
+    disp(tit2)
+    ip = nvx+nvn+ncx+ncn+1;
+    for i=1:nsx
+        if options_.mh_replic || (options_.load_mh_file && ~options_.load_results_after_load_mh)
+            draws = getalldraws(ip);
+            [post_mean, post_median, post_var, hpd_interval, post_deciles, density] = posterior_moments(draws, options_.mh_conf_sig);
+            k = estim_params_.skew_exo(i,1);
+            name = M_.exo_names{k};
+            oo_ = Filloo(oo_, name, type, post_mean, hpd_interval, post_median, post_var, post_deciles, density);
+            M_.Skew_e(k) = post_mean;
+        else
+            try
+                k = estim_params_.skew_exo(i,1);
+                name = M_.exo_names{k};
+                [post_mean, hpd_interval, post_var] = Extractoo(oo_, name, type);
+            catch
+                draws = getalldraws(ip);
+                [post_mean, post_median, post_var, hpd_interval, post_deciles, density] = posterior_moments(draws, options_.mh_conf_sig);
+                k = estim_params_.var_exo(i,1);
+                name = M_.exo_names{k};
+                oo_ = Filloo(oo_, name, type, post_mean, hpd_interval, post_median, post_var, post_deciles, density);
+                M_.Skew_e(k) = post_mean;
+            end
+        end
+        dprintf(pformat, header_width, name, bayestopt_.p1(ip), post_mean, hpd_interval, pnames{bayestopt_.pshape(ip)+1}, bayestopt_.p2(ip));
+        if TeX
+            name = M_.exo_names_tex{k};
+            TeXCore(fid,name, pnames{bayestopt_.pshape(ip)+1}, bayestopt_.p1(ip), bayestopt_.p2(ip), post_mean, sqrt(post_var), hpd_interval);
+        end
+        ip = ip+1;
+    end
+    if TeX
+        TeXEnd(fid, 6, 'skewness of structural shocks');
+    end
+end
 
 %
 %% subfunctions:
diff --git a/matlab/estimation/PlotPosteriorDistributions.m b/matlab/estimation/PlotPosteriorDistributions.m
index 633ab1cf56a8363a581349259e6b7f9e891f070c..3d2d5bc211aba518109d7b34838371f3a6d77687 100644
--- a/matlab/estimation/PlotPosteriorDistributions.m
+++ b/matlab/estimation/PlotPosteriorDistributions.m
@@ -40,8 +40,9 @@ nvx     = estim_params_.nvx;
 nvn     = estim_params_.nvn;
 ncx     = estim_params_.ncx;
 ncn     = estim_params_.ncn;
+nsx     = estim_params_.nsx;
 np      = estim_params_.np ;
-npar    = nvx+nvn+ncx+ncn+np;
+npar    = nvx+nvn+ncx+ncn+nsx+np;
 
 MaxNumberOfPlotPerFigure = 9;% The square root must be an integer!
 nn = sqrt(MaxNumberOfPlotPerFigure);
@@ -109,8 +110,17 @@ for i=1:npar
         if ~issmc(options_) && ~options_.mh_posterior_mode_estimation
             pmod = oo_.posterior_mode.measurement_errors_corr.(name);
         end
+    elseif i <= nvx+nvn+ncx+ncn+nsx
+        name = M_.exo_names{estim_params_.skew_exo(i-(nvx+nvn+ncx+ncn),1)};
+        x1 = oo_.posterior_density.shocks_skew.(name)(:,1);
+        f1 = oo_.posterior_density.shocks_skew.(name)(:,2);
+        oo_.prior_density.shocks_skew.(name)(:,1) = x2;
+        oo_.prior_density.shocks_skew.(name)(:,2) = f2;
+        if ~issmc(options_) && ~options_.mh_posterior_mode_estimation
+            pmod = oo_.posterior_mode.shocks_skew.(name);
+        end
     else
-        j = i - (nvx+nvn+ncx+ncn);
+        j = i - (nvx+nvn+ncx+ncn+nsx);
         name = M_.param_names{estim_params_.param_vals(j,1)};
         x1 = oo_.posterior_density.parameters.(name)(:,1);
         f1 = oo_.posterior_density.parameters.(name)(:,2);
diff --git a/matlab/estimation/PosteriorIRF.m b/matlab/estimation/PosteriorIRF.m
index 00366f0900626d97f03458c858bb42d911dd0f5e..a50ac92d5f1b700cec0624c5f37a9e477b940457 100644
--- a/matlab/estimation/PosteriorIRF.m
+++ b/matlab/estimation/PosteriorIRF.m
@@ -67,7 +67,7 @@ end
 irf_shocks_indx = getIrfShocksIndx(M_, options_);
 
 % Set various parameters & Check or create directories
-npar = estim_params_.nvx+estim_params_.nvn+estim_params_.ncx+estim_params_.ncn+estim_params_.np ;
+npar = estim_params_.nvx+estim_params_.nvn+estim_params_.ncx+estim_params_.ncn+estim_params_.nsx+estim_params_.np ;
 
 nvobs = dataset_.vobs;
 gend = dataset_.nobs;
diff --git a/matlab/estimation/check_bounds_and_definiteness_estimation.m b/matlab/estimation/check_bounds_and_definiteness_estimation.m
index 54410b1d4a1b26c23b3ae88935f9c7a5aaa03c70..db9f397ef769a440f2c89d44f61598349cd3f405 100644
--- a/matlab/estimation/check_bounds_and_definiteness_estimation.m
+++ b/matlab/estimation/check_bounds_and_definiteness_estimation.m
@@ -105,3 +105,30 @@ if ~issquare(H) || estim_params_.ncn || isfield(estim_params_,'calibrated_covari
         end
     end
 end
+
+% skewness transformation failed
+if any(M_.csn.error_indicator)
+    warning('Skewness transformation failed, check if M_.csn.Gamma_e is extremely large and/or M_.csn.Sigma_e is extremely small');
+    penalty = sum(abs(M_.Skew_e));
+    fval = Inf;
+    exit_flag = 0;
+    info(1) = 56;
+    info(4) = penalty;
+    return
+end
+
+% theoretical bound on skewness coefficient
+if any(diag(M_.csn.Gamma_e))
+    skewnessBound = abs((sqrt(2)*(pi-4))/(pi-2)^(3/2));
+    penalty = 0;
+    for jp = 1:M_.exo_nbr
+        penalty = penalty + max(0,abs(csnSkewness_univariate(M_.csn.Sigma_e(jp,jp),M_.csn.Gamma_e(jp,jp))) - skewnessBound);
+    end
+    if penalty > 0
+        fval = Inf;
+        exit_flag = 0;
+        info(1) = 57;
+        info(4) = penalty;
+        return
+    end
+end
\ No newline at end of file
diff --git a/matlab/estimation/display_estimation_results_table.m b/matlab/estimation/display_estimation_results_table.m
index f24729cb30b9cf76ddfa255e254cab0c9611c995..c5d139778d2578e70c5919fb13b9853b0b6cea77 100644
--- a/matlab/estimation/display_estimation_results_table.m
+++ b/matlab/estimation/display_estimation_results_table.m
@@ -41,8 +41,9 @@ nvx = estim_params_.nvx;  % Variance of the structural innovations (number of pa
 nvn = estim_params_.nvn;  % Variance of the measurement innovations (number of parameters).
 ncx = estim_params_.ncx;  % Covariance of the structural innovations (number of parameters).
 ncn = estim_params_.ncn;  % Covariance of the measurement innovations (number of parameters).
+nsx = estim_params_.nsx;  % Skewness of the structural innovations (number of parameters).
 np  = estim_params_.np ;  % Number of deep parameters.
-nx  = nvx+nvn+ncx+ncn+np; % Total number of parameters to be estimated.
+nx  = nvx+nvn+ncx+ncn+nsx+np; % Total number of parameters to be estimated.
 
 skipline()
 disp(['RESULTS FROM ' upper(table_title) ' ESTIMATION'])
@@ -57,7 +58,7 @@ else
     tit1 = sprintf('%-*s %10s %7s %6s\n', header_width, ' ', 'Estimate', 's.d.', 't-stat');
 end
 if np
-    ip = nvx+nvn+ncx+ncn+1;
+    ip = nvx+nvn+ncx+ncn+nsx+1;
     disp('parameters')
     disp(tit1)
     for i=1:np
@@ -173,6 +174,29 @@ if ncn
     skipline()
 end
 
+if nsx
+    disp('skewness of shocks')
+    disp(tit1)
+    ip = nvx+nvn+ncx+ncn+1;
+    for i=1:nsx
+        k = estim_params_.skew_exo(i,1);
+        name = sprintf('%s', M_.exo_names{k});
+        NAME = sprintf('%s', M_.exo_names{k});
+        if contains(field_name,'posterior')
+            fprintf('%-*s %10.4f %8.4f %7.4f %6s %6.4f \n', ...
+                    header_width, name, bayestopt_.p1(ip), xparam1(ip), stdh(ip), ...
+                    pnames{bayestopt_.pshape(ip)+1}, bayestopt_.p2(ip));
+        else
+            fprintf('%-*s %10.4f %7.4f %7.4f \n',header_width, name, xparam1(ip), ...
+                    stdh(ip), tstath(ip));
+        end
+        oo_.(sprintf('%s_mode', field_name)).shocks_skew.(NAME) = xparam1(ip);
+        oo_.(sprintf('%s_std_at_mode', field_name)).shocks_skew.(NAME) = stdh(ip);
+        ip = ip+1;
+    end
+    skipline()
+end
+
 if any(xparam1(1:nvx+nvn)<0)
     warning(sprintf('Some estimated standard deviations are negative.\n         Dynare internally works with variances so that the sign does not matter.\n         Nevertheless, it is recommended to impose either prior restrictions (Bayesian Estimation)\n         or a lower bound (ML) to assure positive values.'))
 end
@@ -184,7 +208,7 @@ if any(bayestopt_.pshape > 0) && options_.TeX %% Bayesian estimation (posterior
         filename = [latexDirectoryName '/' M_.fname '_Posterior_Mode_1.tex'];
         fidTeX = fopen(filename,'w');
         TeXBegin_Bayesian(fidTeX,1,'parameters')
-        ip = nvx+nvn+ncx+ncn+1;
+        ip = nvx+nvn+ncx+ncn+nsx+1;
         for i=1:np
             fprintf(fidTeX,'$%s$ & %s & %7.3f & %6.4f & %8.4f & %7.4f \\\\ \n',...
                     M_.param_names_tex{estim_params_.param_vals(i,1)}, ...
@@ -271,12 +295,30 @@ if any(bayestopt_.pshape > 0) && options_.TeX %% Bayesian estimation (posterior
         end
         TeXEnd(fidTeX)
     end
+    if nsx
+        TeXfile = [latexDirectoryName '/' M_.fname '_Posterior_Mode_6.tex'];
+        fidTeX = fopen(TeXfile,'w');
+        TeXBegin_Bayesian(fidTeX,6,'skeweness of structural shocks')
+        ip = nvx+nvn+ncx+ncn+1;
+        for i=1:nsx
+            k = estim_params_.skew_exo(i,1);
+            fprintf(fidTeX,'$%s$ & %4s & %7.3f & %6.4f & %8.4f & %7.4f \\\\ \n',...
+                    M_.exo_names_tex{k}, ...
+                    pnames{bayestopt_.pshape(ip)+1}, ...
+                    bayestopt_.p1(ip), ...
+                    bayestopt_.p2(ip), ...
+                    xparam1(ip), ...
+                    stdh(ip));
+            ip = ip+1;
+        end
+        TeXEnd(fidTeX)
+    end
 elseif all(bayestopt_.pshape == 0) && options_.TeX %% MLE and GMM Latex output
     if np
         filename = [latexDirectoryName '/' M_.fname '_' LaTeXtitle '_Mode_1.tex'];
         fidTeX = fopen(filename, 'w');
         TeXBegin_ML(fidTeX, 1, 'parameters', table_title, LaTeXtitle)
-        ip = nvx+nvn+ncx+ncn+1;
+        ip = nvx+nvn+ncx+ncn+nsx+1;
         for i=1:np
             fprintf(fidTeX,'$%s$ & %8.4f & %7.4f & %7.4f\\\\ \n',...
                     M_.param_names_tex{estim_params_.param_vals(i,1)}, ...
@@ -353,6 +395,22 @@ elseif all(bayestopt_.pshape == 0) && options_.TeX %% MLE and GMM Latex output
         end
         TeXEnd(fidTeX)
     end
+    if nsx
+        filename = [latexDirectoryName '/' M_.fname '_' LaTeXtitle '_Mode_6.tex'];
+        fidTeX = fopen(filename, 'w');
+        TeXBegin_ML(fidTeX, 6, 'skewness of structural shocks', table_title, LaTeXtitle)
+        ip = nvx+nvn+ncx+ncn+1;
+        for i=1:nsx
+            k = estim_params_.skew_exo(i,1);
+            fprintf(fidTeX, '$%s$  & %8.4f & %7.4f & %7.4f \\\\ \n', ...
+                    M_.exo_names_tex{k}, ...
+                    xparam1(ip), ...
+                    stdh(ip), ...
+                    tstath(ip));
+            ip = ip+1;
+        end
+        TeXEnd(fidTeX)
+    end
 end
 
 
diff --git a/matlab/estimation/do_parameter_initialization.m b/matlab/estimation/do_parameter_initialization.m
index ac6c0a0b2e0c230a874631f1c2c6ecd4ef4ec8d3..f16e5cdd6559467939ea352488c6a6f3388936d0 100644
--- a/matlab/estimation/do_parameter_initialization.m
+++ b/matlab/estimation/do_parameter_initialization.m
@@ -44,16 +44,18 @@ nvx = size(estim_params_.var_exo,1);
 nvn = size(estim_params_.var_endo,1);
 ncx = size(estim_params_.corrx,1);
 ncn = size(estim_params_.corrn,1);
+nsx = size(estim_params_.skew_exo,1);
 np = size(estim_params_.param_vals,1);
 
 estim_params_.nvx = nvx; %exogenous shock variances
 estim_params_.nvn = nvn; %endogenous variances, i.e. measurement error
 estim_params_.ncx = ncx; %exogenous shock correlations
 estim_params_.ncn = ncn; % correlation between endogenous variables, i.e. measurement error.
+estim_params_.nsx = nsx; % skewness parameters of independent shocks
 estim_params_.np = np;   % other parameters of the model
 
-xparam1_explicitly_initialized = NaN(nvx+nvn+ncx+ncn+np,1);
-xparam1_properly_calibrated = NaN(nvx+nvn+ncx+ncn+np,1);
+xparam1_explicitly_initialized = NaN(nvx+nvn+ncx+ncn+nsx+np,1);
+xparam1_properly_calibrated = NaN(nvx+nvn+ncx+ncn+nsx+np,1);
 
 offset=0;
 if nvx
@@ -125,6 +127,19 @@ if ncn
     end
 end
 offset=offset+ncn;
+if nsx
+    initialized_par_index=find(~isnan(estim_params_.skew_exo(:,2)));
+    calibrated_par_index=find(isnan(estim_params_.skew_exo(:,2)) & ~isnan(xparam1_calib(offset+1:offset+nsx,1)));
+    uninitialized_par_index=find(isnan(estim_params_.skew_exo(:,2)) & isnan(xparam1_calib(offset+1:offset+nsx,1)));
+    xparam1_explicitly_initialized(offset+initialized_par_index,1) = estim_params_.skew_exo(initialized_par_index,2);
+    estim_params_.skew_exo(calibrated_par_index,2)=xparam1_calib(offset+calibrated_par_index,1);
+    xparam1_properly_calibrated(offset+calibrated_par_index,1) = xparam1_calib(offset+calibrated_par_index,1);
+    if uninitialized_par_index
+        fprintf('PARAMETER INITIALIZATION: Warning, some estimated skewness coefficients of shocks are not\n')
+        fprintf('PARAMETER INITIALIZATION: initialized. They will be initialized with the prior mean.\n')
+    end
+end
+offset=offset+nsx;
 if np
     initialized_par_index=find(~isnan(estim_params_.param_vals(:,2)));
     calibrated_par_index=find(isnan(estim_params_.param_vals(:,2)) & ~isnan(xparam1_calib(offset+1:offset+np,1)));
diff --git a/matlab/estimation/dsge_likelihood.m b/matlab/estimation/dsge_likelihood.m
index 6a72e9e38a4b97c9e3325e36d49582a01e56713a..c85dea0fc7cf6fba19706e8052647469f86f56d8 100644
--- a/matlab/estimation/dsge_likelihood.m
+++ b/matlab/estimation/dsge_likelihood.m
@@ -77,6 +77,11 @@ if ~isempty(xparam1)
     xparam1 = xparam1(:);
 end
 
+% transform parameters back from unbounded to bounded (only during optimization)
+if estim_params_.transformed && any(estim_params_.transform)
+    xparam1(estim_params_.transform==1) = transform_to_bounded(xparam1(estim_params_.transform==1),BoundsInfo.lb(estim_params_.transform==1),BoundsInfo.ub(estim_params_.transform==1));
+end
+
 % Set flag related to analytical derivatives.
 analytic_derivation = options_.analytic_derivation;
 
@@ -135,7 +140,12 @@ if options_.occbin.likelihood.status
     occbin_.info= {options_, dr,endo_steady_state,exo_steady_state,exo_det_steady_state, M_, occbin_options, TTx, RRx, CCx,T0,R0};
 else
     % Linearize the model around the deterministic steady state and extract the matrices of the state equation (T and R).
-    [T,R,SteadyState,info,dr, M_.params] = dynare_resolve(M_,options_,dr, endo_steady_state, exo_steady_state, exo_det_steady_state,'restrict');
+    if isfield(M_,'csn')
+        is_restrict_state_space = false;
+        [T,R,SteadyState,info,dr, M_.params] = dynare_resolve(M_,options_,dr, endo_steady_state, exo_steady_state, exo_det_steady_state);
+    else
+        [T,R,SteadyState,info,dr, M_.params] = dynare_resolve(M_,options_,dr, endo_steady_state, exo_steady_state, exo_det_steady_state,'restrict');
+    end
     occbin_.status = false;
 end
 
@@ -626,13 +636,32 @@ if ((kalman_algo==1) || (kalman_algo==3))% Multivariate Kalman Filter
                                               T,Q,R,Z,Zflag,H,diffuse_periods, ...
                                               options_.presample);
             else
-                [LIK,lik] = kalman_filter(Y,diffuse_periods+1,size(Y,2), ...
-                                          a_0_given_tm1,Pstar, ...
-                                          kalman_tol, riccati_tol, ...
-                                          options_.rescale_prediction_error_covariance, ...
-                                          options_.presample, ...
-                                          T,Q,R,H,Z,mm,pp,rr,Zflag,diffuse_periods, ...
-                                          analytic_deriv_info{:});
+                if all(M_.Skew_e==0) && ~options_.kalman.pskf.use_in_gaussian_case
+                    [LIK,lik] = kalman_filter(Y,diffuse_periods+1,size(Y,2), ...
+                                              a_0_given_tm1,Pstar, ...
+                                              kalman_tol, riccati_tol, ...
+                                              options_.rescale_prediction_error_covariance, ...
+                                              options_.presample, ...
+                                              T,Q,R,H,Z,mm,pp,rr,Zflag,diffuse_periods, ...
+                                              analytic_deriv_info{:});
+                else
+                    Z = zeros(length(bayestopt_.mf),size(T,1));
+                    for i = 1:length(bayestopt_.mf)
+                        Z(i,bayestopt_.mf(i)) = 1;
+                    end
+                    Zflag = 1;
+                    Gamma_0 = zeros(size(Pstar)); % initialize at Gaussian distribution
+                    nu_0    = zeros(size(a)); % normalization
+                    Delta_0 = eye(size(a,1)); % normalization
+                    [LIK, lik] = kalman_filter_pruned_skewed( ...
+                                    Y,diffuse_periods+1,size(Y,2), ...
+                                    a,Pstar,Gamma_0,nu_0,Delta_0, ...
+                                    kalman_tol,riccati_tol,options_.rescale_prediction_error_covariance,...
+                                    options_.presample,diffuse_periods, ...
+                                    T,R,Z,Zflag, ...
+                                    M_.csn.mu_e,M_.csn.Sigma_e,M_.csn.Gamma_e,M_.csn.nu_e,M_.csn.Delta_e,H, ...
+                                    options_.kalman.pskf.prune_tol);
+                end
             end
         end
     else
diff --git a/matlab/estimation/dynare_estimation_1.m b/matlab/estimation/dynare_estimation_1.m
index e82e4389ddcb1e9669c851d9068a8734f33bb00d..8f174bc2d47d1eed09bac2768975dc3d8189d49b 100644
--- a/matlab/estimation/dynare_estimation_1.m
+++ b/matlab/estimation/dynare_estimation_1.m
@@ -154,8 +154,9 @@ nvx = estim_params_.nvx;  % Variance of the structural innovations (number of pa
 nvn = estim_params_.nvn;  % Variance of the measurement innovations (number of parameters).
 ncx = estim_params_.ncx;  % Covariance of the structural innovations (number of parameters).
 ncn = estim_params_.ncn;  % Covariance of the measurement innovations (number of parameters).
+nsx = estim_params_.nsx;  % Skewness of the structural innovations (number of parameters).
 np  = estim_params_.np ;  % Number of deep parameters.
-nx  = nvx+nvn+ncx+ncn+np; % Total number of parameters to be estimated.
+nx  = nvx+nvn+ncx+ncn+nsx+np; % Total number of parameters to be estimated.
 
 if ~isempty(estim_params_)
     M_ = set_all_parameters(xparam1,estim_params_,M_);
@@ -245,7 +246,15 @@ if ~isequal(options_.mode_compute,0) && ~options_.mh_posterior_mode_estimation &
                 end
             end
         end
-        [xparam1, fval, ~, hh, options_, Scale, new_rat_hess_info] = dynare_minimize_objective(objective_function,xparam1,current_optimizer,options_,[bounds.lb bounds.ub],bayestopt_.name,bayestopt_,hh,dataset_,dataset_info,options_,M_,estim_params_,bayestopt_,bounds,oo_.dr, oo_.steady_state,oo_.exo_steady_state,oo_.exo_det_steady_state);
+        % transform parameters from bounded to unbounded domain
+        bounds0 = bounds;
+        if any(estim_params_.transform)
+            estim_params_.transformed = true;
+            xparam1(estim_params_.transform==1) = transform_to_unbounded(xparam1(estim_params_.transform==1),bounds0.lb(estim_params_.transform==1),bounds0.ub(estim_params_.transform==1));
+            bounds.lb(estim_params_.transform==1) = -Inf;
+            bounds.ub(estim_params_.transform==1) = Inf;
+        end
+        [xparam1, fval, ~, hh, options_, Scale, new_rat_hess_info] = dynare_minimize_objective(objective_function,xparam1,current_optimizer,options_,[bounds.lb bounds.ub],bayestopt_.name,bayestopt_,hh,dataset_,dataset_info,options_,M_,estim_params_,bayestopt_,bounds0,oo_.dr, oo_.steady_state,oo_.exo_steady_state,oo_.exo_det_steady_state);
         fprintf('\nFinal value of minus the log posterior (or likelihood):%f \n', fval);
 
         if isnumeric(current_optimizer)
@@ -261,6 +270,14 @@ if ~isequal(options_.mode_compute,0) && ~options_.mh_posterior_mode_estimation &
                 bayestopt_.jscale(:) = options_.mh_jscale;
             end
         end
+
+        % transform parameters back from unbounded to bounded
+        if any(estim_params_.transform)
+            estim_params_.transformed = false;
+            bounds = bounds0;
+            xparam1(estim_params_.transform==1) = transform_to_bounded(xparam1(estim_params_.transform==1),bounds0.lb(estim_params_.transform==1),bounds0.ub(estim_params_.transform==1));
+        end
+
         if ~isnumeric(current_optimizer) || ~isequal(current_optimizer,6) %always already computes covariance matrix
             if options_.cova_compute == 1 %user did not request covariance not to be computed
                 if options_.analytic_derivation && strcmp(func2str(objective_function),'dsge_likelihood')
@@ -275,9 +292,17 @@ if ~isequal(options_.mode_compute,0) && ~options_.mh_posterior_mode_estimation &
                     % the hessian from outer product gradient of optimizer 5 below
                     if options_.hessian.use_penalized_objective
                         penalized_objective_function = str2func('penalty_objective_function');
-                        hh = hessian(penalized_objective_function, xparam1, options_.gstep, objective_function, fval, dataset_, dataset_info, options_, M_, estim_params_, bayestopt_, bounds,oo_.dr,oo_.steady_state,oo_.exo_steady_state,oo_.exo_det_steady_state);
+                        if isfield(options_.hessian,'use_onesided') && options_.hessian.use_onesided == 1
+                            hh = hessian_with_bounds(penalized_objective_function, xparam1, options_.gstep, bounds, objective_function, fval, dataset_, dataset_info, options_, M_, estim_params_, bayestopt_, bounds,oo_.dr,oo_.steady_state,oo_.exo_steady_state,oo_.exo_det_steady_state);
+                        else
+                            hh = hessian(penalized_objective_function, xparam1, options_.gstep, objective_function, fval, dataset_, dataset_info, options_, M_, estim_params_, bayestopt_, bounds,oo_.dr,oo_.steady_state,oo_.exo_steady_state,oo_.exo_det_steady_state);
+                        end
                     else
-                        hh = hessian(objective_function, xparam1, options_.gstep, dataset_, dataset_info, options_, M_, estim_params_, bayestopt_, bounds,oo_.dr,oo_.steady_state,oo_.exo_steady_state,oo_.exo_det_steady_state);
+                        if isfield(options_.hessian,'use_onesided') && options_.hessian.use_onesided == 1
+                            hh = hessian_with_bounds(objective_function, xparam1, options_.gstep, bounds, dataset_, dataset_info, options_, M_, estim_params_, bayestopt_, bounds,oo_.dr,oo_.steady_state,oo_.exo_steady_state,oo_.exo_det_steady_state);
+                        else
+                            hh = hessian(objective_function, xparam1, options_.gstep, dataset_, dataset_info, options_, M_, estim_params_, bayestopt_, bounds,oo_.dr,oo_.steady_state,oo_.exo_steady_state,oo_.exo_det_steady_state);
+                        end
                     end 
                     hh = reshape(hh, nx, nx);
                 elseif isnumeric(current_optimizer) && isequal(current_optimizer,5)
@@ -587,7 +612,9 @@ elseif options_.partial_information ||...
     % smoothing not yet supported
 else
     %% ML estimation, or posterior mode without Metropolis-Hastings or Metropolis without Bayesian smoothed variables
-    oo_=save_display_classical_smoother_results(xparam1,M_,oo_,options_,bayestopt_,dataset_,dataset_info,estim_params_);
+    if ~isfield(M_,'csn')
+        oo_=save_display_classical_smoother_results(xparam1,M_,oo_,options_,bayestopt_,dataset_,dataset_info,estim_params_);
+    end
 end
 
 if options_.forecast == 0 || options_.mh_replic > 0 || options_.load_mh_file
diff --git a/matlab/estimation/dynare_estimation_init.m b/matlab/estimation/dynare_estimation_init.m
index ffa982c0c29a434a867a655288db6e00f0d217b1..d9dec60e96708eaf2a0a3f66b346ea227aa7e303 100644
--- a/matlab/estimation/dynare_estimation_init.m
+++ b/matlab/estimation/dynare_estimation_init.m
@@ -138,7 +138,7 @@ else
 end
 
 % Set priors over the estimated parameters.
-if ~isempty(estim_params_) && ~(isfield(estim_params_,'nvx') && (size(estim_params_.var_exo,1)+size(estim_params_.var_endo,1)+size(estim_params_.corrx,1)+size(estim_params_.corrn,1)+size(estim_params_.param_vals,1))==0)
+if ~isempty(estim_params_) && ~(isfield(estim_params_,'nvx') && (size(estim_params_.skew_exo,1)+size(estim_params_.var_exo,1)+size(estim_params_.var_endo,1)+size(estim_params_.corrx,1)+size(estim_params_.corrn,1)+size(estim_params_.param_vals,1))==0)
     [xparam1,estim_params_,bayestopt_,lb,ub,M_] = set_prior(estim_params_,M_,options_);
 end
 
@@ -152,12 +152,12 @@ if exist([M_.fname '_prior_restrictions.m'],'file')
 end
 
 % Check that the provided mode_file is compatible with the current estimation settings.
-if ~isempty(estim_params_) && ~(isfield(estim_params_,'nvx') && sum(estim_params_.nvx+estim_params_.nvn+estim_params_.ncx+estim_params_.ncn+estim_params_.np)==0) && ~isempty(options_.mode_file) && ~options_.mh_posterior_mode_estimation
+if ~isempty(estim_params_) && ~(isfield(estim_params_,'nvx') && sum(estim_params_.nvx+estim_params_.nvn+estim_params_.ncx+estim_params_.ncn+estim_params_.nsx+estim_params_.np)==0) && ~isempty(options_.mode_file) && ~options_.mh_posterior_mode_estimation
     [xparam1, hh] = check_mode_file(xparam1, hh, options_, bayestopt_);
 end
 
 %check for calibrated covariances before updating parameters
-if ~isempty(estim_params_) && ~(isfield(estim_params_,'nvx') && sum(estim_params_.nvx+estim_params_.nvn+estim_params_.ncx+estim_params_.ncn+estim_params_.np)==0)
+if ~isempty(estim_params_) && ~(isfield(estim_params_,'nvx') && sum(estim_params_.nvx+estim_params_.nvn+estim_params_.ncx+estim_params_.ncn+estim_params_.nsx+estim_params_.np)==0)
     estim_params_=check_for_calibrated_covariances(estim_params_,M_);
 end
 
@@ -180,7 +180,7 @@ if ~isempty(bayestopt_) && all(bayestopt_.pshape==0) && any(isnan(xparam1))
     error('ML estimation requires all estimated parameters to be initialized, either in an estimated_params or estimated_params_init-block ')
 end
 
-if ~isempty(estim_params_) && ~(all(strcmp(fieldnames(estim_params_),'full_calibration_detected'))  || (isfield(estim_params_,'nvx') && sum(estim_params_.nvx+estim_params_.nvn+estim_params_.ncx+estim_params_.ncn+estim_params_.np)==0))
+if ~isempty(estim_params_) && ~(all(strcmp(fieldnames(estim_params_),'full_calibration_detected'))  || (isfield(estim_params_,'nvx') && sum(estim_params_.nvx+estim_params_.nvn+estim_params_.ncx+estim_params_.ncn+estim_params_.nsx+estim_params_.np)==0))
     if ~isempty(bayestopt_) && any(bayestopt_.pshape > 0)
         % Plot prior densities.
         if ~options_.nograph && options_.plot_priors
@@ -210,7 +210,7 @@ if ~isempty(estim_params_) && ~(all(strcmp(fieldnames(estim_params_),'full_calib
     end
 end
 
-if isempty(estim_params_) || all(strcmp(fieldnames(estim_params_),'full_calibration_detected')) || (isfield(estim_params_,'nvx') && sum(estim_params_.nvx+estim_params_.nvn+estim_params_.ncx+estim_params_.ncn+estim_params_.np)==0) % If estim_params_ is empty (e.g. when running the smoother on a calibrated model)
+if isempty(estim_params_) || all(strcmp(fieldnames(estim_params_),'full_calibration_detected')) || (isfield(estim_params_,'nvx') && sum(estim_params_.nvx+estim_params_.nvn+estim_params_.ncx+estim_params_.ncn+estim_params_.nsx+estim_params_.np)==0) % If estim_params_ is empty (e.g. when running the smoother on a calibrated model)
     if ~options_.smoother
         error('Estimation: the ''estimated_params'' block is mandatory (unless you are running a smoother)')
     end
@@ -229,11 +229,13 @@ if isempty(estim_params_) || all(strcmp(fieldnames(estim_params_),'full_calibrat
     estim_params_.var_endo=[];
     estim_params_.corrx=[];
     estim_params_.corrn=[];
+    estim_params_.skew_exo=[];
     estim_params_.param_vals=[];
     estim_params_.nvx = 0;
     estim_params_.nvn = 0;
     estim_params_.ncx = 0;
     estim_params_.ncn = 0;
+    estim_params_.nsx = 0;
     estim_params_.np = 0;
     bounds.lb = [];
     bounds.ub = [];
@@ -333,7 +335,7 @@ if options_.analytic_derivation
         if isfield(options_,'identification_check_endogenous_params_with_no_prior')
             M_local.params = M_local.params*1.01; %vary parameters
         else
-            M_local.params(estim_params_.param_vals(:,1)) = xparam1(estim_params_.nvx+estim_params_.ncx+estim_params_.nvn+estim_params_.ncn+1:end); %set parameters
+            M_local.params(estim_params_.param_vals(:,1)) = xparam1(estim_params_.nvx+estim_params_.ncx+estim_params_.nvn+estim_params_.nsx+estim_params_.ncn+1:end); %set parameters
             M_local.params(estim_params_.param_vals(:,1)) = M_local.params(estim_params_.param_vals(:,1))*1.01; %vary parameters
         end
         if options_.diffuse_filter || options_.steadystate.nocheck
@@ -416,8 +418,9 @@ nvx = estim_params_.nvx;
 ncx = estim_params_.ncx;
 nvn = estim_params_.nvn;
 ncn = estim_params_.ncn;
+nsx = estim_params_.nsx;
 if estim_params_.np
-    M_local.params(estim_params_.param_vals(:,1)) = xparam1(nvx+ncx+nvn+ncn+1:end);
+    M_local.params(estim_params_.param_vals(:,1)) = xparam1(nvx+ncx+nvn+ncn+nsx+1:end);
 end
 [oo_.steady_state, params,info] = evaluate_steady_state(oo_.steady_state,[oo_.exo_steady_state; oo_.exo_det_steady_state],M_local,options_,steadystate_check_flag);
 
diff --git a/matlab/estimation/execute_prior_posterior_function.m b/matlab/estimation/execute_prior_posterior_function.m
index 898cf63005952007353f40404ec49f83ee749613..d39c1f15b88f715b54436656f6f73884d7312cd6 100644
--- a/matlab/estimation/execute_prior_posterior_function.m
+++ b/matlab/estimation/execute_prior_posterior_function.m
@@ -62,7 +62,7 @@ if strcmpi(type,'posterior')
 elseif strcmpi(type,'prior')
     % Get informations about the prior distribution.
     if isempty(bayestopt_)
-        if ~isempty(estim_params_) && ~(isfield(estim_params_,'nvx') && (size(estim_params_.var_exo,1)+size(estim_params_.var_endo,1)+size(estim_params_.corrx,1)+size(estim_params_.corrn,1)+size(estim_params_.param_vals,1))==0)
+        if ~isempty(estim_params_) && ~(isfield(estim_params_,'nvx') && (size(estim_params_.var_exo,1)+size(estim_params_.var_endo,1)+size(estim_params_.corrx,1)+size(estim_params_.corrn,1)+size(estim_params_.skew_exo,1)+size(estim_params_.param_vals,1))==0)
             [~,estim_params_,bayestopt_,~,~,M_] = set_prior(estim_params_,M_,options_);
         else
             error('The prior distributions are not properly set up.')
diff --git a/matlab/estimation/fill_mh_mode.m b/matlab/estimation/fill_mh_mode.m
index 0d2581ce108a843c92e368fe0f84750114b733f1..7cd90d5c7bf2f95e45d4dffc40f2b577f717ffc1 100644
--- a/matlab/estimation/fill_mh_mode.m
+++ b/matlab/estimation/fill_mh_mode.m
@@ -37,10 +37,11 @@ nvx = estim_params_.nvx;  % Variance of the structural innovations (number of pa
 nvn = estim_params_.nvn;  % Variance of the measurement innovations (number of parameters).
 ncx = estim_params_.ncx;  % Covariance of the structural innovations (number of parameters).
 ncn = estim_params_.ncn;  % Covariance of the measurement innovations (number of parameters).
+nsx = estim_params_.nsx;  % Skewness of the structural innovations (numberr of parameters).
 np  = estim_params_.np ;  % Number of deep parameters.
 
 if np
-    ip = nvx+nvn+ncx+ncn+1;
+    ip = nvx+nvn+ncx+ncn+nsx+1;
     for i=1:np
         k = estim_params_.param_vals(i,1);
         name = M_.param_names{k};
@@ -68,7 +69,6 @@ if nvn
         ip = ip+1;
     end
 end
-
 if ncx
     ip = nvx+nvn+1;
     for i=1:ncx
@@ -80,7 +80,6 @@ if ncx
         ip = ip+1;
     end
 end
-
 if ncn
     ip = nvx+nvn+ncx+1;
     for i=1:ncn
@@ -92,3 +91,13 @@ if ncn
         ip = ip+1;
     end
 end
+if nsx
+    ip = nvx+nvn+ncx+ncn+1;
+    for i=1:nsx
+        k = estim_params_.skew_exo(i,1);
+        name = M_.exo_names{k};
+        oo_.([field_name '_mode']).shocks_skew.(name)= xparam1(ip);
+        oo_.([field_name '_std_at_mode']).shocks_skew.(name) = stdh(ip);
+        ip = ip+1;
+    end
+end
\ No newline at end of file
diff --git a/matlab/estimation/get_posterior_parameters.m b/matlab/estimation/get_posterior_parameters.m
index ffec01826c5485dbe5c17b7591bfbf418cb09ddf..679d570d8a41bc477d7bee437376439b3c5438cd 100644
--- a/matlab/estimation/get_posterior_parameters.m
+++ b/matlab/estimation/get_posterior_parameters.m
@@ -39,9 +39,10 @@ nvx = estim_params_.nvx;
 nvn = estim_params_.nvn;
 ncx = estim_params_.ncx;
 ncn = estim_params_.ncn;
+nsx = estim_params_.nsx;
 np  = estim_params_.np;
 
-xparam = zeros(nvx+nvn+ncx+ncn+np,1);
+xparam = zeros(nvx+nvn+ncx+ncn+nsx+np,1);
 
 m = 1;
 for i=1:nvx
@@ -76,6 +77,13 @@ for i=1:ncn
     m = m+1;
 end
 
+for i=1:nsx
+    k1 = estim_params_.skew_exo(i,1);
+    name1 = M_.exo_names{k1};
+    xparam(m) = oo_.([field1 type]).shocks_skew.(name1);
+    m = m+1;
+end
+
 FirstDeep = m;
 
 for i=1:np
diff --git a/matlab/estimation/initial_estimation_checks.m b/matlab/estimation/initial_estimation_checks.m
index 03596d646e0ae361b0770b4244e8a600e8e9f253..99dc35ab7edb3c1f7aa69f103d895a76c5ca3387 100644
--- a/matlab/estimation/initial_estimation_checks.m
+++ b/matlab/estimation/initial_estimation_checks.m
@@ -166,7 +166,7 @@ end
 
 % check and display warning if negative values of stderr or corr params are outside unit circle for Bayesian estimation
 if any(bayestopt_.pshape)
-    check_prior_stderr_corr(estim_params_,bayestopt_);
+    check_prior_stderr_corr_skew(estim_params_,bayestopt_);
 end
 
 % display warning if some parameters are still NaN
diff --git a/matlab/estimation/prior_posterior_statistics.m b/matlab/estimation/prior_posterior_statistics.m
index a0fb6128cc73a382992d562163771867004122db..9ecc415942419b54bf7e1da1176091d9a8a62d32 100644
--- a/matlab/estimation/prior_posterior_statistics.m
+++ b/matlab/estimation/prior_posterior_statistics.m
@@ -48,7 +48,7 @@ Y = transpose(dataset_.data);
 gend = dataset_.nobs;
 
 nvn  = estim_params_.nvn;
-npar = estim_params_.nvx+nvn+estim_params_.ncx+estim_params_.ncn+estim_params_.np;
+npar = estim_params_.nvx+nvn+estim_params_.ncx+estim_params_.ncn+nvn+estim_params_.nsx+estim_params_.np;
 naK = length(options_.filter_step_ahead);
 
 MaxNumberOfBytes=options_.MaxNumberOfBytes;
diff --git a/matlab/estimation/selec_posterior_draws.m b/matlab/estimation/selec_posterior_draws.m
index 161f8e8e39f284442928c94723c02036e7ebd6c6..cb94d33b4563e14f992fcca3a6c015cae650f93d 100644
--- a/matlab/estimation/selec_posterior_draws.m
+++ b/matlab/estimation/selec_posterior_draws.m
@@ -47,6 +47,7 @@ npar = estim_params_.nvx;
 npar = npar + estim_params_.nvn;
 npar = npar + estim_params_.ncx;
 npar = npar + estim_params_.ncn;
+npar = npar + estim_params_.nsx;
 npar = npar + estim_params_.np;
 
 % Select one task:
diff --git a/matlab/estimation/set_prior.m b/matlab/estimation/set_prior.m
index 3069a8a09598ace5870d106aee51f254b80af1d9..5d16342ac3da64054dcc0602c66fd2332957c593 100644
--- a/matlab/estimation/set_prior.m
+++ b/matlab/estimation/set_prior.m
@@ -39,13 +39,17 @@ nvx = size(estim_params_.var_exo,1);
 nvn = size(estim_params_.var_endo,1);
 ncx = size(estim_params_.corrx,1);
 ncn = size(estim_params_.corrn,1);
+nsx = size(estim_params_.skew_exo,1);
 np = size(estim_params_.param_vals,1);
 
 estim_params_.nvx = nvx; %exogenous shock variances
 estim_params_.nvn = nvn; %endogenous variances, i.e. measurement error
 estim_params_.ncx = ncx; %exogenous shock correlations
 estim_params_.ncn = ncn; % correlation between endogenous variables, i.e. measurement error.
+estim_params_.nsx = nsx; %exogenous shock skewness
 estim_params_.np = np;   % other parameters of the model
+estim_params_.transform = []; % index for transformed parameters
+estim_params_.transformed = false; % indicator whether current parameters are transformed (only during optimization)
 
 xparam1 = [];
 ub = []; % Upper bound imposed for optimization.
@@ -55,23 +59,24 @@ bayestopt_.p1 = []; % prior mean
 bayestopt_.p2 = []; % prior standard deviation
 bayestopt_.p3 = []; % lower bound of the distribution, only considering whether a generalized distribution is used, not when the prior is truncated
 bayestopt_.p4 = []; % upper bound of the distribution, only considering whether a generalized distribution is used, not when the prior is truncated
-bayestopt_.p5 = zeros(nvx+nvn+ncx+ncn+np,1); % prior mode
+bayestopt_.p5 = zeros(nvx+nvn+ncx+ncn+nsx+np,1); % prior mode
 bayestopt_.p6 = []; % first hyper-parameter (\alpha for the BETA and GAMMA distributions, s for the INVERSE GAMMAs, expectation for the GAUSSIAN distribution, lower bound for the UNIFORM distribution).
 bayestopt_.p7 = []; % second hyper-parameter (\beta for the BETA and GAMMA distributions, \nu for the INVERSE GAMMAs, standard deviation for the GAUSSIAN distribution, upper bound for the UNIFORM distribution).
 
 bayestopt_.jscale = []; %jscale might subsequently be overwritten by mode_compute=6 or check_posterior_sampler_options
 bayestopt_.name = {};
 if nvx
-    xparam1 = estim_params_.var_exo(:,2);
-    ub = estim_params_.var_exo(:,4);
-    lb = estim_params_.var_exo(:,3);
-    bayestopt_.pshape =  estim_params_.var_exo(:,5);
-    bayestopt_.p1 =  estim_params_.var_exo(:,6);
-    bayestopt_.p2 =  estim_params_.var_exo(:,7);
-    bayestopt_.p3 =  estim_params_.var_exo(:,8); %take generalized distribution into account
-    bayestopt_.p4 =  estim_params_.var_exo(:,9); %take generalized distribution into account
-    bayestopt_.jscale =  estim_params_.var_exo(:,10);
-    bayestopt_.name = M_.exo_names(estim_params_.var_exo(:,1));
+    xparam1 = [xparam1; estim_params_.var_exo(:,2)];
+    ub = [ub; estim_params_.var_exo(:,4)];
+    lb = [lb; estim_params_.var_exo(:,3)];
+    estim_params_.transform = [estim_params_.transform; estim_params_.var_exo(:,11)];
+    bayestopt_.pshape = [ bayestopt_.pshape; estim_params_.var_exo(:,5)];
+    bayestopt_.p1 =  [ bayestopt_.p1; estim_params_.var_exo(:,6) ];
+    bayestopt_.p2 =  [ bayestopt_.p2; estim_params_.var_exo(:,7) ];
+    bayestopt_.p3 =  [ bayestopt_.p3; estim_params_.var_exo(:,8) ]; %take generalized distribution into account
+    bayestopt_.p4 =  [ bayestopt_.p4; estim_params_.var_exo(:,9) ]; %take generalized distribution into account
+    bayestopt_.jscale =  [ bayestopt_.jscale; estim_params_.var_exo(:,10) ];
+    bayestopt_.name = [ bayestopt_.name; M_.exo_names(estim_params_.var_exo(:,1)) ];
 end
 if nvn
     estim_params_.nvn_observable_correspondence=NaN(nvn,1); % stores number of corresponding observable
@@ -90,6 +95,7 @@ if nvn
     xparam1 = [xparam1; estim_params_.var_endo(:,2)];
     ub = [ub; estim_params_.var_endo(:,4)];
     lb = [lb; estim_params_.var_endo(:,3)];
+    estim_params_.transform = [estim_params_.transform; estim_params_.var_endo(:,11)];
     bayestopt_.pshape = [ bayestopt_.pshape; estim_params_.var_endo(:,5)];
     bayestopt_.p1 = [ bayestopt_.p1; estim_params_.var_endo(:,6)];
     bayestopt_.p2 = [ bayestopt_.p2; estim_params_.var_endo(:,7)];
@@ -102,6 +108,7 @@ if ncx
     xparam1 = [xparam1; estim_params_.corrx(:,3)];
     ub = [ub; max(min(estim_params_.corrx(:,5),1),-1)];
     lb = [lb; min(max(estim_params_.corrx(:,4),-1),1)];
+    estim_params_.transform = [estim_params_.transform; estim_params_.corrx(:,12)];
     bayestopt_.pshape = [ bayestopt_.pshape; estim_params_.corrx(:,6)];
     bayestopt_.p1 = [ bayestopt_.p1; estim_params_.corrx(:,7)];
     bayestopt_.p2 = [ bayestopt_.p2; estim_params_.corrx(:,8)];
@@ -122,10 +129,12 @@ if ncn
         nvarobs = length(options_.varobs);
         M_.H = zeros(nvarobs,nvarobs);
         M_.Correlation_matrix_ME = eye(nvarobs);
+        M_.Sigma_eps = M_.H;
     end
     xparam1 = [xparam1; estim_params_.corrn(:,3)];
     ub = [ub; max(min(estim_params_.corrn(:,5),1),-1)];
     lb = [lb; min(max(estim_params_.corrn(:,4),-1),1)];
+    estim_params_.transform = [estim_params_.transform; estim_params_.corrn(:,12)];
     bayestopt_.pshape = [ bayestopt_.pshape; estim_params_.corrn(:,6)];
     bayestopt_.p1 = [ bayestopt_.p1; estim_params_.corrn(:,7)];
     bayestopt_.p2 = [ bayestopt_.p2; estim_params_.corrn(:,8)];
@@ -145,10 +154,28 @@ if ncn
         estim_params_.corrn_observable_correspondence(i,:)=[obsi1, obsi2];
     end
 end
+if nsx
+    xparam1 = [xparam1; estim_params_.skew_exo(:,2)];
+    ub = [ub; estim_params_.skew_exo(:,4)];
+    lb = [lb; estim_params_.skew_exo(:,3)];
+    estim_params_.transform = [estim_params_.transform; estim_params_.skew_exo(:,11)];
+    bayestopt_.pshape = [ bayestopt_.pshape; estim_params_.skew_exo(:,5)];
+    bayestopt_.p1 =  [ bayestopt_.p1; estim_params_.skew_exo(:,6) ];
+    bayestopt_.p2 =  [ bayestopt_.p2; estim_params_.skew_exo(:,7) ];
+    bayestopt_.p3 =  [ bayestopt_.p3; estim_params_.skew_exo(:,8) ]; %take generalized distribution into account
+    bayestopt_.p4 =  [ bayestopt_.p4; estim_params_.skew_exo(:,9) ]; %take generalized distribution into account
+    bayestopt_.jscale =  [ bayestopt_.jscale; estim_params_.skew_exo(:,10) ];
+    baseid = length(bayestopt_.name);
+    bayestopt_.name = [bayestopt_.name; cell(nsx, 1)];
+    for i = 1:nsx
+        bayestopt_.name(baseid+i) = {sprintf('skew %s', M_.exo_names{estim_params_.skew_exo(i,1)})};
+    end
+end
 if np
     xparam1 = [xparam1; estim_params_.param_vals(:,2)];
     ub = [ub; estim_params_.param_vals(:,4)];
     lb = [lb; estim_params_.param_vals(:,3)];
+    estim_params_.transform = [estim_params_.transform; estim_params_.param_vals(:,11)];
     bayestopt_.pshape = [ bayestopt_.pshape; estim_params_.param_vals(:,5)];
     bayestopt_.p1 = [ bayestopt_.p1; estim_params_.param_vals(:,6)];
     bayestopt_.p2 = [ bayestopt_.p2; estim_params_.param_vals(:,7)];
diff --git a/matlab/get_all_parameters.m b/matlab/get_all_parameters.m
index 8c7614a81d1b9ebf63fe9f158093f90baa740bf1..5a95e19e5d6ba675308d64195b77dc2d027098d7 100644
--- a/matlab/get_all_parameters.m
+++ b/matlab/get_all_parameters.m
@@ -37,20 +37,24 @@ if ~isempty(estim_params_)
     ncx = estim_params_.ncx;
     nvn = estim_params_.nvn;
     ncn = estim_params_.ncn;
+    nsx = estim_params_.nsx;
     np = estim_params_.np;
 else
     nvx = 0;
     ncx = 0;
     nvn = 0;
     ncn = 0;
+    nsx = 0;
     np = 0;
 end
 Sigma_e = M_.Sigma_e;
 Correlation_matrix = M_.Correlation_matrix;
 H = M_.H;
 Correlation_matrix_ME = M_.Correlation_matrix_ME;
+Skew_e = M_.Skew_e;
+
+xparam1=NaN(nvx+nvn+ncx+ncn+nsx+np,1);
 
-xparam1=NaN(nvx+ncx+nvn+ncn+np,1);
 % stderrs of the exogenous shocks
 if nvx
     var_exo = estim_params_.var_exo;
@@ -59,21 +63,18 @@ if nvx
         xparam1(i)=sqrt(Sigma_e(k,k));
     end
 end
-% update offset
-offset = nvx;
+offset = nvx; % update offset
 
-% setting measument error variance
+% stderr of measurement errors
 if nvn
     for i=1:nvn
         k = estim_params_.nvn_observable_correspondence(i,1);
         xparam1(offset+i)=sqrt(H(k,k));
     end
 end
+offset = nvx+nvn; % update offset
 
-% update offset
-offset = nvx+nvn;
-
-% correlations among shocks (ncx)
+% correlations among shocks
 if ncx
     corrx = estim_params_.corrx;
     for i=1:ncx
@@ -82,9 +83,9 @@ if ncx
         xparam1(i+offset)=Correlation_matrix(k1,k2);
     end
 end
-% update offset
-offset = nvx+nvn+ncx;
+offset = nvx+nvn+ncx; % update offset
 
+% correlations among measurement errors
 if ncn
     corrn_observable_correspondence = estim_params_.corrn_observable_correspondence;
     for i=1:ncn
@@ -93,10 +94,17 @@ if ncn
         xparam1(i+offset)=Correlation_matrix_ME(k1,k2);
     end
 end
+offset = nvx+nvn+ncx+ncn; % update offset
 
+if nsx
+    skew_exo = estim_params_.skew_exo;
+    for i=1:nsx
+        k = skew_exo(i,1);
+        xparam1(i+offset)=Skew_e(k);
+    end
+end
 % update offset
-offset = nvx+ncx+nvn+ncn;
-
+offset = nvx+nvn+ncx+ncn+nsx;
 
 % structural parameters
 if np
diff --git a/matlab/get_error_message.m b/matlab/get_error_message.m
index 7156e3c253c4e7d2dc1b60b35d92491e4d016227..4c5b97a9818d5fa4e9193fd011376e9c8cbee107 100644
--- a/matlab/get_error_message.m
+++ b/matlab/get_error_message.m
@@ -113,6 +113,10 @@ switch info(1)
         message = 'You are estimating a DSGE-VAR model, but the implied covariance matrix of the VAR''s innovations, based on the artificial sample, is not positive definite!';
     case 55
         message = 'Fast Kalman filter only works with stationary models [lik_init=1] or stationary observables for non-stationary models [lik_init=3]';
+    case 56
+        message = 'The skewness transformation failed.';
+    case 57
+        message = 'The skewness coefficient of structural shocks is beyond its theoretical bound.';
     case 61 %Discretionary policy
         message = 'Discretionary policy: maximum number of iterations has been reached. Procedure failed.';
     case 62
diff --git a/matlab/get_the_name.m b/matlab/get_the_name.m
index a373699a7f8ee96cc5fca7fd54d91df102af4a70..b8826e653c03a8ea40972b1f7e23353bd88575ad 100644
--- a/matlab/get_the_name.m
+++ b/matlab/get_the_name.m
@@ -43,6 +43,7 @@ nvx = estim_params_.nvx;
 nvn = estim_params_.nvn;
 ncx = estim_params_.ncx;
 ncn = estim_params_.ncn;
+nsx = estim_params_.nsx;
 
 if k <= nvx
     vname = M_.exo_names{estim_params_.var_exo(k,1)};
@@ -78,8 +79,16 @@ elseif  k <= (nvx+nvn+ncx+ncn)
         tname  = sprintf('%s,%s', M_.endo_names_tex{k1}, M_.endo_names_tex{k2});
         texnam = sprintf('$ \\rho^{ME}_{%s} $', tname);
     end
-else
+elseif k <= (nvx+nvn+ncx+ncn+nsx)
     jj = k - (nvx+nvn+ncx+ncn);
+    vname = M_.exo_names{estim_params_.skew_exo(jj,1)};
+    nam = sprintf('SKEW_%s', vname);
+    if TeX
+        tname  = M_.exo_names_tex{estim_params_.skew_exo(jj,1)};
+        texnam = sprintf('$ skew_{%s} $', tname);
+    end
+else
+    jj = k - (nvx+nvn+ncx+ncn+nsx);
     jj1 = estim_params_.param_vals(jj,1);
     nam = M_.param_names{jj1};
     if TeX
diff --git a/matlab/hessian_with_bounds.m b/matlab/hessian_with_bounds.m
new file mode 100644
index 0000000000000000000000000000000000000000..5ae817046163804fa93c79d7285f771e7d57fabd
--- /dev/null
+++ b/matlab/hessian_with_bounds.m
@@ -0,0 +1,144 @@
+% This file is part of the replication files for the paper "Pruned Skewed
+% Kalman Filter and Smoother: Pruned Skewed Kalman Filter and Smoother:
+% With Applications to the Yield Curve and Asymmetric Monetary Policy Shocks"
+% by Gaygysyz Guljanov, Willi Mutschler, Mark Trede
+
+function hessian_mat = hessian_with_bounds(func, x, gstep, bounds, varargin)
+% Computes second order partial derivatives using two-sided finite
+% difference method.
+% based on get_hessian.m from Dynare with the following changes:
+% - if a step up or down of a parameter passes the lower or upper bounds,
+%   then the partial derivatives are computed using one-sided finite
+%   differences.
+%
+% INPUTS
+%    func        [string]   name of the function
+%    x           [double]   vector, the Hessian of "func" is evaluated at x.
+%    gstep       [double]   scalar, size of epsilon.
+%    varargin    [void]     list of additional arguments for "func".
+%
+% OUTPUTS
+%    hessian_mat [double]   Hessian matrix
+%
+% ALGORITHM
+%    Uses Abramowitz and Stegun (1965) formulas 25.3.23
+% \[
+%     \frac{\partial^2 f_{0,0}}{\partial {x^2}} = \frac{1}{h^2}\left( f_{1,0} - 2f_{0,0} + f_{ - 1,0} \right)
+% \]
+% and 25.3.27 p. 884
+%
+% \[
+%     \frac{\partial ^2f_{0,0}}{\partial x\partial y} = \frac{-1}{2h^2}\left(f_{1,0} + f_{-1,0} + f_{0,1} + f_{0,-1} - 2f_{0,0} - f_{1,1} - f_{-1,-1} \right)
+% \]
+%
+% SPECIAL REQUIREMENTS
+%    none
+%
+
+% Copyright (C) 2001-2017 Dynare Team
+% Copyright (C) 2023 Willi Mutschler
+%
+% This is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% It is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+verbose = false;
+
+if ~isa(func, 'function_handle')
+    func = str2func(func);
+end
+ub = bounds.ub;
+lb = bounds.lb;
+n   = size(x,1);
+h1  = max(abs(x), sqrt(gstep(1))*ones(n, 1))*eps^(1/6)*gstep(2);
+h_1 = h1;
+xh1 = x+h1;
+h1  = xh1-x;
+xh1 = x-h_1;
+h_1 = x-xh1;
+xh1 = x;
+f0  = feval(func, x, varargin{:});
+f1  = zeros(size(f0, 1), n);
+f_1 = f1;
+
+for i=1:n
+    %do step up
+    xh1(i)   = x(i)+h1(i);
+    if xh1(i) <= ub(i)
+        f1(:,i)  = feval(func, xh1, varargin{:});
+    else
+        if verbose
+            fprintf('  - don''t do step up for parameter %d\n',i);
+        end
+        f1(:,i)  = f0;
+    end
+    %do step down
+    xh1(i)   = x(i)-h_1(i);
+    if xh1(i) >= lb(i)        
+        f_1(:,i) = feval(func, xh1, varargin{:});
+    else
+        if verbose
+            fprintf('  - don''t do step down for parameter %d\n',i);
+        end
+        f_1(:,i) = f0;
+    end
+    %reset parameter
+    xh1(i)   = x(i);
+end
+
+xh_1 = xh1;
+temp = f1+f_1-f0*ones(1, n); %term f_(1,0)+f_(-1,0)-f_(0,0) used later
+
+hessian_mat = zeros(size(f0,1), n*n);
+
+for i=1:n
+    if i > 1
+        %fill symmetric part of Hessian based on previously computed results
+        k = [i:n:n*(i-1)];
+        hessian_mat(:,(i-1)*n+1:(i-1)*n+i-1) = hessian_mat(:,k);
+    end
+    hessian_mat(:,(i-1)*n+i) = (f1(:,i)+f_1(:,i)-2*f0)./(h1(i)*h_1(i)); %formula 25.3.23
+    for j=i+1:n
+        %step in up direction
+        xh1(i) = x(i)+h1(i); 
+        if xh1(i) > ub(i)
+            xh1(i) = x(i);
+            if verbose
+                fprintf('  - don''t do cross step up for parameter %d\n',i);
+            end
+        end
+        xh1(j) = x(j)+h_1(j);
+        if xh1(j) > ub(j)
+            xh1(j) = x(j);
+            if verbose
+                fprintf('  - don''t do cross step up for parameter %d\n',j);
+            end
+        end
+        %step in down direction
+        xh_1(i) = x(i)-h1(i);
+        if xh_1(i) < lb(i)
+            xh_1(i) = x(i);
+            if verbose
+                fprintf('  - don''t do cross step down for parameter %d\n',i);
+            end
+        end
+        xh_1(j) = x(j)-h_1(j);
+        if xh_1(j) < lb(j)
+            xh_1(j) = x(j);
+            if verbose 
+                fprintf('  - don''t do cross step down for parameter %d\n',j);
+            end
+        end
+        hessian_mat(:,(i-1)*n+j) =-(-feval(func, xh1, varargin{:})-feval(func, xh_1, varargin{:})+temp(:,i)+temp(:,j))./(2*h1(i)*h_1(j)); %formula 25.3.27
+        %reset grid points
+        xh1(i)  = x(i);
+        xh1(j)  = x(j);
+        xh_1(i) = x(i);
+        xh_1(j) = x(j);
+    end
+end
\ No newline at end of file
diff --git a/matlab/kalman/csnPruneParams.m b/matlab/kalman/csnPruneParams.m
new file mode 100644
index 0000000000000000000000000000000000000000..c0a48176335bc8cca365baa33758f77c78cac928
--- /dev/null
+++ b/matlab/kalman/csnPruneParams.m
@@ -0,0 +1,91 @@
+function [Sigma, Gamma, nu, Delta] = csnPruneParams(Sigma, Gamma, nu, Delta, tol, debug_dim)
+% [Sigma, Gamma, nu, Delta] = csnPruneParams(Sigma, Gamma, nu, Delta, tol, debug_dim)
+% -------------------------------------------------------------------------
+% Reduces the dimension of a CSN distributed random variable
+% Idea: 
+% 1) Representation of CSN distribution:
+%    X ~ CSN(mu,Sigma,Gamma,nu,Delta) is equivalent to X = W|Z>=0 where
+%   [W;Z] ~ N([mu;-nu], [Sigma, Sigma*Gamma'; Gamma*Sigma, Delta+Gamma*Sigma*Gamma']
+% 2) Correlation introduces skewness:
+%    Skewness in CSN is based on the correlation between W and Z:
+%    - CSN and N are the same distribution if Gamma=0
+%    - if correlation is small, then CSN very close to N
+% 3) Prune dimensions if correlation in absolute value is below tol.
+%    This reduces the overall skewness dimension to qq < q.
+% -------------------------------------------------------------------------
+% INPUTS
+% - Sigma         [p by p]    2nd parameter of the CSN distribution (scale)
+% - Gamma         [q by p]    3rd parameter of the CSN distribution (regulates skewness from Gaussian (Gamma=0) to half normal)
+% - nu            [q by 1]    4th parameter of the CSN distribution (enables closure of CSN distribution under conditioning)
+% - Delta         [q by q]    5th parameter of the CSN distribution (enables closure of CSN distribution und marginalization)
+% - tol           [double]    threshold value for correlation (in absolute value) below which correlated variables are pruned
+% - debug_dim     [boolean]   optional notification if there are more than debug_dim dimensions left unpruned
+% where p is the normal dimension and q the skewness dimension
+% -------------------------------------------------------------------------
+% OUTPUTS
+% - Sigma         [p by p]    2nd parameter of the pruned CSN distribution (scale)
+% - Gamma         [qq by p]   3rd parameter of the pruned CSN distribution (regulates skewness from Gaussian (Gamma=0) to half normal)
+% - nu            [qq by 1]   4th parameter of the pruned CSN distribution (enables closure of CSN distribution under conditioning)
+% - Delta         [qq by q]   5th parameter of the pruned CSN distribution (enables closure of CSN distribution und marginalization)
+% where qq < q is the skewness dimension of the pruned distribution
+% =========================================================================
+% Copyright (C) 2022-2023 Gaygysyz Guljanov, Willi Mutschler
+%
+% This is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% This is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+% -------------------------------------------------------------------------
+% This file is part of the replication files for the paper "Pruned Skewed
+% Kalman Filter and Smoother: Pruned Skewed Kalman Filter and Smoother:
+% With Applications to the Yield Curve and Asymmetric Monetary Policy Shocks"
+% by Gaygysyz Guljanov, Willi Mutschler, Mark Trede
+% =========================================================================
+if nargin < 6
+    debug_dim = [];
+end
+
+p = length(Sigma); % normal dimension
+
+% create correlation matrix of conditional definition of CSN distributed variable
+P = [Sigma, Sigma*Gamma'; Gamma*Sigma, Delta+Gamma*Sigma*Gamma']; P = 0.5*(P + P'); % covariance matrix
+n = length(P);
+try
+    % create correlation matrix from covariance matrix
+    normalization = diag(1./sqrt(diag(P)));
+    R = abs(normalization*P*normalization);
+catch
+    % error handling
+    Sigma = 0;
+    Gamma = 0;
+    nu    = 0;
+    Delta = 0;
+    return
+end
+
+% prune dimensions in R if they are in absolute value lower than tol
+R = R-diag(repelem(Inf, n));
+logi2 = max(R(p+1:end, 1:p), [], 2);
+logi2 = (logi2 < tol);
+
+% prune dimensions in CSN parameters
+Gamma(logi2, :) = [];
+nu(logi2)       = [];
+Delta(logi2, :) = [];
+Delta(:, logi2) = [];
+
+% Notify if there are more than ... dimensions left unpruned
+if ~isempty(debug_dim)
+    if sum(logi2 > tol) > debug_dim
+        disp('----');
+        disp(max(logi2)); disp(sum(logi2 > tol));
+        disp('----');
+    end    
+end
+
+end % csnPruneParams
\ No newline at end of file
diff --git a/matlab/kalman/csn_statespace_linear_transform.m b/matlab/kalman/csn_statespace_linear_transform.m
new file mode 100644
index 0000000000000000000000000000000000000000..2726d7421c34e6f3a543839257f29c308eb8f589
--- /dev/null
+++ b/matlab/kalman/csn_statespace_linear_transform.m
@@ -0,0 +1,66 @@
+function [mu_tr, Sigma_tr, Gamma_tr, nu_tr, Delta_tr] = csn_statespace_linear_transform(G_bar, mu_bar, Sigma_bar, Gamma_bar, nu_bar, Delta_bar)
+% function [mu_tr, Sigma_tr, Gamma_tr, nu_tr, Delta_tr] = csn_statespace_linear_transform(G_bar, mu_bar, Sigma_bar, Gamma_bar, nu_bar, Delta_bar)
+% -------------------------------------------------------------------------
+% Compute CSN parameters for joint distribution of [x_t', eta_t']' from
+% state transition equation: x(t) = G*x(t-1) + R*eta(t)
+% 1) make proper csn random variable first (in case of singularity)
+% 2) do either rank deficient or full rank linear transformation
+% -----------------------------------------------------------------------
+% INPUTS
+%   - G_bar = [G, R] multiplying the joint distribution of x_t and eta_t
+%   - mu_bar = [mu_t_t; mu_eta]
+%   - nu_bar = [nu_t_t; nu_eta];
+%   - Sigma_bar = blkdiag_two(Sigma_t_t, Sigma_eta);
+%   - Gamma_bar = blkdiag_two(Gamma_t_t, Gamma_eta);
+%   - Delta_bar = blkdiag_two(Delta_t_t, Delta_eta);
+% -----------------------------------------------------------------------
+% OUTPUT
+% transformed parameters of CSN joint distribution of x_t and eta_t:
+% mu_tr, Sigma_tr, Gamma_tr, nu_tr, Delta_tr
+% =========================================================================
+% Copyright (C) 2023 Gaygysyz Guljanov
+%
+% This is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% This is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+% -------------------------------------------------------------------------
+% This file is part of the replication files for the paper "Pruned Skewed
+% Kalman Filter and Smoother: Pruned Skewed Kalman Filter and Smoother:
+% With Applications to the Yield Curve and Asymmetric Monetary Policy Shocks"
+% by Gaygysyz Guljanov, Willi Mutschler, Mark Trede
+% =========================================================================
+tol = 1e-8;
+
+mu_tr = G_bar * mu_bar;
+Sigma_tr = G_bar * Sigma_bar * G_bar';
+mu_bar = zeros(size(mu_bar)); % make mu_bar a zero vector
+
+%% singular skew-normal to closed skew-normal   
+if rcond(Sigma_bar) < 1e-10
+    % Sigma_bar is rank deficient
+    [S_hat, ~, Sigma_bar, Gamma_bar] = singular_skew_normal_2_closed_skew_normal(mu_bar, Sigma_bar, Gamma_bar, tol, 0);        
+    G_bar = G_bar * S_hat;
+end
+
+%% Linear Transformation    
+% Check if A_mat is rank deficient
+dimensions = size(G_bar);
+if dimensions(1) > dimensions(2)
+    is_singular = rcond(G_bar' * G_bar) < 1e-8;
+else
+    is_singular = rcond(Sigma_tr) < 1e-8;
+end
+% If not full rank, use rank deficient linear transformation
+if is_singular
+    [Gamma_tr, nu_tr, Delta_tr] = csn_statespace_linear_transform_rank_deficient(G_bar, Sigma_bar, Gamma_bar, nu_bar, Delta_bar, tol);
+    return
+end
+[Gamma_tr, nu_tr, Delta_tr] = csn_statespace_linear_transform_full_rank(G_bar, Sigma_bar, Sigma_tr, Gamma_bar, nu_bar, Delta_bar);
+        
+end % csn_statespace_linear_transform
\ No newline at end of file
diff --git a/matlab/kalman/csn_statespace_linear_transform_full_rank.m b/matlab/kalman/csn_statespace_linear_transform_full_rank.m
new file mode 100644
index 0000000000000000000000000000000000000000..0fda18103b668a7a9fc844a450502521dc157e92
--- /dev/null
+++ b/matlab/kalman/csn_statespace_linear_transform_full_rank.m
@@ -0,0 +1,57 @@
+function [Gamma_tr, nu_tr, Delta_tr] = csn_statespace_linear_transform_full_rank(G_bar, Sigma_bar, Sigma_tr, Gamma_bar, nu_bar, Delta_bar)
+% function [Gamma_tr, nu_tr, Delta_tr] = csn_statespace_linear_transform_full_rank(G_bar, Sigma_bar, Sigma_tr, Gamma_bar, nu_bar, Delta_bar)
+% -------------------------------------------------------------------------
+% Compute CSN parameters for joint distribution of [x_t', eta_t']' from
+% state transition equation: x(t) = G*x(t-1) + R*eta(t)
+% helper function for full rank linear transformation of CSN distributed random variable
+% -----------------------------------------------------------------------
+% INPUTS
+%   - G_bar = [G, R] multiplying the joint distribution of x_t and eta_t
+%   - Sigma_bar = blkdiag_two(Sigma_t_t, Sigma_eta);
+%   - Sigma_tr : transformed (rank deficient) parameter matrix
+%   - Gamma_bar = blkdiag_two(Gamma_t_t, Gamma_eta);
+%   - nu_bar = [nu_t_t; nu_eta];
+%   - Delta_bar = blkdiag_two(Delta_t_t, Delta_eta);
+% -----------------------------------------------------------------------
+% OUTPUT
+% transformed parameters of rank-deficient CSN joint distribution of x_t and eta_t:
+% Gamma_tr, nu_tr, Delta_tr (returns only skewness parameters, as other parameters are easy to obtain)
+% =========================================================================
+% Copyright (C) 2023 Gaygysyz Guljanov
+%
+% This is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% This is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+% -------------------------------------------------------------------------
+% This file is part of the replication files for the paper "Pruned Skewed
+% Kalman Filter and Smoother: Pruned Skewed Kalman Filter and Smoother:
+% With Applications to the Yield Curve and Asymmetric Monetary Policy Shocks"
+% by Gaygysyz Guljanov, Willi Mutschler, Mark Trede
+% =========================================================================
+[nrow, ncol] = size(G_bar);
+
+%% more rows
+if nrow >= ncol
+    nu_tr = nu_bar;
+    Delta_tr = Delta_bar;
+    if nrow == ncol
+        Gamma_tr = Gamma_bar / G_bar;
+        return
+    end
+    Gamma_tr = Gamma_bar / (G_bar' * G_bar) * G_bar';
+    return
+end
+
+%% more columns
+Tmp_mat = Sigma_bar * G_bar' / Sigma_tr;
+Gamma_tr = Gamma_bar * Tmp_mat;
+nu_tr = nu_bar;
+Delta_tr = Delta_bar + Gamma_bar * Sigma_bar * Gamma_bar' - Gamma_bar * Tmp_mat * G_bar * Sigma_bar * Gamma_bar';
+
+end
\ No newline at end of file
diff --git a/matlab/kalman/csn_statespace_linear_transform_rank_deficient.m b/matlab/kalman/csn_statespace_linear_transform_rank_deficient.m
new file mode 100644
index 0000000000000000000000000000000000000000..6fda2a197417d1a33accab38225d36f7e8669f2e
--- /dev/null
+++ b/matlab/kalman/csn_statespace_linear_transform_rank_deficient.m
@@ -0,0 +1,60 @@
+function [Gamma_tr, nu_tr, Delta_tr] = csn_statespace_linear_transform_rank_deficient(G_bar, Sigma_bar, Gamma_bar, nu_bar, Delta_bar, tol)
+% function [Gamma_tr, nu_tr, Delta_tr] = csn_statespace_linear_transform(G_bar, mu_bar, Sigma_bar, Gamma_bar, nu_bar, Delta_bar)
+% -------------------------------------------------------------------------
+% Compute CSN parameters for joint distribution of [x_t', eta_t']' from
+% state transition equation: x(t) = G*x(t-1) + R*eta(t)
+% helper function for rank deficient linear transformation of CSN distributed random variable
+% -----------------------------------------------------------------------
+% INPUTS
+%   - G_bar = [G, R] multiplying the joint distribution of x_t and eta_t
+%   - Sigma_bar = blkdiag_two(Sigma_t_t, Sigma_eta);
+%   - Gamma_bar = blkdiag_two(Gamma_t_t, Gamma_eta);
+%   - nu_bar = [nu_t_t; nu_eta];
+%   - Delta_bar = blkdiag_two(Delta_t_t, Delta_eta);
+%   - tol: tolerance level showing which values should be assumed to be numerically zero
+% -----------------------------------------------------------------------
+% OUTPUT
+% transformed parameters of rank-deficient CSN joint distribution of x_t and eta_t:
+% Gamma_tr, nu_tr, Delta_tr (returns only skewness parameters, as other parameters are easy to obtain)
+% =========================================================================
+% Copyright (C) 2023 Gaygysyz Guljanov
+%
+% This is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% This is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+% -------------------------------------------------------------------------
+% This file is part of the replication files for the paper "Pruned Skewed
+% Kalman Filter and Smoother: Pruned Skewed Kalman Filter and Smoother:
+% With Applications to the Yield Curve and Asymmetric Monetary Policy Shocks"
+% by Gaygysyz Guljanov, Willi Mutschler, Mark Trede
+% =========================================================================
+[nrow, ncol] = size(G_bar);
+difference = abs(nrow - ncol);
+[S_mat, Lambda_mat, T_mat] = svd(G_bar); % apply singular value decomposition
+if nrow >= ncol % more rows
+    S_mat = S_mat(:, 1:end-difference);
+    Lambda_mat = Lambda_mat(1:end-difference, :);
+else
+    T_mat = T_mat(:, 1:end-difference);
+    Lambda_mat = Lambda_mat(:, 1:end-difference);
+end    
+hold_vec = abs(diag(Lambda_mat)) > tol;      % which dimensions to delete
+S_mat = S_mat(:, hold_vec);                  % delete respective columns
+Lambda_mat = Lambda_mat(hold_vec, hold_vec); % delete respective rows and columns    
+T_mat = T_mat(:, hold_vec);                  % delete respective columns
+
+% Apply the final formulas of theorem
+Tmp_mat = T_mat' * Sigma_bar * T_mat;
+Tmp_mat2 = Gamma_bar * Sigma_bar;
+Tmp_mat3 = Tmp_mat2 * T_mat / Tmp_mat;
+Gamma_tr = (Tmp_mat3 / Lambda_mat) / (S_mat' * S_mat) * S_mat';
+nu_tr = nu_bar;
+Delta_tr = Delta_bar + Tmp_mat2 * Gamma_bar' - Tmp_mat3 * T_mat' * Sigma_bar * Gamma_bar';
+
+end % csn_statespace_linear_transform_rank_deficient
\ No newline at end of file
diff --git a/matlab/kalman/likelihood/kalman_filter_pruned_skewed.m b/matlab/kalman/likelihood/kalman_filter_pruned_skewed.m
new file mode 100644
index 0000000000000000000000000000000000000000..cb9d909fd21f1880eddb6aa5bbe3d8f6760e8938
--- /dev/null
+++ b/matlab/kalman/likelihood/kalman_filter_pruned_skewed.m
@@ -0,0 +1,457 @@
+function [LIK, LIKK] = kalman_filter_pruned_skewed(Y,start,last,mu_tm1_tm1,Sigma_tm1_tm1,Gamma_tm1_tm1,nu_tm1_tm1,Delta_tm1_tm1,kalman_tol,riccati_tol,rescale_prediction_error_covariance,presample,diffuse_periods,G,R,F,Fflag,mu_eta,Sigma_eta,Gamma_eta,nu_eta,Delta_eta,Sigma_eps,prune_tol,cdfmvna_fct)
+% -------------------------------------------------------------------------
+% Evaluate (1) log-likelihood value and (2) filtered states
+% of linear state space model with csn distributed innovations and normally distributed noise:
+%   x(t) = G*x(t-1) + R*eta(t)   [state transition equation]
+%   y(t) = F*x(t)   + eps(t)     [observation equation]
+%   eta(t) ~ CSN(mu_eta,Sigma_eta,Gamma_eta,nu_eta,Delta_eta) [innovations, shocks]
+%   eps(t) ~ N(0,Sigma_eps)                                   [noise, measurement error]
+% Dimensions:
+%   x(t) is (x_nbr by 1) state vector
+%   y(t) is (y_nbr by 1) control vector, i.e. observable variables
+%   eta(t) is (eta_nbr by 1) vector of innovations
+%   eps(t) is (y_nbr by 1) vector of noise (measurement errors)
+% Note that mu_eta is such that E[eta(t)] = 0
+% -------------------------------------------------------------------------
+% INPUTS
+% - Y               [y_nbr by obs_nbr]             matrix with data
+% - start           [integer scalar]               first period
+% - last            [integer scalar]               last period, (last-first) has to be inferior to obs_nbr
+% - mu_tm1_tm1      [x_nbr by 1]                   initial filtered value of location parameter of CSN distributed states x (does not equal expectation vector unless Gamma_tm1_tm1=0), i.e. mu_0_0
+% - Sigma_tm1_tm1   [x_nbr by x_nbr]               initial filtered value of scale parameter of CSN distributed states x (does not equal covariance matrix unless Gamma_tm1_tm1=0), i.e. Sigma_0_0
+% - Gamma_tm1_tm1   [skewx_dim by x_nbr]           initial filtered value of skewness size parameter of CSN distributed states x (regulates skewness from Gaussian (Gamma=0) to half normal), i.e. Gamma_0_0
+% - nu_tm1_tm1      [skewx_dim by x_nbr]           initial filtered value of skewness conditioning parameter of CSN distributed states x (enables closure of CSN distribution under conditioning), i.e. nu_0_0
+% - Delta_tm1_tm1   [skewx_dim by skewx_dim]       initial filtered value of skewness marginalization parameter of CSN distributed states x (enables closure of CSN distribution under marginalization), i.e. Delta_0_0
+% - kalman_tol      [double scalar]                tolerance parameter for rcond and invertibility of covariance matrix
+% - riccati_tol     [double scalar]                tolerance parameter for iteration over the Riccati equation
+% - presample       [integer scalar]               number of initial iterations to be discarded when evaluating the likelihood
+% - diffuse_periods [integer scalar]               number of diffuse filter periods in the initialization step
+% - G               [x_nbr by x_nbr]               state transition matrix mapping previous states to current states
+% - R               [x_nbr by eta_nbr]             state transition matrix mapping current innovations to current states
+% - F               [y_nbr by x_nbr]               observation equation matrix mapping current states into current observables (if Fflag=1) 
+%                   [y_nbr by 1]                   indices for picking observables in transition matrix (if Fflag=0)
+% - Fflag           [boolean]                      0: if F is a vector of indices targeting observed variables in state vector
+%                                                  1: if F is matrix in observation equation
+% - mu_eta          [eta_nbr by 1]                 value of location parameter of CSN distributed innovations eta (does not equal expectation vector unless Gamma_eta=0), i.e. mu_eta
+% - Sigma_eta       [eta_nbr by eta_nbr]           value of scale parameter of CSN distributed innovations eta (does not equal covariance matrix unless Gamma_eta=0), i.e. Sigma_eta
+% - Gamma_eta       [skeweta_dim by eta_nbr]       value of skewness size parameter of CSN distributed innovations eta (regulates skewness from Gaussian (Gamma=0) to half normal), i.e. Gamma_eta
+% - nu_eta          [skeweta_dim by eta_nbr]       value of skewness conditioning parameter of CSN distributed innovations eta (enables closure of CSN distribution under conditioning), i.e. nu_eta
+% - Delta_eta       [skeweta_dim by skeweta_dim]   value of skewness marginalization parameter of CSN distributed innovations eta (enables closure of CSN distribution under marginalization), i.e. Delta_eta
+% - Sigma_eps       [y_nbr by y_nbr]               scale parameter of normally distributed measurement errors eps (equals covariance matrix), if no measurement errors this is a zero scalar
+% - G_singular      [boolean]                      indicator if prediction step is done on joint distribution, [x_t', eta_t']', useful for models where G is singular
+% - prune_tol       [double]                       correlation threshold to prune redundant skewness dimensions, if set to 0 no pruning will be done
+% - cdfmvna_fct     [string]                       name of function to compute log Gaussian cdf, possible values: 'logmvncdf_ME', 'mvncdf', 'qsilatmvnv', 'qsimvnv'
+% -------------------------------------------------------------------------
+% OUTPUTS
+% - LIK             [double scalar]        value of negative log likelihood
+% - LIKK            [(last-start+1) by 1]  vector of densities for each observation
+% =========================================================================
+% Copyright (C) 2024 Gaygysyz Guljanov, Willi Mutschler
+%
+% This is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% This is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+% -------------------------------------------------------------------------
+% This file is part of the replication files for the paper "Pruned Skewed
+% Kalman Filter and Smoother: Pruned Skewed Kalman Filter and Smoother:
+% With Applications to the Yield Curve and Asymmetric Monetary Policy Shocks"
+% by Gaygysyz Guljanov, Willi Mutschler, Mark Trede
+% =========================================================================
+
+% Set defaults.
+verbose = false; % for development use
+
+if nargin < 25
+    cdfmvna_fct = 'logmvncdf_ME';
+end
+% initializations
+smpl = last-start+1;         % sample size
+t    = start;                % time index
+likk = zeros(smpl,1);        % vector gathering the densities
+LIK  = Inf;                  % default value of the log likelihood
+oldK_Gauss = Inf;             % old Gaussian Kalman gain for switching to steady-state Kalman filter (not yet implemented)
+oldK_Skewed = Inf;             % old Skewed Kalman gain for switching to steady-state Kalman filter (not yet implemented)
+old_mu = Inf;
+old_Sigma = Inf;
+old_Gamma = Inf;
+old_nu = Inf;
+old_Delta = Inf;
+notsteady   = [1 1];         % initialize indicator whether to break the loop and call the steady-state Kalman filter (not yet implemented, so just print convergence period)
+notsteady_Skew = [1 1];       % initialize indicator whether to break the loop and call the steady-state Kalman filter (not yet implemented, so just print convergence period)
+notsteady_mu = [1 1];
+notsteady_Sigma = [1 1];
+notsteady_Gamma = [1 1];
+notsteady_nu = [1 1];
+notsteady_Delta = [1 1];
+Omega_singular  = true;      % indicator whether Omega is singular
+LIKK = [];                   % output vector for individal density contributions
+rescale_prediction_error_covariance0 = rescale_prediction_error_covariance; % store option
+const2pi = -0.5*size(Y,1)*log(2*pi);
+
+if rcond(G) < kalman_tol
+    G_singular = true;
+    G_bar = [G, R]; % multiplying matrix of joint distribution
+else
+    if verbose
+        warning('G is non-singular');
+    end
+    G_singular = false;
+    mu_eta    = R*mu_eta;
+    Sigma_eta = R*Sigma_eta*R';
+    Gamma_eta = Gamma_eta/(R'*R)*R';
+    Gamma_eta_X_Sigma_eta = Gamma_eta*Sigma_eta;
+    Delta22_common = Delta_eta + Gamma_eta_X_Sigma_eta*Gamma_eta';
+end
+
+while notsteady(1) && t<=last
+    s = t-start+1;
+
+    %%%%%%%%%%%%%%
+    % PREDICTION %
+    %%%%%%%%%%%%%%
+    if G_singular
+        % Parameters of joint distribution, [x_t', eta_t']'
+        mu_bar_tm1_tm1 = [mu_tm1_tm1; mu_eta];
+        nu_bar_tm1_tm1 = [nu_tm1_tm1; nu_eta];
+        Sigma_bar_tm1_tm1 = blkdiag_two(Sigma_tm1_tm1, Sigma_eta);
+        Gamma_bar_tm1_tm1 = blkdiag_two(Gamma_tm1_tm1, Gamma_eta);
+        Delta_bar_tm1_tm1 = blkdiag_two(Delta_tm1_tm1, Delta_eta);
+        % Linear transformation of the joint distribution
+        [mu_t_tm1, Sigma_t_tm1, Gamma_t_tm1, nu_t_tm1, Delta_t_tm1] = csn_statespace_linear_transform(G_bar, mu_bar_tm1_tm1, Sigma_bar_tm1_tm1, Gamma_bar_tm1_tm1, nu_bar_tm1_tm1, Delta_bar_tm1_tm1);
+    else
+        % auxiliary matrices
+        Gamma_tm1_tm1_X_Sigma_tm1_tm1      = Gamma_tm1_tm1*Sigma_tm1_tm1;
+        Gamma_tm1_tm1_X_Sigma_tm1_tm1_X_GT = Gamma_tm1_tm1_X_Sigma_tm1_tm1*G';
+        mu_t_tm1  = G*mu_tm1_tm1 + mu_eta;
+        Sigma_t_tm1 = G*Sigma_tm1_tm1*G' + Sigma_eta;
+        Sigma_t_tm1 = 0.5*(Sigma_t_tm1 + Sigma_t_tm1'); % ensure symmetry
+        invSigma_t_tm1 = inv(Sigma_t_tm1);
+        Gamma_t_tm1 = [Gamma_tm1_tm1_X_Sigma_tm1_tm1_X_GT; Gamma_eta_X_Sigma_eta]*invSigma_t_tm1;
+        nu_t_tm1 = [nu_tm1_tm1; nu_eta];
+        Delta11_t_tm1 = Delta_tm1_tm1 + Gamma_tm1_tm1_X_Sigma_tm1_tm1*Gamma_tm1_tm1' - Gamma_tm1_tm1_X_Sigma_tm1_tm1_X_GT*invSigma_t_tm1*Gamma_tm1_tm1_X_Sigma_tm1_tm1_X_GT';
+        Delta22_t_tm1 = Delta22_common - Gamma_eta_X_Sigma_eta*invSigma_t_tm1*Gamma_eta_X_Sigma_eta';
+        Delta12_t_tm1 = -Gamma_tm1_tm1_X_Sigma_tm1_tm1_X_GT*invSigma_t_tm1*Gamma_eta_X_Sigma_eta';
+        Delta_t_tm1 = [Delta11_t_tm1 , Delta12_t_tm1; Delta12_t_tm1' , Delta22_t_tm1];
+        Delta_t_tm1 = 0.5*(Delta_t_tm1 + Delta_t_tm1'); % ensure symmetry
+    end
+    % pruning redundant skewness dimensions to speed up filtering
+    if prune_tol > 0
+        [Sigma_t_tm1, Gamma_t_tm1, nu_t_tm1, Delta_t_tm1] = csnPruneParams(Sigma_t_tm1,Gamma_t_tm1,nu_t_tm1,Delta_t_tm1,prune_tol);
+    end
+    % Omega is Gaussian prediction error covariance
+    if Fflag
+        prediction_error = Y(:,t)-F*mu_t_tm1;
+        Omega = F*Sigma_t_tm1*F' + Sigma_eps;
+    else
+        prediction_error = Y(:,t)-mu_t_tm1(F);
+        Omega = Sigma_t_tm1(F,F) + Sigma_eps;
+    end
+    badly_conditioned_Omega = false;
+    if rescale_prediction_error_covariance
+        sigOmega = sqrt(diag(Omega)); % standard deviations
+        if any(diag(Omega)<kalman_tol) || rcond(Omega./(sigOmega*sigOmega'))<kalman_tol % Omega./(sigOmega*sigOmega') effectively converts Omega to a correlation matrix
+            badly_conditioned_Omega = true;
+        end
+    else
+        if rcond(Omega)<kalman_tol
+            sigOmega = sqrt(diag(Omega)); % standard deviations
+            if any(diag(Omega)<kalman_tol) || rcond(Omega./(sigOmega*sigOmega'))<kalman_tol % Omega./(sigOmega*sigOmega') effectively converts Omega to a correlation matrix
+                badly_conditioned_Omega = true;
+            else
+                rescale_prediction_error_covariance = 1;
+            end
+        end
+    end
+    if badly_conditioned_Omega
+        % if ~all(abs(Omega(:))<kalman_tol), then use univariate filter (will remove
+        % observations with zero variance prediction error), otherwise this is a
+        % pathological case and the draw is discarded
+        if verbose
+            warning('Omega is badly conditioned, discard draw as univariate filter will not be used (this overwrites Dynare''s default behavior');
+        end
+        return
+    else
+        Omega_singular = false;
+        if rescale_prediction_error_covariance % Omega needs to be rescaled to avoid numerical instability
+            % compute the log-determinant of covariance matrix Omega in a numerically stable way:
+            % let: corrOmega = Omega./(sigOmega*sigOmega') be the correlation matrix corresponding to Omega
+            % then: Omega = (sigOmega*sigOmega') .* corrOmega = diag(sigOmega) * corrOmega * diag(sigOmega)
+            % determinant: det(Omega) = det(diag(sigOmega)) * det(corrOmega) * det(diag(sigOmega)) = det(corrOmega) * prod(sigOmega)^2
+            % taking logs: log(det(Omega)) = log(det(corrOmega)) + 2*sum(log(sigOmega))
+            log_detOmega = log(det(Omega./(sigOmega*sigOmega'))) + 2*sum(log(sigOmega));
+            % compute inv(Omega) in a numerically stable way
+            % let: corrOmega = Omega./(sigOmega*sigOmega') be the correlation matrix corresponding to Omega
+            % then: Omega = (sigOmega*sigOmega') .* corrOmega = diag(sigOmega) * corrOmega * diag(sigOmega)
+            %       inv(Omega) = diag(1./sigOmega) * inv(corrOmega) * diag(1./sigOmega) = inv(corrOmega) ./ (sigOmega*sigOmega')
+            invOmega = inv(Omega./(sigOmega*sigOmega'))./(sigOmega*sigOmega');
+            rescale_prediction_error_covariance = rescale_prediction_error_covariance0; % reset option as it might have been updated above
+        else
+            log_detOmega = log(det(Omega)); % compute the log-determinant of Omega directly
+            invOmega = inv(Omega); % compute the inverse of Omega directly
+        end
+
+        % Gaussian Kalman Gain
+        if Fflag
+            K_Gauss = Sigma_t_tm1*F'*invOmega;
+        else
+            K_Gauss = Sigma_t_tm1(:,F)*invOmega;
+        end
+        K_Skewed = Gamma_t_tm1*K_Gauss; % Skewed Kalman Gain
+        
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % LOG-LIKELIHOOD CONTRIBUTIONS %
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % The conditional distribution of y(t) given y(t-1) is:
+        % (y(t)|y(t-1)) ~ CSN(mu_y,Sigma_y,Gamma_y,nu_y,Delta_y)
+        %               = mvncdf(Gamma_y*(y(t)-mu_y),nu_y,Delta_y) / mvncdf(0,nu_y,Delta_y+Gamma_y*Sigma_y*Gamma_y') * mvnpdf(y(t),mu_y,Sigma_y)
+        % where:
+        %   mu_y    = F*mu_t_tm1 + mu_eps = y_predicted
+        %   Sigma_y = F*Sigma_t_tm1*F' + Sigma_eps = Omega
+        %   Gamma_y = Gamma_t_tm1*Sigma_t_tm1*F'*inv(F*Sigma_t_tm1*F' + Sigma_eps) = K_Skewed
+        %   nu_y    = nu_t_tm1
+        %   Delta_y = Delta_t_tm1 + Gamma_t_tm1*Sigma_t_tm1*Gamma_t_tm1'...
+        %             - Gamma_t_tm1*Sigma_t_tm1*F'*inv(F*Sigma_t_tm1*F')*F*Sigma_t_tm1*Gamma_t_tm1'...
+        %             + (Gamma_t_tm1*Sigma_t_tm1*F'*inv(F*Sigma_t_tm1*F') - Gamma_t_tm1*Sigma_t_tm1*F'*inv(F*Sigma_t_tm1*F' + Sigma_eps))*F*Sigma_t_tm1*Gamma_t_tm1';
+        %           = Delta_t_tm1 + (Gamma_t_tm1-K_Skewed*F)*Sigma_t_tm1*Gamma_t_tm1'
+        tmp = Gamma_t_tm1*Sigma_t_tm1;
+        Delta_y = Delta_t_tm1 + tmp*Gamma_t_tm1' - K_Skewed*F*tmp';
+        Delta_y = 0.5 * (Delta_y + Delta_y');  %ensure symmetry
+
+        % evaluate Gaussian cdfs, i.e.
+        %  - bottom one: mvncdf(0,nu_y,Delta_y + Gamma_y*Sigma_y*Gamma_y')
+        %  - top one: mvncdf(Gamma_y*(y(t)-mu_y),nu_y,Delta_y)
+
+        cdf_bottom_cov = Delta_y + K_Skewed*Omega*K_Skewed';
+        cdf_bottom_cov = 0.5*(cdf_bottom_cov + cdf_bottom_cov'); % ensure symmetry
+        if strcmp(cdfmvna_fct,'logmvncdf_ME')
+            % requires zero mean and correlation matrix as inputs            
+            normalization_Delta_y = diag(1./sqrt(diag(cdf_bottom_cov)));
+            cdf_bottom_cov = normalization_Delta_y*cdf_bottom_cov*normalization_Delta_y; % this is now a correlation matrix!
+            cdf_bottom_cov = 0.5*(cdf_bottom_cov + cdf_bottom_cov'); % ensure symmetry
+            if ~isempty(cdf_bottom_cov)
+                try
+                    log_gaussian_cdf_bottom = logmvncdf_ME(-normalization_Delta_y*nu_t_tm1, cdf_bottom_cov);
+                catch
+                    if verbose
+                        warning('log_gaussian_cdf_bottom something wrong');
+                    end
+                    return
+                end
+            else
+                log_gaussian_cdf_bottom = 0;
+            end
+
+            normalization_Delta_y = diag(1./sqrt(diag(Delta_y)));
+            Delta_y = normalization_Delta_y*Delta_y*normalization_Delta_y; % this is now a correlation matrix!
+            Delta_y = 0.5*(Delta_y + Delta_y'); % ensure symmetry
+            if ~isempty(Delta_y)
+                try
+                    log_gaussian_cdf_top = logmvncdf_ME(normalization_Delta_y*(K_Skewed*prediction_error - nu_t_tm1), Delta_y);
+                catch
+                    if verbose
+                        warning('log_gaussian_cdf_top something wrong')
+                    end
+                    return
+                end
+            else
+                log_gaussian_cdf_top = 0;
+            end
+        elseif strcmp(cdfmvna_fct,'mvncdf')
+            try
+                log_gaussian_cdf_bottom = log(mvncdf(zeros(size(nu_t_tm1,1),1), nu_t_tm1, cdf_bottom_cov));
+            catch
+                if verbose
+                    warning('log_gaussian_cdf_bottom something wrong')
+                end
+                return
+            end
+            try
+                log_gaussian_cdf_top = log(mvncdf(K_Skewed*prediction_error, nu_t_tm1, Delta_y));
+            catch
+                if verbose
+                    warning('log_gaussian_cdf_top something wrong')
+                end
+                return
+            end
+        elseif strcmp(cdfmvna_fct,'qsilatmvnv')
+            k = size(nu_t_tm1,1);
+            if k > 1
+                try
+                    log_gaussian_cdf_bottom = log(qsilatmvnv( 1000*k, cdf_bottom_cov, repmat(-Inf,k,1)-nu_t_tm1, zeros(k,1)-nu_t_tm1 ));
+                catch
+                    if verbose
+                        warning('log_gaussian_cdf_bottom something wrong');
+                    end
+                    return
+                end
+                try
+                    log_gaussian_cdf_top = log(qsilatmvnv( 1000*k, Delta_y, repmat(-Inf,k,1)-nu_t_tm1, K_Skewed*prediction_error-nu_t_tm1 ));
+                catch
+                    if verbose
+                        warning('log_gaussian_cdf_top something wrong');
+                    end
+                    return
+                end
+            else
+                try
+                    log_gaussian_cdf_bottom = log(normcdf(0, nu_t_tm1, cdf_bottom_cov));
+                catch
+                    if verbose
+                        warning('log_gaussian_cdf_bottom something wrong');
+                    end
+                    return
+                end
+                try
+                    log_gaussian_cdf_top = log(normcdf(K_Skewed*prediction_error, nu_t_tm1, Delta_y));
+                catch
+                    if verbose
+                        warning('log_gaussian_cdf_top something wrong');
+                    end
+                    return
+                end
+            end
+        elseif strcmp(cdfmvna_fct,'qsimvnv')
+            k = size(nu_t_tm1,1);
+            if k > 1
+                try
+                    log_gaussian_cdf_bottom = log(qsimvnv( 1000*k, cdf_bottom_cov, repmat(-Inf,k,1)-nu_t_tm1, zeros(k,1)-nu_t_tm1 ));
+                catch
+                    if verbose
+                        warning('log_gaussian_cdf_bottom something wrong');
+                    end
+                    return
+                end
+                try
+                    log_gaussian_cdf_top = log(qsimvnv( 1000*k, Delta_y, repmat(-Inf,k,1)-nu_t_tm1, K_Skewed*prediction_error-nu_t_tm1 ));
+                catch
+                    if verbose
+                        warning('log_gaussian_cdf_top something wrong');
+                    end
+                    return
+                end
+            else
+                try
+                    log_gaussian_cdf_bottom = log(normcdf(0, nu_t_tm1, cdf_bottom_cov));
+                catch
+                    if verbose
+                        warning('log_gaussian_cdf_bottom something wrong');
+                    end
+                    return
+                end
+                try
+                    log_gaussian_cdf_top = log(normcdf(K_Skewed*prediction_error, nu_t_tm1, Delta_y));
+                catch
+                    if verbose
+                        warning('log_gaussian_cdf top something wrong');
+                    end
+                    return
+                end
+            end
+        end
+
+        % evaluate Gaussian pdf
+        % log_gaussian_pdf = log(mvnpdf(Y(:,t), y_predicted, Omega));
+        try
+            log_gaussian_pdf = const2pi - 0.5*log_detOmega - 0.5*transpose(prediction_error)*invOmega*prediction_error;
+        catch
+            if verbose
+                warning('log_gaussian_pdf something wrong');
+            end
+            return
+        end
+
+        % likelihood contribution
+        likk(s) = -log_gaussian_cdf_bottom + log_gaussian_pdf + log_gaussian_cdf_top;
+        
+        %%%%%%%%%%%%%
+        % FILTERING %
+        %%%%%%%%%%%%%
+        mu_t_t    = mu_t_tm1 + K_Gauss*prediction_error;
+        if Fflag
+            Sigma_t_t = Sigma_t_tm1 - K_Gauss*F*Sigma_t_tm1;
+        else
+            Sigma_t_t = Sigma_t_tm1 - K_Gauss*Sigma_t_tm1(F,:);
+        end
+        Gamma_t_t = Gamma_t_tm1;
+        nu_t_t    = nu_t_tm1 - K_Skewed*prediction_error;
+        Delta_t_t = Delta_t_tm1;
+        Sigma_t_t = 0.5*(Sigma_t_t + Sigma_t_t'); % ensure symmetry
+        Delta_t_t = 0.5*(Delta_t_t + Delta_t_t'); % ensure symmetry
+        
+        % assign for next time step
+        mu_tm1_tm1    = mu_t_t;
+        Sigma_tm1_tm1 = Sigma_t_t;
+        Gamma_tm1_tm1 = Gamma_t_t;
+        nu_tm1_tm1    = nu_t_t;
+        Delta_tm1_tm1 = Delta_t_t;
+
+        % check for steady-state Kalman filter (not yet implemented)
+        if verbose
+            if max(abs(K_Gauss(:)-oldK_Gauss)) < riccati_tol
+                if notsteady(2) == 1
+                    fprintf('Gaussian Kalman gain converged after %d/%d periods (but steady-state PSKF filter is not implemented yet)\n',s,smpl);
+                    notsteady(2) = 0;
+                end
+            else
+                if notsteady(2) == 0
+                    error('Gaussian Kalman gain diverged after %d/%d periods\n',s,smpl);
+                    notsteady(2) = 1;
+                end
+            end
+            if numel(K_Skewed) == numel(oldK_Skewed) && (max(abs(K_Skewed(:)-oldK_Skewed)) < riccati_tol)
+                if notsteady_Skew(2) == 1
+                    fprintf('Skewed Kalman gain converged after %d/%d periods with skewness dimension: %d\n',s,smpl,size(K_Skewed,1));
+                    notsteady_Skew(2) = 0;
+                end
+            else
+                if notsteady_Skew(2) == 0
+                    error('Skewed Kalman gain diverged after %d/%d periods\n',s,smpl);
+                    notsteady_Skew(2) = 1;
+                end
+            end
+        end
+        oldK_Gauss = K_Gauss(:);
+        oldK_Skewed = K_Skewed(:);
+        old_mu = mu_t_t(:);
+        old_Sigma = Sigma_t_t(:);
+        old_Gamma = Gamma_t_t(:);
+        old_nu = nu_t_t(:);
+        old_Delta = Delta_t_t(:);
+    end
+    t = t+1;
+end
+
+if verbose
+    fprintf('Skewness Dimension: %d\n',size(Gamma_t_t,1));
+end
+
+if Omega_singular
+    error('The variance of the forecast error remains singular until the end of the sample')
+end
+
+% Compute minus the log-likelihood.
+if presample>diffuse_periods
+    LIK = -1*sum(likk(1+(presample-diffuse_periods):end));
+else
+    LIK = -1*sum(likk);
+end
+LIKK = -1*likk;
+
+
+%% auxiliary functions
+function res_mat = blkdiag_two(mat1, mat2)
+    % Makes a block diagonal matrix out of two matrices
+    [nrow_mat1, ncol_mat1] = size(mat1); [nrow_mat2, ncol_mat2] = size(mat2);
+    upper_mat = zeros(nrow_mat1, ncol_mat2);
+    lower_mat = zeros(nrow_mat2, ncol_mat1);
+    res_mat = [mat1, upper_mat; lower_mat, mat2];
+end % blkdiag_two
+  
+
+end % kalman_filter_pruned_skewed
\ No newline at end of file
diff --git a/matlab/name2index.m b/matlab/name2index.m
index 78b121690918eb5e95f04eaef07a724e440e2977..ce35b765df27233269406a70f73309520216f649 100644
--- a/matlab/name2index.m
+++ b/matlab/name2index.m
@@ -1,7 +1,8 @@
 function i = name2index(options_, M_, estim_params_, type, name1, name2 )
 % Returns the index associated to an estimated object (deep parameter,
 % variance of a structural shock or measurement error, covariance between
-% two structural shocks, covariance between two measurement errors).
+% two structural shocks, covariance between two measurement errors, or 
+% skewness of structural shocks).
 %
 % INPUTS:
 %   options_        [structure]    Dynare structure.
@@ -16,7 +17,7 @@ function i = name2index(options_, M_, estim_params_, type, name1, name2 )
 % SPECIAL REQUIREMENTS
 %   none
 
-% Copyright © 2008-2018 Dynare Team
+% Copyright © 2008-2024 Dynare Team
 %
 % This file is part of Dynare.
 %
@@ -37,13 +38,14 @@ nvx     = estim_params_.nvx;
 nvn     = estim_params_.nvn;
 ncx     = estim_params_.ncx;
 ncn     = estim_params_.ncn;
+nsx     = estim_params_.nsx;
 npa     = estim_params_.np ;
-nnn = nvx+nvn+ncx+ncn+npa;
+nnn = nvx+nvn+ncx+ncn+nsx+npa;
 
 i = [];
 
 if strcmpi(type,'DeepParameter')
-    i = nvx + nvn + ncx + ncn + ...
+    i = nvx + nvn + ncx + ncn + nsx + ...
         strmatch(name1, M_.param_names(estim_params_.param_vals(:,1)), 'exact');
     if nargin>5
         disp('The last input argument is useless!')
@@ -114,4 +116,12 @@ if strcmpi(type,'MeasurementError')
             disp('Off diagonal terms of the covariance matrix are not estimated (measurement equation)')
         end
     end
+end
+
+if strcmpi(type,'StructuralShockSkewness')
+    i = strmatch(name1, M_.exo_names(estim_params_.skew_exo(:,1)), 'exact');
+    if isempty(i)
+        disp(['The skewness of ' name1  ' is not an estimated parameter!'])
+        return
+    end
 end
\ No newline at end of file
diff --git a/matlab/optimization/transform_to_bounded.m b/matlab/optimization/transform_to_bounded.m
new file mode 100644
index 0000000000000000000000000000000000000000..d2b087c69c0a438c0e1100ef3fc4cf3e350a1658
--- /dev/null
+++ b/matlab/optimization/transform_to_bounded.m
@@ -0,0 +1,40 @@
+function X = transform_to_bounded(Y,a,b)
+% function X = transform_to_bounded(Y,a,b)
+% -------------------------------------------------------------------------
+% transforms an unbounded parameter vector back to original bounded parameters
+% using an inverse log-odds transform as described at
+% https://mc-stan.org/docs/reference-manual/logit-transform-jacobian.html
+% -------------------------------------------------------------------------
+% INPUTS
+% - Y      [double vector]   unbounded parameter vector
+% - a      [double vector]   lower bound of original parameters
+% - b      [double vector]   upper bound of original parameters
+% -------------------------------------------------------------------------
+% OUTPUTS
+% - X      [double vector]   original bounded parameter vector
+% =========================================================================
+% Copyright (C) 2023 Willi Mutschler
+%
+% This is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% This is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+% -------------------------------------------------------------------------
+% This file is part of the replication files for the paper "Pruned Skewed
+% Kalman Filter and Smoother: Pruned Skewed Kalman Filter and Smoother:
+% With Applications to the Yield Curve and Asymmetric Monetary Policy Shocks"
+% by Gaygysyz Guljanov, Willi Mutschler, Mark Trede
+% =========================================================================
+
+X = a + (b-a).*inv_logit(Y);
+
+function u = inv_logit(v)
+    u = 1./(1+exp(-v));
+end %inv_logit
+
+end % transform_to_unbounded
\ No newline at end of file
diff --git a/matlab/optimization/transform_to_bounded_derivative.m b/matlab/optimization/transform_to_bounded_derivative.m
new file mode 100644
index 0000000000000000000000000000000000000000..2538e3d260aae9ff146f524598406d518854b4cf
--- /dev/null
+++ b/matlab/optimization/transform_to_bounded_derivative.m
@@ -0,0 +1,39 @@
+function dX_dY = transform_to_bounded_derivative(Y,a,b)
+% function dX_dY = transform_to_bounded_derivative(Y,a,b)
+% -------------------------------------------------------------------------
+% Jacobian of inverse logit transform as described at
+% https://mc-stan.org/docs/reference-manual/logit-transform-jacobian.html
+% -------------------------------------------------------------------------
+% INPUTS
+% - Y      [double vector]   unbounded parameter vector
+% - a      [double vector]   lower bound of original parameters
+% - b      [double vector]   upper bound of original parameters
+% -------------------------------------------------------------------------
+% OUTPUTS
+% - dX_dY  [double vector]   computes Jacobian of original bounded parameter vector
+%                            wrt to unbounded parameters
+% =========================================================================
+% Copyright (C) 2023 Willi Mutschler
+%
+% This is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% This is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+% -------------------------------------------------------------------------
+% This file is part of the replication files for the paper "Pruned Skewed
+% Kalman Filter and Smoother: Pruned Skewed Kalman Filter and Smoother:
+% With Applications to the Yield Curve and Asymmetric Monetary Policy Shocks"
+% by Gaygysyz Guljanov, Willi Mutschler, Mark Trede
+% =========================================================================
+dX_dY = (b-a).*inv_logit(Y).*(1-inv_logit(Y));
+
+function u = inv_logit(v)
+    u = 1./(1+exp(-v));
+end %inv_logit
+
+end % transform_to_unbounded
\ No newline at end of file
diff --git a/matlab/optimization/transform_to_unbounded.m b/matlab/optimization/transform_to_unbounded.m
new file mode 100644
index 0000000000000000000000000000000000000000..ed0979594ab078cb9d04785e79a40065c73939ff
--- /dev/null
+++ b/matlab/optimization/transform_to_unbounded.m
@@ -0,0 +1,39 @@
+function Y = transform_to_unbounded(X,a,b)
+% function Y = transform_to_unbounded(X,a,b)
+% -------------------------------------------------------------------------
+% transforms an original bounded parameter vector to unbounded parameters
+% using a log-odds transform as described at
+% https://mc-stan.org/docs/reference-manual/logit-transform-jacobian.html
+% -------------------------------------------------------------------------
+% INPUTS
+% - X      [double vector]   original bounded parameter vector
+% - a      [double vector]   lower bound of original parameters
+% - b      [double vector]   upper bound of original parameters
+% -------------------------------------------------------------------------
+% OUTPUTS
+% - Y      [double vector]   unbounded parameter vector
+% =========================================================================
+% Copyright (C) 2023 Willi Mutschler
+%
+% This is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% This is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+% -------------------------------------------------------------------------
+% This file is part of the replication files for the paper "Pruned Skewed
+% Kalman Filter and Smoother: Pruned Skewed Kalman Filter and Smoother:
+% With Applications to the Yield Curve and Asymmetric Monetary Policy Shocks"
+% by Gaygysyz Guljanov, Willi Mutschler, Mark Trede
+% =========================================================================
+Y = logit((X-a)./(b-a));
+
+function logit_u = logit(u)
+    logit_u = log(u./(1-u));
+end % logit
+
+end % transform_to_unbounded
\ No newline at end of file
diff --git a/matlab/row_header_width.m b/matlab/row_header_width.m
index 763be482fbba52f3b51b2e1de9dd4d6d084e2a93..d77b5fe4906ea8640d4a321881571d614486fef5 100644
--- a/matlab/row_header_width.m
+++ b/matlab/row_header_width.m
@@ -34,6 +34,7 @@ np = estim_params_.np;
 nvx = estim_params_.nvx;
 nvn = estim_params_.nvn;
 ncx = estim_params_.ncx;
+nsx = estim_params_.nsx;
 ncn = estim_params_.ncn;
 
 w = 0;
@@ -41,7 +42,7 @@ if np
     w = cellofchararraymaxlength(bayestopt_.name);
 end
 if nvx
-    w = max(w, cellofchararraymaxlength(M_.endo_names(estim_params_.var_exo(1:nvx,1))));
+    w = max(w, cellofchararraymaxlength(M_.exo_names(estim_params_.var_exo(1:nvx,1))));
 end
 if nvn
     w = max(w, cellofchararraymaxlength(M_.endo_names(estim_params_.var_endo(1:nvn,1))));
@@ -61,3 +62,6 @@ if ncn
         w = max(w, length(M_.endo_names{k1})+length(M_.endo_names{k2}));
     end
 end
+if nsx
+    w = max(w, cellofchararraymaxlength(M_.exo_names(estim_params_.skew_exo(1:nsx,1))));
+end
\ No newline at end of file
diff --git a/matlab/set_all_parameters.m b/matlab/set_all_parameters.m
index ed090a1768b04cfa2f6db10d3b6d9f67743d85b8..0da0a946e657a48d9d460d360bbfa7f925948fb3 100644
--- a/matlab/set_all_parameters.m
+++ b/matlab/set_all_parameters.m
@@ -54,6 +54,7 @@ nvx = estim_params_.nvx;
 ncx = estim_params_.ncx;
 nvn = estim_params_.nvn;
 ncn = estim_params_.ncn;
+nsx = estim_params_.nsx;
 np = estim_params_.np;
 if nvx || ncx
     Sigma_e = M_.Sigma_e;
@@ -70,8 +71,7 @@ if nvx
         Sigma_e(k,k) = xparam1(i)^2;
     end
 end
-% update offset
-offset = nvx;
+offset = nvx; % update offset
 
 % setting measument error variance; on the diagonal of Covariance matrix; used later
 % for updating covariances
@@ -81,9 +81,7 @@ if nvn
         H(k,k) = xparam1(i+offset)^2;
     end
 end
-
-% update offset
-offset = nvx+nvn;
+offset = nvx+nvn; % update offset
 
 % setting shocks covariances
 if ncx
@@ -95,8 +93,7 @@ if ncx
         Correlation_matrix(k2,k1) = Correlation_matrix(k1,k2);
     end
 end
-% update offset
-offset = nvx+nvn+ncx;
+offset = nvx+nvn+ncx; % update offset
 
 % setting measurement error covariances
 if ncn
@@ -108,11 +105,18 @@ if ncn
         Correlation_matrix_ME(k2,k1) = Correlation_matrix_ME(k1,k2);
     end
 end
+offset = nvx+nvn+ncx+ncn; % update offset
+
+% setting skewness coefficient of structural shocks
+if nsx
+    skew_exo = estim_params_.skew_exo;
+    for i=1:nsx
+        M_.Skew_e(skew_exo(i,1)) = xparam1(i+offset);
+    end
+end
+offset = nvx+nvn+ncx+ncn+nsx; % update offset
 
-% update offset
-offset = nvx+ncx+nvn+ncn;
 % setting structural parameters
-%
 if np
     M_.params(estim_params_.param_vals(:,1)) = xparam1(offset+1:end);
 end
@@ -139,4 +143,26 @@ if nvn || ncn
     end
     M_.H = H;
     M_.Correlation_matrix_ME=Correlation_matrix_ME;
+end
+% update parameters of CSN distributed shocks
+M_.csn.error_indicator = zeros(M_.exo_nbr,1);
+for jexo = 1:M_.exo_nbr
+    if M_.Skew_e(jexo,1) == 0 % Gaussian
+        M_.csn.Sigma_e(jexo,jexo) = M_.Sigma_e(jexo,jexo);
+        M_.csn.Gamma_e(jexo,jexo) = 0;
+    else % CSN
+        if abs(M_.Skew_e(jexo,1)) >= 0.995
+            %warning('Skewness parameter very close to theoretical bound')
+        end
+        [M_.csn.Sigma_e(jexo,jexo),M_.csn.Gamma_e(jexo,jexo),M_.csn.error_indicator(jexo)] = csnVarSkew_To_SigmaGamma_univariate(M_.Sigma_e(jexo,jexo),M_.Skew_e(jexo,1),false);
+    end
+end
+if all(M_.csn.error_indicator == 0)
+    if iszero(diag(M_.csn.Gamma_e))
+        M_.csn.mu_e = zeros(M_.exo_nbr,1);
+    else
+        M_.csn.mu_e  = -csnMean(zeros(M_.exo_nbr,1),M_.csn.Sigma_e,M_.csn.Gamma_e,M_.csn.nu_e,M_.csn.Delta_e); % ensures E[shocks]=0
+    end
+else
+    M_.csn.mu_e = [];
 end
\ No newline at end of file
diff --git a/matlab/set_parameters_locally.m b/matlab/set_parameters_locally.m
index b3fce1696a6d2fe5bd3c759879aedc444711be0e..75669f0fb177f755acd2e8f441d1aaf0acbaa2ba 100644
--- a/matlab/set_parameters_locally.m
+++ b/matlab/set_parameters_locally.m
@@ -39,6 +39,7 @@ nvx = estim_params_.nvx;
 ncx = estim_params_.ncx;
 nvn = estim_params_.nvn;
 ncn = estim_params_.ncn;
+nsx = estim_params_.nsx;
 np = estim_params_.np;
 Sigma_e = M_.Sigma_e;
 Correlation_matrix = M_.Correlation_matrix;
@@ -76,10 +77,42 @@ end
 % and update offset
 offset = offset + ncx + ncn;
 
+% setting skewness coefficient of structural shocks
+if nsx
+    skew_exo = estim_params_.skew_exo;
+    for i=1:nsx
+        M_.Skew_e(skew_exo(i,1)) = xparam1(i+offset);
+    end
+end
+offset = offset + nsx; % update offset
+
 % structural parameters
 if np
     M_.params(estim_params_.param_vals(:,1)) = xparam1(offset+1:end);
 end
 
 M_.Sigma_e = Sigma_e;
-M_.Correlation_matrix=Correlation_matrix;
\ No newline at end of file
+M_.Correlation_matrix=Correlation_matrix;
+
+% update parameters of CSN distributed shocks
+M_.csn.error_indicator = zeros(M_.exo_nbr,1);
+for jexo = 1:M_.exo_nbr
+    if M_.Skew_e(jexo,1) == 0 % Gaussian
+        M_.csn.Sigma_e(jexo,jexo) = M_.Sigma_e(jexo,jexo);
+        M_.csn.Gamma_e(jexo,jexo) = 0;
+    else % CSN
+        if abs(M_.Skew_e(jexo,1)) >= 0.995
+            %warning('Skewness parameter very close to theoretical bound')
+        end
+        [M_.csn.Sigma_e(jexo,jexo),M_.csn.Gamma_e(jexo,jexo),M_.csn.error_indicator(jexo)] = csnVarSkew_To_SigmaGamma_univariate(M_.Sigma_e(jexo,jexo),M_.Skew_e(jexo,1),false);
+    end
+end
+if all(M_.csn.error_indicator == 0)
+    if iszero(diag(M_.csn.Gamma_e))
+        M_.csn.mu_e = zeros(M_.exo_nbr,1);
+    else
+        M_.csn.mu_e  = -csnMean(zeros(M_.exo_nbr,1),M_.csn.Sigma_e,M_.csn.Gamma_e,M_.csn.nu_e,M_.csn.Delta_e); % ensures E[shocks]=0
+    end
+else
+    M_.csn.mu_e = [];
+end
\ No newline at end of file
diff --git a/matlab/stochastic_solver/simult.m b/matlab/stochastic_solver/simult.m
index 4787d0e6198ff69480b7aed25699dcbdc753e460..e98e07aac1aadb387cb70a5bf07f8b66f1df0818 100644
--- a/matlab/stochastic_solver/simult.m
+++ b/matlab/stochastic_solver/simult.m
@@ -77,11 +77,42 @@ nxs = length(i_exo_var);
 exo_simul = zeros(options_.periods,M_.exo_nbr);
 chol_S = chol(M_.Sigma_e(i_exo_var,i_exo_var));
 
+% update parameters of CSN distributed shocks with unit variance for simulation (as we re-scale with chol_S)
+M_.csn.error_indicator = zeros(M_.exo_nbr,1);
+for jexo = 1:M_.exo_nbr
+    if M_.Skew_e(jexo,1) == 0 % Gaussian
+        M_.csn.Sigma_e(jexo,jexo) = 1;
+        M_.csn.Gamma_e(jexo,jexo) = 0;
+    else % CSN
+        if abs(M_.Skew_e(jexo,1)) >= 0.995
+            %warning('Skewness parameter very close to theoretical bound')
+        end
+        [M_.csn.Sigma_e(jexo,jexo),M_.csn.Gamma_e(jexo,jexo),M_.csn.error_indicator(jexo)] = csnVarSkew_To_SigmaGamma_univariate(1,M_.Skew_e(jexo,1),true);
+    end
+end
+M_.csn.mu_e = nan(M_.exo_nbr,1);
+if all(M_.csn.error_indicator(i_exo_var) == 0)
+    if iszero(diag(M_.csn.Gamma_e(i_exo_var,i_exo_var)))
+        M_.csn.mu_e(i_exo_var,1) = zeros(nxs,1);
+    else
+        M_.csn.mu_e(i_exo_var,1) = -csnMean(zeros(nxs,1),M_.csn.Sigma_e(i_exo_var,i_exo_var),M_.csn.Gamma_e(i_exo_var,i_exo_var),M_.csn.nu_e(i_exo_var,1),M_.csn.Delta_e(i_exo_var,i_exo_var)); % ensures E[shocks]=0
+    end
+else
+    M_.csn.mu_e = [];
+end
+
 for i=1:replic
     if ~isempty(M_.Sigma_e)
         % we fill the shocks row wise to have the same values
         % independently of the length of the simulation
-        exo_simul(:,i_exo_var) = randn(nxs,options_.periods)'*chol_S;
+        if iszero(diag(M_.csn.Gamma_e(i_exo_var,i_exo_var)))
+            exo_simul(:,i_exo_var) = transpose(randn(nxs,options_.periods))*chol_S;
+        else
+            if ~isdiag(chol_S)
+                error('Correlated CSN shocks are currently not supported.')
+            end
+            exo_simul(:,i_exo_var) = transpose(csnRandDirect(options_.periods, M_.csn.mu_e(i_exo_var,1), M_.csn.Sigma_e(i_exo_var,i_exo_var), M_.csn.Gamma_e(i_exo_var,i_exo_var), M_.csn.nu_e(i_exo_var,1), M_.csn.Delta_e(i_exo_var,i_exo_var)))*chol_S;
+        end
     end
     y_ = simult_(M_,options_,y0,dr,exo_simul,order);
     % elimninating initial value
diff --git a/matlab/stochastic_solver/stoch_simul.m b/matlab/stochastic_solver/stoch_simul.m
index 376de52368289594b0e0a1abfa3f4275cd53a234..fba0fb77ea79e75a09c5388ff1473fa87586bea5 100644
--- a/matlab/stochastic_solver/stoch_simul.m
+++ b/matlab/stochastic_solver/stoch_simul.m
@@ -141,6 +141,19 @@ if ~options_.noprint
             lh = cellofchararraymaxlength(labels)+2;
             dyn_latex_table(M_, options_, my_title, 'covar_ex_shocks', headers, labels, M_.Sigma_e, lh, 10, 6);
         end
+        if ~all(M_.Skew_e==0)
+            my_title='SKEWNESS OF EXOGENOUS SHOCKS';
+            labels = M_.exo_names;
+            headers = vertcat('Variables', {'Skewness'});
+            lh = cellofchararraymaxlength(labels)+2;
+            dyntable(options_, my_title, headers, labels, M_.Skew_e, lh, 10, 6);
+            if options_.TeX
+                labels = M_.exo_names_tex;
+                headers = vertcat('Variables', {'Skewness'});
+                lh = cellofchararraymaxlength(labels)+2;
+                dyn_latex_table(M_, options_, my_title, 'skew_ex_shocks', headers, labels, M_.Skew_e, lh, 10, 6);
+            end
+        end
         if ~all(diag(M_.H)==0)
             my_title='MATRIX OF COVARIANCE OF MEASUREMENT ERRORS';
             labels = cellfun(@(x) horzcat('SE_', x), options_.varobs, 'UniformOutput', false);
diff --git a/matlab/utilities/estimation/check_prior_stderr_corr.m b/matlab/utilities/estimation/check_prior_stderr_corr_skew.m
similarity index 81%
rename from matlab/utilities/estimation/check_prior_stderr_corr.m
rename to matlab/utilities/estimation/check_prior_stderr_corr_skew.m
index 867e0ba7cd4876dc1c53f4ae5f72b01dda6305a0..23d5dd6d66c40ce0f52943704872a2a6d7bd59ef 100644
--- a/matlab/utilities/estimation/check_prior_stderr_corr.m
+++ b/matlab/utilities/estimation/check_prior_stderr_corr_skew.m
@@ -1,8 +1,9 @@
-function check_prior_stderr_corr(estim_params_,bayestopt_)
-% function check_prior_stderr_corr(estim_params_,bayestopt_)
+function check_prior_stderr_corr_skew(estim_params_,bayestopt_)
+% function check_prior_stderr_corr_skew(estim_params_,bayestopt_)
 % -------------------------------------------------------------------------
-% Check if the prior allows for negative standard deviations and
-% correlations larger than +-1. If so, issue a warning.
+% Check if the prior allows for negative standard deviations,
+% correlations larger than +-1, or skewness larger than +-1.
+% If so, issue a warning.
 % -------------------------------------------------------------------------
 % INPUTS
 %  o estim_params_:           [struct] information on estimated parameters
@@ -50,4 +51,9 @@ offset = nvx+nvn+ncx;
 ncn = estim_params_.ncn; % number of corr parameters for measurement errors
 if ncn && (any(bayestopt_.p3(1+offset:offset+ncn)<-1) || any(bayestopt_.p4(1+offset:offset+ncn)>1))
     warning('Your prior allows for correlations between measurement errors larger than +-1 and will not integrate to 1 due to truncation. Please change your prior')
+end
+offset = nvx+nvn+ncx+ncn;
+nsx = estim_params_.nsx; % number of skewness parameters for structural shocks
+if nsx && (any(bayestopt_.p3(1+offset:offset+nsx)<-1) || any(bayestopt_.p4(1+offset:offset+nsx)>1))
+    warning('Your prior allows for skewness parameters larger than +-1 and will not integrate to 1 due to truncation. Please change your prior')
 end
\ No newline at end of file